diff options
Diffstat (limited to 'drivers/media/video/cx231xx/cx231xx-cards.c')
-rw-r--r-- | drivers/media/video/cx231xx/cx231xx-cards.c | 86 |
1 files changed, 40 insertions, 46 deletions
diff --git a/drivers/media/video/cx231xx/cx231xx-cards.c b/drivers/media/video/cx231xx/cx231xx-cards.c index 60b021e79864..919ed77b32f2 100644 --- a/drivers/media/video/cx231xx/cx231xx-cards.c +++ b/drivers/media/video/cx231xx/cx231xx-cards.c @@ -843,25 +843,34 @@ 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); + clear_bit(dev->devno, &cx231xx_devused); + + 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; } /* * cx231xx_init_dev() * allocates and inits the device structs, registers i2c bus and v4l device */ -static int cx231xx_init_dev(struct cx231xx **devhandle, struct usb_device *udev, +static int cx231xx_init_dev(struct cx231xx *dev, struct usb_device *udev, int minor) { - struct cx231xx *dev = *devhandle; int retval = -ENOMEM; int errCode; unsigned int maxh, maxw; @@ -1016,7 +1025,6 @@ static int cx231xx_usb_probe(struct usb_interface *interface, int i, isoc_pipe = 0; char *speed; char descr[255] = ""; - struct usb_interface *lif = NULL; struct usb_interface_assoc_descriptor *assoc_desc; udev = usb_get_dev(interface_to_usbdev(interface)); @@ -1030,21 +1038,21 @@ static int cx231xx_usb_probe(struct usb_interface *interface, return -ENODEV; /* Check to see next free device and mark as used */ - nr = find_first_zero_bit(&cx231xx_devused, CX231XX_MAXBOARDS); - cx231xx_devused |= 1 << nr; - - if (nr >= CX231XX_MAXBOARDS) { - cx231xx_err(DRIVER_NAME - ": Supports only %i cx231xx boards.\n", CX231XX_MAXBOARDS); - cx231xx_devused &= ~(1 << nr); - return -ENOMEM; - } + do { + nr = find_first_zero_bit(&cx231xx_devused, CX231XX_MAXBOARDS); + if (nr >= CX231XX_MAXBOARDS) { + /* No free device slots */ + cx231xx_err(DRIVER_NAME ": Supports only %i devices.\n", + CX231XX_MAXBOARDS); + return -ENOMEM; + } + } while (test_and_set_bit(nr, &cx231xx_devused)); /* allocate memory for our device state and initialize it */ dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (dev == NULL) { cx231xx_err(DRIVER_NAME ": out of memory!\n"); - cx231xx_devused &= ~(1 << nr); + clear_bit(dev->devno, &cx231xx_devused); return -ENOMEM; } @@ -1071,9 +1079,6 @@ static int cx231xx_usb_probe(struct usb_interface *interface, /* init CIR module TBD */ - /* store the current interface */ - lif = interface; - /*mode_tv: digital=1 or analog=0*/ dev->mode_tv = 0; @@ -1113,9 +1118,6 @@ static int cx231xx_usb_probe(struct usb_interface *interface, le16_to_cpu(udev->descriptor.idProduct), dev->max_iad_interface_count); - /* store the interface 0 back */ - lif = udev->actconfig->interface[0]; - /* increment interface count */ dev->interface_count++; @@ -1126,7 +1128,7 @@ static int cx231xx_usb_probe(struct usb_interface *interface, if (assoc_desc->bFirstInterface != ifnum) { cx231xx_err(DRIVER_NAME ": Not found " "matching IAD interface\n"); - cx231xx_devused &= ~(1 << nr); + clear_bit(dev->devno, &cx231xx_devused); kfree(dev); dev = NULL; return -ENODEV; @@ -1135,7 +1137,7 @@ static int cx231xx_usb_probe(struct usb_interface *interface, cx231xx_info("registering interface %d\n", ifnum); /* save our data pointer in this interface device */ - usb_set_intfdata(lif, dev); + usb_set_intfdata(interface, dev); /* * AV device initialization - only done at the last interface @@ -1145,19 +1147,19 @@ static int cx231xx_usb_probe(struct usb_interface *interface, retval = v4l2_device_register(&interface->dev, &dev->v4l2_dev); if (retval) { cx231xx_errdev("v4l2_device_register failed\n"); - cx231xx_devused &= ~(1 << nr); + clear_bit(dev->devno, &cx231xx_devused); kfree(dev); dev = NULL; return -EIO; } /* allocate device struct */ - retval = cx231xx_init_dev(&dev, udev, nr); + retval = cx231xx_init_dev(dev, udev, nr); if (retval) { - cx231xx_devused &= ~(1 << dev->devno); + clear_bit(dev->devno, &cx231xx_devused); v4l2_device_unregister(&dev->v4l2_dev); kfree(dev); dev = NULL; - usb_set_intfdata(lif, NULL); + usb_set_intfdata(interface, NULL); return retval; } @@ -1178,7 +1180,7 @@ static int cx231xx_usb_probe(struct usb_interface *interface, if (dev->video_mode.alt_max_pkt_size == NULL) { cx231xx_errdev("out of memory!\n"); - cx231xx_devused &= ~(1 << nr); + clear_bit(dev->devno, &cx231xx_devused); v4l2_device_unregister(&dev->v4l2_dev); kfree(dev); dev = NULL; @@ -1212,7 +1214,7 @@ static int cx231xx_usb_probe(struct usb_interface *interface, if (dev->vbi_mode.alt_max_pkt_size == NULL) { cx231xx_errdev("out of memory!\n"); - cx231xx_devused &= ~(1 << nr); + clear_bit(dev->devno, &cx231xx_devused); v4l2_device_unregister(&dev->v4l2_dev); kfree(dev); dev = NULL; @@ -1247,7 +1249,7 @@ static int cx231xx_usb_probe(struct usb_interface *interface, if (dev->sliced_cc_mode.alt_max_pkt_size == NULL) { cx231xx_errdev("out of memory!\n"); - cx231xx_devused &= ~(1 << nr); + clear_bit(dev->devno, &cx231xx_devused); v4l2_device_unregister(&dev->v4l2_dev); kfree(dev); dev = NULL; @@ -1283,7 +1285,7 @@ static int cx231xx_usb_probe(struct usb_interface *interface, if (dev->ts1_mode.alt_max_pkt_size == NULL) { cx231xx_errdev("out of memory!\n"); - cx231xx_devused &= ~(1 << nr); + clear_bit(dev->devno, &cx231xx_devused); v4l2_device_unregister(&dev->v4l2_dev); kfree(dev); dev = NULL; @@ -1334,10 +1336,9 @@ static void cx231xx_usb_disconnect(struct usb_interface *interface) if (!dev->udev) return; - flush_request_modules(dev); + dev->state |= DEV_DISCONNECTED; - /* delete v4l2 device */ - v4l2_device_unregister(&dev->v4l2_dev); + flush_request_modules(dev); /* wait until all current v4l2 io is finished then deallocate resources */ @@ -1351,31 +1352,24 @@ static void cx231xx_usb_disconnect(struct usb_interface *interface) "deallocation are deferred on close.\n", video_device_node_name(dev->vdev)); - dev->state |= DEV_MISCONFIGURED; + /* Even having users, it is safe to remove the RC i2c driver */ + cx231xx_ir_exit(dev); + if (dev->USE_ISO) cx231xx_uninit_isoc(dev); else cx231xx_uninit_bulk(dev); - dev->state |= DEV_DISCONNECTED; wake_up_interruptible(&dev->wait_frame); 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 = { |