diff options
Diffstat (limited to 'drivers/media/video/cx231xx')
-rw-r--r-- | drivers/media/video/cx231xx/Kconfig | 6 | ||||
-rw-r--r-- | drivers/media/video/cx231xx/cx231xx-audio.c | 24 | ||||
-rw-r--r-- | drivers/media/video/cx231xx/cx231xx-cards.c | 86 | ||||
-rw-r--r-- | drivers/media/video/cx231xx/cx231xx-core.c | 7 | ||||
-rw-r--r-- | drivers/media/video/cx231xx/cx231xx-dvb.c | 4 | ||||
-rw-r--r-- | drivers/media/video/cx231xx/cx231xx-input.c | 11 | ||||
-rw-r--r-- | drivers/media/video/cx231xx/cx231xx-vbi.c | 4 | ||||
-rw-r--r-- | drivers/media/video/cx231xx/cx231xx-video.c | 14 | ||||
-rw-r--r-- | drivers/media/video/cx231xx/cx231xx.h | 2 |
9 files changed, 88 insertions, 70 deletions
diff --git a/drivers/media/video/cx231xx/Kconfig b/drivers/media/video/cx231xx/Kconfig index ae85a7a..446f692 100644 --- a/drivers/media/video/cx231xx/Kconfig +++ b/drivers/media/video/cx231xx/Kconfig @@ -40,10 +40,10 @@ config VIDEO_CX231XX_ALSA config VIDEO_CX231XX_DVB tristate "DVB/ATSC Support for Cx231xx based TV cards" - depends on VIDEO_CX231XX && DVB_CORE + depends on VIDEO_CX231XX && DVB_CORE && DVB_CAPTURE_DRIVERS select VIDEOBUF_DVB - select MEDIA_TUNER_XC5000 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_NXP18271 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE select DVB_MB86A20S if !DVB_FE_CUSTOMISE ---help--- diff --git a/drivers/media/video/cx231xx/cx231xx-audio.c b/drivers/media/video/cx231xx/cx231xx-audio.c index 30d13c1..a2c2b7d 100644 --- a/drivers/media/video/cx231xx/cx231xx-audio.c +++ b/drivers/media/video/cx231xx/cx231xx-audio.c @@ -111,6 +111,9 @@ static void cx231xx_audio_isocirq(struct urb *urb) struct snd_pcm_substream *substream; struct snd_pcm_runtime *runtime; + if (dev->state & DEV_DISCONNECTED) + return; + switch (urb->status) { case 0: /* success */ case -ETIMEDOUT: /* NAK */ @@ -196,6 +199,9 @@ static void cx231xx_audio_bulkirq(struct urb *urb) struct snd_pcm_substream *substream; struct snd_pcm_runtime *runtime; + if (dev->state & DEV_DISCONNECTED) + return; + switch (urb->status) { case 0: /* success */ case -ETIMEDOUT: /* NAK */ @@ -273,6 +279,9 @@ static int cx231xx_init_audio_isoc(struct cx231xx *dev) cx231xx_info("%s: Starting ISO AUDIO transfers\n", __func__); + if (dev->state & DEV_DISCONNECTED) + return -ENODEV; + sb_size = CX231XX_ISO_NUM_AUDIO_PACKETS * dev->adev.max_pkt_size; for (i = 0; i < CX231XX_AUDIO_BUFS; i++) { @@ -298,7 +307,7 @@ static int cx231xx_init_audio_isoc(struct cx231xx *dev) urb->context = dev; urb->pipe = usb_rcvisocpipe(dev->udev, dev->adev.end_point_addr); - urb->transfer_flags = URB_ISO_ASAP; + urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; urb->transfer_buffer = dev->adev.transfer_buffer[i]; urb->interval = 1; urb->complete = cx231xx_audio_isocirq; @@ -331,6 +340,9 @@ static int cx231xx_init_audio_bulk(struct cx231xx *dev) cx231xx_info("%s: Starting BULK AUDIO transfers\n", __func__); + if (dev->state & DEV_DISCONNECTED) + return -ENODEV; + sb_size = CX231XX_NUM_AUDIO_PACKETS * dev->adev.max_pkt_size; for (i = 0; i < CX231XX_AUDIO_BUFS; i++) { @@ -356,7 +368,7 @@ static int cx231xx_init_audio_bulk(struct cx231xx *dev) urb->context = dev; urb->pipe = usb_rcvbulkpipe(dev->udev, dev->adev.end_point_addr); - urb->transfer_flags = 0; + urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; urb->transfer_buffer = dev->adev.transfer_buffer[i]; urb->complete = cx231xx_audio_bulkirq; urb->transfer_buffer_length = sb_size; @@ -432,6 +444,11 @@ static int snd_cx231xx_capture_open(struct snd_pcm_substream *substream) return -ENODEV; } + if (dev->state & DEV_DISCONNECTED) { + cx231xx_errdev("Can't open. the device was removed.\n"); + return -ENODEV; + } + /* Sets volume, mute, etc */ dev->mute = 0; @@ -571,6 +588,9 @@ static int snd_cx231xx_capture_trigger(struct snd_pcm_substream *substream, struct cx231xx *dev = snd_pcm_substream_chip(substream); int retval; + if (dev->state & DEV_DISCONNECTED) + return -ENODEV; + spin_lock(&dev->adev.slock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: diff --git a/drivers/media/video/cx231xx/cx231xx-cards.c b/drivers/media/video/cx231xx/cx231xx-cards.c index 60b021e..919ed77 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 = { diff --git a/drivers/media/video/cx231xx/cx231xx-core.c b/drivers/media/video/cx231xx/cx231xx-core.c index d4457f9..08dd930 100644 --- a/drivers/media/video/cx231xx/cx231xx-core.c +++ b/drivers/media/video/cx231xx/cx231xx-core.c @@ -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; @@ -1071,7 +1074,7 @@ int cx231xx_init_isoc(struct cx231xx *dev, int max_packets, sb_size, cx231xx_isoc_irq_callback, dma_q, 1); urb->number_of_packets = max_packets; - urb->transfer_flags = URB_ISO_ASAP; + urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; k = 0; for (j = 0; j < max_packets; j++) { @@ -1182,7 +1185,7 @@ int cx231xx_init_bulk(struct cx231xx *dev, int max_packets, return -ENOMEM; } dev->video_mode.bulk_ctl.urb[i] = urb; - urb->transfer_flags = 0; + urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; dev->video_mode.bulk_ctl.transfer_buffer[i] = usb_alloc_coherent(dev->udev, sb_size, GFP_KERNEL, diff --git a/drivers/media/video/cx231xx/cx231xx-dvb.c b/drivers/media/video/cx231xx/cx231xx-dvb.c index da9a4a0..7c4e360 100644 --- a/drivers/media/video/cx231xx/cx231xx-dvb.c +++ b/drivers/media/video/cx231xx/cx231xx-dvb.c @@ -196,7 +196,7 @@ static inline int dvb_isoc_copy(struct cx231xx *dev, struct urb *urb) if (!dev) return 0; - if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED)) + if (dev->state & DEV_DISCONNECTED) return 0; if (urb->status < 0) { @@ -228,7 +228,7 @@ static inline int dvb_bulk_copy(struct cx231xx *dev, struct urb *urb) if (!dev) return 0; - if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED)) + if (dev->state & DEV_DISCONNECTED) return 0; if (urb->status < 0) { diff --git a/drivers/media/video/cx231xx/cx231xx-input.c b/drivers/media/video/cx231xx/cx231xx-input.c index 45e14ca..96176e9 100644 --- a/drivers/media/video/cx231xx/cx231xx-input.c +++ b/drivers/media/video/cx231xx/cx231xx-input.c @@ -27,12 +27,16 @@ static int get_key_isdbt(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) { + int rc; u8 cmd, scancode; dev_dbg(&ir->rc->input_dev->dev, "%s\n", __func__); /* poll IR chip */ - if (1 != i2c_master_recv(ir->c, &cmd, 1)) + rc = i2c_master_recv(ir->c, &cmd, 1); + if (rc < 0) + return rc; + if (rc != 1) return -EIO; /* it seems that 0xFE indicates that a button is still hold @@ -102,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; } diff --git a/drivers/media/video/cx231xx/cx231xx-vbi.c b/drivers/media/video/cx231xx/cx231xx-vbi.c index 1c7a4da..8cdee5f 100644 --- a/drivers/media/video/cx231xx/cx231xx-vbi.c +++ b/drivers/media/video/cx231xx/cx231xx-vbi.c @@ -93,7 +93,7 @@ static inline int cx231xx_isoc_vbi_copy(struct cx231xx *dev, struct urb *urb) if (!dev) return 0; - if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED)) + if (dev->state & DEV_DISCONNECTED) return 0; if (urb->status < 0) { @@ -452,7 +452,7 @@ int cx231xx_init_vbi_isoc(struct cx231xx *dev, int max_packets, return -ENOMEM; } dev->vbi_mode.bulk_ctl.urb[i] = urb; - urb->transfer_flags = 0; + urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; dev->vbi_mode.bulk_ctl.transfer_buffer[i] = kzalloc(sb_size, GFP_KERNEL); diff --git a/drivers/media/video/cx231xx/cx231xx-video.c b/drivers/media/video/cx231xx/cx231xx-video.c index 6e81f97..829a41b 100644 --- a/drivers/media/video/cx231xx/cx231xx-video.c +++ b/drivers/media/video/cx231xx/cx231xx-video.c @@ -337,7 +337,7 @@ static inline int cx231xx_isoc_copy(struct cx231xx *dev, struct urb *urb) if (!dev) return 0; - if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED)) + if (dev->state & DEV_DISCONNECTED) return 0; if (urb->status < 0) { @@ -440,7 +440,7 @@ static inline int cx231xx_bulk_copy(struct cx231xx *dev, struct urb *urb) if (!dev) return 0; - if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED)) + if (dev->state & DEV_DISCONNECTED) return 0; if (urb->status < 0) { @@ -1000,12 +1000,6 @@ static int check_dev(struct cx231xx *dev) cx231xx_errdev("v4l2 ioctl: device not present\n"); return -ENODEV; } - - if (dev->state & DEV_MISCONFIGURED) { - cx231xx_errdev("v4l2 ioctl: device is misconfigured; " - "close and open it again\n"); - return -EIO; - } return 0; } @@ -2347,7 +2341,8 @@ static int cx231xx_v4l2_close(struct file *filp) return 0; } - if (dev->users == 1) { + dev->users--; + if (!dev->users) { videobuf_stop(&fh->vb_vidq); videobuf_mmap_free(&fh->vb_vidq); @@ -2374,7 +2369,6 @@ static int cx231xx_v4l2_close(struct file *filp) cx231xx_set_alt_setting(dev, INDEX_VIDEO, 0); } kfree(fh); - dev->users--; wake_up_interruptible_nr(&dev->open, 1); return 0; } diff --git a/drivers/media/video/cx231xx/cx231xx.h b/drivers/media/video/cx231xx/cx231xx.h index 2000bc6..e174475 100644 --- a/drivers/media/video/cx231xx/cx231xx.h +++ b/drivers/media/video/cx231xx/cx231xx.h @@ -377,7 +377,6 @@ struct cx231xx_board { enum cx231xx_dev_state { DEV_INITIALIZED = 0x01, DEV_DISCONNECTED = 0x02, - DEV_MISCONFIGURED = 0x04, }; enum AFE_MODE { @@ -621,6 +620,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 */ |