[media] cx231xx: Fix unregister logic
authorMauro Carvalho Chehab <mchehab@redhat.com>
Tue, 10 Jan 2012 11:20:01 +0000 (09:20 -0200)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Wed, 11 Jan 2012 00:35:29 +0000 (22:35 -0200)
There are several weirdness at the unregister logic.

First of all, IR has a poll thread. This thread needs to be
removed, as it uses some resources associated to the main driver.
So, the driver needs to explicitly unregister the I2C client for
ir-kbd-i2c.

If, for some reason, the driver needs to wait for a close()
to happen, not all memories will be freed, because the free
logic were in the wrong place.

Also, v4l2_device_unregister() seems to be called too early,
as devices are still using it.

Finally, even with the device disconnected, there is one
USB function call that will still try to talk with it.

Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/video/cx231xx/cx231xx-cards.c
drivers/media/video/cx231xx/cx231xx-core.c
drivers/media/video/cx231xx/cx231xx-input.c
drivers/media/video/cx231xx/cx231xx.h
drivers/media/video/ir-kbd-i2c.c

index 2a28882ee1d32654a0374fa24dca7fd2d0f2ad2e..bd82f017ccdfe25e45155ff4b3fecaec07421e43 100644 (file)
@@ -843,15 +843,25 @@ void cx231xx_release_resources(struct cx231xx *dev)
 
        cx231xx_remove_from_devlist(dev);
 
+       cx231xx_ir_exit(dev);
+
        /* Release I2C buses */
        cx231xx_dev_uninit(dev);
 
-       cx231xx_ir_exit(dev);
+       /* delete v4l2 device */
+       v4l2_device_unregister(&dev->v4l2_dev);
 
        usb_put_dev(dev->udev);
 
        /* Mark device as unused */
        cx231xx_devused &= ~(1 << dev->devno);
+
+       kfree(dev->video_mode.alt_max_pkt_size);
+       kfree(dev->vbi_mode.alt_max_pkt_size);
+       kfree(dev->sliced_cc_mode.alt_max_pkt_size);
+       kfree(dev->ts1_mode.alt_max_pkt_size);
+       kfree(dev);
+       dev = NULL;
 }
 
 /*
@@ -1329,9 +1339,6 @@ static void cx231xx_usb_disconnect(struct usb_interface *interface)
 
        flush_request_modules(dev);
 
-       /* delete v4l2 device */
-       v4l2_device_unregister(&dev->v4l2_dev);
-
        /* wait until all current v4l2 io is finished then deallocate
           resources */
        mutex_lock(&dev->lock);
@@ -1344,6 +1351,9 @@ static void cx231xx_usb_disconnect(struct usb_interface *interface)
                     "deallocation are deferred on close.\n",
                     video_device_node_name(dev->vdev));
 
+               /* Even having users, it is safe to remove the RC i2c driver */
+               cx231xx_ir_exit(dev);
+
                dev->state |= DEV_MISCONFIGURED;
                if (dev->USE_ISO)
                        cx231xx_uninit_isoc(dev);
@@ -1354,21 +1364,14 @@ static void cx231xx_usb_disconnect(struct usb_interface *interface)
                wake_up_interruptible(&dev->wait_stream);
        } else {
                dev->state |= DEV_DISCONNECTED;
-               cx231xx_release_resources(dev);
        }
 
        cx231xx_close_extension(dev);
 
        mutex_unlock(&dev->lock);
 
-       if (!dev->users) {
-               kfree(dev->video_mode.alt_max_pkt_size);
-               kfree(dev->vbi_mode.alt_max_pkt_size);
-               kfree(dev->sliced_cc_mode.alt_max_pkt_size);
-               kfree(dev->ts1_mode.alt_max_pkt_size);
-               kfree(dev);
-               dev = NULL;
-       }
+       if (!dev->users)
+               cx231xx_release_resources(dev);
 }
 
 static struct usb_driver cx231xx_usb_driver = {
index d4457f9488eee6c6e06feb1dd7c7ef727d6b91b8..39e9878cb38f14151bff28c17994a7df2e248a94 100644 (file)
@@ -166,6 +166,9 @@ int cx231xx_send_usb_command(struct cx231xx_i2c *i2c_bus,
        u8 _i2c_nostop = 0;
        u8 _i2c_reserve = 0;
 
+       if (dev->state & DEV_DISCONNECTED)
+               return -ENODEV;
+
        /* Get the I2C period, nostop and reserve parameters */
        _i2c_period = i2c_bus->i2c_period;
        _i2c_nostop = i2c_bus->i2c_nostop;
index 8a75a908e7096477fab98090f0960c2a966b8baf..96176e9db5a28faa01086e1aca1c364b401efe15 100644 (file)
@@ -106,11 +106,14 @@ int cx231xx_ir_init(struct cx231xx *dev)
        ir_i2c_bus = cx231xx_boards[dev->model].ir_i2c_master;
        dev_dbg(&dev->udev->dev, "Trying to bind ir at bus %d, addr 0x%02x\n",
                ir_i2c_bus, info.addr);
-       i2c_new_device(&dev->i2c_bus[ir_i2c_bus].i2c_adap, &info);
+       dev->ir_i2c_client = i2c_new_device(&dev->i2c_bus[ir_i2c_bus].i2c_adap, &info);
 
        return 0;
 }
 
 void cx231xx_ir_exit(struct cx231xx *dev)
 {
+       if (dev->ir_i2c_client)
+               i2c_unregister_device(dev->ir_i2c_client);
+       dev->ir_i2c_client = NULL;
 }
index 2000bc64c49784af168855f9dfab150b078a6d48..5d498a4112d7aee84ded8aede93f9673d3200d45 100644 (file)
@@ -621,6 +621,7 @@ struct cx231xx {
 
        /* For I2C IR support */
        struct IR_i2c_init_data    init_data;
+       struct i2c_client          *ir_i2c_client;
 
        unsigned int stream_on:1;       /* Locks streams */
        unsigned int vbi_stream_on:1;   /* Locks streams for VBI */
index 37d0c20125190a8e070144ee0a283cb552e0849c..a7c41d32f4140b02e03350d2e4222b2a0fd38430 100644 (file)
@@ -498,11 +498,3 @@ static void __exit ir_fini(void)
 
 module_init(ir_init);
 module_exit(ir_fini);
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */