diff options
Diffstat (limited to 'drivers/media/usb')
116 files changed, 3732 insertions, 2963 deletions
diff --git a/drivers/media/usb/airspy/airspy.c b/drivers/media/usb/airspy/airspy.c index 462eb8423506..08f0920cf6ca 100644 --- a/drivers/media/usb/airspy/airspy.c +++ b/drivers/media/usb/airspy/airspy.c @@ -482,12 +482,13 @@ static int airspy_queue_setup(struct vb2_queue *vq, unsigned int *nplanes, unsigned int sizes[], struct device *alloc_devs[]) { struct airspy *s = vb2_get_drv_priv(vq); + unsigned int q_num_bufs = vb2_get_num_buffers(vq); dev_dbg(s->dev, "nbuffers=%d\n", *nbuffers); /* Need at least 8 buffers */ - if (vq->num_buffers + *nbuffers < 8) - *nbuffers = 8 - vq->num_buffers; + if (q_num_bufs + *nbuffers < 8) + *nbuffers = 8 - q_num_bufs; *nplanes = 1; sizes[0] = PAGE_ALIGN(s->buffersize); @@ -602,8 +603,6 @@ static const struct vb2_ops airspy_vb2_ops = { .buf_queue = airspy_buf_queue, .start_streaming = airspy_start_streaming, .stop_streaming = airspy_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int airspy_querycap(struct file *file, void *fh, @@ -1016,6 +1015,7 @@ static int airspy_probe(struct usb_interface *intf, s->vb_queue.ops = &airspy_vb2_ops; s->vb_queue.mem_ops = &vb2_vmalloc_memops; s->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + s->vb_queue.lock = &s->vb_queue_lock; ret = vb2_queue_init(&s->vb_queue); if (ret) { dev_err(s->dev, "Could not initialize vb2 queue\n"); @@ -1025,7 +1025,6 @@ static int airspy_probe(struct usb_interface *intf, /* Init video_device structure */ s->vdev = airspy_template; s->vdev.queue = &s->vb_queue; - s->vdev.queue->lock = &s->vb_queue_lock; video_set_drvdata(&s->vdev, s); /* Register the v4l2_device structure */ diff --git a/drivers/media/usb/as102/as102_usb_drv.c b/drivers/media/usb/as102/as102_usb_drv.c index 50419e8ae56c..e0ef66a522e2 100644 --- a/drivers/media/usb/as102/as102_usb_drv.c +++ b/drivers/media/usb/as102/as102_usb_drv.c @@ -259,7 +259,7 @@ static int as102_alloc_usb_stream_buffer(struct as102_dev_t *dev) for (i = 0; i < MAX_STREAM_URB; i++) { struct urb *urb; - urb = usb_alloc_urb(0, GFP_ATOMIC); + urb = usb_alloc_urb(0, GFP_KERNEL); if (urb == NULL) { as102_free_usb_stream_buffer(dev); return -ENOMEM; @@ -303,10 +303,8 @@ static void as102_usb_release(struct kref *kref) struct as102_dev_t *as102_dev; as102_dev = container_of(kref, struct as102_dev_t, kref); - if (as102_dev != NULL) { - usb_put_dev(as102_dev->bus_adap.usb_dev); - kfree(as102_dev); - } + usb_put_dev(as102_dev->bus_adap.usb_dev); + kfree(as102_dev); } static void as102_usb_disconnect(struct usb_interface *intf) diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c index 877e85a451cb..1e246b47766d 100644 --- a/drivers/media/usb/au0828/au0828-core.c +++ b/drivers/media/usb/au0828/au0828-core.c @@ -211,7 +211,7 @@ static int au0828_media_device_init(struct au0828_dev *dev, static void au0828_media_graph_notify(struct media_entity *new, void *notify_data) { - struct au0828_dev *dev = (struct au0828_dev *) notify_data; + struct au0828_dev *dev = notify_data; int ret; struct media_entity *entity, *mixer = NULL, *decoder = NULL; @@ -250,7 +250,7 @@ static void au0828_media_graph_notify(struct media_entity *new, create_link: if (decoder && mixer) { - ret = media_get_pad_index(decoder, false, + ret = media_get_pad_index(decoder, MEDIA_PAD_FL_SOURCE, PAD_SIGNAL_AUDIO); if (ret >= 0) ret = media_create_pad_link(decoder, ret, @@ -627,14 +627,9 @@ static int au0828_media_device_register(struct au0828_dev *dev, /* register entity_notify callback */ dev->entity_notify.notify_data = (void *) dev; dev->entity_notify.notify = (void *) au0828_media_graph_notify; - ret = media_device_register_entity_notify(dev->media_dev, + media_device_register_entity_notify(dev->media_dev, &dev->entity_notify); - if (ret) { - dev_err(&udev->dev, - "Media Device register entity_notify Error: %d\n", - ret); - return ret; - } + /* set enable_source */ mutex_lock(&dev->media_dev->graph_mutex); dev->media_dev->source_priv = (void *) dev; diff --git a/drivers/media/usb/au0828/au0828-dvb.c b/drivers/media/usb/au0828/au0828-dvb.c index 2a8691a0d7fa..5d0447ff7d06 100644 --- a/drivers/media/usb/au0828/au0828-dvb.c +++ b/drivers/media/usb/au0828/au0828-dvb.c @@ -97,7 +97,7 @@ static void au0828_restart_dvb_streaming(struct work_struct *work); static void au0828_bulk_timeout(struct timer_list *t) { - struct au0828_dev *dev = from_timer(dev, t, bulk_timeout); + struct au0828_dev *dev = timer_container_of(dev, t, bulk_timeout); dprintk(1, "%s called\n", __func__); dev->bulk_timeout_running = 0; @@ -143,7 +143,7 @@ static void urb_completion(struct urb *purb) */ dprintk(1, "%s cancelling bulk timeout\n", __func__); dev->bulk_timeout_running = 0; - del_timer(&dev->bulk_timeout); + timer_delete(&dev->bulk_timeout); } /* Feed the transport payload into the kernel demux */ @@ -168,7 +168,7 @@ static int stop_urb_transfer(struct au0828_dev *dev) if (dev->bulk_timeout_running == 1) { dev->bulk_timeout_running = 0; - del_timer(&dev->bulk_timeout); + timer_delete(&dev->bulk_timeout); } dev->urb_streaming = false; @@ -273,7 +273,7 @@ static void au0828_stop_transport(struct au0828_dev *dev, int full_stop) static int au0828_dvb_start_feed(struct dvb_demux_feed *feed) { struct dvb_demux *demux = feed->demux; - struct au0828_dev *dev = (struct au0828_dev *) demux->priv; + struct au0828_dev *dev = demux->priv; struct au0828_dvb *dvb = &dev->dvb; int ret = 0; @@ -305,7 +305,7 @@ static int au0828_dvb_start_feed(struct dvb_demux_feed *feed) static int au0828_dvb_stop_feed(struct dvb_demux_feed *feed) { struct dvb_demux *demux = feed->demux; - struct au0828_dev *dev = (struct au0828_dev *) demux->priv; + struct au0828_dev *dev = demux->priv; struct au0828_dvb *dvb = &dev->dvb; int ret = 0; diff --git a/drivers/media/usb/au0828/au0828-vbi.c b/drivers/media/usb/au0828/au0828-vbi.c index b0333637b747..11203adf47ea 100644 --- a/drivers/media/usb/au0828/au0828-vbi.c +++ b/drivers/media/usb/au0828/au0828-vbi.c @@ -74,6 +74,4 @@ const struct vb2_ops au0828_vbi_qops = { .prepare_streaming = v4l_vb2q_enable_media_source, .start_streaming = au0828_start_analog_streaming, .stop_streaming = au0828_stop_vbi_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index fd9fc43d47e0..fbaa542c8259 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -602,10 +602,7 @@ static inline int au0828_isoc_copy(struct au0828_dev *dev, struct urb *urb) vbi_field_size = dev->vbi_width * dev->vbi_height * 2; if (dev->vbi_read < vbi_field_size) { remain = vbi_field_size - dev->vbi_read; - if (len < remain) - lencopy = len; - else - lencopy = remain; + lencopy = umin(len, remain); if (vbi_buf != NULL) au0828_copy_vbi(dev, vbi_dma_q, vbi_buf, p, @@ -860,7 +857,7 @@ static void au0828_stop_streaming(struct vb2_queue *vq) } dev->vid_timeout_running = 0; - del_timer_sync(&dev->vid_timeout); + timer_delete_sync(&dev->vid_timeout); spin_lock_irqsave(&dev->slock, flags); if (dev->isoc_ctl.buf != NULL) { @@ -908,7 +905,7 @@ void au0828_stop_vbi_streaming(struct vb2_queue *vq) spin_unlock_irqrestore(&dev->slock, flags); dev->vbi_timeout_running = 0; - del_timer_sync(&dev->vbi_timeout); + timer_delete_sync(&dev->vbi_timeout); } static const struct vb2_ops au0828_video_qops = { @@ -918,8 +915,6 @@ static const struct vb2_ops au0828_video_qops = { .prepare_streaming = v4l_vb2q_enable_media_source, .start_streaming = au0828_start_analog_streaming, .stop_streaming = au0828_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; /* ------------------------------------------------------------------ @@ -953,7 +948,7 @@ int au0828_analog_unregister(struct au0828_dev *dev) such as tvtime from hanging) */ static void au0828_vid_buffer_timeout(struct timer_list *t) { - struct au0828_dev *dev = from_timer(dev, t, vid_timeout); + struct au0828_dev *dev = timer_container_of(dev, t, vid_timeout); struct au0828_dmaqueue *dma_q = &dev->vidq; struct au0828_buffer *buf; unsigned char *vid_data; @@ -977,7 +972,7 @@ static void au0828_vid_buffer_timeout(struct timer_list *t) static void au0828_vbi_buffer_timeout(struct timer_list *t) { - struct au0828_dev *dev = from_timer(dev, t, vbi_timeout); + struct au0828_dev *dev = timer_container_of(dev, t, vbi_timeout); struct au0828_dmaqueue *dma_q = &dev->vbiq; struct au0828_buffer *buf; unsigned char *vbi_data; @@ -1045,12 +1040,12 @@ static int au0828_v4l2_close(struct file *filp) if (vdev->vfl_type == VFL_TYPE_VIDEO && dev->vid_timeout_running) { /* Cancel timeout thread in case they didn't call streamoff */ dev->vid_timeout_running = 0; - del_timer_sync(&dev->vid_timeout); + timer_delete_sync(&dev->vid_timeout); } else if (vdev->vfl_type == VFL_TYPE_VBI && dev->vbi_timeout_running) { /* Cancel timeout thread in case they didn't call streamoff */ dev->vbi_timeout_running = 0; - del_timer_sync(&dev->vbi_timeout); + timer_delete_sync(&dev->vbi_timeout); } if (test_bit(DEV_DISCONNECTED, &dev->dev_state)) @@ -1699,9 +1694,9 @@ void au0828_v4l2_suspend(struct au0828_dev *dev) } if (dev->vid_timeout_running) - del_timer_sync(&dev->vid_timeout); + timer_delete_sync(&dev->vid_timeout); if (dev->vbi_timeout_running) - del_timer_sync(&dev->vbi_timeout); + timer_delete_sync(&dev->vbi_timeout); } void au0828_v4l2_resume(struct au0828_dev *dev) @@ -1926,9 +1921,8 @@ int au0828_analog_register(struct au0828_dev *dev, iface_desc = interface->cur_altsetting; for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) { endpoint = &iface_desc->endpoint[i].desc; - if (((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) - == USB_DIR_IN) && - ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) + if (usb_endpoint_dir_in(endpoint) && + (usb_endpoint_type(endpoint) == USB_ENDPOINT_XFER_ISOC)) { /* we find our isoc in endpoint */ diff --git a/drivers/media/usb/b2c2/flexcop-usb.c b/drivers/media/usb/b2c2/flexcop-usb.c index 790787f0eba8..8033622543f2 100644 --- a/drivers/media/usb/b2c2/flexcop-usb.c +++ b/drivers/media/usb/b2c2/flexcop-usb.c @@ -179,7 +179,7 @@ static int flexcop_usb_memory_req(struct flexcop_usb *fc_usb, flexcop_usb_request_t req, flexcop_usb_mem_page_t page_start, u32 addr, int extended, u8 *buf, u32 len) { - int i, ret = 0; + int ret = 0; u16 wMax; u32 pagechunk = 0; @@ -196,11 +196,8 @@ static int flexcop_usb_memory_req(struct flexcop_usb *fc_usb, default: return -EINVAL; } - for (i = 0; i < len;) { - pagechunk = - wMax < bytes_left_to_read_on_page(addr, len) ? - wMax : - bytes_left_to_read_on_page(addr, len); + while (len) { + pagechunk = min(wMax, bytes_left_to_read_on_page(addr, len)); deb_info("%x\n", (addr & V8_MEMORY_PAGE_MASK) | (V8_MEMORY_EXTENDED*extended)); @@ -209,11 +206,12 @@ static int flexcop_usb_memory_req(struct flexcop_usb *fc_usb, page_start + (addr / V8_MEMORY_PAGE_SIZE), (addr & V8_MEMORY_PAGE_MASK) | (V8_MEMORY_EXTENDED*extended), - &buf[i], pagechunk); + buf, pagechunk); if (ret < 0) return ret; addr += pagechunk; + buf += pagechunk; len -= pagechunk; } return 0; @@ -448,7 +446,7 @@ static int flexcop_usb_transfer_init(struct flexcop_usb *fc_usb) /* creating iso urbs */ for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++) { fc_usb->iso_urb[i] = usb_alloc_urb(B2C2_USB_FRAMES_PER_ISO, - GFP_ATOMIC); + GFP_KERNEL); if (fc_usb->iso_urb[i] == NULL) { ret = -ENOMEM; goto urb_error; @@ -481,7 +479,7 @@ static int flexcop_usb_transfer_init(struct flexcop_usb *fc_usb) frame_offset += frame_size; } - if ((ret = usb_submit_urb(fc_usb->iso_urb[i],GFP_ATOMIC))) { + if ((ret = usb_submit_urb(fc_usb->iso_urb[i],GFP_KERNEL))) { err("submitting urb %d failed with %d.", i, ret); goto urb_error; } @@ -515,7 +513,7 @@ static int flexcop_usb_init(struct flexcop_usb *fc_usb) alt = fc_usb->uintf->cur_altsetting; - if (alt->desc.bNumEndpoints < 1) + if (alt->desc.bNumEndpoints < 2) return -ENODEV; if (!usb_endpoint_is_isoc_in(&alt->endpoint[0].desc)) return -ENODEV; @@ -531,6 +529,12 @@ static int flexcop_usb_init(struct flexcop_usb *fc_usb) case USB_SPEED_HIGH: info("running at HIGH speed."); break; + case USB_SPEED_SUPER: + info("running at SUPER speed."); + break; + case USB_SPEED_SUPER_PLUS: + info("running at SUPER+ speed."); + break; case USB_SPEED_UNKNOWN: default: err("cannot handle USB speed because it is unknown."); diff --git a/drivers/media/usb/cx231xx/cx231xx-417.c b/drivers/media/usb/cx231xx/cx231xx-417.c index c5e21785fafe..c695a97e202b 100644 --- a/drivers/media/usb/cx231xx/cx231xx-417.c +++ b/drivers/media/usb/cx231xx/cx231xx-417.c @@ -937,7 +937,6 @@ static int cx231xx_load_firmware(struct cx231xx *dev) u32 *p_current_fw, *p_fw; u32 *p_fw_data; int frame = 0; - u16 _buffer_size = 4096; u8 *p_buffer; p_current_fw = vmalloc(1884180 * 4); @@ -947,7 +946,7 @@ static int cx231xx_load_firmware(struct cx231xx *dev) return -ENOMEM; } - p_buffer = vmalloc(4096); + p_buffer = vmalloc(EP5_BUF_SIZE); if (p_buffer == NULL) { dprintk(2, "FAIL!!!\n"); vfree(p_current_fw); @@ -1030,9 +1029,9 @@ static int cx231xx_load_firmware(struct cx231xx *dev) /*download the firmware by ep5-out*/ - for (frame = 0; frame < (int)(CX231xx_FIRM_IMAGE_SIZE*20/_buffer_size); + for (frame = 0; frame < (int)(CX231xx_FIRM_IMAGE_SIZE*20/EP5_BUF_SIZE); frame++) { - for (i = 0; i < _buffer_size; i++) { + for (i = 0; i < EP5_BUF_SIZE; i++) { *(p_buffer + i) = (u8)(*(p_fw + (frame * 128 * 8 + (i / 4))) & 0x000000FF); i++; *(p_buffer + i) = (u8)((*(p_fw + (frame * 128 * 8 + (i / 4))) & 0x0000FF00) >> 8); @@ -1041,7 +1040,7 @@ static int cx231xx_load_firmware(struct cx231xx *dev) i++; *(p_buffer + i) = (u8)((*(p_fw + (frame * 128 * 8 + (i / 4))) & 0xFF000000) >> 24); } - cx231xx_ep5_bulkout(dev, p_buffer, _buffer_size); + cx231xx_ep5_bulkout(dev, p_buffer, EP5_BUF_SIZE); } p_current_fw = p_fw; @@ -1219,12 +1218,13 @@ static int queue_setup(struct vb2_queue *vq, { struct cx231xx *dev = vb2_get_drv_priv(vq); unsigned int size = mpeglinesize * mpeglines; + unsigned int q_num_bufs = vb2_get_num_buffers(vq); dev->ts1.ts_packet_size = mpeglinesize; dev->ts1.ts_packet_count = mpeglines; - if (vq->num_buffers + *nbuffers < CX231XX_MIN_BUF) - *nbuffers = CX231XX_MIN_BUF - vq->num_buffers; + if (q_num_bufs + *nbuffers < CX231XX_MIN_BUF) + *nbuffers = CX231XX_MIN_BUF - q_num_bufs; if (*nplanes) return sizes[0] < size ? -EINVAL : 0; @@ -1453,13 +1453,11 @@ static void stop_streaming(struct vb2_queue *vq) return_all_buffers(dev, VB2_BUF_STATE_ERROR); } -static struct vb2_ops cx231xx_video_qops = { +static const struct vb2_ops cx231xx_video_qops = { .queue_setup = queue_setup, .buf_queue = buffer_queue, .start_streaming = start_streaming, .stop_streaming = stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; /* ------------------------------------------------------------------ */ @@ -1501,7 +1499,7 @@ static int vidioc_g_selection(struct file *file, void *priv, return 0; } -static int vidioc_g_std(struct file *file, void *fh0, v4l2_std_id *norm) +static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *norm) { struct cx231xx *dev = video_drvdata(file); @@ -1540,20 +1538,6 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id) return 0; } -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctl) -{ - struct cx231xx *dev = video_drvdata(file); - struct v4l2_subdev *sd; - - dprintk(3, "enter vidioc_s_ctrl()\n"); - /* Update the A/V core */ - v4l2_device_for_each_subdev(sd, &dev->v4l2_dev) - v4l2_s_ctrl(NULL, sd->ctrl_handler, ctl); - dprintk(3, "exit vidioc_s_ctrl()\n"); - return 0; -} - static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { @@ -1629,7 +1613,6 @@ static const struct v4l2_ioctl_ops mpeg_ioctl_ops = { .vidioc_enum_input = cx231xx_enum_input, .vidioc_g_input = cx231xx_g_input, .vidioc_s_input = cx231xx_s_input, - .vidioc_s_ctrl = vidioc_s_ctrl, .vidioc_g_pixelaspect = vidioc_g_pixelaspect, .vidioc_g_selection = vidioc_g_selection, .vidioc_querycap = cx231xx_querycap, @@ -1722,6 +1705,8 @@ static void cx231xx_video_dev_init( vfd->lock = &dev->lock; vfd->release = video_device_release_empty; vfd->ctrl_handler = &dev->mpeg_ctrl_handler.hdl; + vfd->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | + V4L2_CAP_VIDEO_CAPTURE; video_set_drvdata(vfd, dev); if (dev->tuner_type == TUNER_ABSENT) { v4l2_disable_ioctl(vfd, VIDIOC_G_FREQUENCY); @@ -1759,7 +1744,7 @@ int cx231xx_417_register(struct cx231xx *dev) dev->mpeg_ctrl_handler.ops = &cx231xx_ops; if (dev->sd_cx25840) v4l2_ctrl_add_handler(&dev->mpeg_ctrl_handler.hdl, - dev->sd_cx25840->ctrl_handler, NULL, false); + dev->sd_cx25840->ctrl_handler, NULL, true); if (dev->mpeg_ctrl_handler.hdl.error) { err = dev->mpeg_ctrl_handler.hdl.error; dprintk(3, "%s: can't add cx25840 controls\n", dev->name); @@ -1782,7 +1767,7 @@ int cx231xx_417_register(struct cx231xx *dev) q->ops = &cx231xx_video_qops; q->mem_ops = &vb2_vmalloc_memops; q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - q->min_buffers_needed = 1; + q->min_queued_buffers = 1; q->lock = &dev->lock; err = vb2_queue_init(q); if (err) diff --git a/drivers/media/usb/cx231xx/cx231xx-avcore.c b/drivers/media/usb/cx231xx/cx231xx-avcore.c index 3d3c881c8e58..1cfec76b72f3 100644 --- a/drivers/media/usb/cx231xx/cx231xx-avcore.c +++ b/drivers/media/usb/cx231xx/cx231xx-avcore.c @@ -623,7 +623,7 @@ int cx231xx_set_video_input_mux(struct cx231xx *dev, u8 input) } int cx231xx_set_decoder_video_input(struct cx231xx *dev, - u8 pin_type, u8 input) + u8 pin_type, u32 input) { int status = 0; u32 value = 0; @@ -1338,39 +1338,6 @@ void update_HH_register_after_set_DIF(struct cx231xx *dev) */ } -void cx231xx_dump_HH_reg(struct cx231xx *dev) -{ - u32 value = 0; - u16 i = 0; - - value = 0x45005390; - vid_blk_write_word(dev, 0x104, value); - - for (i = 0x100; i < 0x140; i++) { - vid_blk_read_word(dev, i, &value); - dev_dbg(dev->dev, "reg0x%x=0x%x\n", i, value); - i = i+3; - } - - for (i = 0x300; i < 0x400; i++) { - vid_blk_read_word(dev, i, &value); - dev_dbg(dev->dev, "reg0x%x=0x%x\n", i, value); - i = i+3; - } - - for (i = 0x400; i < 0x440; i++) { - vid_blk_read_word(dev, i, &value); - dev_dbg(dev->dev, "reg0x%x=0x%x\n", i, value); - i = i+3; - } - - vid_blk_read_word(dev, AFE_CTRL_C2HH_SRC_CTRL, &value); - dev_dbg(dev->dev, "AFE_CTRL_C2HH_SRC_CTRL=0x%x\n", value); - vid_blk_write_word(dev, AFE_CTRL_C2HH_SRC_CTRL, 0x4485D390); - vid_blk_read_word(dev, AFE_CTRL_C2HH_SRC_CTRL, &value); - dev_dbg(dev->dev, "AFE_CTRL_C2HH_SRC_CTRL=0x%x\n", value); -} - #if 0 static void cx231xx_dump_SC_reg(struct cx231xx *dev) { @@ -2460,30 +2427,6 @@ int cx231xx_set_power_mode(struct cx231xx *dev, enum AV_MODE mode) return status; } -int cx231xx_power_suspend(struct cx231xx *dev) -{ - u8 value[4] = { 0, 0, 0, 0 }; - u32 tmp = 0; - int status = 0; - - status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, PWR_CTL_EN, - value, 4); - if (status > 0) - return status; - - tmp = le32_to_cpu(*((__le32 *) value)); - tmp &= (~PWR_MODE_MASK); - - value[0] = (u8) tmp; - value[1] = (u8) (tmp >> 8); - value[2] = (u8) (tmp >> 16); - value[3] = (u8) (tmp >> 24); - status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, PWR_CTL_EN, - value, 4); - - return status; -} - /****************************************************************************** * S T R E A M C O N T R O L functions * ******************************************************************************/ @@ -2761,7 +2704,6 @@ int cx231xx_set_gpio_value(struct cx231xx *dev, int pin_number, int pin_value) dev->gpio_dir = value; status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, dev->gpio_val); - value = 0; } if (pin_value == 0) diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c index 92efe6c1f47b..691f073892b3 100644 --- a/drivers/media/usb/cx231xx/cx231xx-cards.c +++ b/drivers/media/usb/cx231xx/cx231xx-cards.c @@ -679,8 +679,7 @@ struct cx231xx_board cx231xx_boards[] = { }, { .type = CX231XX_VMUX_SVIDEO, .vmux = CX231XX_VIN_1_1 | - (CX231XX_VIN_1_2 << 8) | - CX25840_SVIDEO_ON, + (CX231XX_VIN_3_2 << 8), .amux = CX231XX_AMUX_LINE_IN, .gpio = NULL, } @@ -990,10 +989,11 @@ struct cx231xx_board cx231xx_boards[] = { } }, }, }; -const unsigned int cx231xx_bcount = ARRAY_SIZE(cx231xx_boards); /* table of devices that work with this driver */ struct usb_device_id cx231xx_id_table[] = { + {USB_DEVICE(0x1D19, 0x6108), + .driver_info = CX231XX_BOARD_PV_XCAPTURE_USB}, {USB_DEVICE(0x1D19, 0x6109), .driver_info = CX231XX_BOARD_PV_XCAPTURE_USB}, {USB_DEVICE(0x0572, 0x5A3C), diff --git a/drivers/media/usb/cx231xx/cx231xx-core.c b/drivers/media/usb/cx231xx/cx231xx-core.c index 727e6268567f..d8312201694f 100644 --- a/drivers/media/usb/cx231xx/cx231xx-core.c +++ b/drivers/media/usb/cx231xx/cx231xx-core.c @@ -751,13 +751,12 @@ int cx231xx_ep5_bulkout(struct cx231xx *dev, u8 *firmware, u16 size) int ret = -ENOMEM; u32 *buffer; - buffer = kzalloc(4096, GFP_KERNEL); + buffer = kmemdup(firmware, EP5_BUF_SIZE, GFP_KERNEL); if (buffer == NULL) return -ENOMEM; - memcpy(&buffer[0], firmware, 4096); ret = usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 5), - buffer, 4096, &actlen, 2000); + buffer, EP5_BUF_SIZE, &actlen, EP5_TIMEOUT_MS); if (ret) dev_err(dev->dev, @@ -994,7 +993,7 @@ int cx231xx_init_isoc(struct cx231xx *dev, int max_packets, /* De-allocates all pending stuff */ cx231xx_uninit_isoc(dev); - dma_q->p_left_data = kzalloc(4096, GFP_KERNEL); + dma_q->p_left_data = kzalloc(EP5_BUF_SIZE, GFP_KERNEL); if (dma_q->p_left_data == NULL) return -ENOMEM; @@ -1024,6 +1023,7 @@ int cx231xx_init_isoc(struct cx231xx *dev, int max_packets, if (!dev->video_mode.isoc_ctl.urb) { dev_err(dev->dev, "cannot alloc memory for usb buffers\n"); + kfree(dma_q->p_left_data); return -ENOMEM; } @@ -1033,6 +1033,7 @@ int cx231xx_init_isoc(struct cx231xx *dev, int max_packets, dev_err(dev->dev, "cannot allocate memory for usbtransfer\n"); kfree(dev->video_mode.isoc_ctl.urb); + kfree(dma_q->p_left_data); return -ENOMEM; } diff --git a/drivers/media/usb/cx231xx/cx231xx-i2c.c b/drivers/media/usb/cx231xx/cx231xx-i2c.c index c6659253c6fb..6da8e7943d94 100644 --- a/drivers/media/usb/cx231xx/cx231xx-i2c.c +++ b/drivers/media/usb/cx231xx/cx231xx-i2c.c @@ -567,10 +567,7 @@ int cx231xx_i2c_mux_create(struct cx231xx *dev) int cx231xx_i2c_mux_register(struct cx231xx *dev, int mux_no) { - return i2c_mux_add_adapter(dev->muxc, - 0, - mux_no /* chan_id */, - 0 /* class */); + return i2c_mux_add_adapter(dev->muxc, 0, mux_no); } void cx231xx_i2c_mux_unregister(struct cx231xx *dev) diff --git a/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.h b/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.h index 5bc44f194d0a..62ffa16bb82c 100644 --- a/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.h +++ b/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.h @@ -57,19 +57,17 @@ enum USB_SPEED{ }; #define TS_MASK 0x6 -enum TS_PORT{ - NO_TS_PORT = 0x0, /* 2'b00: Neither port used. PCB not a Hybrid, +#define NO_TS_PORT 0x0 /* 2'b00: Neither port used. PCB not a Hybrid, only offers Analog TV or Video */ - TS1_PORT = 0x4, /* 2'b10: TS1 Input (Hybrid mode : +#define TS1_PORT 0x4 /* 2'b10: TS1 Input (Hybrid mode : Digital or External Analog/Compressed source) */ - TS1_TS2_PORT = 0x6, /* 2'b11: TS1 & TS2 Inputs +#define TS1_TS2_PORT 0x6 /* 2'b11: TS1 & TS2 Inputs (Dual inputs from Digital and/or External Analog/Compressed sources) */ - TS1_EXT_CLOCK = 0x6, /* 2'b11: TS1 & TS2 as selector +#define TS1_EXT_CLOCK 0x6 /* 2'b11: TS1 & TS2 as selector to external clock */ - TS1VIP_TS2_PORT = 0x2 /* 2'b01: TS1 used as 656/VIP Output, +#define TS1VIP_TS2_PORT 0x2 /* 2'b01: TS1 used as 656/VIP Output, TS2 Input (from Compressor) */ -}; #define EAVP_MASK 0x8 enum EAV_PRESENT{ @@ -89,10 +87,8 @@ enum AT_MODE{ }; #define PWR_SEL_MASK 0x40 -enum POWE_TYPE{ - SELF_POWER = 0x0, /* 0: self power */ - BUS_POWER = 0x40 /* 1: bus power */ -}; +#define SELF_POWER 0x0 /* 0: self power */ +#define BUS_POWER 0x40 /* 1: bus power */ enum USB_POWE_TYPE{ USB_SELF_POWER = 0, diff --git a/drivers/media/usb/cx231xx/cx231xx-vbi.c b/drivers/media/usb/cx231xx/cx231xx-vbi.c index 33431d9f54c2..338e10148465 100644 --- a/drivers/media/usb/cx231xx/cx231xx-vbi.c +++ b/drivers/media/usb/cx231xx/cx231xx-vbi.c @@ -243,8 +243,6 @@ struct vb2_ops cx231xx_vbi_qops = { .buf_queue = vbi_buf_queue, .start_streaming = vbi_start_streaming, .stop_streaming = vbi_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; /* ------------------------------------------------------------------ diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index e23b8ccd79d4..2cd4e333bc4b 100644 --- a/drivers/media/usb/cx231xx/cx231xx-video.c +++ b/drivers/media/usb/cx231xx/cx231xx-video.c @@ -714,11 +714,12 @@ static int queue_setup(struct vb2_queue *vq, unsigned int sizes[], struct device *alloc_devs[]) { struct cx231xx *dev = vb2_get_drv_priv(vq); + unsigned int q_num_bufs = vb2_get_num_buffers(vq); dev->size = (dev->width * dev->height * dev->format->depth + 7) >> 3; - if (vq->num_buffers + *nbuffers < CX231XX_MIN_BUF) - *nbuffers = CX231XX_MIN_BUF - vq->num_buffers; + if (q_num_bufs + *nbuffers < CX231XX_MIN_BUF) + *nbuffers = CX231XX_MIN_BUF - q_num_bufs; if (*nplanes) return sizes[0] < dev->size ? -EINVAL : 0; @@ -794,13 +795,11 @@ static void stop_streaming(struct vb2_queue *vq) return_all_buffers(dev, VB2_BUF_STATE_ERROR); } -static struct vb2_ops cx231xx_video_qops = { +static const struct vb2_ops cx231xx_video_qops = { .queue_setup = queue_setup, .buf_queue = buffer_queue, .start_streaming = start_streaming, .stop_streaming = stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; /********************* v4l2 interface **************************************/ @@ -1810,7 +1809,7 @@ int cx231xx_register_analog_devices(struct cx231xx *dev) q->ops = &cx231xx_video_qops; q->mem_ops = &vb2_vmalloc_memops; q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - q->min_buffers_needed = 1; + q->min_queued_buffers = 1; q->lock = &dev->lock; ret = vb2_queue_init(q); if (ret) @@ -1870,7 +1869,7 @@ int cx231xx_register_analog_devices(struct cx231xx *dev) q->ops = &cx231xx_vbi_qops; q->mem_ops = &vb2_vmalloc_memops; q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - q->min_buffers_needed = 1; + q->min_queued_buffers = 1; q->lock = &dev->lock; ret = vb2_queue_init(q); if (ret) diff --git a/drivers/media/usb/cx231xx/cx231xx.h b/drivers/media/usb/cx231xx/cx231xx.h index 6929e4d97067..19f5036a78d7 100644 --- a/drivers/media/usb/cx231xx/cx231xx.h +++ b/drivers/media/usb/cx231xx/cx231xx.h @@ -120,6 +120,9 @@ #define CX23417_OSC_EN 8 #define CX23417_RESET 9 +#define EP5_BUF_SIZE 4096 +#define EP5_TIMEOUT_MS 2000 + struct cx23417_fmt { u32 fourcc; /* v4l2 format id */ int depth; @@ -787,7 +790,6 @@ void cx231xx_set_DIF_bandpass(struct cx231xx *dev, u32 if_freq, u8 spectral_invert, u32 mode); void cx231xx_Setup_AFE_for_LowIF(struct cx231xx *dev); void reset_s5h1432_demod(struct cx231xx *dev); -void cx231xx_dump_HH_reg(struct cx231xx *dev); void update_HH_register_after_set_DIF(struct cx231xx *dev); @@ -902,7 +904,6 @@ int cx231xx_initialize_stream_xfer(struct cx231xx *dev, u32 media_type); /* Power control functions */ int cx231xx_set_power_mode(struct cx231xx *dev, enum AV_MODE mode); -int cx231xx_power_suspend(struct cx231xx *dev); /* chip specific control functions */ int cx231xx_init_ctrl_pin_status(struct cx231xx *dev); @@ -913,7 +914,7 @@ int cx231xx_enable_i2c_port_3(struct cx231xx *dev, bool is_port_3); /* video audio decoder related functions */ void video_mux(struct cx231xx *dev, int index); int cx231xx_set_video_input_mux(struct cx231xx *dev, u8 input); -int cx231xx_set_decoder_video_input(struct cx231xx *dev, u8 pin_type, u8 input); +int cx231xx_set_decoder_video_input(struct cx231xx *dev, u8 pin_type, u32 input); int cx231xx_do_mode_ctrl_overrides(struct cx231xx *dev); int cx231xx_set_audio_input(struct cx231xx *dev, u8 input); @@ -946,7 +947,6 @@ extern void cx231xx_pre_card_setup(struct cx231xx *dev); extern void cx231xx_card_setup(struct cx231xx *dev); extern struct cx231xx_board cx231xx_boards[]; extern struct usb_device_id cx231xx_id_table[]; -extern const unsigned int cx231xx_bcount; int cx231xx_tuner_callback(void *ptr, int component, int command, int arg); /* cx23885-417.c */ diff --git a/drivers/media/usb/dvb-usb-v2/af9015.c b/drivers/media/usb/dvb-usb-v2/af9015.c index d33514acc2b5..3eddc40377bf 100644 --- a/drivers/media/usb/dvb-usb-v2/af9015.c +++ b/drivers/media/usb/dvb-usb-v2/af9015.c @@ -260,7 +260,7 @@ static u32 af9015_i2c_func(struct i2c_adapter *adapter) return I2C_FUNC_I2C; } -static struct i2c_algorithm af9015_i2c_algo = { +static const struct i2c_algorithm af9015_i2c_algo = { .master_xfer = af9015_i2c_xfer, .functionality = af9015_i2c_func, }; @@ -1165,7 +1165,7 @@ static int af9015_rc_query(struct dvb_usb_device *d) /* If any of these are non-zero, assume invalid data */ if (buf[1] || buf[2] || buf[3]) { dev_dbg(&intf->dev, "invalid data\n"); - return ret; + return 0; } /* Check for repeat of previous code */ @@ -1174,7 +1174,7 @@ static int af9015_rc_query(struct dvb_usb_device *d) dev_dbg(&intf->dev, "key repeated\n"); rc_repeat(d->rc_dev); state->rc_repeat = buf[6]; - return ret; + return 0; } /* Only process key if canary killed */ diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index 1e9c8d01523b..17062672ea06 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.c +++ b/drivers/media/usb/dvb-usb-v2/af9035.c @@ -323,8 +323,15 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap, } else if ((msg[0].addr == state->af9033_i2c_addr[0]) || (msg[0].addr == state->af9033_i2c_addr[1])) { /* demod access via firmware interface */ - u32 reg = msg[0].buf[0] << 16 | msg[0].buf[1] << 8 | - msg[0].buf[2]; + u32 reg; + + if (msg[0].len < 3 || msg[1].len < 1) { + ret = -EOPNOTSUPP; + goto unlock; + } + + reg = msg[0].buf[0] << 16 | msg[0].buf[1] << 8 | + msg[0].buf[2]; if (msg[0].addr == state->af9033_i2c_addr[1]) reg |= 0x100000; @@ -382,16 +389,20 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap, } else if ((msg[0].addr == state->af9033_i2c_addr[0]) || (msg[0].addr == state->af9033_i2c_addr[1])) { /* demod access via firmware interface */ - u32 reg = msg[0].buf[0] << 16 | msg[0].buf[1] << 8 | - msg[0].buf[2]; + u32 reg; + + if (msg[0].len < 3) { + ret = -EOPNOTSUPP; + goto unlock; + } + + reg = msg[0].buf[0] << 16 | msg[0].buf[1] << 8 | + msg[0].buf[2]; if (msg[0].addr == state->af9033_i2c_addr[1]) reg |= 0x100000; - ret = (msg[0].len >= 3) ? af9035_wr_regs(d, reg, - &msg[0].buf[3], - msg[0].len - 3) - : -EOPNOTSUPP; + ret = af9035_wr_regs(d, reg, &msg[0].buf[3], msg[0].len - 3); } else { /* I2C write */ u8 buf[MAX_XFER_SIZE]; @@ -458,6 +469,7 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap, ret = -EOPNOTSUPP; } +unlock: mutex_unlock(&d->i2c_mutex); if (ret < 0) @@ -471,7 +483,7 @@ static u32 af9035_i2c_functionality(struct i2c_adapter *adapter) return I2C_FUNC_I2C; } -static struct i2c_algorithm af9035_i2c_algo = { +static const struct i2c_algorithm af9035_i2c_algo = { .master_xfer = af9035_i2c_master_xfer, .functionality = af9035_i2c_functionality, }; @@ -862,6 +874,9 @@ static int af9035_read_config(struct dvb_usb_device *d) if ((le16_to_cpu(d->udev->descriptor.idVendor) == USB_VID_AVERMEDIA) && (le16_to_cpu(d->udev->descriptor.idProduct) == USB_PID_AVERMEDIA_TD310)) { state->it930x_addresses = 1; + /* TD310 RC works with NEC defaults */ + state->ir_mode = 0x05; + state->ir_type = 0x00; } return 0; } @@ -2060,6 +2075,11 @@ static const struct dvb_usb_device_properties it930x_props = { .tuner_attach = it930x_tuner_attach, .tuner_detach = it930x_tuner_detach, .init = it930x_init, + /* + * dvb_usbv2_remote_init() calls rc_config() only for those devices + * which have non-empty rc_map, so it's safe to enable it for every IT930x + */ + .get_rc_config = af9035_get_rc_config, .get_stream_config = af9035_get_stream_config, .get_adapter_count = af9035_get_adapter_count, @@ -2151,7 +2171,7 @@ static const struct usb_device_id af9035_id_table[] = { { DVB_USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9303, &it930x_props, "ITE 9303 Generic", NULL) }, { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_TD310, - &it930x_props, "AVerMedia TD310 DVB-T2", NULL) }, + &it930x_props, "AVerMedia TD310 DVB-T2", RC_MAP_AVERMEDIA_RM_KS) }, { DVB_USB_DEVICE(USB_VID_DEXATEK, 0x0100, &it930x_props, "Logilink VG0022A", NULL) }, { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_TC2_STICK, diff --git a/drivers/media/usb/dvb-usb-v2/anysee.c b/drivers/media/usb/dvb-usb-v2/anysee.c index aa45b5d263f6..64bddca5303c 100644 --- a/drivers/media/usb/dvb-usb-v2/anysee.c +++ b/drivers/media/usb/dvb-usb-v2/anysee.c @@ -46,24 +46,15 @@ static int anysee_ctrl_msg(struct dvb_usb_device *d, dev_dbg(&d->udev->dev, "%s: >>> %*ph\n", __func__, slen, state->buf); - /* We need receive one message more after dvb_usb_generic_rw due - to weird transaction flow, which is 1 x send + 2 x receive. */ + /* + * We need receive one message more after dvb_usbv2_generic_rw_locked() + * due to weird transaction flow, which is 1 x send + 2 x receive. + */ ret = dvb_usbv2_generic_rw_locked(d, state->buf, sizeof(state->buf), state->buf, sizeof(state->buf)); if (ret) goto error_unlock; - /* TODO FIXME: dvb_usb_generic_rw() fails rarely with error code -32 - * (EPIPE, Broken pipe). Function supports currently msleep() as a - * parameter but I would not like to use it, since according to - * Documentation/timers/timers-howto.rst it should not be used such - * short, under < 20ms, sleeps. Repeating failed message would be - * better choice as not to add unwanted delays... - * Fixing that correctly is one of those or both; - * 1) use repeat if possible - * 2) add suitable delay - */ - /* get answer, retry few times if error returned */ for (i = 0; i < 3; i++) { /* receive 2nd answer */ @@ -202,14 +193,14 @@ static int anysee_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, while (i < num) { if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) { - if (msg[i].len > 2 || msg[i+1].len > 60) { + if (msg[i].len < 1 || msg[i].len > 2 || msg[i + 1].len > 60) { ret = -EOPNOTSUPP; break; } buf[0] = CMD_I2C_READ; buf[1] = (msg[i].addr << 1) | 0x01; buf[2] = msg[i].buf[0]; - buf[3] = msg[i].buf[1]; + buf[3] = (msg[i].len < 2) ? 0 : msg[i].buf[1]; buf[4] = msg[i].len-1; buf[5] = msg[i+1].len; ret = anysee_ctrl_msg(d, buf, 6, msg[i+1].buf, @@ -244,7 +235,7 @@ static u32 anysee_i2c_func(struct i2c_adapter *adapter) return I2C_FUNC_I2C; } -static struct i2c_algorithm anysee_i2c_algo = { +static const struct i2c_algorithm anysee_i2c_algo = { .master_xfer = anysee_master_xfer, .functionality = anysee_i2c_func, }; diff --git a/drivers/media/usb/dvb-usb-v2/au6610.c b/drivers/media/usb/dvb-usb-v2/au6610.c index be223fc8aa14..c20a9469f564 100644 --- a/drivers/media/usb/dvb-usb-v2/au6610.c +++ b/drivers/media/usb/dvb-usb-v2/au6610.c @@ -115,7 +115,7 @@ static u32 au6610_i2c_func(struct i2c_adapter *adapter) return I2C_FUNC_I2C; } -static struct i2c_algorithm au6610_i2c_algo = { +static const struct i2c_algorithm au6610_i2c_algo = { .master_xfer = au6610_i2c_xfer, .functionality = au6610_i2c_func, }; diff --git a/drivers/media/usb/dvb-usb-v2/az6007.c b/drivers/media/usb/dvb-usb-v2/az6007.c index 62ee09f28a0b..65ef045b74ca 100644 --- a/drivers/media/usb/dvb-usb-v2/az6007.c +++ b/drivers/media/usb/dvb-usb-v2/az6007.c @@ -202,7 +202,8 @@ static int az6007_rc_query(struct dvb_usb_device *d) unsigned code; enum rc_proto proto; - az6007_read(d, AZ6007_READ_IR, 0, 0, st->data, 10); + if (az6007_read(d, AZ6007_READ_IR, 0, 0, st->data, 10) < 0) + return -EIO; if (st->data[1] == 0x44) return 0; @@ -248,7 +249,7 @@ static int az6007_ci_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address) { - struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; + struct dvb_usb_device *d = ca->data; struct az6007_device_state *state = d_to_priv(d); int ret; @@ -290,7 +291,7 @@ static int az6007_ci_write_attribute_mem(struct dvb_ca_en50221 *ca, int address, u8 value) { - struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; + struct dvb_usb_device *d = ca->data; struct az6007_device_state *state = d_to_priv(d); int ret; @@ -321,7 +322,7 @@ static int az6007_ci_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address) { - struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; + struct dvb_usb_device *d = ca->data; struct az6007_device_state *state = d_to_priv(d); int ret; @@ -367,7 +368,7 @@ static int az6007_ci_write_cam_control(struct dvb_ca_en50221 *ca, u8 address, u8 value) { - struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; + struct dvb_usb_device *d = ca->data; struct az6007_device_state *state = d_to_priv(d); int ret; @@ -398,7 +399,7 @@ failed: static int CI_CamReady(struct dvb_ca_en50221 *ca, int slot) { - struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; + struct dvb_usb_device *d = ca->data; int ret; u8 req; @@ -429,7 +430,7 @@ static int CI_CamReady(struct dvb_ca_en50221 *ca, int slot) static int az6007_ci_slot_reset(struct dvb_ca_en50221 *ca, int slot) { - struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; + struct dvb_usb_device *d = ca->data; struct az6007_device_state *state = d_to_priv(d); int ret, i; @@ -485,7 +486,7 @@ static int az6007_ci_slot_shutdown(struct dvb_ca_en50221 *ca, int slot) static int az6007_ci_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot) { - struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; + struct dvb_usb_device *d = ca->data; struct az6007_device_state *state = d_to_priv(d); int ret; @@ -514,7 +515,7 @@ failed: static int az6007_ci_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open) { - struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; + struct dvb_usb_device *d = ca->data; struct az6007_device_state *state = d_to_priv(d); int ret; u8 req; @@ -787,6 +788,10 @@ static int az6007_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], if (az6007_xfer_debug) printk(KERN_DEBUG "az6007: I2C W addr=0x%x len=%d\n", addr, msgs[i].len); + if (msgs[i].len < 1) { + ret = -EIO; + goto err; + } req = AZ6007_I2C_WR; index = msgs[i].buf[0]; value = addr | (1 << 8); @@ -801,6 +806,10 @@ static int az6007_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], if (az6007_xfer_debug) printk(KERN_DEBUG "az6007: I2C R addr=0x%x len=%d\n", addr, msgs[i].len); + if (msgs[i].len < 1) { + ret = -EIO; + goto err; + } req = AZ6007_I2C_RD; index = msgs[i].buf[0]; value = addr; @@ -829,7 +838,7 @@ static u32 az6007_i2c_func(struct i2c_adapter *adapter) return I2C_FUNC_I2C; } -static struct i2c_algorithm az6007_i2c_algo = { +static const struct i2c_algorithm az6007_i2c_algo = { .master_xfer = az6007_i2c_xfer, .functionality = az6007_i2c_func, }; diff --git a/drivers/media/usb/dvb-usb-v2/ce6230.c b/drivers/media/usb/dvb-usb-v2/ce6230.c index 44540de1a206..7ebaf3ee4491 100644 --- a/drivers/media/usb/dvb-usb-v2/ce6230.c +++ b/drivers/media/usb/dvb-usb-v2/ce6230.c @@ -101,6 +101,10 @@ static int ce6230_i2c_master_xfer(struct i2c_adapter *adap, if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) { if (msg[i].addr == ce6230_zl10353_config.demod_address) { + if (msg[i].len < 1) { + i = -EOPNOTSUPP; + break; + } req.cmd = DEMOD_READ; req.value = msg[i].addr >> 1; req.index = msg[i].buf[0]; @@ -117,6 +121,10 @@ static int ce6230_i2c_master_xfer(struct i2c_adapter *adap, } else { if (msg[i].addr == ce6230_zl10353_config.demod_address) { + if (msg[i].len < 1) { + i = -EOPNOTSUPP; + break; + } req.cmd = DEMOD_WRITE; req.value = msg[i].addr >> 1; req.index = msg[i].buf[0]; @@ -146,7 +154,7 @@ static u32 ce6230_i2c_functionality(struct i2c_adapter *adapter) return I2C_FUNC_I2C; } -static struct i2c_algorithm ce6230_i2c_algorithm = { +static const struct i2c_algorithm ce6230_i2c_algorithm = { .master_xfer = ce6230_i2c_master_xfer, .functionality = ce6230_i2c_functionality, }; diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb.h b/drivers/media/usb/dvb-usb-v2/dvb_usb.h index 288c15a7d72b..ecdc20d45132 100644 --- a/drivers/media/usb/dvb-usb-v2/dvb_usb.h +++ b/drivers/media/usb/dvb-usb-v2/dvb_usb.h @@ -243,7 +243,7 @@ struct dvb_usb_device_properties { int (*download_firmware) (struct dvb_usb_device *, const struct firmware *); - struct i2c_algorithm *i2c_algo; + const struct i2c_algorithm *i2c_algo; unsigned int num_adapters; int (*get_adapter_count) (struct dvb_usb_device *); diff --git a/drivers/media/usb/dvb-usb-v2/dvbsky.c b/drivers/media/usb/dvb-usb-v2/dvbsky.c index 1221c924312a..ceac0ea21dab 100644 --- a/drivers/media/usb/dvb-usb-v2/dvbsky.c +++ b/drivers/media/usb/dvb-usb-v2/dvbsky.c @@ -169,7 +169,7 @@ static u32 dvbsky_i2c_func(struct i2c_adapter *adapter) return I2C_FUNC_I2C; } -static struct i2c_algorithm dvbsky_i2c_algo = { +static const struct i2c_algorithm dvbsky_i2c_algo = { .master_xfer = dvbsky_i2c_xfer, .functionality = dvbsky_i2c_func, }; diff --git a/drivers/media/usb/dvb-usb-v2/ec168.c b/drivers/media/usb/dvb-usb-v2/ec168.c index 7ed0ab9e429b..973b32356b17 100644 --- a/drivers/media/usb/dvb-usb-v2/ec168.c +++ b/drivers/media/usb/dvb-usb-v2/ec168.c @@ -115,6 +115,10 @@ static int ec168_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], while (i < num) { if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) { if (msg[i].addr == ec168_ec100_config.demod_address) { + if (msg[i].len < 1) { + i = -EOPNOTSUPP; + break; + } req.cmd = READ_DEMOD; req.value = 0; req.index = 0xff00 + msg[i].buf[0]; /* reg */ @@ -131,6 +135,10 @@ static int ec168_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], } } else { if (msg[i].addr == ec168_ec100_config.demod_address) { + if (msg[i].len < 1) { + i = -EOPNOTSUPP; + break; + } req.cmd = WRITE_DEMOD; req.value = msg[i].buf[1]; /* val */ req.index = 0xff00 + msg[i].buf[0]; /* reg */ @@ -139,6 +147,10 @@ static int ec168_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], ret = ec168_ctrl_msg(d, &req); i += 1; } else { + if (msg[i].len < 1) { + i = -EOPNOTSUPP; + break; + } req.cmd = WRITE_I2C; req.value = msg[i].buf[0]; /* val */ req.index = 0x0100 + msg[i].addr; /* I2C addr */ @@ -164,7 +176,7 @@ static u32 ec168_i2c_func(struct i2c_adapter *adapter) return I2C_FUNC_I2C; } -static struct i2c_algorithm ec168_i2c_algo = { +static const struct i2c_algorithm ec168_i2c_algo = { .master_xfer = ec168_i2c_xfer, .functionality = ec168_i2c_func, }; diff --git a/drivers/media/usb/dvb-usb-v2/gl861.c b/drivers/media/usb/dvb-usb-v2/gl861.c index 0c434259c36f..0538170ccf29 100644 --- a/drivers/media/usb/dvb-usb-v2/gl861.c +++ b/drivers/media/usb/dvb-usb-v2/gl861.c @@ -120,7 +120,7 @@ static int gl861_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], } else if (num == 2 && !(msg[0].flags & I2C_M_RD) && (msg[1].flags & I2C_M_RD)) { /* I2C write + read */ - if (msg[0].len > 1 || msg[1].len > sizeof(ctx->buf)) { + if (msg[0].len != 1 || msg[1].len > sizeof(ctx->buf)) { ret = -EOPNOTSUPP; goto err; } @@ -162,7 +162,7 @@ static u32 gl861_i2c_functionality(struct i2c_adapter *adapter) return I2C_FUNC_I2C; } -static struct i2c_algorithm gl861_i2c_algo = { +static const struct i2c_algorithm gl861_i2c_algo = { .master_xfer = gl861_i2c_master_xfer, .functionality = gl861_i2c_functionality, }; diff --git a/drivers/media/usb/dvb-usb-v2/lmedm04.c b/drivers/media/usb/dvb-usb-v2/lmedm04.c index 8a34e6c0d6a6..05c18b6de5c6 100644 --- a/drivers/media/usb/dvb-usb-v2/lmedm04.c +++ b/drivers/media/usb/dvb-usb-v2/lmedm04.c @@ -70,12 +70,12 @@ #include "ts2020.h" -#define LME2510_C_S7395 "dvb-usb-lme2510c-s7395.fw"; -#define LME2510_C_LG "dvb-usb-lme2510c-lg.fw"; -#define LME2510_C_S0194 "dvb-usb-lme2510c-s0194.fw"; -#define LME2510_C_RS2000 "dvb-usb-lme2510c-rs2000.fw"; -#define LME2510_LG "dvb-usb-lme2510-lg.fw"; -#define LME2510_S0194 "dvb-usb-lme2510-s0194.fw"; +#define LME2510_C_S7395 "dvb-usb-lme2510c-s7395.fw" +#define LME2510_C_LG "dvb-usb-lme2510c-lg.fw" +#define LME2510_C_S0194 "dvb-usb-lme2510c-s0194.fw" +#define LME2510_C_RS2000 "dvb-usb-lme2510c-rs2000.fw" +#define LME2510_LG "dvb-usb-lme2510-lg.fw" +#define LME2510_S0194 "dvb-usb-lme2510-s0194.fw" /* debug */ static int dvb_usb_lme2510_debug; @@ -373,6 +373,7 @@ static int lme2510_int_read(struct dvb_usb_adapter *adap) struct dvb_usb_device *d = adap_to_d(adap); struct lme2510_state *lme_int = adap_to_priv(adap); struct usb_host_endpoint *ep; + int ret; lme_int->lme_urb = usb_alloc_urb(0, GFP_KERNEL); @@ -390,11 +391,20 @@ static int lme2510_int_read(struct dvb_usb_adapter *adap) /* Quirk of pipe reporting PIPE_BULK but behaves as interrupt */ ep = usb_pipe_endpoint(d->udev, lme_int->lme_urb->pipe); + if (!ep) { + usb_free_urb(lme_int->lme_urb); + return -ENODEV; + } if (usb_endpoint_type(&ep->desc) == USB_ENDPOINT_XFER_BULK) lme_int->lme_urb->pipe = usb_rcvbulkpipe(d->udev, 0xa); - usb_submit_urb(lme_int->lme_urb, GFP_KERNEL); + ret = usb_submit_urb(lme_int->lme_urb, GFP_KERNEL); + if (ret) { + usb_free_urb(lme_int->lme_urb); + return ret; + } + info("INT Interrupt Service Started"); return 0; @@ -549,7 +559,7 @@ static u32 lme2510_i2c_func(struct i2c_adapter *adapter) return I2C_FUNC_I2C; } -static struct i2c_algorithm lme2510_i2c_algo = { +static const struct i2c_algorithm lme2510_i2c_algo = { .master_xfer = lme2510_i2c_xfer, .functionality = lme2510_i2c_func, }; diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf.c b/drivers/media/usb/dvb-usb-v2/mxl111sf.c index cd5861a30b6f..870ac3c8b085 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf.c +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf.c @@ -911,7 +911,7 @@ static u32 mxl111sf_i2c_func(struct i2c_adapter *adapter) return I2C_FUNC_I2C; } -static struct i2c_algorithm mxl111sf_i2c_algo = { +static const struct i2c_algorithm mxl111sf_i2c_algo = { .master_xfer = mxl111sf_i2c_xfer, .functionality = mxl111sf_i2c_func, #ifdef NEED_ALGO_CONTROL diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c index 795a012d4020..487c6ab784ab 100644 --- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c +++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c @@ -176,6 +176,10 @@ static int rtl28xxu_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], ret = -EOPNOTSUPP; goto err_mutex_unlock; } else if (msg[0].addr == 0x10) { + if (msg[0].len < 1 || msg[1].len < 1) { + ret = -EOPNOTSUPP; + goto err_mutex_unlock; + } /* method 1 - integrated demod */ if (msg[0].buf[0] == 0x00) { /* return demod page from driver cache */ @@ -189,6 +193,10 @@ static int rtl28xxu_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], ret = rtl28xxu_ctrl_msg(d, &req); } } else if (msg[0].len < 2) { + if (msg[0].len < 1) { + ret = -EOPNOTSUPP; + goto err_mutex_unlock; + } /* method 2 - old I2C */ req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1); req.index = CMD_I2C_RD; @@ -217,8 +225,16 @@ static int rtl28xxu_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], ret = -EOPNOTSUPP; goto err_mutex_unlock; } else if (msg[0].addr == 0x10) { + if (msg[0].len < 1) { + ret = -EOPNOTSUPP; + goto err_mutex_unlock; + } /* method 1 - integrated demod */ if (msg[0].buf[0] == 0x00) { + if (msg[0].len < 2) { + ret = -EOPNOTSUPP; + goto err_mutex_unlock; + } /* save demod page for later demod access */ dev->page = msg[0].buf[1]; ret = 0; @@ -231,6 +247,10 @@ static int rtl28xxu_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], ret = rtl28xxu_ctrl_msg(d, &req); } } else if ((msg[0].len < 23) && (!dev->new_i2c_write)) { + if (msg[0].len < 1) { + ret = -EOPNOTSUPP; + goto err_mutex_unlock; + } /* method 2 - old I2C */ req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1); req.index = CMD_I2C_WR; @@ -270,7 +290,7 @@ static u32 rtl28xxu_i2c_func(struct i2c_adapter *adapter) return I2C_FUNC_I2C; } -static struct i2c_algorithm rtl28xxu_i2c_algo = { +static const struct i2c_algorithm rtl28xxu_i2c_algo = { .master_xfer = rtl28xxu_i2c_xfer, .functionality = rtl28xxu_i2c_func, }; diff --git a/drivers/media/usb/dvb-usb/a800.c b/drivers/media/usb/dvb-usb/a800.c index 5f294784923c..c5f95e48f1d5 100644 --- a/drivers/media/usb/dvb-usb/a800.c +++ b/drivers/media/usb/dvb-usb/a800.c @@ -77,7 +77,7 @@ enum { AVERMEDIA_DVBT_USB2_WARM, }; -static struct usb_device_id a800_table[] = { +static const struct usb_device_id a800_table[] = { DVB_USB_DEV(AVERMEDIA, AVERMEDIA_DVBT_USB2_COLD), DVB_USB_DEV(AVERMEDIA, AVERMEDIA_DVBT_USB2_WARM), { } diff --git a/drivers/media/usb/dvb-usb/af9005-fe.c b/drivers/media/usb/dvb-usb/af9005-fe.c index 9d6fa0556d7b..404e56b32145 100644 --- a/drivers/media/usb/dvb-usb/af9005-fe.c +++ b/drivers/media/usb/dvb-usb/af9005-fe.c @@ -1412,8 +1412,7 @@ static int af9005_fe_get_frontend(struct dvb_frontend *fe, static void af9005_fe_release(struct dvb_frontend *fe) { - struct af9005_fe_state *state = - (struct af9005_fe_state *)fe->demodulator_priv; + struct af9005_fe_state *state = fe->demodulator_priv; kfree(state); } diff --git a/drivers/media/usb/dvb-usb/af9005.c b/drivers/media/usb/dvb-usb/af9005.c index 0827bf3d4e8c..a4bede7e8a1d 100644 --- a/drivers/media/usb/dvb-usb/af9005.c +++ b/drivers/media/usb/dvb-usb/af9005.c @@ -422,6 +422,10 @@ static int af9005_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], if (ret == 0) ret = 2; } else { + if (msg[0].len < 2) { + ret = -EOPNOTSUPP; + goto unlock; + } /* write one or more registers */ reg = msg[0].buf[0]; addr = msg[0].addr; @@ -431,6 +435,7 @@ static int af9005_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], ret = 1; } +unlock: mutex_unlock(&d->i2c_mutex); return ret; } @@ -440,7 +445,7 @@ static u32 af9005_i2c_func(struct i2c_adapter *adapter) return I2C_FUNC_I2C; } -static struct i2c_algorithm af9005_i2c_algo = { +static const struct i2c_algorithm af9005_i2c_algo = { .master_xfer = af9005_i2c_xfer, .functionality = af9005_i2c_func, }; @@ -1000,7 +1005,7 @@ enum { ANSONIC_DVBT_USB, }; -static struct usb_device_id af9005_usb_table[] = { +static const struct usb_device_id af9005_usb_table[] = { DVB_USB_DEV(AFATECH, AFATECH_AF9005), DVB_USB_DEV(TERRATEC, TERRATEC_CINERGY_T_USB_XE), DVB_USB_DEV(ANSONIC, ANSONIC_DVBT_USB), diff --git a/drivers/media/usb/dvb-usb/az6027.c b/drivers/media/usb/dvb-usb/az6027.c index 7d78ee09be5e..056935d3cbd6 100644 --- a/drivers/media/usb/dvb-usb/az6027.c +++ b/drivers/media/usb/dvb-usb/az6027.c @@ -407,8 +407,8 @@ static int az6027_ci_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address) { - struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; - struct az6027_device_state *state = (struct az6027_device_state *)d->priv; + struct dvb_usb_device *d = ca->data; + struct az6027_device_state *state = d->priv; int ret; u8 req; @@ -449,8 +449,8 @@ static int az6027_ci_write_attribute_mem(struct dvb_ca_en50221 *ca, int address, u8 value) { - struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; - struct az6027_device_state *state = (struct az6027_device_state *)d->priv; + struct dvb_usb_device *d = ca->data; + struct az6027_device_state *state = d->priv; int ret; u8 req; @@ -480,8 +480,8 @@ static int az6027_ci_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address) { - struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; - struct az6027_device_state *state = (struct az6027_device_state *)d->priv; + struct dvb_usb_device *d = ca->data; + struct az6027_device_state *state = d->priv; int ret; u8 req; @@ -526,8 +526,8 @@ static int az6027_ci_write_cam_control(struct dvb_ca_en50221 *ca, u8 address, u8 value) { - struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; - struct az6027_device_state *state = (struct az6027_device_state *)d->priv; + struct dvb_usb_device *d = ca->data; + struct az6027_device_state *state = d->priv; int ret; u8 req; @@ -557,7 +557,7 @@ failed: static int CI_CamReady(struct dvb_ca_en50221 *ca, int slot) { - struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; + struct dvb_usb_device *d = ca->data; int ret; u8 req; @@ -588,8 +588,8 @@ static int CI_CamReady(struct dvb_ca_en50221 *ca, int slot) static int az6027_ci_slot_reset(struct dvb_ca_en50221 *ca, int slot) { - struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; - struct az6027_device_state *state = (struct az6027_device_state *)d->priv; + struct dvb_usb_device *d = ca->data; + struct az6027_device_state *state = d->priv; int ret, i; u8 req; @@ -644,8 +644,8 @@ static int az6027_ci_slot_shutdown(struct dvb_ca_en50221 *ca, int slot) static int az6027_ci_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot) { - struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; - struct az6027_device_state *state = (struct az6027_device_state *)d->priv; + struct dvb_usb_device *d = ca->data; + struct az6027_device_state *state = d->priv; int ret; u8 req; @@ -673,8 +673,8 @@ failed: static int az6027_ci_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open) { - struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; - struct az6027_device_state *state = (struct az6027_device_state *)d->priv; + struct dvb_usb_device *d = ca->data; + struct az6027_device_state *state = d->priv; int ret; u8 req; u16 value; @@ -719,7 +719,7 @@ static void az6027_ci_uninit(struct dvb_usb_device *d) if (NULL == d) return; - state = (struct az6027_device_state *)d->priv; + state = d->priv; if (NULL == state) return; @@ -735,7 +735,7 @@ static void az6027_ci_uninit(struct dvb_usb_device *d) static int az6027_ci_init(struct dvb_usb_adapter *a) { struct dvb_usb_device *d = a->dev; - struct az6027_device_state *state = (struct az6027_device_state *)d->priv; + struct az6027_device_state *state = d->priv; int ret; deb_info("%s", __func__); @@ -988,6 +988,10 @@ static int az6027_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int n /* write/read request */ if (i + 1 < num && (msg[i + 1].flags & I2C_M_RD)) { req = 0xB9; + if (msg[i].len < 1) { + i = -EOPNOTSUPP; + break; + } index = (((msg[i].buf[0] << 8) & 0xff00) | (msg[i].buf[1] & 0x00ff)); value = msg[i].addr + (msg[i].len << 8); length = msg[i + 1].len + 6; @@ -1001,6 +1005,10 @@ static int az6027_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int n /* demod 16bit addr */ req = 0xBD; + if (msg[i].len < 1) { + i = -EOPNOTSUPP; + break; + } index = (((msg[i].buf[0] << 8) & 0xff00) | (msg[i].buf[1] & 0x00ff)); value = msg[i].addr + (2 << 8); length = msg[i].len - 2; @@ -1026,6 +1034,10 @@ static int az6027_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int n } else { req = 0xBD; + if (msg[i].len < 1) { + i = -EOPNOTSUPP; + break; + } index = msg[i].buf[0] & 0x00FF; value = msg[i].addr + (1 << 8); length = msg[i].len - 1; @@ -1050,7 +1062,7 @@ static u32 az6027_i2c_func(struct i2c_adapter *adapter) return I2C_FUNC_I2C; } -static struct i2c_algorithm az6027_i2c_algo = { +static const struct i2c_algorithm az6027_i2c_algo = { .master_xfer = az6027_i2c_xfer, .functionality = az6027_i2c_func, }; @@ -1095,7 +1107,7 @@ enum { ELGATO_EYETV_SAT_V3, }; -static struct usb_device_id az6027_usb_table[] = { +static const struct usb_device_id az6027_usb_table[] = { DVB_USB_DEV(AZUREWAVE, AZUREWAVE_AZ6027), DVB_USB_DEV(TERRATEC, TERRATEC_DVBS2CI_V1), DVB_USB_DEV(TERRATEC, TERRATEC_DVBS2CI_V2), diff --git a/drivers/media/usb/dvb-usb/cinergyT2-core.c b/drivers/media/usb/dvb-usb/cinergyT2-core.c index 4926c954e29a..d86c279e2dce 100644 --- a/drivers/media/usb/dvb-usb/cinergyT2-core.c +++ b/drivers/media/usb/dvb-usb/cinergyT2-core.c @@ -197,7 +197,7 @@ enum { TERRATEC_CINERGY_T2, }; -static struct usb_device_id cinergyt2_usb_table[] = { +static const struct usb_device_id cinergyt2_usb_table[] = { DVB_USB_DEV(TERRATEC, TERRATEC_CINERGY_T2), { } }; diff --git a/drivers/media/usb/dvb-usb/cxusb-analog.c b/drivers/media/usb/dvb-usb/cxusb-analog.c index e93183ddd797..3bbee1fcbc8d 100644 --- a/drivers/media/usb/dvb-usb/cxusb-analog.c +++ b/drivers/media/usb/dvb-usb/cxusb-analog.c @@ -817,8 +817,8 @@ static int cxusb_medion_v_start_streaming(struct vb2_queue *q, * doing a large continuous allocation when (if) * s-g isochronous USB transfers are supported */ - streambuf = kmalloc(npackets * CXUSB_VIDEO_PKT_SIZE, - GFP_KERNEL); + streambuf = kmalloc_array(npackets, CXUSB_VIDEO_PKT_SIZE, + GFP_KERNEL); if (!streambuf) { if (i < 2) { ret = -ENOMEM; @@ -956,8 +956,6 @@ static const struct vb2_ops cxdev_video_qops = { .start_streaming = cxusb_medion_v_start_streaming, .stop_streaming = cxusb_medion_v_stop_streaming, .buf_queue = cxusub_medion_v_buf_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish }; static const __u32 videocaps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | @@ -1014,7 +1012,10 @@ static int cxusb_medion_try_s_fmt_vid_cap(struct file *file, { struct dvb_usb_device *dvbdev = video_drvdata(file); struct cxusb_medion_dev *cxdev = dvbdev->priv; - struct v4l2_subdev_format subfmt; + struct v4l2_subdev_format subfmt = { + .which = isset ? V4L2_SUBDEV_FORMAT_ACTIVE : + V4L2_SUBDEV_FORMAT_TRY, + }; u32 field; int ret; @@ -1024,9 +1025,6 @@ static int cxusb_medion_try_s_fmt_vid_cap(struct file *file, field = vb2_start_streaming_called(&cxdev->videoqueue) ? cxdev->field_order : cxusb_medion_field_order(cxdev); - memset(&subfmt, 0, sizeof(subfmt)); - subfmt.which = isset ? V4L2_SUBDEV_FORMAT_ACTIVE : - V4L2_SUBDEV_FORMAT_TRY; subfmt.format.width = f->fmt.pix.width & ~1; subfmt.format.height = f->fmt.pix.height & ~1; subfmt.format.code = MEDIA_BUS_FMT_FIXED; @@ -1464,7 +1462,9 @@ int cxusb_medion_analog_init(struct dvb_usb_device *dvbdev) .buf = tuner_analog_msg_data, .len = sizeof(tuner_analog_msg_data) }; - struct v4l2_subdev_format subfmt; + struct v4l2_subdev_format subfmt = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; int ret; /* switch tuner to analog mode so IF demod will become accessible */ @@ -1507,8 +1507,6 @@ int cxusb_medion_analog_init(struct dvb_usb_device *dvbdev) v4l2_subdev_call(cxdev->tuner, video, s_std, cxdev->norm); v4l2_subdev_call(cxdev->cx25840, video, s_std, cxdev->norm); - memset(&subfmt, 0, sizeof(subfmt)); - subfmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; subfmt.format.width = cxdev->width; subfmt.format.height = cxdev->height; subfmt.format.code = MEDIA_BUS_FMT_FIXED; @@ -1632,7 +1630,7 @@ static int cxusb_medion_register_analog_video(struct dvb_usb_device *dvbdev) cxdev->videoqueue.buf_struct_size = sizeof(struct cxusb_medion_vbuffer); cxdev->videoqueue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - cxdev->videoqueue.min_buffers_needed = 6; + cxdev->videoqueue.min_queued_buffers = 6; cxdev->videoqueue.lock = &cxdev->dev_lock; ret = vb2_queue_init(&cxdev->videoqueue); diff --git a/drivers/media/usb/dvb-usb/cxusb.c b/drivers/media/usb/dvb-usb/cxusb.c index 1d98d3465e28..d0501c1e81d6 100644 --- a/drivers/media/usb/dvb-usb/cxusb.c +++ b/drivers/media/usb/dvb-usb/cxusb.c @@ -78,7 +78,7 @@ enum cxusb_table_index { NR__cxusb_table_index }; -static struct usb_device_id cxusb_table[]; +static const struct usb_device_id cxusb_table[]; int cxusb_ctrl_msg(struct dvb_usb_device *d, u8 cmd, const u8 *wbuf, int wlen, u8 *rbuf, int rlen) @@ -119,9 +119,8 @@ static void cxusb_gpio_tuner(struct dvb_usb_device *d, int onoff) o[0] = GPIO_TUNER; o[1] = onoff; - cxusb_ctrl_msg(d, CMD_GPIO_WRITE, o, 2, &i, 1); - if (i != 0x01) + if (!cxusb_ctrl_msg(d, CMD_GPIO_WRITE, o, 2, &i, 1) && i != 0x01) dev_info(&d->udev->dev, "gpio_write failed.\n"); st->gpio_write_state[GPIO_TUNER] = onoff; @@ -287,7 +286,7 @@ static u32 cxusb_i2c_func(struct i2c_adapter *adapter) return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; } -static struct i2c_algorithm cxusb_i2c_algo = { +static const struct i2c_algorithm cxusb_i2c_algo = { .master_xfer = cxusb_i2c_xfer, .functionality = cxusb_i2c_func, }; @@ -1692,7 +1691,7 @@ static void cxusb_disconnect(struct usb_interface *intf) dvb_usb_device_exit(intf); } -static struct usb_device_id cxusb_table[] = { +static const struct usb_device_id cxusb_table[] = { DVB_USB_DEV(MEDION, MEDION_MD95700), DVB_USB_DEV(DVICO, DVICO_BLUEBIRD_LG064F_COLD), DVB_USB_DEV(DVICO, DVICO_BLUEBIRD_LG064F_WARM), diff --git a/drivers/media/usb/dvb-usb/dib0700_devices.c b/drivers/media/usb/dvb-usb/dib0700_devices.c index 3af594134a6d..6ddc20513393 100644 --- a/drivers/media/usb/dvb-usb/dib0700_devices.c +++ b/drivers/media/usb/dvb-usb/dib0700_devices.c @@ -2412,7 +2412,12 @@ static int stk9090m_frontend_attach(struct dvb_usb_adapter *adap) adap->fe_adap[0].fe = dvb_attach(dib9000_attach, &adap->dev->i2c_adap, 0x80, &stk9090m_config); - return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; + if (!adap->fe_adap[0].fe) { + release_firmware(state->frontend_firmware); + return -ENODEV; + } + + return 0; } static int dib9090_tuner_attach(struct dvb_usb_adapter *adap) @@ -2485,8 +2490,10 @@ static int nim9090md_frontend_attach(struct dvb_usb_adapter *adap) dib9000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x20, 0x80); adap->fe_adap[0].fe = dvb_attach(dib9000_attach, &adap->dev->i2c_adap, 0x80, &nim9090md_config[0]); - if (adap->fe_adap[0].fe == NULL) + if (!adap->fe_adap[0].fe) { + release_firmware(state->frontend_firmware); return -ENODEV; + } i2c = dib9000_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_GPIO_3_4, 0); dib9000_i2c_enumeration(i2c, 1, 0x12, 0x82); @@ -2494,7 +2501,12 @@ static int nim9090md_frontend_attach(struct dvb_usb_adapter *adap) fe_slave = dvb_attach(dib9000_attach, i2c, 0x82, &nim9090md_config[1]); dib9000_set_slave_frontend(adap->fe_adap[0].fe, fe_slave); - return fe_slave == NULL ? -ENODEV : 0; + if (!fe_slave) { + release_firmware(state->frontend_firmware); + return -ENODEV; + } + + return 0; } static int nim9090md_tuner_attach(struct dvb_usb_adapter *adap) diff --git a/drivers/media/usb/dvb-usb/dibusb-common.c b/drivers/media/usb/dvb-usb/dibusb-common.c index aff60c10cb0b..20f1ef3393a5 100644 --- a/drivers/media/usb/dvb-usb/dibusb-common.c +++ b/drivers/media/usb/dvb-usb/dibusb-common.c @@ -14,6 +14,7 @@ static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "set debugging level (1=info (|-able))." DVB_USB_DEBUG_STATUS); +MODULE_DESCRIPTION("Common methods for dibusb-based receivers"); MODULE_LICENSE("GPL"); #define deb_info(args...) dprintk(debug,0x01,args) diff --git a/drivers/media/usb/dvb-usb/dibusb-mb.c b/drivers/media/usb/dvb-usb/dibusb-mb.c index 2cd88cab4c98..431766f19931 100644 --- a/drivers/media/usb/dvb-usb/dibusb-mb.c +++ b/drivers/media/usb/dvb-usb/dibusb-mb.c @@ -155,7 +155,7 @@ enum { ULTIMA_TVBOX_ANCHOR_COLD, }; -static struct usb_device_id dibusb_dib3000mb_table[] = { +static const struct usb_device_id dibusb_dib3000mb_table[] = { DVB_USB_DEV(WIDEVIEW, WIDEVIEW_DVBT_USB_COLD), DVB_USB_DEV(WIDEVIEW, WIDEVIEW_DVBT_USB_WARM), DVB_USB_DEV(COMPRO, COMPRO_DVBU2000_COLD), diff --git a/drivers/media/usb/dvb-usb/dibusb-mc-common.c b/drivers/media/usb/dvb-usb/dibusb-mc-common.c index b8cde4cded33..36bc7762acf4 100644 --- a/drivers/media/usb/dvb-usb/dibusb-mc-common.c +++ b/drivers/media/usb/dvb-usb/dibusb-mc-common.c @@ -8,6 +8,7 @@ #include "dibusb.h" +MODULE_DESCRIPTION("Common methods for DIB3000MC"); MODULE_LICENSE("GPL"); /* 3000MC/P stuff */ diff --git a/drivers/media/usb/dvb-usb/dibusb-mc.c b/drivers/media/usb/dvb-usb/dibusb-mc.c index 00cb016f6266..01eece2687d6 100644 --- a/drivers/media/usb/dvb-usb/dibusb-mc.c +++ b/drivers/media/usb/dvb-usb/dibusb-mc.c @@ -43,7 +43,7 @@ enum { HUMAX_DVB_T_STICK_HIGH_SPEED_WARM, }; -static struct usb_device_id dibusb_dib3000mc_table[] = { +static const struct usb_device_id dibusb_dib3000mc_table[] = { DVB_USB_DEV(DIBCOM, DIBCOM_MOD3001_COLD), DVB_USB_DEV(DIBCOM, DIBCOM_MOD3001_WARM), DVB_USB_DEV(ULTIMA_ELECTRONIC, ULTIMA_TVBOX_USB2_COLD), diff --git a/drivers/media/usb/dvb-usb/digitv.c b/drivers/media/usb/dvb-usb/digitv.c index 2756815a780b..ab229ab1a858 100644 --- a/drivers/media/usb/dvb-usb/digitv.c +++ b/drivers/media/usb/dvb-usb/digitv.c @@ -63,6 +63,10 @@ static int digitv_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num warn("more than 2 i2c messages at a time is not handled yet. TODO."); for (i = 0; i < num; i++) { + if (msg[i].len < 1) { + i = -EOPNOTSUPP; + break; + } /* write/read request */ if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) { if (digitv_ctrl_msg(d, USB_READ_COFDM, msg[i].buf[0], NULL, 0, @@ -84,7 +88,7 @@ static u32 digitv_i2c_func(struct i2c_adapter *adapter) return I2C_FUNC_I2C; } -static struct i2c_algorithm digitv_i2c_algo = { +static const struct i2c_algorithm digitv_i2c_algo = { .master_xfer = digitv_i2c_xfer, .functionality = digitv_i2c_func, }; @@ -295,7 +299,7 @@ enum { ANCHOR_NEBULA_DIGITV, }; -static struct usb_device_id digitv_table[] = { +static const struct usb_device_id digitv_table[] = { DVB_USB_DEV(ANCHOR, ANCHOR_NEBULA_DIGITV), { } }; diff --git a/drivers/media/usb/dvb-usb/dtt200u-fe.c b/drivers/media/usb/dvb-usb/dtt200u-fe.c index 9f83560ba63d..586afe22d817 100644 --- a/drivers/media/usb/dvb-usb/dtt200u-fe.c +++ b/drivers/media/usb/dvb-usb/dtt200u-fe.c @@ -195,7 +195,7 @@ static int dtt200u_fe_get_frontend(struct dvb_frontend* fe, static void dtt200u_fe_release(struct dvb_frontend* fe) { - struct dtt200u_fe_state *state = (struct dtt200u_fe_state*) fe->demodulator_priv; + struct dtt200u_fe_state *state = fe->demodulator_priv; kfree(state); } diff --git a/drivers/media/usb/dvb-usb/dtt200u.c b/drivers/media/usb/dvb-usb/dtt200u.c index e6ee56b3a9dd..83a69df384f2 100644 --- a/drivers/media/usb/dvb-usb/dtt200u.c +++ b/drivers/media/usb/dvb-usb/dtt200u.c @@ -171,7 +171,7 @@ enum { MIGLIA_WT220U_ZAP250_COLD, }; -static struct usb_device_id dtt200u_usb_table[] = { +static const struct usb_device_id dtt200u_usb_table[] = { DVB_USB_DEV(WIDEVIEW, WIDEVIEW_DTT200U_COLD), DVB_USB_DEV(WIDEVIEW, WIDEVIEW_DTT200U_WARM), DVB_USB_DEV(WIDEVIEW, WIDEVIEW_WT220U_COLD), diff --git a/drivers/media/usb/dvb-usb/dtv5100.c b/drivers/media/usb/dvb-usb/dtv5100.c index 56c9d521a34a..c448e2ebda1a 100644 --- a/drivers/media/usb/dvb-usb/dtv5100.c +++ b/drivers/media/usb/dvb-usb/dtv5100.c @@ -55,6 +55,11 @@ static int dtv5100_i2c_msg(struct dvb_usb_device *d, u8 addr, } index = (addr << 8) + wbuf[0]; + if (rlen > sizeof(st->data)) { + warn("rlen = %x is too big!\n", rlen); + return -EINVAL; + } + memcpy(st->data, rbuf, rlen); msleep(1); /* avoid I2C errors */ return usb_control_msg(d->udev, pipe, request, @@ -97,7 +102,7 @@ static u32 dtv5100_i2c_func(struct i2c_adapter *adapter) return I2C_FUNC_I2C; } -static struct i2c_algorithm dtv5100_i2c_algo = { +static const struct i2c_algorithm dtv5100_i2c_algo = { .master_xfer = dtv5100_i2c_xfer, .functionality = dtv5100_i2c_func, }; @@ -166,7 +171,7 @@ enum { AME_DTV5100, }; -static struct usb_device_id dtv5100_table[] = { +static const struct usb_device_id dtv5100_table[] = { DVB_USB_DEV(AME, AME_DTV5100), { } }; diff --git a/drivers/media/usb/dvb-usb/dvb-usb.h b/drivers/media/usb/dvb-usb/dvb-usb.h index 0990aa4a17bb..550006a8d86f 100644 --- a/drivers/media/usb/dvb-usb/dvb-usb.h +++ b/drivers/media/usb/dvb-usb/dvb-usb.h @@ -73,8 +73,8 @@ struct dvb_usb_device_description { const char *name; #define DVB_USB_ID_MAX_NUM 15 - struct usb_device_id *cold_ids[DVB_USB_ID_MAX_NUM]; - struct usb_device_id *warm_ids[DVB_USB_ID_MAX_NUM]; + const struct usb_device_id *cold_ids[DVB_USB_ID_MAX_NUM]; + const struct usb_device_id *warm_ids[DVB_USB_ID_MAX_NUM]; }; static inline u8 rc5_custom(struct rc_map_table *key) @@ -126,8 +126,6 @@ struct usb_data_stream_properties { * @caps: capabilities of the DVB USB device. * @pid_filter_count: number of PID filter position in the optional hardware * PID-filter. - * @num_frontends: number of frontends of the DVB USB adapter. - * @frontend_ctrl: called to power on/off active frontend. * @streaming_ctrl: called to start and stop the MPEG2-TS streaming of the * device (not URB submitting/killing). * This callback will be called without data URBs being active - data URBs @@ -311,7 +309,7 @@ struct dvb_usb_device_properties { struct dvb_rc core; } rc; - struct i2c_algorithm *i2c_algo; + const struct i2c_algorithm *i2c_algo; int generic_bulk_ctrl_endpoint; int generic_bulk_ctrl_endpoint_response; diff --git a/drivers/media/usb/dvb-usb/dw2102.c b/drivers/media/usb/dvb-usb/dw2102.c index 0ca764282c76..4fecf2f965e9 100644 --- a/drivers/media/usb/dvb-usb/dw2102.c +++ b/drivers/media/usb/dvb-usb/dw2102.c @@ -36,7 +36,6 @@ /* Max transfer size done by I2C transfer functions */ #define MAX_XFER_SIZE 64 - #define DW210X_READ_MSG 0 #define DW210X_WRITE_MSG 1 @@ -53,10 +52,10 @@ #define DW2102_FIRMWARE "dvb-usb-dw2102.fw" #define DW2104_FIRMWARE "dvb-usb-dw2104.fw" #define DW3101_FIRMWARE "dvb-usb-dw3101.fw" -#define S630_FIRMWARE "dvb-usb-s630.fw" -#define S660_FIRMWARE "dvb-usb-s660.fw" -#define P1100_FIRMWARE "dvb-usb-p1100.fw" -#define P7500_FIRMWARE "dvb-usb-p7500.fw" +#define S630_FIRMWARE "dvb-usb-s630.fw" +#define S660_FIRMWARE "dvb-usb-s660.fw" +#define P1100_FIRMWARE "dvb-usb-p1100.fw" +#define P7500_FIRMWARE "dvb-usb-p7500.fw" #define err_str "did not find the firmware file '%s'. You can use <kernel_dir>/scripts/get_dvb_firmware to get the firmware" @@ -87,7 +86,7 @@ MODULE_PARM_DESC(demod, "demod to probe (1=cx24116 2=stv0903+stv6110 4=stv0903+s DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); static int dw210x_op_rw(struct usb_device *dev, u8 request, u16 value, - u16 index, u8 * data, u16 len, int flags) + u16 index, u8 *data, u16 len, int flags) { int ret; u8 *u8buf; @@ -99,11 +98,10 @@ static int dw210x_op_rw(struct usb_device *dev, u8 request, u16 value, if (!u8buf) return -ENOMEM; - if (flags == DW210X_WRITE_MSG) memcpy(u8buf, data, len); ret = usb_control_msg(dev, pipe, request, request_type | USB_TYPE_VENDOR, - value, index , u8buf, len, 2000); + value, index, u8buf, len, 2000); if (flags == DW210X_READ_MSG) memcpy(data, u8buf, len); @@ -114,7 +112,7 @@ static int dw210x_op_rw(struct usb_device *dev, u8 request, u16 value, /* I2C */ static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], - int num) + int num) { struct dvb_usb_device *d = i2c_get_adapdata(adap); int i = 0; @@ -128,26 +126,38 @@ static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], switch (num) { case 2: + if (msg[0].len < 1) { + num = -EOPNOTSUPP; + break; + } /* read stv0299 register */ value = msg[0].buf[0];/* register */ for (i = 0; i < msg[1].len; i++) { dw210x_op_rw(d->udev, 0xb5, value + i, 0, - buf6, 2, DW210X_READ_MSG); + buf6, 2, DW210X_READ_MSG); msg[1].buf[i] = buf6[0]; } break; case 1: switch (msg[0].addr) { case 0x68: + if (msg[0].len < 2) { + num = -EOPNOTSUPP; + break; + } /* write to stv0299 register */ buf6[0] = 0x2a; buf6[1] = msg[0].buf[0]; buf6[2] = msg[0].buf[1]; dw210x_op_rw(d->udev, 0xb2, 0, 0, - buf6, 3, DW210X_WRITE_MSG); + buf6, 3, DW210X_WRITE_MSG); break; case 0x60: if (msg[0].flags == 0) { + if (msg[0].len < 4) { + num = -EOPNOTSUPP; + break; + } /* write to tuner pll */ buf6[0] = 0x2c; buf6[1] = 5; @@ -157,25 +167,37 @@ static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], buf6[5] = msg[0].buf[2]; buf6[6] = msg[0].buf[3]; dw210x_op_rw(d->udev, 0xb2, 0, 0, - buf6, 7, DW210X_WRITE_MSG); + buf6, 7, DW210X_WRITE_MSG); } else { + if (msg[0].len < 1) { + num = -EOPNOTSUPP; + break; + } /* read from tuner */ dw210x_op_rw(d->udev, 0xb5, 0, 0, - buf6, 1, DW210X_READ_MSG); + buf6, 1, DW210X_READ_MSG); msg[0].buf[0] = buf6[0]; } break; case (DW2102_RC_QUERY): + if (msg[0].len < 2) { + num = -EOPNOTSUPP; + break; + } dw210x_op_rw(d->udev, 0xb8, 0, 0, - buf6, 2, DW210X_READ_MSG); + buf6, 2, DW210X_READ_MSG); msg[0].buf[0] = buf6[0]; msg[0].buf[1] = buf6[1]; break; case (DW2102_VOLTAGE_CTRL): + if (msg[0].len < 1) { + num = -EOPNOTSUPP; + break; + } buf6[0] = 0x30; buf6[1] = msg[0].buf[0]; dw210x_op_rw(d->udev, 0xb2, 0, 0, - buf6, 2, DW210X_WRITE_MSG); + buf6, 2, DW210X_WRITE_MSG); break; } @@ -187,7 +209,7 @@ static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], } static int dw2102_serit_i2c_transfer(struct i2c_adapter *adap, - struct i2c_msg msg[], int num) + struct i2c_msg msg[], int num) { struct dvb_usb_device *d = i2c_get_adapdata(adap); u8 buf6[] = {0, 0, 0, 0, 0, 0, 0}; @@ -218,10 +240,10 @@ static int dw2102_serit_i2c_transfer(struct i2c_adapter *adap, buf6[1] = msg[0].len; buf6[2] = msg[0].buf[0]; dw210x_op_rw(d->udev, 0xc2, 0, 0, - buf6, msg[0].len + 2, DW210X_WRITE_MSG); + buf6, msg[0].len + 2, DW210X_WRITE_MSG); /* read si2109 register */ dw210x_op_rw(d->udev, 0xc3, 0xd0, 0, - buf6, msg[1].len + 2, DW210X_READ_MSG); + buf6, msg[1].len + 2, DW210X_READ_MSG); memcpy(msg[1].buf, buf6 + 2, msg[1].len); break; @@ -240,11 +262,11 @@ static int dw2102_serit_i2c_transfer(struct i2c_adapter *adap, buf6[1] = msg[0].len; memcpy(buf6 + 2, msg[0].buf, msg[0].len); dw210x_op_rw(d->udev, 0xc2, 0, 0, buf6, - msg[0].len + 2, DW210X_WRITE_MSG); + msg[0].len + 2, DW210X_WRITE_MSG); break; case(DW2102_RC_QUERY): dw210x_op_rw(d->udev, 0xb8, 0, 0, - buf6, 2, DW210X_READ_MSG); + buf6, 2, DW210X_READ_MSG); msg[0].buf[0] = buf6[0]; msg[0].buf[1] = buf6[1]; break; @@ -252,7 +274,7 @@ static int dw2102_serit_i2c_transfer(struct i2c_adapter *adap, buf6[0] = 0x30; buf6[1] = msg[0].buf[0]; dw210x_op_rw(d->udev, 0xb2, 0, 0, - buf6, 2, DW210X_WRITE_MSG); + buf6, 2, DW210X_WRITE_MSG); break; } break; @@ -296,10 +318,10 @@ static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg ms obuf[1] = msg[0].len; obuf[2] = msg[0].buf[0]; dw210x_op_rw(d->udev, 0xc2, 0, 0, - obuf, msg[0].len + 2, DW210X_WRITE_MSG); + obuf, msg[0].len + 2, DW210X_WRITE_MSG); /* second read registers */ - dw210x_op_rw(d->udev, 0xc3, 0xd1 , 0, - ibuf, msg[1].len + 2, DW210X_READ_MSG); + dw210x_op_rw(d->udev, 0xc3, 0xd1, 0, + ibuf, msg[1].len + 2, DW210X_READ_MSG); memcpy(msg[1].buf, ibuf + 2, msg[1].len); break; @@ -321,7 +343,7 @@ static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg ms obuf[1] = msg[0].len; memcpy(obuf + 2, msg[0].buf, msg[0].len); dw210x_op_rw(d->udev, 0xc2, 0, 0, - obuf, msg[0].len + 2, DW210X_WRITE_MSG); + obuf, msg[0].len + 2, DW210X_WRITE_MSG); break; } case 0x61: { @@ -339,22 +361,24 @@ static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg ms obuf[1] = msg[0].len; memcpy(obuf + 2, msg[0].buf, msg[0].len); dw210x_op_rw(d->udev, 0xc2, 0, 0, - obuf, msg[0].len + 2, DW210X_WRITE_MSG); + obuf, msg[0].len + 2, DW210X_WRITE_MSG); break; } case(DW2102_RC_QUERY): { u8 ibuf[2]; + dw210x_op_rw(d->udev, 0xb8, 0, 0, - ibuf, 2, DW210X_READ_MSG); - memcpy(msg[0].buf, ibuf , 2); + ibuf, 2, DW210X_READ_MSG); + memcpy(msg[0].buf, ibuf, 2); break; } case(DW2102_VOLTAGE_CTRL): { u8 obuf[2]; + obuf[0] = 0x30; obuf[1] = msg[0].buf[0]; dw210x_op_rw(d->udev, 0xb2, 0, 0, - obuf, 2, DW210X_WRITE_MSG); + obuf, 2, DW210X_WRITE_MSG); break; } } @@ -382,23 +406,26 @@ static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], i switch (msg[j].addr) { case(DW2102_RC_QUERY): { u8 ibuf[2]; + dw210x_op_rw(d->udev, 0xb8, 0, 0, - ibuf, 2, DW210X_READ_MSG); - memcpy(msg[j].buf, ibuf , 2); + ibuf, 2, DW210X_READ_MSG); + memcpy(msg[j].buf, ibuf, 2); break; } case(DW2102_VOLTAGE_CTRL): { u8 obuf[2]; + obuf[0] = 0x30; obuf[1] = msg[j].buf[0]; dw210x_op_rw(d->udev, 0xb2, 0, 0, - obuf, 2, DW210X_WRITE_MSG); + obuf, 2, DW210X_WRITE_MSG); break; } - /*case 0x55: cx24116 - case 0x6a: stv0903 - case 0x68: ds3000, stv0903 - case 0x60: ts2020, stv6110, stb6100 */ + /* case 0x55: cx24116 + * case 0x6a: stv0903 + * case 0x68: ds3000, stv0903 + * case 0x60: ts2020, stv6110, stb6100 + */ default: { if (msg[j].flags == I2C_M_RD) { /* read registers */ @@ -412,17 +439,16 @@ static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], i } dw210x_op_rw(d->udev, 0xc3, - (msg[j].addr << 1) + 1, 0, - ibuf, msg[j].len + 2, - DW210X_READ_MSG); + (msg[j].addr << 1) + 1, 0, + ibuf, msg[j].len + 2, + DW210X_READ_MSG); memcpy(msg[j].buf, ibuf + 2, msg[j].len); mdelay(10); - } else if (((msg[j].buf[0] == 0xb0) && - (msg[j].addr == 0x68)) || - ((msg[j].buf[0] == 0xf7) && - (msg[j].addr == 0x55))) { + } else if (((msg[j].buf[0] == 0xb0) && (msg[j].addr == 0x68)) || + ((msg[j].buf[0] == 0xf7) && (msg[j].addr == 0x55))) { /* write firmware */ u8 obuf[19]; + obuf[0] = msg[j].addr << 1; obuf[1] = (msg[j].len > 15 ? 17 : msg[j].len); obuf[2] = msg[j].buf[0]; @@ -430,10 +456,10 @@ static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], i i = 1; do { memcpy(obuf + 3, msg[j].buf + i, - (len > 16 ? 16 : len)); + (len > 16 ? 16 : len)); dw210x_op_rw(d->udev, 0xc2, 0, 0, - obuf, (len > 16 ? 16 : len) + 3, - DW210X_WRITE_MSG); + obuf, (len > 16 ? 16 : len) + 3, + DW210X_WRITE_MSG); i += 16; len -= 16; } while (len > 0); @@ -452,13 +478,12 @@ static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], i obuf[1] = msg[j].len; memcpy(obuf + 2, msg[j].buf, msg[j].len); dw210x_op_rw(d->udev, 0xc2, 0, 0, - obuf, msg[j].len + 2, - DW210X_WRITE_MSG); + obuf, msg[j].len + 2, + DW210X_WRITE_MSG); } break; } } - } ret = num; @@ -468,7 +493,7 @@ unlock: } static int dw3101_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], - int num) + int num) { struct dvb_usb_device *d = i2c_get_adapdata(adap); int ret; @@ -501,10 +526,10 @@ static int dw3101_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], obuf[1] = msg[0].len; obuf[2] = msg[0].buf[0]; dw210x_op_rw(d->udev, 0xc2, 0, 0, - obuf, msg[0].len + 2, DW210X_WRITE_MSG); + obuf, msg[0].len + 2, DW210X_WRITE_MSG); /* second read registers */ - dw210x_op_rw(d->udev, 0xc3, 0x19 , 0, - ibuf, msg[1].len + 2, DW210X_READ_MSG); + dw210x_op_rw(d->udev, 0xc3, 0x19, 0, + ibuf, msg[1].len + 2, DW210X_READ_MSG); memcpy(msg[1].buf, ibuf + 2, msg[1].len); break; @@ -526,14 +551,15 @@ static int dw3101_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], obuf[1] = msg[0].len; memcpy(obuf + 2, msg[0].buf, msg[0].len); dw210x_op_rw(d->udev, 0xc2, 0, 0, - obuf, msg[0].len + 2, DW210X_WRITE_MSG); + obuf, msg[0].len + 2, DW210X_WRITE_MSG); break; } case(DW2102_RC_QUERY): { u8 ibuf[2]; + dw210x_op_rw(d->udev, 0xb8, 0, 0, - ibuf, 2, DW210X_READ_MSG); - memcpy(msg[0].buf, ibuf , 2); + ibuf, 2, DW210X_READ_MSG); + memcpy(msg[0].buf, ibuf, 2); break; } } @@ -543,7 +569,7 @@ static int dw3101_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], for (i = 0; i < num; i++) { deb_xfer("%02x:%02x: %s ", i, msg[i].addr, - msg[i].flags == 0 ? ">>>" : "<<<"); + msg[i].flags == 0 ? ">>>" : "<<<"); debug_dump(msg[i].buf, msg[i].len, deb_xfer); } ret = num; @@ -554,7 +580,7 @@ unlock: } static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], - int num) + int num) { struct dvb_usb_device *d = i2c_get_adapdata(adap); struct usb_device *udev; @@ -570,8 +596,9 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], switch (msg[j].addr) { case (DW2102_RC_QUERY): { u8 ibuf[5]; + dw210x_op_rw(d->udev, 0xb8, 0, 0, - ibuf, 5, DW210X_READ_MSG); + ibuf, 5, DW210X_READ_MSG); memcpy(msg[j].buf, ibuf + 3, 2); break; } @@ -581,11 +608,11 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], obuf[0] = 1; obuf[1] = msg[j].buf[1];/* off-on */ dw210x_op_rw(d->udev, 0x8a, 0, 0, - obuf, 2, DW210X_WRITE_MSG); + obuf, 2, DW210X_WRITE_MSG); obuf[0] = 3; obuf[1] = msg[j].buf[0];/* 13v-18v */ dw210x_op_rw(d->udev, 0x8a, 0, 0, - obuf, 2, DW210X_WRITE_MSG); + obuf, 2, DW210X_WRITE_MSG); break; } case (DW2102_LED_CTRL): { @@ -594,14 +621,15 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], obuf[0] = 5; obuf[1] = msg[j].buf[0]; dw210x_op_rw(d->udev, 0x8a, 0, 0, - obuf, 2, DW210X_WRITE_MSG); + obuf, 2, DW210X_WRITE_MSG); break; } - /*case 0x55: cx24116 - case 0x6a: stv0903 - case 0x68: ds3000, stv0903, rs2000 - case 0x60: ts2020, stv6110, stb6100 - case 0xa0: eeprom */ + /* case 0x55: cx24116 + * case 0x6a: stv0903 + * case 0x68: ds3000, stv0903, rs2000 + * case 0x60: ts2020, stv6110, stb6100 + * case 0xa0: eeprom + */ default: { if (msg[j].flags == I2C_M_RD) { /* read registers */ @@ -615,14 +643,14 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], } dw210x_op_rw(d->udev, 0x91, 0, 0, - ibuf, msg[j].len, + ibuf, msg[j].len, DW210X_READ_MSG); memcpy(msg[j].buf, ibuf, msg[j].len); break; - } else if ((msg[j].buf[0] == 0xb0) && - (msg[j].addr == 0x68)) { + } else if ((msg[j].buf[0] == 0xb0) && (msg[j].addr == 0x68)) { /* write firmware */ u8 obuf[19]; + obuf[0] = (msg[j].len > 16 ? 18 : msg[j].len + 1); obuf[1] = msg[j].addr << 1; @@ -631,10 +659,10 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], i = 1; do { memcpy(obuf + 3, msg[j].buf + i, - (len > 16 ? 16 : len)); + (len > 16 ? 16 : len)); dw210x_op_rw(d->udev, 0x80, 0, 0, - obuf, (len > 16 ? 16 : len) + 3, - DW210X_WRITE_MSG); + obuf, (len > 16 ? 16 : len) + 3, + DW210X_WRITE_MSG); i += 16; len -= 16; } while (len > 0); @@ -653,10 +681,9 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], obuf[1] = (msg[j].addr << 1); memcpy(obuf + 2, msg[j].buf, msg[j].len); dw210x_op_rw(d->udev, - le16_to_cpu(udev->descriptor.idProduct) == - 0x7500 ? 0x92 : 0x90, 0, 0, - obuf, msg[j].len + 2, - DW210X_WRITE_MSG); + le16_to_cpu(udev->descriptor.idProduct) == 0x7500 ? 0x92 : 0x90, + 0, 0, obuf, msg[j].len + 2, + DW210X_WRITE_MSG); break; } else { /* write registers */ @@ -672,8 +699,8 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], obuf[1] = (msg[j].addr << 1); memcpy(obuf + 2, msg[j].buf, msg[j].len); dw210x_op_rw(d->udev, 0x80, 0, 0, - obuf, msg[j].len + 2, - DW210X_WRITE_MSG); + obuf, msg[j].len + 2, + DW210X_WRITE_MSG); break; } break; @@ -688,10 +715,11 @@ unlock: } static int su3000_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], - int num) + int num) { struct dvb_usb_device *d = i2c_get_adapdata(adap); struct dw2102_state *state; + int j; if (!d) return -ENODEV; @@ -705,77 +733,102 @@ static int su3000_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], return -EAGAIN; } - switch (num) { - case 1: - switch (msg[0].addr) { + j = 0; + while (j < num) { + switch (msg[j].addr) { case SU3000_STREAM_CTRL: - state->data[0] = msg[0].buf[0] + 0x36; + state->data[0] = msg[j].buf[0] + 0x36; state->data[1] = 3; state->data[2] = 0; if (dvb_usb_generic_rw(d, state->data, 3, - state->data, 0, 0) < 0) + state->data, 0, 0) < 0) err("i2c transfer failed."); break; case DW2102_RC_QUERY: state->data[0] = 0x10; if (dvb_usb_generic_rw(d, state->data, 1, - state->data, 2, 0) < 0) + state->data, 2, 0) < 0) err("i2c transfer failed."); - msg[0].buf[1] = state->data[0]; - msg[0].buf[0] = state->data[1]; + msg[j].buf[1] = state->data[0]; + msg[j].buf[0] = state->data[1]; break; default: - if (3 + msg[0].len > sizeof(state->data)) { - warn("i2c wr: len=%d is too big!\n", - msg[0].len); - num = -EOPNOTSUPP; + /* if the current write msg is followed by a another + * read msg to/from the same address + */ + if ((j + 1 < num) && (msg[j + 1].flags & I2C_M_RD) && + (msg[j].addr == msg[j + 1].addr)) { + /* join both i2c msgs to one usb read command */ + if (4 + msg[j].len > sizeof(state->data)) { + warn("i2c combined wr/rd: write len=%d is too big!\n", + msg[j].len); + num = -EOPNOTSUPP; + break; + } + if (1 + msg[j + 1].len > sizeof(state->data)) { + warn("i2c combined wr/rd: read len=%d is too big!\n", + msg[j + 1].len); + num = -EOPNOTSUPP; + break; + } + + state->data[0] = 0x09; + state->data[1] = msg[j].len; + state->data[2] = msg[j + 1].len; + state->data[3] = msg[j].addr; + memcpy(&state->data[4], msg[j].buf, msg[j].len); + + if (dvb_usb_generic_rw(d, state->data, msg[j].len + 4, + state->data, msg[j + 1].len + 1, 0) < 0) + err("i2c transfer failed."); + + memcpy(msg[j + 1].buf, &state->data[1], msg[j + 1].len); + j++; break; } - /* always i2c write*/ - state->data[0] = 0x08; - state->data[1] = msg[0].addr; - state->data[2] = msg[0].len; + if (msg[j].flags & I2C_M_RD) { + /* single read */ + if (4 + msg[j].len > sizeof(state->data)) { + warn("i2c rd: len=%d is too big!\n", msg[j].len); + num = -EOPNOTSUPP; + break; + } - memcpy(&state->data[3], msg[0].buf, msg[0].len); + state->data[0] = 0x09; + state->data[1] = 0; + state->data[2] = msg[j].len; + state->data[3] = msg[j].addr; + memcpy(&state->data[4], msg[j].buf, msg[j].len); - if (dvb_usb_generic_rw(d, state->data, msg[0].len + 3, - state->data, 1, 0) < 0) - err("i2c transfer failed."); + if (dvb_usb_generic_rw(d, state->data, 4, + state->data, msg[j].len + 1, 0) < 0) + err("i2c transfer failed."); - } - break; - case 2: - /* always i2c read */ - if (4 + msg[0].len > sizeof(state->data)) { - warn("i2c rd: len=%d is too big!\n", - msg[0].len); - num = -EOPNOTSUPP; - break; - } - if (1 + msg[1].len > sizeof(state->data)) { - warn("i2c rd: len=%d is too big!\n", - msg[1].len); - num = -EOPNOTSUPP; - break; - } + memcpy(msg[j].buf, &state->data[1], msg[j].len); + break; + } - state->data[0] = 0x09; - state->data[1] = msg[0].len; - state->data[2] = msg[1].len; - state->data[3] = msg[0].addr; - memcpy(&state->data[4], msg[0].buf, msg[0].len); + /* single write */ + if (3 + msg[j].len > sizeof(state->data)) { + warn("i2c wr: len=%d is too big!\n", msg[j].len); + num = -EOPNOTSUPP; + break; + } - if (dvb_usb_generic_rw(d, state->data, msg[0].len + 4, - state->data, msg[1].len + 1, 0) < 0) - err("i2c transfer failed."); + state->data[0] = 0x08; + state->data[1] = msg[j].addr; + state->data[2] = msg[j].len; - memcpy(msg[1].buf, &state->data[1], msg[1].len); - break; - default: - warn("more than 2 i2c messages at a time is not handled yet."); - break; - } + memcpy(&state->data[3], msg[j].buf, msg[j].len); + + if (dvb_usb_generic_rw(d, state->data, msg[j].len + 3, + state->data, 1, 0) < 0) + err("i2c transfer failed."); + } // switch + j++; + + } // while mutex_unlock(&d->data_mutex); mutex_unlock(&d->i2c_mutex); return num; @@ -786,37 +839,37 @@ static u32 dw210x_i2c_func(struct i2c_adapter *adapter) return I2C_FUNC_I2C; } -static struct i2c_algorithm dw2102_i2c_algo = { +static const struct i2c_algorithm dw2102_i2c_algo = { .master_xfer = dw2102_i2c_transfer, .functionality = dw210x_i2c_func, }; -static struct i2c_algorithm dw2102_serit_i2c_algo = { +static const struct i2c_algorithm dw2102_serit_i2c_algo = { .master_xfer = dw2102_serit_i2c_transfer, .functionality = dw210x_i2c_func, }; -static struct i2c_algorithm dw2102_earda_i2c_algo = { +static const struct i2c_algorithm dw2102_earda_i2c_algo = { .master_xfer = dw2102_earda_i2c_transfer, .functionality = dw210x_i2c_func, }; -static struct i2c_algorithm dw2104_i2c_algo = { +static const struct i2c_algorithm dw2104_i2c_algo = { .master_xfer = dw2104_i2c_transfer, .functionality = dw210x_i2c_func, }; -static struct i2c_algorithm dw3101_i2c_algo = { +static const struct i2c_algorithm dw3101_i2c_algo = { .master_xfer = dw3101_i2c_transfer, .functionality = dw210x_i2c_func, }; -static struct i2c_algorithm s6x0_i2c_algo = { +static const struct i2c_algorithm s6x0_i2c_algo = { .master_xfer = s6x0_i2c_transfer, .functionality = dw210x_i2c_func, }; -static struct i2c_algorithm su3000_i2c_algo = { +static const struct i2c_algorithm su3000_i2c_algo = { .master_xfer = su3000_i2c_transfer, .functionality = dw210x_i2c_func, }; @@ -828,11 +881,11 @@ static int dw210x_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) u8 eeprom[256], eepromline[16]; for (i = 0; i < 256; i++) { - if (dw210x_op_rw(d->udev, 0xb6, 0xa0 , i, ibuf, 2, DW210X_READ_MSG) < 0) { + if (dw210x_op_rw(d->udev, 0xb6, 0xa0, i, ibuf, 2, DW210X_READ_MSG) < 0) { err("read eeprom failed."); - return -1; + return -EIO; } else { - eepromline[i%16] = ibuf[0]; + eepromline[i % 16] = ibuf[0]; eeprom[i] = ibuf[0]; } if ((i % 16) == 15) { @@ -869,7 +922,7 @@ static int s6x0_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) ret = s6x0_i2c_transfer(&d->i2c_adap, msg, 2); if (ret != 2) { err("read eeprom failed."); - return -1; + return -EIO; } else { eepromline[i % 16] = ibuf[0]; eeprom[i] = ibuf[0]; @@ -903,7 +956,7 @@ static int su3000_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) static int su3000_power_ctrl(struct dvb_usb_device *d, int i) { - struct dw2102_state *state = (struct dw2102_state *)d->priv; + struct dw2102_state *state = d->priv; int ret = 0; info("%s: %d, initialized %d", __func__, i, state->initialized); @@ -939,14 +992,13 @@ static int su3000_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) .flags = I2C_M_RD, .buf = ibuf, .len = 1, - } }; for (i = 0; i < 6; i++) { obuf[1] = 0xf0 + i; if (i2c_transfer(&d->i2c_adap, msg, 2) != 2) - break; + return -EIO; else mac[i] = ibuf[0]; } @@ -959,8 +1011,6 @@ static int su3000_identify_state(struct usb_device *udev, const struct dvb_usb_device_description **desc, int *cold) { - info("%s", __func__); - *cold = 0; return 0; } @@ -978,8 +1028,8 @@ static int dw210x_set_voltage(struct dvb_frontend *fe, .len = 2, }; - struct dvb_usb_adapter *udev_adap = - (struct dvb_usb_adapter *)(fe->dvb->priv); + struct dvb_usb_adapter *udev_adap = fe->dvb->priv; + if (voltage == SEC_VOLTAGE_18) msg.buf = command_18v; else if (voltage == SEC_VOLTAGE_13) @@ -993,9 +1043,8 @@ static int dw210x_set_voltage(struct dvb_frontend *fe, static int s660_set_voltage(struct dvb_frontend *fe, enum fe_sec_voltage voltage) { - struct dvb_usb_adapter *d = - (struct dvb_usb_adapter *)(fe->dvb->priv); - struct dw2102_state *st = (struct dw2102_state *)d->dev->priv; + struct dvb_usb_adapter *d = fe->dvb->priv; + struct dw2102_state *st = d->dev->priv; dw210x_set_voltage(fe, voltage); if (st->old_set_voltage) @@ -1014,8 +1063,7 @@ static void dw210x_led_ctrl(struct dvb_frontend *fe, int offon) .buf = led_off, .len = 1 }; - struct dvb_usb_adapter *udev_adap = - (struct dvb_usb_adapter *)(fe->dvb->priv); + struct dvb_usb_adapter *udev_adap = fe->dvb->priv; if (offon) msg.buf = led_on; @@ -1025,9 +1073,8 @@ static void dw210x_led_ctrl(struct dvb_frontend *fe, int offon) static int tt_s2_4600_read_status(struct dvb_frontend *fe, enum fe_status *status) { - struct dvb_usb_adapter *d = - (struct dvb_usb_adapter *)(fe->dvb->priv); - struct dw2102_state *st = (struct dw2102_state *)d->dev->priv; + struct dvb_usb_adapter *d = fe->dvb->priv; + struct dw2102_state *st = d->dev->priv; int ret; ret = st->fe_read_status(fe, status); @@ -1186,11 +1233,11 @@ static int dw2104_frontend_attach(struct dvb_usb_adapter *d) if (demod_probe & 4) { d->fe_adap[0].fe = dvb_attach(stv0900_attach, &dw2104a_stv0900_config, - &d->dev->i2c_adap, 0); - if (d->fe_adap[0].fe != NULL) { + &d->dev->i2c_adap, 0); + if (d->fe_adap[0].fe) { if (dvb_attach(stb6100_attach, d->fe_adap[0].fe, - &dw2104a_stb6100_config, - &d->dev->i2c_adap)) { + &dw2104a_stb6100_config, + &d->dev->i2c_adap)) { tuner_ops = &d->fe_adap[0].fe->ops.tuner_ops; tuner_ops->set_frequency = stb6100_set_freq; tuner_ops->get_frequency = stb6100_get_freq; @@ -1205,11 +1252,11 @@ static int dw2104_frontend_attach(struct dvb_usb_adapter *d) if (demod_probe & 2) { d->fe_adap[0].fe = dvb_attach(stv0900_attach, &dw2104_stv0900_config, - &d->dev->i2c_adap, 0); - if (d->fe_adap[0].fe != NULL) { + &d->dev->i2c_adap, 0); + if (d->fe_adap[0].fe) { if (dvb_attach(stv6110_attach, d->fe_adap[0].fe, - &dw2104_stv6110_config, - &d->dev->i2c_adap)) { + &dw2104_stv6110_config, + &d->dev->i2c_adap)) { d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage; info("Attached STV0900+STV6110A!"); return 0; @@ -1219,8 +1266,8 @@ static int dw2104_frontend_attach(struct dvb_usb_adapter *d) if (demod_probe & 1) { d->fe_adap[0].fe = dvb_attach(cx24116_attach, &dw2104_config, - &d->dev->i2c_adap); - if (d->fe_adap[0].fe != NULL) { + &d->dev->i2c_adap); + if (d->fe_adap[0].fe) { d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage; info("Attached cx24116!"); return 0; @@ -1228,10 +1275,10 @@ static int dw2104_frontend_attach(struct dvb_usb_adapter *d) } d->fe_adap[0].fe = dvb_attach(ds3000_attach, &dw2104_ds3000_config, - &d->dev->i2c_adap); - if (d->fe_adap[0].fe != NULL) { + &d->dev->i2c_adap); + if (d->fe_adap[0].fe) { dvb_attach(ts2020_attach, d->fe_adap[0].fe, - &dw2104_ts2020_config, &d->dev->i2c_adap); + &dw2104_ts2020_config, &d->dev->i2c_adap); d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage; info("Attached DS3000!"); return 0; @@ -1249,8 +1296,8 @@ static int dw2102_frontend_attach(struct dvb_usb_adapter *d) if (dw2102_properties.i2c_algo == &dw2102_serit_i2c_algo) { /*dw2102_properties.adapter->tuner_attach = NULL;*/ d->fe_adap[0].fe = dvb_attach(si21xx_attach, &serit_sp1511lhb_config, - &d->dev->i2c_adap); - if (d->fe_adap[0].fe != NULL) { + &d->dev->i2c_adap); + if (d->fe_adap[0].fe) { d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage; info("Attached si21xx!"); return 0; @@ -1259,10 +1306,10 @@ static int dw2102_frontend_attach(struct dvb_usb_adapter *d) if (dw2102_properties.i2c_algo == &dw2102_earda_i2c_algo) { d->fe_adap[0].fe = dvb_attach(stv0288_attach, &earda_config, - &d->dev->i2c_adap); - if (d->fe_adap[0].fe != NULL) { + &d->dev->i2c_adap); + if (d->fe_adap[0].fe) { if (dvb_attach(stb6000_attach, d->fe_adap[0].fe, 0x61, - &d->dev->i2c_adap)) { + &d->dev->i2c_adap)) { d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage; info("Attached stv0288!"); return 0; @@ -1273,8 +1320,8 @@ static int dw2102_frontend_attach(struct dvb_usb_adapter *d) if (dw2102_properties.i2c_algo == &dw2102_i2c_algo) { /*dw2102_properties.adapter->tuner_attach = dw2102_tuner_attach;*/ d->fe_adap[0].fe = dvb_attach(stv0299_attach, &sharp_z0194a_config, - &d->dev->i2c_adap); - if (d->fe_adap[0].fe != NULL) { + &d->dev->i2c_adap); + if (d->fe_adap[0].fe) { d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage; info("Attached stv0299!"); return 0; @@ -1286,8 +1333,8 @@ static int dw2102_frontend_attach(struct dvb_usb_adapter *d) static int dw3101_frontend_attach(struct dvb_usb_adapter *d) { d->fe_adap[0].fe = dvb_attach(tda10023_attach, &dw3101_tda10023_config, - &d->dev->i2c_adap, 0x48); - if (d->fe_adap[0].fe != NULL) { + &d->dev->i2c_adap, 0x48); + if (d->fe_adap[0].fe) { info("Attached tda10023!"); return 0; } @@ -1297,10 +1344,10 @@ static int dw3101_frontend_attach(struct dvb_usb_adapter *d) static int zl100313_frontend_attach(struct dvb_usb_adapter *d) { d->fe_adap[0].fe = dvb_attach(mt312_attach, &zl313_config, - &d->dev->i2c_adap); - if (d->fe_adap[0].fe != NULL) { + &d->dev->i2c_adap); + if (d->fe_adap[0].fe) { if (dvb_attach(zl10039_attach, d->fe_adap[0].fe, 0x60, - &d->dev->i2c_adap)) { + &d->dev->i2c_adap)) { d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage; info("Attached zl100313+zl10039!"); return 0; @@ -1315,12 +1362,12 @@ static int stv0288_frontend_attach(struct dvb_usb_adapter *d) u8 obuf[] = {7, 1}; d->fe_adap[0].fe = dvb_attach(stv0288_attach, &earda_config, - &d->dev->i2c_adap); + &d->dev->i2c_adap); - if (d->fe_adap[0].fe == NULL) + if (!d->fe_adap[0].fe) return -EIO; - if (NULL == dvb_attach(stb6000_attach, d->fe_adap[0].fe, 0x61, &d->dev->i2c_adap)) + if (dvb_attach(stb6000_attach, d->fe_adap[0].fe, 0x61, &d->dev->i2c_adap) == NULL) return -EIO; d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage; @@ -1330,7 +1377,6 @@ static int stv0288_frontend_attach(struct dvb_usb_adapter *d) info("Attached stv0288+stb6000!"); return 0; - } static int ds3000_frontend_attach(struct dvb_usb_adapter *d) @@ -1339,13 +1385,13 @@ static int ds3000_frontend_attach(struct dvb_usb_adapter *d) u8 obuf[] = {7, 1}; d->fe_adap[0].fe = dvb_attach(ds3000_attach, &s660_ds3000_config, - &d->dev->i2c_adap); + &d->dev->i2c_adap); - if (d->fe_adap[0].fe == NULL) + if (!d->fe_adap[0].fe) return -EIO; dvb_attach(ts2020_attach, d->fe_adap[0].fe, &s660_ts2020_config, - &d->dev->i2c_adap); + &d->dev->i2c_adap); st->old_set_voltage = d->fe_adap[0].fe->ops.set_voltage; d->fe_adap[0].fe->ops.set_voltage = s660_set_voltage; @@ -1362,8 +1408,8 @@ static int prof_7500_frontend_attach(struct dvb_usb_adapter *d) u8 obuf[] = {7, 1}; d->fe_adap[0].fe = dvb_attach(stv0900_attach, &prof_7500_stv0900_config, - &d->dev->i2c_adap, 0); - if (d->fe_adap[0].fe == NULL) + &d->dev->i2c_adap, 0); + if (!d->fe_adap[0].fe) return -EIO; d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage; @@ -1419,12 +1465,12 @@ static int su3000_frontend_attach(struct dvb_usb_adapter *adap) mutex_unlock(&d->data_mutex); adap->fe_adap[0].fe = dvb_attach(ds3000_attach, &su3000_ds3000_config, - &d->i2c_adap); - if (adap->fe_adap[0].fe == NULL) + &d->i2c_adap); + if (!adap->fe_adap[0].fe) return -EIO; if (dvb_attach(ts2020_attach, adap->fe_adap[0].fe, - &dw2104_ts2020_config, + &dw2104_ts2020_config, &d->i2c_adap)) { info("Attached DS3000/TS2020!"); return 0; @@ -1479,10 +1525,10 @@ static int t220_frontend_attach(struct dvb_usb_adapter *adap) mutex_unlock(&d->data_mutex); adap->fe_adap[0].fe = dvb_attach(cxd2820r_attach, &cxd2820r_config, - &d->i2c_adap, NULL); - if (adap->fe_adap[0].fe != NULL) { + &d->i2c_adap, NULL); + if (adap->fe_adap[0].fe) { if (dvb_attach(tda18271_attach, adap->fe_adap[0].fe, 0x60, - &d->i2c_adap, &tda18271_config)) { + &d->i2c_adap, &tda18271_config)) { info("Attached TDA18271HD/CXD2820R!"); return 0; } @@ -1507,14 +1553,14 @@ static int m88rs2000_frontend_attach(struct dvb_usb_adapter *adap) mutex_unlock(&d->data_mutex); adap->fe_adap[0].fe = dvb_attach(m88rs2000_attach, - &s421_m88rs2000_config, - &d->i2c_adap); + &s421_m88rs2000_config, + &d->i2c_adap); - if (adap->fe_adap[0].fe == NULL) + if (!adap->fe_adap[0].fe) return -EIO; if (dvb_attach(ts2020_attach, adap->fe_adap[0].fe, - &dw2104_ts2020_config, + &dw2104_ts2020_config, &d->i2c_adap)) { info("Attached RS2000/TS2020!"); return 0; @@ -1681,14 +1727,14 @@ static int tt_s2_4600_frontend_attach(struct dvb_usb_adapter *adap) static int dw2102_tuner_attach(struct dvb_usb_adapter *adap) { dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60, - &adap->dev->i2c_adap, DVB_PLL_OPERA1); + &adap->dev->i2c_adap, DVB_PLL_OPERA1); return 0; } static int dw3101_tuner_attach(struct dvb_usb_adapter *adap) { dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60, - &adap->dev->i2c_adap, DVB_PLL_TUA6034); + &adap->dev->i2c_adap, DVB_PLL_TUA6034); return 0; } @@ -1706,7 +1752,7 @@ static int dw2102_rc_query(struct dvb_usb_device *d) if (d->props.i2c_algo->master_xfer(&d->i2c_adap, &msg, 1) == 1) { if (msg.buf[0] != 0xff) { deb_rc("%s: rc code: %x, %x\n", - __func__, key[0], key[1]); + __func__, key[0], key[1]); rc_keydown(d->rc_dev, RC_PROTO_UNKNOWN, key[0], 0); } } @@ -1727,7 +1773,7 @@ static int prof_rc_query(struct dvb_usb_device *d) if (d->props.i2c_algo->master_xfer(&d->i2c_adap, &msg, 1) == 1) { if (msg.buf[0] != 0xff) { deb_rc("%s: rc code: %x, %x\n", - __func__, key[0], key[1]); + __func__, key[0], key[1]); rc_keydown(d->rc_dev, RC_PROTO_UNKNOWN, key[0] ^ 0xff, 0); } @@ -1749,7 +1795,7 @@ static int su3000_rc_query(struct dvb_usb_device *d) if (d->props.i2c_algo->master_xfer(&d->i2c_adap, &msg, 1) == 1) { if (msg.buf[0] != 0xff) { deb_rc("%s: rc code: %x, %x\n", - __func__, key[0], key[1]); + __func__, key[0], key[1]); rc_keydown(d->rc_dev, RC_PROTO_RC5, RC_SCANCODE_RC5(key[1], key[0]), 0); } @@ -1787,11 +1833,10 @@ enum dw2102_table_entry { TECHNOTREND_CONNECT_S2_4600, TEVII_S482_1, TEVII_S482_2, - TERRATEC_CINERGY_S2_BOX, TEVII_S662 }; -static struct usb_device_id dw2102_table[] = { +static const struct usb_device_id dw2102_table[] = { DVB_USB_DEV(CYPRESS, CYPRESS_DW2102), DVB_USB_DEV(CYPRESS, CYPRESS_DW2101), DVB_USB_DEV(CYPRESS, CYPRESS_DW2104), @@ -1820,7 +1865,6 @@ static struct usb_device_id dw2102_table[] = { DVB_USB_DEV(TECHNOTREND, TECHNOTREND_CONNECT_S2_4600), DVB_USB_DEV(TEVII, TEVII_S482_1), DVB_USB_DEV(TEVII, TEVII_S482_2), - DVB_USB_DEV(TERRATEC, TERRATEC_CINERGY_S2_BOX), DVB_USB_DEV(TEVII, TEVII_S662), { } }; @@ -1828,7 +1872,7 @@ static struct usb_device_id dw2102_table[] = { MODULE_DEVICE_TABLE(usb, dw2102_table); static int dw2102_load_firmware(struct usb_device *dev, - const struct firmware *frmwr) + const struct firmware *frmwr) { u8 *b, *p; int ret = 0, i; @@ -1855,12 +1899,12 @@ static int dw2102_load_firmware(struct usb_device *dev, dw210x_op_rw(dev, 0xa0, 0x7f92, 0, &reset, 1, DW210X_WRITE_MSG); dw210x_op_rw(dev, 0xa0, 0xe600, 0, &reset, 1, DW210X_WRITE_MSG); - if (p != NULL) { + if (p) { memcpy(p, fw->data, fw->size); for (i = 0; i < fw->size; i += 0x40) { - b = (u8 *) p + i; - if (dw210x_op_rw(dev, 0xa0, i, 0, b , 0x40, - DW210X_WRITE_MSG) != 0x40) { + b = (u8 *)p + i; + if (dw210x_op_rw(dev, 0xa0, i, 0, b, 0x40, + DW210X_WRITE_MSG) != 0x40) { err("error while transferring firmware"); ret = -EINVAL; break; @@ -1886,50 +1930,49 @@ static int dw2102_load_firmware(struct usb_device *dev, case USB_PID_CYPRESS_DW2104: reset = 1; dw210x_op_rw(dev, 0xc4, 0x0000, 0, &reset, 1, - DW210X_WRITE_MSG); + DW210X_WRITE_MSG); fallthrough; case USB_PID_CYPRESS_DW3101: reset = 0; dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0, - DW210X_WRITE_MSG); + DW210X_WRITE_MSG); break; case USB_PID_TERRATEC_CINERGY_S: case USB_PID_CYPRESS_DW2102: dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0, - DW210X_WRITE_MSG); + DW210X_WRITE_MSG); dw210x_op_rw(dev, 0xb9, 0x0000, 0, &reset16[0], 2, - DW210X_READ_MSG); + DW210X_READ_MSG); /* check STV0299 frontend */ dw210x_op_rw(dev, 0xb5, 0, 0, &reset16[0], 2, - DW210X_READ_MSG); + DW210X_READ_MSG); if ((reset16[0] == 0xa1) || (reset16[0] == 0x80)) { dw2102_properties.i2c_algo = &dw2102_i2c_algo; dw2102_properties.adapter->fe[0].tuner_attach = &dw2102_tuner_attach; break; - } else { - /* check STV0288 frontend */ - reset16[0] = 0xd0; - reset16[1] = 1; - reset16[2] = 0; - dw210x_op_rw(dev, 0xc2, 0, 0, &reset16[0], 3, - DW210X_WRITE_MSG); - dw210x_op_rw(dev, 0xc3, 0xd1, 0, &reset16[0], 3, - DW210X_READ_MSG); - if (reset16[2] == 0x11) { - dw2102_properties.i2c_algo = &dw2102_earda_i2c_algo; - break; - } + } + /* check STV0288 frontend */ + reset16[0] = 0xd0; + reset16[1] = 1; + reset16[2] = 0; + dw210x_op_rw(dev, 0xc2, 0, 0, &reset16[0], 3, + DW210X_WRITE_MSG); + dw210x_op_rw(dev, 0xc3, 0xd1, 0, &reset16[0], 3, + DW210X_READ_MSG); + if (reset16[2] == 0x11) { + dw2102_properties.i2c_algo = &dw2102_earda_i2c_algo; + break; } fallthrough; case 0x2101: dw210x_op_rw(dev, 0xbc, 0x0030, 0, &reset16[0], 2, - DW210X_READ_MSG); + DW210X_READ_MSG); dw210x_op_rw(dev, 0xba, 0x0000, 0, &reset16[0], 7, - DW210X_READ_MSG); + DW210X_READ_MSG); dw210x_op_rw(dev, 0xba, 0x0000, 0, &reset16[0], 7, - DW210X_READ_MSG); + DW210X_READ_MSG); dw210x_op_rw(dev, 0xb9, 0x0000, 0, &reset16[0], 2, - DW210X_READ_MSG); + DW210X_READ_MSG); break; } @@ -2531,7 +2574,7 @@ static struct dvb_usb_device_properties tt_s2_4600_properties = { { NULL }, }, { "Terratec Cinergy S2 USB BOX", - { &dw2102_table[TERRATEC_CINERGY_S2_BOX], NULL }, + { &dw2102_table[TERRATEC_CINERGY_S2_R4], NULL }, { NULL }, }, { "TeVii S662", @@ -2542,18 +2585,18 @@ static struct dvb_usb_device_properties tt_s2_4600_properties = { }; static int dw2102_probe(struct usb_interface *intf, - const struct usb_device_id *id) + const struct usb_device_id *id) { if (!(dvb_usb_device_init(intf, &dw2102_properties, - THIS_MODULE, NULL, adapter_nr) && + THIS_MODULE, NULL, adapter_nr) && dvb_usb_device_init(intf, &dw2104_properties, THIS_MODULE, NULL, adapter_nr) && dvb_usb_device_init(intf, &dw3101_properties, - THIS_MODULE, NULL, adapter_nr) && + THIS_MODULE, NULL, adapter_nr) && dvb_usb_device_init(intf, &s6x0_properties, - THIS_MODULE, NULL, adapter_nr) && + THIS_MODULE, NULL, adapter_nr) && dvb_usb_device_init(intf, &p1100_properties, - THIS_MODULE, NULL, adapter_nr) && + THIS_MODULE, NULL, adapter_nr) && dvb_usb_device_init(intf, &s660_properties, THIS_MODULE, NULL, adapter_nr) && dvb_usb_device_init(intf, &p7500_properties, @@ -2566,7 +2609,6 @@ static int dw2102_probe(struct usb_interface *intf, THIS_MODULE, NULL, adapter_nr) && dvb_usb_device_init(intf, &tt_s2_4600_properties, THIS_MODULE, NULL, adapter_nr))) { - return 0; } @@ -2576,7 +2618,7 @@ static int dw2102_probe(struct usb_interface *intf, static void dw2102_disconnect(struct usb_interface *intf) { struct dvb_usb_device *d = usb_get_intfdata(intf); - struct dw2102_state *st = (struct dw2102_state *)d->priv; + struct dw2102_state *st = d->priv; struct i2c_client *client; /* remove I2C client for tuner */ diff --git a/drivers/media/usb/dvb-usb/gp8psk.c b/drivers/media/usb/dvb-usb/gp8psk.c index b2b27a86dfe5..96a255500b38 100644 --- a/drivers/media/usb/dvb-usb/gp8psk.c +++ b/drivers/media/usb/dvb-usb/gp8psk.c @@ -287,7 +287,7 @@ static int gp8psk_frontend_attach(struct dvb_usb_adapter *adap) int id = le16_to_cpu(d->udev->descriptor.idProduct); int is_rev1; - is_rev1 = (id == USB_PID_GENPIX_8PSK_REV_1_WARM) ? true : false; + is_rev1 = id == USB_PID_GENPIX_8PSK_REV_1_WARM; adap->fe_adap[0].fe = dvb_attach(gp8psk_fe_attach, &gp8psk_fe_ops, d, is_rev1); @@ -319,7 +319,7 @@ enum { GENPIX_SKYWALKER_CW3K, }; -static struct usb_device_id gp8psk_usb_table[] = { +static const struct usb_device_id gp8psk_usb_table[] = { DVB_USB_DEV(GENPIX, GENPIX_8PSK_REV_1_COLD), DVB_USB_DEV(GENPIX, GENPIX_8PSK_REV_1_WARM), DVB_USB_DEV(GENPIX, GENPIX_8PSK_REV_2), diff --git a/drivers/media/usb/dvb-usb/m920x.c b/drivers/media/usb/dvb-usb/m920x.c index fea5bcf72a31..45337ba0a0a3 100644 --- a/drivers/media/usb/dvb-usb/m920x.c +++ b/drivers/media/usb/dvb-usb/m920x.c @@ -17,7 +17,7 @@ #include <media/tuner.h> #include "tuner-simple.h" -#include <asm/unaligned.h> +#include <linux/unaligned.h> /* debug */ static int dvb_usb_m920x_debug; @@ -277,7 +277,6 @@ static int m920x_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int nu char *read = kmalloc(1, GFP_KERNEL); if (!read) { ret = -ENOMEM; - kfree(read); goto unlock; } @@ -288,8 +287,10 @@ static int m920x_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int nu if ((ret = m920x_read(d->udev, M9206_I2C, 0x0, 0x20 | stop, - read, 1)) != 0) + read, 1)) != 0) { + kfree(read); goto unlock; + } msg[i].buf[j] = read[0]; } @@ -318,7 +319,7 @@ static u32 m920x_i2c_func(struct i2c_adapter *adapter) return I2C_FUNC_I2C; } -static struct i2c_algorithm m920x_i2c_algo = { +static const struct i2c_algorithm m920x_i2c_algo = { .master_xfer = m920x_i2c_xfer, .functionality = m920x_i2c_func, }; @@ -908,7 +909,7 @@ enum { AZUREWAVE_TWINHAN_VP7049, }; -static struct usb_device_id m920x_table[] = { +static const struct usb_device_id m920x_table[] = { DVB_USB_DEV(MSI, MSI_MEGASKY580), DVB_USB_DEV(ANUBIS_ELECTRONIC, ANUBIS_MSI_DIGI_VOX_MINI_II), DVB_USB_DEV(ANUBIS_ELECTRONIC, ANUBIS_LIFEVIEW_TV_WALKER_TWIN_COLD), diff --git a/drivers/media/usb/dvb-usb/nova-t-usb2.c b/drivers/media/usb/dvb-usb/nova-t-usb2.c index 4782d0780913..2e5cbfacbeed 100644 --- a/drivers/media/usb/dvb-usb/nova-t-usb2.c +++ b/drivers/media/usb/dvb-usb/nova-t-usb2.c @@ -165,7 +165,7 @@ enum { HAUPPAUGE_WINTV_NOVA_T_USB2_WARM, }; -static struct usb_device_id nova_t_table[] = { +static const struct usb_device_id nova_t_table[] = { DVB_USB_DEV(HAUPPAUGE, HAUPPAUGE_WINTV_NOVA_T_USB2_COLD), DVB_USB_DEV(HAUPPAUGE, HAUPPAUGE_WINTV_NOVA_T_USB2_WARM), { } diff --git a/drivers/media/usb/dvb-usb/opera1.c b/drivers/media/usb/dvb-usb/opera1.c index 0da86f58aff6..3c79cc6848b4 100644 --- a/drivers/media/usb/dvb-usb/opera1.c +++ b/drivers/media/usb/dvb-usb/opera1.c @@ -32,10 +32,6 @@ struct opera1_state { u32 last_key_pressed; }; -struct rc_map_opera_table { - u32 keycode; - u32 event; -}; static int dvb_usb_opera1_debug; module_param_named(debug, dvb_usb_opera1_debug, int, 0644); @@ -159,7 +155,7 @@ static u32 opera1_i2c_func(struct i2c_adapter *adapter) return I2C_FUNC_I2C; } -static struct i2c_algorithm opera1_i2c_algo = { +static const struct i2c_algorithm opera1_i2c_algo = { .master_xfer = opera1_i2c_xfer, .functionality = opera1_i2c_func, }; @@ -172,8 +168,7 @@ static int opera1_set_voltage(struct dvb_frontend *fe, struct i2c_msg msg[] = { {.addr = ADDR_B600_VOLTAGE_13V,.flags = 0,.buf = command_13v,.len = 1}, }; - struct dvb_usb_adapter *udev_adap = - (struct dvb_usb_adapter *)(fe->dvb->priv); + struct dvb_usb_adapter *udev_adap = fe->dvb->priv; if (voltage == SEC_VOLTAGE_18) { msg[0].addr = ADDR_B601_VOLTAGE_18V; msg[0].buf = command_18v; @@ -430,7 +425,7 @@ enum { OPERA1_WARM, }; -static struct usb_device_id opera1_table[] = { +static const struct usb_device_id opera1_table[] = { DVB_USB_DEV(CYPRESS, CYPRESS_OPERA1_COLD), DVB_USB_DEV(OPERA1, OPERA1_WARM), { } @@ -440,9 +435,14 @@ MODULE_DEVICE_TABLE(usb, opera1_table); static int opera1_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) { + int ret; u8 command[] = { READ_MAC_ADDR }; - opera1_xilinx_rw(d->udev, 0xb1, 0xa0, command, 1, OPERA_WRITE_MSG); - opera1_xilinx_rw(d->udev, 0xb1, 0xa1, mac, 6, OPERA_READ_MSG); + ret = opera1_xilinx_rw(d->udev, 0xb1, 0xa0, command, 1, OPERA_WRITE_MSG); + if (ret) + return ret; + ret = opera1_xilinx_rw(d->udev, 0xb1, 0xa1, mac, 6, OPERA_READ_MSG); + if (ret) + return ret; return 0; } static int opera1_xilinx_load_firmware(struct usb_device *dev, diff --git a/drivers/media/usb/dvb-usb/pctv452e.c b/drivers/media/usb/dvb-usb/pctv452e.c index f0794c68c622..bc7a224d829e 100644 --- a/drivers/media/usb/dvb-usb/pctv452e.c +++ b/drivers/media/usb/dvb-usb/pctv452e.c @@ -26,6 +26,8 @@ #include <media/dvb_ca_en50221.h> #include "ttpci-eeprom.h" +#include <linux/etherdevice.h> + static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); @@ -106,7 +108,7 @@ struct pctv452e_state { static int tt3650_ci_msg(struct dvb_usb_device *d, u8 cmd, u8 *data, unsigned int write_len, unsigned int read_len) { - struct pctv452e_state *state = (struct pctv452e_state *)d->priv; + struct pctv452e_state *state = d->priv; u8 *buf; u8 id; unsigned int rlen; @@ -157,8 +159,8 @@ static int tt3650_ci_msg_locked(struct dvb_ca_en50221 *ca, u8 cmd, u8 *data, unsigned int write_len, unsigned int read_len) { - struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; - struct pctv452e_state *state = (struct pctv452e_state *)d->priv; + struct dvb_usb_device *d = ca->data; + struct pctv452e_state *state = d->priv; int ret; mutex_lock(&state->ca_mutex); @@ -290,8 +292,8 @@ static int tt3650_ci_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot) static int tt3650_ci_slot_reset(struct dvb_ca_en50221 *ca, int slot) { - struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; - struct pctv452e_state *state = (struct pctv452e_state *)d->priv; + struct dvb_usb_device *d = ca->data; + struct pctv452e_state *state = d->priv; u8 buf[1]; int ret; @@ -359,7 +361,7 @@ static void tt3650_ci_uninit(struct dvb_usb_device *d) if (NULL == d) return; - state = (struct pctv452e_state *)d->priv; + state = d->priv; if (NULL == state) return; @@ -377,7 +379,7 @@ static void tt3650_ci_uninit(struct dvb_usb_device *d) static int tt3650_ci_init(struct dvb_usb_adapter *a) { struct dvb_usb_device *d = a->dev; - struct pctv452e_state *state = (struct pctv452e_state *)d->priv; + struct pctv452e_state *state = d->priv; int ret; ci_dbg("%s", __func__); @@ -415,21 +417,20 @@ static int pctv452e_i2c_msg(struct dvb_usb_device *d, u8 addr, const u8 *snd_buf, u8 snd_len, u8 *rcv_buf, u8 rcv_len) { - struct pctv452e_state *state = (struct pctv452e_state *)d->priv; + struct pctv452e_state *state = d->priv; u8 *buf; u8 id; int ret; + if (snd_len > 64 - 7 || rcv_len > 64 - 7) + return -EINVAL; + buf = kmalloc(64, GFP_KERNEL); if (!buf) return -ENOMEM; id = state->c++; - ret = -EINVAL; - if (snd_len > 64 - 7 || rcv_len > 64 - 7) - goto failed; - buf[0] = SYNC_BYTE_OUT; buf[1] = id; buf[2] = PCTV_CMD_I2C; @@ -514,7 +515,7 @@ static u32 pctv452e_i2c_func(struct i2c_adapter *adapter) static int pctv452e_power_ctrl(struct dvb_usb_device *d, int i) { - struct pctv452e_state *state = (struct pctv452e_state *)d->priv; + struct pctv452e_state *state = d->priv; u8 *b0, *rx; int ret; @@ -565,7 +566,7 @@ ret: static int pctv452e_rc_query(struct dvb_usb_device *d) { - struct pctv452e_state *state = (struct pctv452e_state *)d->priv; + struct pctv452e_state *state = d->priv; u8 *b, *rx; int ret, i; u8 id; @@ -904,14 +905,14 @@ static struct stb6100_config stb6100_config = { }; -static struct i2c_algorithm pctv452e_i2c_algo = { +static const struct i2c_algorithm pctv452e_i2c_algo = { .master_xfer = pctv452e_i2c_xfer, .functionality = pctv452e_i2c_func }; static int pctv452e_frontend_attach(struct dvb_usb_adapter *a) { - struct usb_device_id *id; + const struct usb_device_id *id; a->fe_adap[0].fe = dvb_attach(stb0899_attach, &stb0899_config, &a->dev->i2c_adap); @@ -957,7 +958,7 @@ enum { TECHNOTREND_CONNECT_S2_3650_CI, }; -static struct usb_device_id pctv452e_usb_table[] = { +static const struct usb_device_id pctv452e_usb_table[] = { DVB_USB_DEV(PINNACLE, PINNACLE_PCTV_452E), DVB_USB_DEV(TECHNOTREND, TECHNOTREND_CONNECT_S2_3600), DVB_USB_DEV(TECHNOTREND, TECHNOTREND_CONNECT_S2_3650_CI), diff --git a/drivers/media/usb/dvb-usb/technisat-usb2.c b/drivers/media/usb/dvb-usb/technisat-usb2.c index df90c6c5f3b9..1e43aab2bc27 100644 --- a/drivers/media/usb/dvb-usb/technisat-usb2.c +++ b/drivers/media/usb/dvb-usb/technisat-usb2.c @@ -199,7 +199,7 @@ static u32 technisat_usb2_i2c_func(struct i2c_adapter *adapter) return I2C_FUNC_I2C; } -static struct i2c_algorithm technisat_usb2_i2c_algo = { +static const struct i2c_algorithm technisat_usb2_i2c_algo = { .master_xfer = technisat_usb2_i2c_xfer, .functionality = technisat_usb2_i2c_func, }; @@ -693,7 +693,7 @@ enum { TECHNISAT_USB2_DVB_S2, }; -static struct usb_device_id technisat_usb2_id_table[] = { +static const struct usb_device_id technisat_usb2_id_table[] = { DVB_USB_DEV(TECHNISAT, TECHNISAT_USB2_DVB_S2), { } }; diff --git a/drivers/media/usb/dvb-usb/ttusb2.c b/drivers/media/usb/dvb-usb/ttusb2.c index 373ffa7f641e..acde6149d278 100644 --- a/drivers/media/usb/dvb-usb/ttusb2.c +++ b/drivers/media/usb/dvb-usb/ttusb2.c @@ -434,7 +434,7 @@ static u32 ttusb2_i2c_func(struct i2c_adapter *adapter) return I2C_FUNC_I2C; } -static struct i2c_algorithm ttusb2_i2c_algo = { +static const struct i2c_algorithm ttusb2_i2c_algo = { .master_xfer = ttusb2_i2c_xfer, .functionality = ttusb2_i2c_func, }; @@ -638,7 +638,7 @@ enum { TECHNOTREND_CONNECT_S2400_8KEEPROM, }; -static struct usb_device_id ttusb2_table[] = { +static const struct usb_device_id ttusb2_table[] = { DVB_USB_DEV(PINNACLE, PINNACLE_PCTV_400E), DVB_USB_DEV(PINNACLE, PINNACLE_PCTV_450E), DVB_USB_DEV(TECHNOTREND, TECHNOTREND_CONNECT_S2400), diff --git a/drivers/media/usb/dvb-usb/umt-010.c b/drivers/media/usb/dvb-usb/umt-010.c index 464699b0b75b..8f23f92946d4 100644 --- a/drivers/media/usb/dvb-usb/umt-010.c +++ b/drivers/media/usb/dvb-usb/umt-010.c @@ -86,7 +86,7 @@ enum { HANFTEK_UMT_010_WARM, }; -static struct usb_device_id umt_table[] = { +static const struct usb_device_id umt_table[] = { DVB_USB_DEV(HANFTEK, HANFTEK_UMT_010_COLD), DVB_USB_DEV(HANFTEK, HANFTEK_UMT_010_WARM), { } diff --git a/drivers/media/usb/dvb-usb/vp702x.c b/drivers/media/usb/dvb-usb/vp702x.c index 5b6740cbd1d1..034b0652b9a1 100644 --- a/drivers/media/usb/dvb-usb/vp702x.c +++ b/drivers/media/usb/dvb-usb/vp702x.c @@ -375,7 +375,7 @@ enum { VISIONPLUS_VP7020_WARM, }; -static struct usb_device_id vp702x_usb_table[] = { +static const struct usb_device_id vp702x_usb_table[] = { DVB_USB_DEV(VISIONPLUS, VISIONPLUS_VP7021_COLD), // DVB_USB_DEV(VISIONPLUS, VISIONPLUS_VP7020_COLD), // DVB_USB_DEV(VISIONPLUS, VISIONPLUS_VP7020_WARM), diff --git a/drivers/media/usb/dvb-usb/vp7045.c b/drivers/media/usb/dvb-usb/vp7045.c index 1dc2b18d44d8..5224c3233f8c 100644 --- a/drivers/media/usb/dvb-usb/vp7045.c +++ b/drivers/media/usb/dvb-usb/vp7045.c @@ -179,7 +179,7 @@ enum { VISIONPLUS_TINYUSB2_WARM, }; -static struct usb_device_id vp7045_usb_table[] = { +static const struct usb_device_id vp7045_usb_table[] = { DVB_USB_DEV(VISIONPLUS, VISIONPLUS_VP7045_COLD), DVB_USB_DEV(VISIONPLUS, VISIONPLUS_VP7045_WARM), DVB_USB_DEV(VISIONPLUS, VISIONPLUS_TINYUSB2_COLD), diff --git a/drivers/media/usb/em28xx/Kconfig b/drivers/media/usb/em28xx/Kconfig index b3c472b8c5a9..3122d4bdfc59 100644 --- a/drivers/media/usb/em28xx/Kconfig +++ b/drivers/media/usb/em28xx/Kconfig @@ -12,8 +12,8 @@ config VIDEO_EM28XX_V4L2 select VIDEO_SAA711X if MEDIA_SUBDRV_AUTOSELECT select VIDEO_TVP5150 if MEDIA_SUBDRV_AUTOSELECT select VIDEO_MSP3400 if MEDIA_SUBDRV_AUTOSELECT - select VIDEO_MT9V011 if MEDIA_SUBDRV_AUTOSELECT && MEDIA_CAMERA_SUPPORT - select VIDEO_OV2640 if MEDIA_SUBDRV_AUTOSELECT && MEDIA_CAMERA_SUPPORT + select VIDEO_MT9V011 if MEDIA_SUBDRV_AUTOSELECT && VIDEO_CAMERA_SENSOR + select VIDEO_OV2640 if MEDIA_SUBDRV_AUTOSELECT && VIDEO_CAMERA_SENSOR help This is a video4linux driver for Empia 28xx based TV cards. @@ -68,6 +68,7 @@ config VIDEO_EM28XX_DVB select MEDIA_TUNER_XC5000 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT select DVB_MXL692 if MEDIA_SUBDRV_AUTOSELECT + select GPIOLIB_LEGACY if GPIOLIB && DVB_CXD2820R help This adds support for DVB cards based on the Empiatech em28xx chips. diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index 4d037c92af7c..a51cbcf429e1 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -555,6 +555,30 @@ static struct em28xx_reg_seq hauppauge_usb_quadhd_atsc_reg_seq[] = { }; /* + * MyGica USB TV Box + * GPIO_1,0: 00=Composite audio + * 01=Tuner audio + * 10=Mute audio + * 11=FM radio? (if equipped) + * GPIO_2-6: Unused + * GPIO_7: ?? + */ +static const struct em28xx_reg_seq mygica_utv3_composite_audio_gpio[] = { + {EM2820_R08_GPIO_CTRL, 0xfc, 0xff, 0}, + { -1, -1, -1, -1}, +}; + +static const struct em28xx_reg_seq mygica_utv3_tuner_audio_gpio[] = { + {EM2820_R08_GPIO_CTRL, 0xfd, 0xff, 0}, + { -1, -1, -1, -1}, +}; + +static const struct em28xx_reg_seq mygica_utv3_suspend_gpio[] = { + {EM2820_R08_GPIO_CTRL, 0xfe, 0xff, 0}, + { -1, -1, -1, -1}, +}; + +/* * Button definitions */ static const struct em28xx_button std_snapshot_button[] = { @@ -2578,6 +2602,32 @@ const struct em28xx_board em28xx_boards[] = { .tuner_gpio = hauppauge_usb_quadhd_atsc_reg_seq, .leds = hauppauge_usb_quadhd_leds, }, + /* + * eb1a:2860 MyGica UTV3 Analog USB2.0 TV Box + * Empia EM2860, Philips SAA7113, NXP TDA9801T demod, + * Tena TNF931D-DFDR1 tuner (contains NXP TDA6509A), + * ST HCF4052 demux (switches audio to line out), + * no audio over USB + */ + [EM2860_BOARD_MYGICA_UTV3] = { + .name = "MyGica UTV3 Analog USB2.0 TV Box", + .xclk = EM28XX_XCLK_IR_RC5_MODE | EM28XX_XCLK_FREQUENCY_12MHZ, + .tuner_type = TUNER_TENA_TNF_931D_DFDR1, + .ir_codes = RC_MAP_MYGICA_UTV3, + .decoder = EM28XX_SAA711X, + .suspend_gpio = mygica_utv3_suspend_gpio, + .input = { { + .type = EM28XX_VMUX_COMPOSITE, + .vmux = SAA7115_COMPOSITE0, + .amux = EM28XX_AMUX_VIDEO, + .gpio = mygica_utv3_composite_audio_gpio, + }, { + .type = EM28XX_VMUX_TELEVISION, + .vmux = SAA7115_COMPOSITE2, + .amux = EM28XX_AMUX_VIDEO, + .gpio = mygica_utv3_tuner_audio_gpio, + } }, + }, }; EXPORT_SYMBOL_GPL(em28xx_boards); @@ -2819,6 +2869,7 @@ static const struct em28xx_hash_table em28xx_eeprom_hash[] = { {0x63f653bd, EM2870_BOARD_REDDO_DVB_C_USB_BOX, TUNER_ABSENT}, {0x4e913442, EM2882_BOARD_DIKOM_DK300, TUNER_XC2028}, {0x85dd871e, EM2882_BOARD_ZOLID_HYBRID_TV_STICK, TUNER_XC2028}, + {0x8f597549, EM2860_BOARD_MYGICA_UTV3, TUNER_TENA_TNF_931D_DFDR1}, }; /* I2C devicelist hash table for devices with generic USB IDs */ @@ -2831,6 +2882,7 @@ static const struct em28xx_hash_table em28xx_i2c_hash[] = { {0x4ba50080, EM2861_BOARD_GADMEI_UTV330PLUS, TUNER_TNF_5335MF}, {0x6b800080, EM2874_BOARD_LEADERSHIP_ISDBT, TUNER_ABSENT}, {0x27e10080, EM2882_BOARD_ZOLID_HYBRID_TV_STICK, TUNER_XC2028}, + {0x840d0484, EM2860_BOARD_MYGICA_UTV3, TUNER_TENA_TNF_931D_DFDR1}, }; /* NOTE: introduce a separate hash table for devices with 16 bit eeproms */ @@ -4094,6 +4146,10 @@ static int em28xx_usb_probe(struct usb_interface *intf, * topology will likely change after the load of the em28xx subdrivers. */ #ifdef CONFIG_MEDIA_CONTROLLER + /* + * No need to check the return value, the device will still be + * usable without media controller API. + */ retval = media_device_register(dev->media_dev); #endif diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c index 61d7bf701d57..29a7f3f19b56 100644 --- a/drivers/media/usb/em28xx/em28xx-core.c +++ b/drivers/media/usb/em28xx/em28xx-core.c @@ -416,8 +416,9 @@ int em28xx_audio_analog_set(struct em28xx *dev) int ret, i; u8 xclk; + /* Set GPIOs here for boards without audio */ if (dev->int_audio_type == EM28XX_INT_AUDIO_NONE) - return 0; + return em28xx_gpio_set(dev, INPUT(dev->ctl_input)->gpio); /* * It is assumed that all devices use master volume for output. diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c index 9fce59979e3b..b94f5c70ab75 100644 --- a/drivers/media/usb/em28xx/em28xx-dvb.c +++ b/drivers/media/usb/em28xx/em28xx-dvb.c @@ -727,7 +727,7 @@ static int em28xx_pctv_290e_set_lna(struct dvb_frontend *fe) struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct em28xx_i2c_bus *i2c_bus = fe->dvb->priv; struct em28xx *dev = i2c_bus->dev; -#ifdef CONFIG_GPIOLIB +#ifdef CONFIG_GPIOLIB_LEGACY struct em28xx_dvb *dvb = dev->dvb; int ret; unsigned long flags; @@ -1705,7 +1705,7 @@ static int em28xx_dvb_init(struct em28xx *dev) goto out_free; } -#ifdef CONFIG_GPIOLIB +#ifdef CONFIG_GPIOLIB_LEGACY /* enable LNA for DVB-T, DVB-T2 and DVB-C */ result = gpio_request_one(dvb->lna_gpio, GPIOF_OUT_INIT_LOW, NULL); diff --git a/drivers/media/usb/em28xx/em28xx-vbi.c b/drivers/media/usb/em28xx/em28xx-vbi.c index b253c44c9724..8c5d95181223 100644 --- a/drivers/media/usb/em28xx/em28xx-vbi.c +++ b/drivers/media/usb/em28xx/em28xx-vbi.c @@ -84,6 +84,4 @@ const struct vb2_ops em28xx_vbi_qops = { .buf_queue = vbi_buffer_queue, .start_streaming = em28xx_start_analog_streaming, .stop_streaming = em28xx_stop_vbi_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 25e0620deff1..2dfa3242a7ab 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -264,7 +264,7 @@ static void em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart, u8 overflow = (height >> 9 & 0x02) | (width >> 10 & 0x01); /* NOTE: size limit: 2047x1023 = 2MPix */ - em28xx_videodbg("capture area set to (%d,%d): %dx%d\n", + em28xx_videodbg("capture area set to (%u,%u)/%ux%u\n", hstart, vstart, ((overflow & 2) << 9 | cwidth << 2), ((overflow & 1) << 10 | cheight << 2)); @@ -1229,8 +1229,6 @@ static const struct vb2_ops em28xx_video_qops = { .buf_queue = buffer_queue, .start_streaming = em28xx_start_analog_streaming, .stop_streaming = em28xx_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int em28xx_vb2_setup(struct em28xx *dev) @@ -1607,7 +1605,8 @@ static int vidioc_g_parm(struct file *file, void *priv, p->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; if (dev->is_webcam) { rc = v4l2_device_call_until_err(&v4l2->v4l2_dev, 0, - video, g_frame_interval, &ival); + pad, get_frame_interval, NULL, + &ival); if (!rc) p->parm.capture.timeperframe = ival.interval; } else { @@ -1639,7 +1638,8 @@ static int vidioc_s_parm(struct file *file, void *priv, p->parm.capture.readbuffers = EM28XX_MIN_BUF; p->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; rc = v4l2_device_call_until_err(&dev->v4l2->v4l2_dev, 0, - video, s_frame_interval, &ival); + pad, set_frame_interval, NULL, + &ival); if (!rc) p->parm.capture.timeperframe = ival.interval; return rc; diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index db18dd814a67..f3449c240d21 100644 --- a/drivers/media/usb/em28xx/em28xx.h +++ b/drivers/media/usb/em28xx/em28xx.h @@ -143,6 +143,7 @@ #define EM28178_BOARD_PCTV_461E_V2 104 #define EM2860_BOARD_MYGICA_IGRABBER 105 #define EM2874_BOARD_HAUPPAUGE_USB_QUADHD 106 +#define EM2860_BOARD_MYGICA_UTV3 107 /* Limits minimum and default number of buffers */ #define EM28XX_MIN_BUF 4 diff --git a/drivers/media/usb/go7007/Kconfig b/drivers/media/usb/go7007/Kconfig index 4ff79940ad8d..b2a15d9fb1f3 100644 --- a/drivers/media/usb/go7007/Kconfig +++ b/drivers/media/usb/go7007/Kconfig @@ -12,8 +12,8 @@ config VIDEO_GO7007 select VIDEO_TW2804 if MEDIA_SUBDRV_AUTOSELECT select VIDEO_TW9903 if MEDIA_SUBDRV_AUTOSELECT select VIDEO_TW9906 if MEDIA_SUBDRV_AUTOSELECT - select VIDEO_OV7640 if MEDIA_SUBDRV_AUTOSELECT && MEDIA_CAMERA_SUPPORT select VIDEO_UDA1342 if MEDIA_SUBDRV_AUTOSELECT + select VIDEO_OV7640 if MEDIA_SUBDRV_AUTOSELECT && VIDEO_CAMERA_SENSOR help This is a video4linux driver for the WIS GO7007 MPEG encoder chip. diff --git a/drivers/media/usb/go7007/go7007-driver.c b/drivers/media/usb/go7007/go7007-driver.c index 0c24e2984304..468406302cd5 100644 --- a/drivers/media/usb/go7007/go7007-driver.c +++ b/drivers/media/usb/go7007/go7007-driver.c @@ -80,7 +80,7 @@ static int go7007_load_encoder(struct go7007 *go) const struct firmware *fw_entry; char fw_name[] = "go7007/go7007fw.bin"; void *bounce; - int fw_len, rv = 0; + int fw_len; u16 intr_val, intr_data; if (go->boot_fw == NULL) { @@ -109,9 +109,11 @@ static int go7007_load_encoder(struct go7007 *go) go7007_read_interrupt(go, &intr_val, &intr_data) < 0 || (intr_val & ~0x1) != 0x5a5a) { v4l2_err(go, "error transferring firmware\n"); - rv = -1; + kfree(go->boot_fw); + go->boot_fw = NULL; + return -1; } - return rv; + return 0; } MODULE_FIRMWARE("go7007/go7007fw.bin"); @@ -734,4 +736,5 @@ void go7007_update_board(struct go7007 *go) } EXPORT_SYMBOL(go7007_update_board); +MODULE_DESCRIPTION("WIS GO7007 MPEG encoder support"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/usb/go7007/go7007-fw.c b/drivers/media/usb/go7007/go7007-fw.c index 018019ba47d4..86ce593e0c54 100644 --- a/drivers/media/usb/go7007/go7007-fw.c +++ b/drivers/media/usb/go7007/go7007-fw.c @@ -1289,8 +1289,8 @@ static int avsync_to_package(struct go7007 *go, __le16 *code, int space) 0xbf99, (u16)((-adjratio) >> 16), 0xbf92, 0, 0xbf93, 0, - 0xbff4, f1 > f2 ? f1 : f2, - 0xbff5, f1 < f2 ? f1 : f2, + 0xbff4, max(f1, f2), + 0xbff5, min(f1, f2), 0xbff6, f1 < f2 ? ratio : ratio + 1, 0xbff7, f1 > f2 ? ratio : ratio + 1, 0xbff8, 0, diff --git a/drivers/media/usb/go7007/go7007-i2c.c b/drivers/media/usb/go7007/go7007-i2c.c index 38339dd2f83f..f6ce28a4a768 100644 --- a/drivers/media/usb/go7007/go7007-i2c.c +++ b/drivers/media/usb/go7007/go7007-i2c.c @@ -33,7 +33,21 @@ /* There is only one I2C port on the TW2804 that feeds all four GO7007 VIPs * on the Adlink PCI-MPG24, so access is shared between all of them. */ -static DEFINE_MUTEX(adlink_mpg24_i2c_lock); +static DEFINE_MUTEX(adlink_mpg24_i2c_mutex); + +static inline void adlink_mpg24_i2c_lock(struct go7007 *go) +{ + /* Bridge the I2C port on this GO7007 to the shared bus */ + mutex_lock(&adlink_mpg24_i2c_mutex); + go7007_write_addr(go, 0x3c82, 0x0020); +} + +static inline void adlink_mpg24_i2c_unlock(struct go7007 *go) +{ + /* Isolate the I2C port on this GO7007 from the shared bus */ + go7007_write_addr(go, 0x3c82, 0x0000); + mutex_unlock(&adlink_mpg24_i2c_mutex); +} static int go7007_i2c_xfer(struct go7007 *go, u16 addr, int read, u16 command, int flags, u8 *data) @@ -56,11 +70,8 @@ static int go7007_i2c_xfer(struct go7007 *go, u16 addr, int read, mutex_lock(&go->hw_lock); - if (go->board_id == GO7007_BOARDID_ADLINK_MPG24) { - /* Bridge the I2C port on this GO7007 to the shared bus */ - mutex_lock(&adlink_mpg24_i2c_lock); - go7007_write_addr(go, 0x3c82, 0x0020); - } + if (go->board_id == GO7007_BOARDID_ADLINK_MPG24) + adlink_mpg24_i2c_lock(go); /* Wait for I2C adapter to be ready */ for (i = 0; i < 10; ++i) { @@ -116,11 +127,8 @@ static int go7007_i2c_xfer(struct go7007 *go, u16 addr, int read, ret = 0; i2c_done: - if (go->board_id == GO7007_BOARDID_ADLINK_MPG24) { - /* Isolate the I2C port on this GO7007 from the shared bus */ - go7007_write_addr(go, 0x3c82, 0x0000); - mutex_unlock(&adlink_mpg24_i2c_lock); - } + if (go->board_id == GO7007_BOARDID_ADLINK_MPG24) + adlink_mpg24_i2c_unlock(go); mutex_unlock(&go->hw_lock); return ret; } @@ -165,8 +173,6 @@ static int go7007_i2c_master_xfer(struct i2c_adapter *adapter, } else if (msgs[i].len == 3) { if (msgs[i].flags & I2C_M_RD) return -EIO; - if (msgs[i].len != 3) - return -EIO; if (go7007_i2c_xfer(go, msgs[i].addr, 0, (msgs[i].buf[0] << 8) | msgs[i].buf[1], 0x01, &msgs[i].buf[2]) < 0) diff --git a/drivers/media/usb/go7007/go7007-usb.c b/drivers/media/usb/go7007/go7007-usb.c index eeb85981e02b..334cdde81a5c 100644 --- a/drivers/media/usb/go7007/go7007-usb.c +++ b/drivers/media/usb/go7007/go7007-usb.c @@ -1201,7 +1201,9 @@ static int go7007_usb_probe(struct usb_interface *intf, u16 channel; /* read channel number from GPIO[1:0] */ - go7007_read_addr(go, 0x3c81, &channel); + if (go7007_read_addr(go, 0x3c81, &channel)) + goto allocfail; + channel &= 0x3; go->board_id = GO7007_BOARDID_ADLINK_MPG24; usb->board = board = &board_adlink_mpg24; @@ -1350,4 +1352,5 @@ static struct usb_driver go7007_usb_driver = { }; module_usb_driver(go7007_usb_driver); +MODULE_DESCRIPTION("WIS GO7007 USB support"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/usb/go7007/go7007-v4l2.c b/drivers/media/usb/go7007/go7007-v4l2.c index b2edc4deaca3..2087ffcb85a5 100644 --- a/drivers/media/usb/go7007/go7007-v4l2.c +++ b/drivers/media/usb/go7007/go7007-v4l2.c @@ -404,16 +404,13 @@ static int go7007_start_streaming(struct vb2_queue *q, unsigned int count) go->next_seq = 0; go->active_buf = NULL; go->modet_event_status = 0; - q->streaming = 1; if (go7007_start_encoder(go) < 0) ret = -EIO; else ret = 0; mutex_unlock(&go->hw_lock); - if (ret) { - q->streaming = 0; + if (ret) return ret; - } call_all(&go->v4l2_dev, video, s_stream, 1); v4l2_ctrl_grab(go->mpeg_video_gop_size, true); v4l2_ctrl_grab(go->mpeg_video_gop_closure, true); @@ -430,7 +427,6 @@ static void go7007_stop_streaming(struct vb2_queue *q) struct go7007 *go = vb2_get_drv_priv(q); unsigned long flags; - q->streaming = 0; go7007_stream_stop(go); mutex_lock(&go->hw_lock); go7007_reset_encoder(go); @@ -456,8 +452,6 @@ static const struct vb2_ops go7007_video_qops = { .buf_finish = go7007_buf_finish, .start_streaming = go7007_start_streaming, .stop_streaming = go7007_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int vidioc_g_parm(struct file *filp, void *priv, diff --git a/drivers/media/usb/go7007/s2250-board.c b/drivers/media/usb/go7007/s2250-board.c index 29dfcc6d0b0a..a155b987282f 100644 --- a/drivers/media/usb/go7007/s2250-board.c +++ b/drivers/media/usb/go7007/s2250-board.c @@ -611,7 +611,7 @@ static void s2250_remove(struct i2c_client *client) } static const struct i2c_device_id s2250_id[] = { - { "s2250", 0 }, + { "s2250" }, { } }; MODULE_DEVICE_TABLE(i2c, s2250_id); @@ -620,7 +620,7 @@ static struct i2c_driver s2250_driver = { .driver = { .name = "s2250", }, - .probe_new = s2250_probe, + .probe = s2250_probe, .remove = s2250_remove, .id_table = s2250_id, }; diff --git a/drivers/media/usb/gspca/cpia1.c b/drivers/media/usb/gspca/cpia1.c index 46ed95483e22..14aaf36cde6e 100644 --- a/drivers/media/usb/gspca/cpia1.c +++ b/drivers/media/usb/gspca/cpia1.c @@ -18,6 +18,7 @@ #include <linux/input.h> #include <linux/sched/signal.h> +#include <linux/bitops.h> #include "gspca.h" @@ -603,10 +604,8 @@ static int find_over_exposure(int brightness) MaxAllowableOverExposure = FLICKER_MAX_EXPOSURE - brightness - FLICKER_BRIGHTNESS_CONSTANT; - if (MaxAllowableOverExposure < FLICKER_ALLOWABLE_OVER_EXPOSURE) - OverExposure = MaxAllowableOverExposure; - else - OverExposure = FLICKER_ALLOWABLE_OVER_EXPOSURE; + OverExposure = min(MaxAllowableOverExposure, + FLICKER_ALLOWABLE_OVER_EXPOSURE); return OverExposure; } @@ -1028,6 +1027,8 @@ static int set_flicker(struct gspca_dev *gspca_dev, int on, int apply) sd->params.exposure.expMode = 2; sd->exposure_status = EXPOSURE_NORMAL; } + if (sd->params.exposure.gain >= BITS_PER_TYPE(currentexp)) + return -EINVAL; currentexp = currentexp << sd->params.exposure.gain; sd->params.exposure.gain = 0; /* round down current exposure to nearest value */ diff --git a/drivers/media/usb/gspca/gspca.c b/drivers/media/usb/gspca/gspca.c index 770714c34295..3fc15d16df8e 100644 --- a/drivers/media/usb/gspca/gspca.c +++ b/drivers/media/usb/gspca/gspca.c @@ -1029,15 +1029,15 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, return 0; } -static int vidioc_g_fmt_vid_cap(struct file *file, void *_priv, +static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *fmt) { struct gspca_dev *gspca_dev = video_drvdata(file); - u32 priv = fmt->fmt.pix.priv; + u32 fmt_priv = fmt->fmt.pix.priv; fmt->fmt.pix = gspca_dev->pixfmt; /* some drivers use priv internally, so keep the original value */ - fmt->fmt.pix.priv = priv; + fmt->fmt.pix.priv = fmt_priv; return 0; } @@ -1075,24 +1075,24 @@ static int try_fmt_vid_cap(struct gspca_dev *gspca_dev, return mode; /* used when s_fmt */ } -static int vidioc_try_fmt_vid_cap(struct file *file, void *_priv, +static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *fmt) { struct gspca_dev *gspca_dev = video_drvdata(file); - u32 priv = fmt->fmt.pix.priv; + u32 fmt_priv = fmt->fmt.pix.priv; if (try_fmt_vid_cap(gspca_dev, fmt) < 0) return -EINVAL; /* some drivers use priv internally, so keep the original value */ - fmt->fmt.pix.priv = priv; + fmt->fmt.pix.priv = fmt_priv; return 0; } -static int vidioc_s_fmt_vid_cap(struct file *file, void *_priv, +static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *fmt) { struct gspca_dev *gspca_dev = video_drvdata(file); - u32 priv = fmt->fmt.pix.priv; + u32 fmt_priv = fmt->fmt.pix.priv; int mode; if (vb2_is_busy(&gspca_dev->queue)) @@ -1109,7 +1109,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *_priv, else gspca_dev->pixfmt = gspca_dev->cam.cam_mode[mode]; /* some drivers use priv internally, so keep the original value */ - fmt->fmt.pix.priv = priv; + fmt->fmt.pix.priv = fmt_priv; return 0; } @@ -1257,7 +1257,7 @@ static int vidioc_g_parm(struct file *filp, void *priv, { struct gspca_dev *gspca_dev = video_drvdata(filp); - parm->parm.capture.readbuffers = gspca_dev->queue.min_buffers_needed; + parm->parm.capture.readbuffers = gspca_dev->queue.min_queued_buffers; if (!gspca_dev->sd_desc->get_streamparm) return 0; @@ -1273,7 +1273,7 @@ static int vidioc_s_parm(struct file *filp, void *priv, { struct gspca_dev *gspca_dev = video_drvdata(filp); - parm->parm.capture.readbuffers = gspca_dev->queue.min_buffers_needed; + parm->parm.capture.readbuffers = gspca_dev->queue.min_queued_buffers; if (!gspca_dev->sd_desc->set_streamparm) { parm->parm.capture.capability = 0; @@ -1380,8 +1380,6 @@ static const struct vb2_ops gspca_qops = { .buf_queue = gspca_buffer_queue, .start_streaming = gspca_start_streaming, .stop_streaming = gspca_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static const struct v4l2_file_operations dev_fops = { @@ -1517,7 +1515,7 @@ int gspca_dev_probe2(struct usb_interface *intf, q->ops = &gspca_qops; q->mem_ops = &vb2_vmalloc_memops; q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - q->min_buffers_needed = 2; + q->min_queued_buffers = 2; q->lock = &gspca_dev->usb_lock; ret = vb2_queue_init(q); if (ret) diff --git a/drivers/media/usb/gspca/ov534.c b/drivers/media/usb/gspca/ov534.c index 8b6a57f170d0..bdff64a29a33 100644 --- a/drivers/media/usb/gspca/ov534.c +++ b/drivers/media/usb/gspca/ov534.c @@ -847,7 +847,7 @@ static void set_frame_rate(struct gspca_dev *gspca_dev) r = rate_1; i = ARRAY_SIZE(rate_1); } - while (--i > 0) { + while (--i >= 0) { if (sd->frame_rate >= r->fps) break; r++; diff --git a/drivers/media/usb/gspca/stv06xx/stv06xx_hdcs.c b/drivers/media/usb/gspca/stv06xx/stv06xx_hdcs.c index 5a47dcbf1c8e..303b055fefea 100644 --- a/drivers/media/usb/gspca/stv06xx/stv06xx_hdcs.c +++ b/drivers/media/usb/gspca/stv06xx/stv06xx_hdcs.c @@ -520,12 +520,13 @@ static int hdcs_init(struct sd *sd) static int hdcs_dump(struct sd *sd) { u16 reg, val; + int err = 0; pr_info("Dumping sensor registers:\n"); - for (reg = HDCS_IDENT; reg <= HDCS_ROWEXPH; reg++) { - stv06xx_read_sensor(sd, reg, &val); + for (reg = HDCS_IDENT; reg <= HDCS_ROWEXPH && !err; reg++) { + err = stv06xx_read_sensor(sd, reg, &val); pr_info("reg 0x%02x = 0x%02x\n", reg, val); } - return 0; + return (err < 0) ? err : 0; } diff --git a/drivers/media/usb/gspca/vicam.c b/drivers/media/usb/gspca/vicam.c index d98343fd33fe..91e177aa8136 100644 --- a/drivers/media/usb/gspca/vicam.c +++ b/drivers/media/usb/gspca/vicam.c @@ -227,6 +227,7 @@ static int sd_init(struct gspca_dev *gspca_dev) const struct ihex_binrec *rec; const struct firmware *fw; u8 *firmware_buf; + int len; ret = request_ihex_firmware(&fw, VICAM_FIRMWARE, &gspca_dev->dev->dev); @@ -241,9 +242,14 @@ static int sd_init(struct gspca_dev *gspca_dev) goto exit; } for (rec = (void *)fw->data; rec; rec = ihex_next_binrec(rec)) { - memcpy(firmware_buf, rec->data, be16_to_cpu(rec->len)); + len = be16_to_cpu(rec->len); + if (len > PAGE_SIZE) { + ret = -EINVAL; + break; + } + memcpy(firmware_buf, rec->data, len); ret = vicam_control_msg(gspca_dev, 0xff, 0, 0, firmware_buf, - be16_to_cpu(rec->len)); + len); if (ret < 0) break; } diff --git a/drivers/media/usb/hackrf/hackrf.c b/drivers/media/usb/hackrf/hackrf.c index 3e535be2c520..0b50de8775a3 100644 --- a/drivers/media/usb/hackrf/hackrf.c +++ b/drivers/media/usb/hackrf/hackrf.c @@ -753,12 +753,13 @@ static int hackrf_queue_setup(struct vb2_queue *vq, unsigned int *nplanes, unsigned int sizes[], struct device *alloc_devs[]) { struct hackrf_dev *dev = vb2_get_drv_priv(vq); + unsigned int q_num_bufs = vb2_get_num_buffers(vq); dev_dbg(dev->dev, "nbuffers=%d\n", *nbuffers); /* Need at least 8 buffers */ - if (vq->num_buffers + *nbuffers < 8) - *nbuffers = 8 - vq->num_buffers; + if (q_num_bufs + *nbuffers < 8) + *nbuffers = 8 - q_num_bufs; *nplanes = 1; sizes[0] = PAGE_ALIGN(dev->buffersize); @@ -887,8 +888,6 @@ static const struct vb2_ops hackrf_vb2_ops = { .buf_queue = hackrf_buf_queue, .start_streaming = hackrf_start_streaming, .stop_streaming = hackrf_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int hackrf_querycap(struct file *file, void *fh, @@ -1397,6 +1396,7 @@ static int hackrf_probe(struct usb_interface *intf, dev->rx_vb2_queue.drv_priv = dev; dev->rx_vb2_queue.buf_struct_size = sizeof(struct hackrf_buffer); dev->rx_vb2_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + dev->rx_vb2_queue.lock = &dev->vb_queue_lock; ret = vb2_queue_init(&dev->rx_vb2_queue); if (ret) { dev_err(dev->dev, "Could not initialize rx vb2 queue\n"); @@ -1412,6 +1412,7 @@ static int hackrf_probe(struct usb_interface *intf, dev->tx_vb2_queue.drv_priv = dev; dev->tx_vb2_queue.buf_struct_size = sizeof(struct hackrf_buffer); dev->tx_vb2_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + dev->tx_vb2_queue.lock = &dev->vb_queue_lock; ret = vb2_queue_init(&dev->tx_vb2_queue); if (ret) { dev_err(dev->dev, "Could not initialize tx vb2 queue\n"); @@ -1473,7 +1474,6 @@ static int hackrf_probe(struct usb_interface *intf, /* Init video_device structure for receiver */ dev->rx_vdev = hackrf_template; dev->rx_vdev.queue = &dev->rx_vb2_queue; - dev->rx_vdev.queue->lock = &dev->vb_queue_lock; dev->rx_vdev.v4l2_dev = &dev->v4l2_dev; dev->rx_vdev.ctrl_handler = &dev->rx_ctrl_handler; dev->rx_vdev.lock = &dev->v4l2_lock; @@ -1493,7 +1493,6 @@ static int hackrf_probe(struct usb_interface *intf, /* Init video_device structure for transmitter */ dev->tx_vdev = hackrf_template; dev->tx_vdev.queue = &dev->tx_vb2_queue; - dev->tx_vdev.queue->lock = &dev->vb_queue_lock; dev->tx_vdev.v4l2_dev = &dev->v4l2_dev; dev->tx_vdev.ctrl_handler = &dev->tx_ctrl_handler; dev->tx_vdev.lock = &dev->v4l2_lock; diff --git a/drivers/media/usb/hdpvr/hdpvr-i2c.c b/drivers/media/usb/hdpvr/hdpvr-i2c.c index 070559b01b01..9eacc85e3f11 100644 --- a/drivers/media/usb/hdpvr/hdpvr-i2c.c +++ b/drivers/media/usb/hdpvr/hdpvr-i2c.c @@ -124,32 +124,12 @@ static int hdpvr_transfer(struct i2c_adapter *i2c_adapter, struct i2c_msg *msgs, else retval = hdpvr_i2c_write(dev, 1, addr, msgs[0].buf, msgs[0].len); - } else if (num == 2) { - if (msgs[0].addr != msgs[1].addr) { - v4l2_warn(&dev->v4l2_dev, "refusing 2-phase i2c xfer with conflicting target addresses\n"); - retval = -EINVAL; - goto out; - } - - if ((msgs[0].flags & I2C_M_RD) || !(msgs[1].flags & I2C_M_RD)) { - v4l2_warn(&dev->v4l2_dev, "refusing complex xfer with r0=%d, r1=%d\n", - msgs[0].flags & I2C_M_RD, - msgs[1].flags & I2C_M_RD); - retval = -EINVAL; - goto out; - } - - /* - * Write followed by atomic read is the only complex xfer that - * we actually support here. - */ + } else { + /* do write-then-read */ retval = hdpvr_i2c_read(dev, 1, addr, msgs[0].buf, msgs[0].len, msgs[1].buf, msgs[1].len); - } else { - v4l2_warn(&dev->v4l2_dev, "refusing %d-phase i2c xfer\n", num); } -out: mutex_unlock(&dev->i2c_mutex); return retval ? retval : num; @@ -165,10 +145,16 @@ static const struct i2c_algorithm hdpvr_algo = { .functionality = hdpvr_functionality, }; +/* prevent invalid 0-length usb_control_msg and support only write-then-read */ +static const struct i2c_adapter_quirks hdpvr_quirks = { + .flags = I2C_AQ_NO_ZERO_LEN_READ | I2C_AQ_COMB_WRITE_THEN_READ, +}; + static const struct i2c_adapter hdpvr_i2c_adapter_template = { .name = "Hauppauge HD PVR I2C", .owner = THIS_MODULE, .algo = &hdpvr_algo, + .quirks = &hdpvr_quirks, }; static int hdpvr_activate_ir(struct hdpvr_device *dev) diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c index fd7d2a9d0449..8c7ae362d992 100644 --- a/drivers/media/usb/hdpvr/hdpvr-video.c +++ b/drivers/media/usb/hdpvr/hdpvr-video.c @@ -52,6 +52,11 @@ struct hdpvr_fh { bool legacy_mode; }; +static inline struct hdpvr_fh *file_to_hdpvr_fh(struct file *file) +{ + return container_of(file_to_v4l2_fh(file), struct hdpvr_fh, fh); +} + static uint list_size(struct list_head *list) { struct list_head *tmp; @@ -380,8 +385,7 @@ static int hdpvr_open(struct file *file) return -ENOMEM; fh->legacy_mode = true; v4l2_fh_init(&fh->fh, video_devdata(file)); - v4l2_fh_add(&fh->fh); - file->private_data = fh; + v4l2_fh_add(&fh->fh, file); return 0; } @@ -390,7 +394,7 @@ static int hdpvr_release(struct file *file) struct hdpvr_device *dev = video_drvdata(file); mutex_lock(&dev->io_mutex); - if (file->private_data == dev->owner) { + if (file_to_v4l2_fh(file) == dev->owner) { hdpvr_stop_streaming(dev); dev->owner = NULL; } @@ -426,7 +430,7 @@ static ssize_t hdpvr_read(struct file *file, char __user *buffer, size_t count, mutex_unlock(&dev->io_mutex); goto err; } - dev->owner = file->private_data; + dev->owner = file_to_v4l2_fh(file); print_buffer_status(); } mutex_unlock(&dev->io_mutex); @@ -541,7 +545,7 @@ static __poll_t hdpvr_poll(struct file *filp, poll_table *wait) "start_streaming failed\n"); dev->status = STATUS_IDLE; } else { - dev->owner = filp->private_data; + dev->owner = file_to_v4l2_fh(filp); } print_buffer_status(); @@ -586,11 +590,11 @@ static int vidioc_querycap(struct file *file, void *priv, return 0; } -static int vidioc_s_std(struct file *file, void *_fh, +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id std) { struct hdpvr_device *dev = video_drvdata(file); - struct hdpvr_fh *fh = _fh; + struct hdpvr_fh *fh = file_to_hdpvr_fh(file); u8 std_type = 1; if (!fh->legacy_mode && dev->options.video_input == HDPVR_COMPONENT) @@ -606,11 +610,12 @@ static int vidioc_s_std(struct file *file, void *_fh, return hdpvr_config_call(dev, CTRL_VIDEO_STD_TYPE, std_type); } -static int vidioc_g_std(struct file *file, void *_fh, +static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *std) { struct hdpvr_device *dev = video_drvdata(file); - struct hdpvr_fh *fh = _fh; + struct hdpvr_fh *fh = file_to_hdpvr_fh(file); + if (!fh->legacy_mode && dev->options.video_input == HDPVR_COMPONENT) return -ENODATA; @@ -618,11 +623,11 @@ static int vidioc_g_std(struct file *file, void *_fh, return 0; } -static int vidioc_querystd(struct file *file, void *_fh, v4l2_std_id *a) +static int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *a) { struct hdpvr_device *dev = video_drvdata(file); + struct hdpvr_fh *fh = file_to_hdpvr_fh(file); struct hdpvr_video_info vid_info; - struct hdpvr_fh *fh = _fh; int ret; *a = V4L2_STD_UNKNOWN; @@ -637,11 +642,11 @@ static int vidioc_querystd(struct file *file, void *_fh, v4l2_std_id *a) return ret; } -static int vidioc_s_dv_timings(struct file *file, void *_fh, +static int vidioc_s_dv_timings(struct file *file, void *priv, struct v4l2_dv_timings *timings) { struct hdpvr_device *dev = video_drvdata(file); - struct hdpvr_fh *fh = _fh; + struct hdpvr_fh *fh = file_to_hdpvr_fh(file); int i; fh->legacy_mode = false; @@ -660,11 +665,11 @@ static int vidioc_s_dv_timings(struct file *file, void *_fh, return 0; } -static int vidioc_g_dv_timings(struct file *file, void *_fh, +static int vidioc_g_dv_timings(struct file *file, void *priv, struct v4l2_dv_timings *timings) { struct hdpvr_device *dev = video_drvdata(file); - struct hdpvr_fh *fh = _fh; + struct hdpvr_fh *fh = file_to_hdpvr_fh(file); fh->legacy_mode = false; if (dev->options.video_input) @@ -673,11 +678,11 @@ static int vidioc_g_dv_timings(struct file *file, void *_fh, return 0; } -static int vidioc_query_dv_timings(struct file *file, void *_fh, +static int vidioc_query_dv_timings(struct file *file, void *priv, struct v4l2_dv_timings *timings) { struct hdpvr_device *dev = video_drvdata(file); - struct hdpvr_fh *fh = _fh; + struct hdpvr_fh *fh = file_to_hdpvr_fh(file); struct hdpvr_video_info vid_info; bool interlaced; int ret = 0; @@ -715,11 +720,11 @@ static int vidioc_query_dv_timings(struct file *file, void *_fh, return ret; } -static int vidioc_enum_dv_timings(struct file *file, void *_fh, +static int vidioc_enum_dv_timings(struct file *file, void *priv, struct v4l2_enum_dv_timings *timings) { struct hdpvr_device *dev = video_drvdata(file); - struct hdpvr_fh *fh = _fh; + struct hdpvr_fh *fh = file_to_hdpvr_fh(file); fh->legacy_mode = false; memset(timings->reserved, 0, sizeof(timings->reserved)); @@ -731,11 +736,11 @@ static int vidioc_enum_dv_timings(struct file *file, void *_fh, return 0; } -static int vidioc_dv_timings_cap(struct file *file, void *_fh, +static int vidioc_dv_timings_cap(struct file *file, void *priv, struct v4l2_dv_timings_cap *cap) { struct hdpvr_device *dev = video_drvdata(file); - struct hdpvr_fh *fh = _fh; + struct hdpvr_fh *fh = file_to_hdpvr_fh(file); fh->legacy_mode = false; if (dev->options.video_input) @@ -758,7 +763,7 @@ static const char *iname[] = { [HDPVR_COMPOSITE] = "Composite", }; -static int vidioc_enum_input(struct file *file, void *_fh, struct v4l2_input *i) +static int vidioc_enum_input(struct file *file, void *priv, struct v4l2_input *i) { unsigned int n; @@ -778,7 +783,7 @@ static int vidioc_enum_input(struct file *file, void *_fh, struct v4l2_input *i) return 0; } -static int vidioc_s_input(struct file *file, void *_fh, +static int vidioc_s_input(struct file *file, void *priv, unsigned int index) { struct hdpvr_device *dev = video_drvdata(file); @@ -812,7 +817,7 @@ static int vidioc_s_input(struct file *file, void *_fh, return retval; } -static int vidioc_g_input(struct file *file, void *private_data, +static int vidioc_g_input(struct file *file, void *priv, unsigned int *index) { struct hdpvr_device *dev = video_drvdata(file); @@ -844,7 +849,7 @@ static int vidioc_enumaudio(struct file *file, void *priv, return 0; } -static int vidioc_s_audio(struct file *file, void *private_data, +static int vidioc_s_audio(struct file *file, void *priv, const struct v4l2_audio *audio) { struct hdpvr_device *dev = video_drvdata(file); @@ -863,7 +868,7 @@ static int vidioc_s_audio(struct file *file, void *private_data, return retval; } -static int vidioc_g_audio(struct file *file, void *private_data, +static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *audio) { struct hdpvr_device *dev = video_drvdata(file); @@ -980,7 +985,7 @@ static int hdpvr_s_ctrl(struct v4l2_ctrl *ctrl) return ret; } -static int vidioc_enum_fmt_vid_cap(struct file *file, void *private_data, +static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { if (f->index != 0) @@ -991,11 +996,11 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *private_data, return 0; } -static int vidioc_g_fmt_vid_cap(struct file *file, void *_fh, +static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct hdpvr_device *dev = video_drvdata(file); - struct hdpvr_fh *fh = _fh; + struct hdpvr_fh *fh = file_to_hdpvr_fh(file); int ret; /* @@ -1048,7 +1053,7 @@ static int vidioc_encoder_cmd(struct file *filp, void *priv, switch (a->cmd) { case V4L2_ENC_CMD_START: - if (dev->owner && filp->private_data != dev->owner) { + if (dev->owner && file_to_v4l2_fh(filp) != dev->owner) { res = -EBUSY; break; } @@ -1056,12 +1061,12 @@ static int vidioc_encoder_cmd(struct file *filp, void *priv, break; res = hdpvr_start_streaming(dev); if (!res) - dev->owner = filp->private_data; + dev->owner = file_to_v4l2_fh(filp); else dev->status = STATUS_IDLE; break; case V4L2_ENC_CMD_STOP: - if (dev->owner && filp->private_data != dev->owner) { + if (dev->owner && file_to_v4l2_fh(filp) != dev->owner) { res = -EBUSY; break; } diff --git a/drivers/media/usb/msi2500/msi2500.c b/drivers/media/usb/msi2500/msi2500.c index 9759996ee6a4..33099f39146a 100644 --- a/drivers/media/usb/msi2500/msi2500.c +++ b/drivers/media/usb/msi2500/msi2500.c @@ -107,7 +107,7 @@ struct msi2500_dev { struct video_device vdev; struct v4l2_device v4l2_dev; struct v4l2_subdev *v4l2_subdev; - struct spi_master *master; + struct spi_controller *ctlr; /* videobuf2 queue and queued buffers list */ struct vb2_queue vb_queue; @@ -574,7 +574,7 @@ static void msi2500_disconnect(struct usb_interface *intf) dev->udev = NULL; v4l2_device_disconnect(&dev->v4l2_dev); video_unregister_device(&dev->vdev); - spi_unregister_master(dev->master); + spi_unregister_controller(dev->ctlr); mutex_unlock(&dev->v4l2_lock); mutex_unlock(&dev->vb_queue_lock); @@ -883,8 +883,6 @@ static const struct vb2_ops msi2500_vb2_ops = { .buf_queue = msi2500_buf_queue, .start_streaming = msi2500_start_streaming, .stop_streaming = msi2500_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int msi2500_enum_fmt_sdr_cap(struct file *file, void *priv, @@ -1136,10 +1134,10 @@ static void msi2500_video_release(struct v4l2_device *v) kfree(dev); } -static int msi2500_transfer_one_message(struct spi_master *master, +static int msi2500_transfer_one_message(struct spi_controller *ctlr, struct spi_message *m) { - struct msi2500_dev *dev = spi_master_get_devdata(master); + struct msi2500_dev *dev = spi_controller_get_devdata(ctlr); struct spi_transfer *t; int ret = 0; u32 data; @@ -1154,7 +1152,7 @@ static int msi2500_transfer_one_message(struct spi_master *master, } m->status = ret; - spi_finalize_current_message(master); + spi_finalize_current_message(ctlr); return ret; } @@ -1163,7 +1161,7 @@ static int msi2500_probe(struct usb_interface *intf, { struct msi2500_dev *dev; struct v4l2_subdev *sd; - struct spi_master *master; + struct spi_controller *ctlr; int ret; static struct spi_board_info board_info = { .modalias = "msi001", @@ -1199,6 +1197,7 @@ static int msi2500_probe(struct usb_interface *intf, dev->vb_queue.ops = &msi2500_vb2_ops; dev->vb_queue.mem_ops = &vb2_vmalloc_memops; dev->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + dev->vb_queue.lock = &dev->vb_queue_lock; ret = vb2_queue_init(&dev->vb_queue); if (ret) { dev_err(dev->dev, "Could not initialize vb2 queue\n"); @@ -1208,7 +1207,6 @@ static int msi2500_probe(struct usb_interface *intf, /* Init video_device structure */ dev->vdev = msi2500_template; dev->vdev.queue = &dev->vb_queue; - dev->vdev.queue->lock = &dev->vb_queue_lock; video_set_drvdata(&dev->vdev, dev); /* Register the v4l2_device structure */ @@ -1219,31 +1217,31 @@ static int msi2500_probe(struct usb_interface *intf, goto err_free_mem; } - /* SPI master adapter */ - master = spi_alloc_master(dev->dev, 0); - if (master == NULL) { + /* SPI host adapter */ + ctlr = spi_alloc_host(dev->dev, 0); + if (ctlr == NULL) { ret = -ENOMEM; goto err_unregister_v4l2_dev; } - dev->master = master; - master->bus_num = -1; - master->num_chipselect = 1; - master->transfer_one_message = msi2500_transfer_one_message; - spi_master_set_devdata(master, dev); - ret = spi_register_master(master); + dev->ctlr = ctlr; + ctlr->bus_num = -1; + ctlr->num_chipselect = 1; + ctlr->transfer_one_message = msi2500_transfer_one_message; + spi_controller_set_devdata(ctlr, dev); + ret = spi_register_controller(ctlr); if (ret) { - spi_master_put(master); + spi_controller_put(ctlr); goto err_unregister_v4l2_dev; } /* load v4l2 subdevice */ - sd = v4l2_spi_new_subdev(&dev->v4l2_dev, master, &board_info); + sd = v4l2_spi_new_subdev(&dev->v4l2_dev, ctlr, &board_info); dev->v4l2_subdev = sd; if (sd == NULL) { dev_err(dev->dev, "cannot get v4l2 subdevice\n"); ret = -ENODEV; - goto err_unregister_master; + goto err_unregister_controller; } /* Register controls */ @@ -1276,8 +1274,8 @@ static int msi2500_probe(struct usb_interface *intf, return 0; err_free_controls: v4l2_ctrl_handler_free(&dev->hdl); -err_unregister_master: - spi_unregister_master(dev->master); +err_unregister_controller: + spi_unregister_controller(dev->ctlr); err_unregister_v4l2_dev: v4l2_device_unregister(&dev->v4l2_dev); err_free_mem: diff --git a/drivers/media/usb/pvrusb2/Kconfig b/drivers/media/usb/pvrusb2/Kconfig index f2b64e49c5a2..0df10270dbdf 100644 --- a/drivers/media/usb/pvrusb2/Kconfig +++ b/drivers/media/usb/pvrusb2/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config VIDEO_PVRUSB2 tristate "Hauppauge WinTV-PVR USB2 support" - depends on VIDEO_DEV && I2C + depends on VIDEO_DEV && I2C && DVB_CORE select VIDEO_TUNER select VIDEO_TVEEPROM select VIDEO_CX2341X @@ -37,6 +37,7 @@ config VIDEO_PVRUSB2_DVB bool "pvrusb2 ATSC/DVB support" default y depends on VIDEO_PVRUSB2 && DVB_CORE + depends on VIDEO_PVRUSB2=m || DVB_CORE=y select DVB_LGDT330X if MEDIA_SUBDRV_AUTOSELECT select DVB_S5H1409 if MEDIA_SUBDRV_AUTOSELECT select DVB_S5H1411 if MEDIA_SUBDRV_AUTOSELECT diff --git a/drivers/media/usb/pvrusb2/pvrusb2-context.c b/drivers/media/usb/pvrusb2/pvrusb2-context.c index 14170a5d72b3..73c95ba2328a 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-context.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-context.c @@ -90,8 +90,10 @@ static void pvr2_context_destroy(struct pvr2_context *mp) } -static void pvr2_context_notify(struct pvr2_context *mp) +static void pvr2_context_notify(void *ptr) { + struct pvr2_context *mp = ptr; + pvr2_context_set_notify(mp,!0); } @@ -106,9 +108,7 @@ static void pvr2_context_check(struct pvr2_context *mp) pvr2_trace(PVR2_TRACE_CTXT, "pvr2_context %p (initialize)", mp); /* Finish hardware initialization */ - if (pvr2_hdw_initialize(mp->hdw, - (void (*)(void *))pvr2_context_notify, - mp)) { + if (pvr2_hdw_initialize(mp->hdw, pvr2_context_notify, mp)) { mp->video_stream.stream = pvr2_hdw_get_video_stream(mp->hdw); /* Trigger interface initialization. By doing this @@ -267,8 +267,9 @@ static void pvr2_context_exit(struct pvr2_context *mp) void pvr2_context_disconnect(struct pvr2_context *mp) { pvr2_hdw_disconnect(mp->hdw); + if (!pvr2_context_shutok()) + pvr2_context_notify(mp); mp->disconnect_flag = !0; - pvr2_context_notify(mp); } diff --git a/drivers/media/usb/pvrusb2/pvrusb2-debugifc.c b/drivers/media/usb/pvrusb2/pvrusb2-debugifc.c index 84cfb5ce8b8d..81d711269ab5 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-debugifc.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-debugifc.c @@ -9,11 +9,6 @@ #include "pvrusb2-hdw.h" #include "pvrusb2-debug.h" -struct debugifc_mask_item { - const char *name; - unsigned long msk; -}; - static unsigned int debugifc_count_whitespace(const char *buf, unsigned int count) diff --git a/drivers/media/usb/pvrusb2/pvrusb2-dvb.c b/drivers/media/usb/pvrusb2/pvrusb2-dvb.c index 26811efe0fb5..3610139fb9ad 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-dvb.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-dvb.c @@ -33,9 +33,6 @@ static int pvr2_dvb_feed_func(struct pvr2_dvb_adapter *adap) for (;;) { if (kthread_should_stop()) break; - /* Not sure about this... */ - try_to_freeze(); - bp = pvr2_stream_get_ready_buffer(stream); if (bp != NULL) { count = pvr2_buffer_get_count(bp); @@ -62,8 +59,7 @@ static int pvr2_dvb_feed_func(struct pvr2_dvb_adapter *adap) /* Wait until more buffers become available or we're told not to wait any longer. */ - ret = wait_event_interruptible( - adap->buffer_wait_data, + ret = wait_event_freezable(adap->buffer_wait_data, (pvr2_stream_get_ready_count(stream) > 0) || kthread_should_stop()); if (ret < 0) break; @@ -88,8 +84,10 @@ static int pvr2_dvb_feed_thread(void *data) return stat; } -static void pvr2_dvb_notify(struct pvr2_dvb_adapter *adap) +static void pvr2_dvb_notify(void *ptr) { + struct pvr2_dvb_adapter *adap = ptr; + wake_up(&adap->buffer_wait_data); } @@ -149,7 +147,7 @@ static int pvr2_dvb_stream_do_start(struct pvr2_dvb_adapter *adap) } pvr2_stream_set_callback(pvr->video_stream.stream, - (pvr2_stream_callback) pvr2_dvb_notify, adap); + pvr2_dvb_notify, adap); ret = pvr2_stream_set_buffer_count(stream, PVR2_DVB_BUFFER_COUNT); if (ret < 0) return ret; diff --git a/drivers/media/usb/pvrusb2/pvrusb2-encoder.c b/drivers/media/usb/pvrusb2/pvrusb2-encoder.c index c8102772344b..a5eabac1ec6e 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-encoder.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-encoder.c @@ -257,7 +257,7 @@ rdData[0]); ret = -EBUSY; } if (ret) { - del_timer_sync(&hdw->encoder_run_timer); + timer_delete_sync(&hdw->encoder_run_timer); hdw->state_encoder_ok = 0; pvr2_trace(PVR2_TRACE_STBITS, "State bit %s <-- %s", diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c index 75c89b07e86a..b32bb906a9de 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c @@ -1527,7 +1527,7 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw) /* Encoder is about to be reset so note that as far as we're concerned now, the encoder has never been run. */ - del_timer_sync(&hdw->encoder_run_timer); + timer_delete_sync(&hdw->encoder_run_timer); if (hdw->state_encoder_runok) { hdw->state_encoder_runok = 0; trace_stbit("state_encoder_runok",hdw->state_encoder_runok); @@ -3285,12 +3285,14 @@ int pvr2_hdw_get_cropcap(struct pvr2_hdw *hdw, struct v4l2_cropcap *pp) /* Return information about the tuner */ int pvr2_hdw_get_tuner_status(struct pvr2_hdw *hdw,struct v4l2_tuner *vtp) { - LOCK_TAKE(hdw->big_lock); do { + LOCK_TAKE(hdw->big_lock); + do { if (hdw->tuner_signal_stale) { pvr2_hdw_status_poll(hdw); } memcpy(vtp,&hdw->tuner_signal_info,sizeof(struct v4l2_tuner)); - } while (0); LOCK_GIVE(hdw->big_lock); + } while (0); + LOCK_GIVE(hdw->big_lock); return 0; } @@ -3560,7 +3562,7 @@ struct hdw_timer { static void pvr2_ctl_timeout(struct timer_list *t) { - struct hdw_timer *timer = from_timer(timer, t, timer); + struct hdw_timer *timer = timer_container_of(timer, t, timer); struct pvr2_hdw *hdw = timer->hdw; if (hdw->ctl_write_pend_flag || hdw->ctl_read_pend_flag) { @@ -3620,7 +3622,7 @@ static int pvr2_send_request_ex(struct pvr2_hdw *hdw, pvr2_trace( PVR2_TRACE_ERROR_LEGS, "Attempted to execute %d byte control-read transfer (limit=%d)", - write_len,PVR2_CTL_BUFFSIZE); + read_len, PVR2_CTL_BUFFSIZE); return -EINVAL; } if ((!write_len) && (!read_len)) { @@ -3722,7 +3724,7 @@ status); hdw->cmd_debug_state = 5; /* Stop timer */ - del_timer_sync(&timer.timer); + timer_delete_sync(&timer.timer); hdw->cmd_debug_state = 6; status = 0; @@ -3804,7 +3806,7 @@ status); if ((status < 0) && (!probe_fl)) { pvr2_hdw_render_useless(hdw); } - destroy_timer_on_stack(&timer.timer); + timer_destroy_on_stack(&timer.timer); return status; } @@ -4246,7 +4248,7 @@ static int state_eval_encoder_config(struct pvr2_hdw *hdw) hdw->state_encoder_waitok = 0; trace_stbit("state_encoder_waitok",hdw->state_encoder_waitok); /* paranoia - solve race if timer just completed */ - del_timer_sync(&hdw->encoder_wait_timer); + timer_delete_sync(&hdw->encoder_wait_timer); } else { if (!hdw->state_pathway_ok || (hdw->pathway_state != PVR2_PATHWAY_ANALOG) || @@ -4259,7 +4261,7 @@ static int state_eval_encoder_config(struct pvr2_hdw *hdw) anything has happened that might have disturbed the encoder. This should be a rare case. */ if (timer_pending(&hdw->encoder_wait_timer)) { - del_timer_sync(&hdw->encoder_wait_timer); + timer_delete_sync(&hdw->encoder_wait_timer); } if (hdw->state_encoder_waitok) { /* Must clear the state - therefore we did @@ -4397,7 +4399,7 @@ static int state_eval_encoder_run(struct pvr2_hdw *hdw) if (hdw->state_encoder_run) { if (!state_check_disable_encoder_run(hdw)) return 0; if (hdw->state_encoder_ok) { - del_timer_sync(&hdw->encoder_run_timer); + timer_delete_sync(&hdw->encoder_run_timer); if (pvr2_encoder_stop(hdw) < 0) return !0; } hdw->state_encoder_run = 0; @@ -4419,7 +4421,7 @@ static int state_eval_encoder_run(struct pvr2_hdw *hdw) /* Timeout function for quiescent timer. */ static void pvr2_hdw_quiescent_timeout(struct timer_list *t) { - struct pvr2_hdw *hdw = from_timer(hdw, t, quiescent_timer); + struct pvr2_hdw *hdw = timer_container_of(hdw, t, quiescent_timer); hdw->state_decoder_quiescent = !0; trace_stbit("state_decoder_quiescent",hdw->state_decoder_quiescent); hdw->state_stale = !0; @@ -4430,7 +4432,8 @@ static void pvr2_hdw_quiescent_timeout(struct timer_list *t) /* Timeout function for decoder stabilization timer. */ static void pvr2_hdw_decoder_stabilization_timeout(struct timer_list *t) { - struct pvr2_hdw *hdw = from_timer(hdw, t, decoder_stabilization_timer); + struct pvr2_hdw *hdw = timer_container_of(hdw, t, + decoder_stabilization_timer); hdw->state_decoder_ready = !0; trace_stbit("state_decoder_ready", hdw->state_decoder_ready); hdw->state_stale = !0; @@ -4441,7 +4444,7 @@ static void pvr2_hdw_decoder_stabilization_timeout(struct timer_list *t) /* Timeout function for encoder wait timer. */ static void pvr2_hdw_encoder_wait_timeout(struct timer_list *t) { - struct pvr2_hdw *hdw = from_timer(hdw, t, encoder_wait_timer); + struct pvr2_hdw *hdw = timer_container_of(hdw, t, encoder_wait_timer); hdw->state_encoder_waitok = !0; trace_stbit("state_encoder_waitok",hdw->state_encoder_waitok); hdw->state_stale = !0; @@ -4452,7 +4455,7 @@ static void pvr2_hdw_encoder_wait_timeout(struct timer_list *t) /* Timeout function for encoder run timer. */ static void pvr2_hdw_encoder_run_timeout(struct timer_list *t) { - struct pvr2_hdw *hdw = from_timer(hdw, t, encoder_run_timer); + struct pvr2_hdw *hdw = timer_container_of(hdw, t, encoder_run_timer); if (!hdw->state_encoder_runok) { hdw->state_encoder_runok = !0; trace_stbit("state_encoder_runok",hdw->state_encoder_runok); @@ -4477,11 +4480,11 @@ static int state_eval_decoder_run(struct pvr2_hdw *hdw) hdw->state_decoder_quiescent = 0; hdw->state_decoder_run = 0; /* paranoia - solve race if timer(s) just completed */ - del_timer_sync(&hdw->quiescent_timer); + timer_delete_sync(&hdw->quiescent_timer); /* Kill the stabilization timer, in case we're killing the encoder before the previous stabilization interval has been properly timed. */ - del_timer_sync(&hdw->decoder_stabilization_timer); + timer_delete_sync(&hdw->decoder_stabilization_timer); hdw->state_decoder_ready = 0; } else { if (!hdw->state_decoder_quiescent) { @@ -4515,7 +4518,7 @@ static int state_eval_decoder_run(struct pvr2_hdw *hdw) !hdw->state_pipeline_config || !hdw->state_encoder_config || !hdw->state_encoder_ok) return 0; - del_timer_sync(&hdw->quiescent_timer); + timer_delete_sync(&hdw->quiescent_timer); if (hdw->flag_decoder_missed) return 0; if (pvr2_decoder_enable(hdw,!0) < 0) return 0; hdw->state_decoder_quiescent = 0; diff --git a/drivers/media/usb/pvrusb2/pvrusb2-io.c b/drivers/media/usb/pvrusb2/pvrusb2-io.c index 675dc7153e2b..28ffe7981f8c 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-io.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-io.c @@ -335,8 +335,8 @@ static int pvr2_stream_buffer_count(struct pvr2_stream *sp, unsigned int cnt) if (scnt < sp->buffer_slot_count) { struct pvr2_buffer **nb = NULL; if (scnt) { - nb = kmemdup(sp->buffers, scnt * sizeof(*nb), - GFP_KERNEL); + nb = kmemdup_array(sp->buffers, scnt, sizeof(*nb), + GFP_KERNEL); if (!nb) return -ENOMEM; } kfree(sp->buffers); diff --git a/drivers/media/usb/pvrusb2/pvrusb2-main.c b/drivers/media/usb/pvrusb2/pvrusb2-main.c index ce4d566e4e5a..721dafd2c14b 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-main.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-main.c @@ -16,9 +16,7 @@ #include "pvrusb2-context.h" #include "pvrusb2-debug.h" #include "pvrusb2-v4l2.h" -#ifdef CONFIG_VIDEO_PVRUSB2_SYSFS #include "pvrusb2-sysfs.h" -#endif /* CONFIG_VIDEO_PVRUSB2_SYSFS */ #define DRIVER_AUTHOR "Mike Isely <isely@pobox.com>" #define DRIVER_DESC "Hauppauge WinTV-PVR-USB2 MPEG2 Encoder/Tuner" @@ -36,10 +34,6 @@ int pvrusb2_debug = DEFAULT_DEBUG_MASK; module_param_named(debug,pvrusb2_debug,int,S_IRUGO|S_IWUSR); MODULE_PARM_DESC(debug, "Debug trace mask"); -#ifdef CONFIG_VIDEO_PVRUSB2_SYSFS -static struct pvr2_sysfs_class *class_ptr = NULL; -#endif /* CONFIG_VIDEO_PVRUSB2_SYSFS */ - static void pvr_setup_attach(struct pvr2_context *pvr) { /* Create association with v4l layer */ @@ -48,9 +42,7 @@ static void pvr_setup_attach(struct pvr2_context *pvr) /* Create association with dvb layer */ pvr2_dvb_create(pvr); #endif -#ifdef CONFIG_VIDEO_PVRUSB2_SYSFS - pvr2_sysfs_create(pvr,class_ptr); -#endif /* CONFIG_VIDEO_PVRUSB2_SYSFS */ + pvr2_sysfs_create(pvr); } static int pvr_probe(struct usb_interface *intf, @@ -115,9 +107,7 @@ static int __init pvr_init(void) return ret; } -#ifdef CONFIG_VIDEO_PVRUSB2_SYSFS - class_ptr = pvr2_sysfs_class_create(); -#endif /* CONFIG_VIDEO_PVRUSB2_SYSFS */ + pvr2_sysfs_class_create(); ret = usb_register(&pvr_driver); @@ -141,9 +131,7 @@ static void __exit pvr_exit(void) pvr2_context_global_done(); -#ifdef CONFIG_VIDEO_PVRUSB2_SYSFS - pvr2_sysfs_class_destroy(class_ptr); -#endif /* CONFIG_VIDEO_PVRUSB2_SYSFS */ + pvr2_sysfs_class_destroy(); pvr2_trace(PVR2_TRACE_INIT,"pvr_exit complete"); } diff --git a/drivers/media/usb/pvrusb2/pvrusb2-std.c b/drivers/media/usb/pvrusb2/pvrusb2-std.c index e7ab41401577..81c994e62241 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-std.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-std.c @@ -212,173 +212,6 @@ unsigned int pvr2_std_id_to_str(char *bufPtr, unsigned int bufSize, } -// Template data for possible enumerated video standards. Here we group -// standards which share common frame rates and resolution. -static struct v4l2_standard generic_standards[] = { - { - .id = (TSTD_B|TSTD_B1| - TSTD_D|TSTD_D1| - TSTD_G| - TSTD_H| - TSTD_I| - TSTD_K|TSTD_K1| - TSTD_L| - V4L2_STD_SECAM_LC | - TSTD_N|TSTD_Nc), - .frameperiod = - { - .numerator = 1, - .denominator= 25 - }, - .framelines = 625, - .reserved = {0,0,0,0} - }, { - .id = (TSTD_M| - V4L2_STD_NTSC_M_JP| - V4L2_STD_NTSC_M_KR), - .frameperiod = - { - .numerator = 1001, - .denominator= 30000 - }, - .framelines = 525, - .reserved = {0,0,0,0} - }, { // This is a total wild guess - .id = (TSTD_60), - .frameperiod = - { - .numerator = 1001, - .denominator= 30000 - }, - .framelines = 525, - .reserved = {0,0,0,0} - }, { // This is total wild guess - .id = V4L2_STD_NTSC_443, - .frameperiod = - { - .numerator = 1001, - .denominator= 30000 - }, - .framelines = 525, - .reserved = {0,0,0,0} - } -}; - -static struct v4l2_standard *match_std(v4l2_std_id id) -{ - unsigned int idx; - for (idx = 0; idx < ARRAY_SIZE(generic_standards); idx++) { - if (generic_standards[idx].id & id) { - return generic_standards + idx; - } - } - return NULL; -} - -static int pvr2_std_fill(struct v4l2_standard *std,v4l2_std_id id) -{ - struct v4l2_standard *template; - int idx; - unsigned int bcnt; - template = match_std(id); - if (!template) return 0; - idx = std->index; - memcpy(std,template,sizeof(*template)); - std->index = idx; - std->id = id; - bcnt = pvr2_std_id_to_str(std->name,sizeof(std->name)-1,id); - std->name[bcnt] = 0; - pvr2_trace(PVR2_TRACE_STD,"Set up standard idx=%u name=%s", - std->index,std->name); - return !0; -} - -/* These are special cases of combined standards that we should enumerate - separately if the component pieces are present. */ -static v4l2_std_id std_mixes[] = { - V4L2_STD_PAL_B | V4L2_STD_PAL_G, - V4L2_STD_PAL_D | V4L2_STD_PAL_K, - V4L2_STD_SECAM_B | V4L2_STD_SECAM_G, - V4L2_STD_SECAM_D | V4L2_STD_SECAM_K, -}; - -struct v4l2_standard *pvr2_std_create_enum(unsigned int *countptr, - v4l2_std_id id) -{ - unsigned int std_cnt = 0; - unsigned int idx,bcnt,idx2; - v4l2_std_id idmsk,cmsk,fmsk; - struct v4l2_standard *stddefs; - - if (pvrusb2_debug & PVR2_TRACE_STD) { - char buf[100]; - bcnt = pvr2_std_id_to_str(buf,sizeof(buf),id); - pvr2_trace( - PVR2_TRACE_STD,"Mapping standards mask=0x%x (%.*s)", - (int)id,bcnt,buf); - } - - *countptr = 0; - std_cnt = 0; - fmsk = 0; - for (idmsk = 1, cmsk = id; cmsk; idmsk <<= 1) { - if (!(idmsk & cmsk)) continue; - cmsk &= ~idmsk; - if (match_std(idmsk)) { - std_cnt++; - continue; - } - fmsk |= idmsk; - } - - for (idx2 = 0; idx2 < ARRAY_SIZE(std_mixes); idx2++) { - if ((id & std_mixes[idx2]) == std_mixes[idx2]) std_cnt++; - } - - /* Don't complain about ATSC standard values */ - fmsk &= ~CSTD_ATSC; - - if (fmsk) { - char buf[100]; - bcnt = pvr2_std_id_to_str(buf,sizeof(buf),fmsk); - pvr2_trace( - PVR2_TRACE_ERROR_LEGS, - "***WARNING*** Failed to classify the following standard(s): %.*s", - bcnt,buf); - } - - pvr2_trace(PVR2_TRACE_STD,"Setting up %u unique standard(s)", - std_cnt); - if (!std_cnt) return NULL; // paranoia - - stddefs = kcalloc(std_cnt, sizeof(struct v4l2_standard), - GFP_KERNEL); - if (!stddefs) - return NULL; - - for (idx = 0; idx < std_cnt; idx++) - stddefs[idx].index = idx; - - idx = 0; - - /* Enumerate potential special cases */ - for (idx2 = 0; (idx2 < ARRAY_SIZE(std_mixes)) && (idx < std_cnt); - idx2++) { - if (!(id & std_mixes[idx2])) continue; - if (pvr2_std_fill(stddefs+idx,std_mixes[idx2])) idx++; - } - /* Now enumerate individual pieces */ - for (idmsk = 1, cmsk = id; cmsk && (idx < std_cnt); idmsk <<= 1) { - if (!(idmsk & cmsk)) continue; - cmsk &= ~idmsk; - if (!pvr2_std_fill(stddefs+idx,idmsk)) continue; - idx++; - } - - *countptr = std_cnt; - return stddefs; -} - v4l2_std_id pvr2_std_get_usable(void) { return CSTD_ALL; diff --git a/drivers/media/usb/pvrusb2/pvrusb2-std.h b/drivers/media/usb/pvrusb2/pvrusb2-std.h index d8b4c6dc72fe..74b05ecb9708 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-std.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-std.h @@ -23,12 +23,6 @@ int pvr2_std_str_to_id(v4l2_std_id *idPtr,const char *bufPtr, unsigned int pvr2_std_id_to_str(char *bufPtr, unsigned int bufSize, v4l2_std_id id); -// Create an array of suitable v4l2_standard structures given a bit mask of -// video standards to support. The array is allocated from the heap, and -// the number of elements is returned in the first argument. -struct v4l2_standard *pvr2_std_create_enum(unsigned int *countptr, - v4l2_std_id id); - // Return mask of which video standard bits are valid v4l2_std_id pvr2_std_get_usable(void); diff --git a/drivers/media/usb/pvrusb2/pvrusb2-sysfs.c b/drivers/media/usb/pvrusb2/pvrusb2-sysfs.c index 3e42e209be37..3077399901aa 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-sysfs.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-sysfs.c @@ -66,10 +66,6 @@ struct pvr2_sysfs_ctl_item { char name[80]; }; -struct pvr2_sysfs_class { - struct class class; -}; - static ssize_t show_name(struct device *class_dev, struct device_attribute *attr, char *buf) @@ -81,7 +77,7 @@ static ssize_t show_name(struct device *class_dev, pvr2_sysfs_trace("pvr2_sysfs(%p) show_name(cid=%d) is %s", cip->chptr, cip->ctl_id, name); if (!name) return -EINVAL; - return scnprintf(buf, PAGE_SIZE, "%s\n", name); + return sysfs_emit(buf, "%s\n", name); } static ssize_t show_type(struct device *class_dev, @@ -102,7 +98,7 @@ static ssize_t show_type(struct device *class_dev, } pvr2_sysfs_trace("pvr2_sysfs(%p) show_type(cid=%d) is %s", cip->chptr, cip->ctl_id, name); - return scnprintf(buf, PAGE_SIZE, "%s\n", name); + return sysfs_emit(buf, "%s\n", name); } static ssize_t show_min(struct device *class_dev, @@ -115,7 +111,7 @@ static ssize_t show_min(struct device *class_dev, val = pvr2_ctrl_get_min(cip->cptr); pvr2_sysfs_trace("pvr2_sysfs(%p) show_min(cid=%d) is %ld", cip->chptr, cip->ctl_id, val); - return scnprintf(buf, PAGE_SIZE, "%ld\n", val); + return sysfs_emit(buf, "%ld\n", val); } static ssize_t show_max(struct device *class_dev, @@ -128,7 +124,7 @@ static ssize_t show_max(struct device *class_dev, val = pvr2_ctrl_get_max(cip->cptr); pvr2_sysfs_trace("pvr2_sysfs(%p) show_max(cid=%d) is %ld", cip->chptr, cip->ctl_id, val); - return scnprintf(buf, PAGE_SIZE, "%ld\n", val); + return sysfs_emit(buf, "%ld\n", val); } static ssize_t show_def(struct device *class_dev, @@ -487,15 +483,6 @@ static void pvr2_sysfs_tear_down_controls(struct pvr2_sysfs *sfp) } -static void pvr2_sysfs_class_release(struct class *class) -{ - struct pvr2_sysfs_class *clp; - clp = container_of(class,struct pvr2_sysfs_class,class); - pvr2_sysfs_trace("Destroying pvr2_sysfs_class id=%p",clp); - kfree(clp); -} - - static void pvr2_sysfs_release(struct device *class_dev) { pvr2_sysfs_trace("Releasing class_dev id=%p",class_dev); @@ -503,6 +490,12 @@ static void pvr2_sysfs_release(struct device *class_dev) } +static struct class pvr2_class = { + .name = "pvrusb2", + .dev_release = pvr2_sysfs_release, +}; + + static void class_dev_destroy(struct pvr2_sysfs *sfp) { struct device *dev; @@ -551,7 +544,7 @@ static ssize_t v4l_minor_number_show(struct device *class_dev, struct pvr2_sysfs *sfp; sfp = dev_get_drvdata(class_dev); if (!sfp) return -EINVAL; - return scnprintf(buf,PAGE_SIZE,"%d\n", + return sysfs_emit(buf, "%d\n", pvr2_hdw_v4l_get_minor_number(sfp->channel.hdw, pvr2_v4l_type_video)); } @@ -563,7 +556,7 @@ static ssize_t bus_info_show(struct device *class_dev, struct pvr2_sysfs *sfp; sfp = dev_get_drvdata(class_dev); if (!sfp) return -EINVAL; - return scnprintf(buf,PAGE_SIZE,"%s\n", + return sysfs_emit(buf, "%s\n", pvr2_hdw_get_bus_info(sfp->channel.hdw)); } @@ -574,7 +567,7 @@ static ssize_t hdw_name_show(struct device *class_dev, struct pvr2_sysfs *sfp; sfp = dev_get_drvdata(class_dev); if (!sfp) return -EINVAL; - return scnprintf(buf,PAGE_SIZE,"%s\n", + return sysfs_emit(buf, "%s\n", pvr2_hdw_get_type(sfp->channel.hdw)); } @@ -585,7 +578,7 @@ static ssize_t hdw_desc_show(struct device *class_dev, struct pvr2_sysfs *sfp; sfp = dev_get_drvdata(class_dev); if (!sfp) return -EINVAL; - return scnprintf(buf,PAGE_SIZE,"%s\n", + return sysfs_emit(buf, "%s\n", pvr2_hdw_get_desc(sfp->channel.hdw)); } @@ -597,7 +590,7 @@ static ssize_t v4l_radio_minor_number_show(struct device *class_dev, struct pvr2_sysfs *sfp; sfp = dev_get_drvdata(class_dev); if (!sfp) return -EINVAL; - return scnprintf(buf,PAGE_SIZE,"%d\n", + return sysfs_emit(buf, "%d\n", pvr2_hdw_v4l_get_minor_number(sfp->channel.hdw, pvr2_v4l_type_radio)); } @@ -609,13 +602,12 @@ static ssize_t unit_number_show(struct device *class_dev, struct pvr2_sysfs *sfp; sfp = dev_get_drvdata(class_dev); if (!sfp) return -EINVAL; - return scnprintf(buf,PAGE_SIZE,"%d\n", + return sysfs_emit(buf, "%d\n", pvr2_hdw_get_unit_number(sfp->channel.hdw)); } -static void class_dev_create(struct pvr2_sysfs *sfp, - struct pvr2_sysfs_class *class_ptr) +static void class_dev_create(struct pvr2_sysfs *sfp) { struct usb_device *usb_dev; struct device *class_dev; @@ -628,7 +620,7 @@ static void class_dev_create(struct pvr2_sysfs *sfp, pvr2_sysfs_trace("Creating class_dev id=%p",class_dev); - class_dev->class = &class_ptr->class; + class_dev->class = &pvr2_class; dev_set_name(class_dev, "%s", pvr2_hdw_get_device_identifier(sfp->channel.hdw)); @@ -753,47 +745,30 @@ static void pvr2_sysfs_internal_check(struct pvr2_channel *chp) } -struct pvr2_sysfs *pvr2_sysfs_create(struct pvr2_context *mp, - struct pvr2_sysfs_class *class_ptr) +void pvr2_sysfs_create(struct pvr2_context *mp) { struct pvr2_sysfs *sfp; sfp = kzalloc(sizeof(*sfp),GFP_KERNEL); - if (!sfp) return sfp; + if (!sfp) + return; pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr2_sysfs id=%p",sfp); pvr2_channel_init(&sfp->channel,mp); sfp->channel.check_func = pvr2_sysfs_internal_check; - class_dev_create(sfp,class_ptr); - return sfp; + class_dev_create(sfp); } - -struct pvr2_sysfs_class *pvr2_sysfs_class_create(void) +void pvr2_sysfs_class_create(void) { - struct pvr2_sysfs_class *clp; - clp = kzalloc(sizeof(*clp),GFP_KERNEL); - if (!clp) return clp; - pvr2_sysfs_trace("Creating and registering pvr2_sysfs_class id=%p", - clp); - clp->class.name = "pvrusb2"; - clp->class.class_release = pvr2_sysfs_class_release; - clp->class.dev_release = pvr2_sysfs_release; - if (class_register(&clp->class)) { - pvr2_sysfs_trace( - "Registration failed for pvr2_sysfs_class id=%p",clp); - kfree(clp); - clp = NULL; - } - return clp; + if (class_register(&pvr2_class)) + pvr2_sysfs_trace("Registration failed for pvr2_sysfs_class"); } -void pvr2_sysfs_class_destroy(struct pvr2_sysfs_class *clp) +void pvr2_sysfs_class_destroy(void) { - pvr2_sysfs_trace("Unregistering pvr2_sysfs_class id=%p", clp); - if (clp) - class_unregister(&clp->class); + class_unregister(&pvr2_class); } diff --git a/drivers/media/usb/pvrusb2/pvrusb2-sysfs.h b/drivers/media/usb/pvrusb2/pvrusb2-sysfs.h index ac580ff39b5f..375a5372e95c 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-sysfs.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-sysfs.h @@ -10,13 +10,15 @@ #include <linux/sysfs.h> #include "pvrusb2-context.h" -struct pvr2_sysfs; -struct pvr2_sysfs_class; +#ifdef CONFIG_VIDEO_PVRUSB2_SYSFS +void pvr2_sysfs_class_create(void); +void pvr2_sysfs_class_destroy(void); +void pvr2_sysfs_create(struct pvr2_context *mp); +#else +static inline void pvr2_sysfs_class_create(void) { } +static inline void pvr2_sysfs_class_destroy(void) { } +static inline void pvr2_sysfs_create(struct pvr2_context *mp) { } +#endif -struct pvr2_sysfs_class *pvr2_sysfs_class_create(void); -void pvr2_sysfs_class_destroy(struct pvr2_sysfs_class *); - -struct pvr2_sysfs *pvr2_sysfs_create(struct pvr2_context *, - struct pvr2_sysfs_class *); #endif /* __PVRUSB2_SYSFS_H */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c index c04ab7258d64..f9535a484738 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c @@ -21,8 +21,6 @@ #include <media/v4l2-common.h> #include <media/v4l2-ioctl.h> -struct pvr2_v4l2_dev; -struct pvr2_v4l2_fh; struct pvr2_v4l2; struct pvr2_v4l2_dev { @@ -48,6 +46,11 @@ struct pvr2_v4l2_fh { unsigned int input_cnt; }; +static inline struct pvr2_v4l2_fh *to_pvr2_v4l2_fh(struct file *filp) +{ + return container_of(file_to_v4l2_fh(filp), struct pvr2_v4l2_fh, fh); +} + struct pvr2_v4l2 { struct pvr2_channel channel; @@ -108,7 +111,7 @@ static struct v4l2_format pvr_format [] = { */ static int pvr2_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; strscpy(cap->driver, "pvrusb2", sizeof(cap->driver)); @@ -123,7 +126,7 @@ static int pvr2_querycap(struct file *file, void *priv, struct v4l2_capability * static int pvr2_g_std(struct file *file, void *priv, v4l2_std_id *std) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; int val = 0; int ret; @@ -136,7 +139,7 @@ static int pvr2_g_std(struct file *file, void *priv, v4l2_std_id *std) static int pvr2_s_std(struct file *file, void *priv, v4l2_std_id std) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; int ret; @@ -148,7 +151,7 @@ static int pvr2_s_std(struct file *file, void *priv, v4l2_std_id std) static int pvr2_querystd(struct file *file, void *priv, v4l2_std_id *std) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; int val = 0; int ret; @@ -161,7 +164,7 @@ static int pvr2_querystd(struct file *file, void *priv, v4l2_std_id *std) static int pvr2_enum_input(struct file *file, void *priv, struct v4l2_input *vi) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; struct pvr2_ctrl *cptr; struct v4l2_input tmp; @@ -209,7 +212,7 @@ static int pvr2_enum_input(struct file *file, void *priv, struct v4l2_input *vi) static int pvr2_g_input(struct file *file, void *priv, unsigned int *i) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; unsigned int idx; struct pvr2_ctrl *cptr; @@ -231,7 +234,7 @@ static int pvr2_g_input(struct file *file, void *priv, unsigned int *i) static int pvr2_s_input(struct file *file, void *priv, unsigned int inp) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; int ret; @@ -286,7 +289,7 @@ static int pvr2_s_audio(struct file *file, void *priv, const struct v4l2_audio * static int pvr2_g_tuner(struct file *file, void *priv, struct v4l2_tuner *vt) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; if (vt->index != 0) @@ -298,7 +301,7 @@ static int pvr2_g_tuner(struct file *file, void *priv, struct v4l2_tuner *vt) static int pvr2_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *vt) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; int ret; @@ -314,7 +317,7 @@ static int pvr2_s_tuner(struct file *file, void *priv, const struct v4l2_tuner * static int pvr2_s_frequency(struct file *file, void *priv, const struct v4l2_frequency *vf) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; unsigned long fv; struct v4l2_tuner vt; @@ -349,7 +352,7 @@ static int pvr2_s_frequency(struct file *file, void *priv, const struct v4l2_fre static int pvr2_g_frequency(struct file *file, void *priv, struct v4l2_frequency *vf) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; int val = 0; int cur_input; @@ -391,7 +394,7 @@ static int pvr2_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtd static int pvr2_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *vf) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; int val; @@ -411,7 +414,7 @@ static int pvr2_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format static int pvr2_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *vf) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; int lmin, lmax, ldef; struct pvr2_ctrl *hcp, *vcp; @@ -449,7 +452,7 @@ static int pvr2_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_forma static int pvr2_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *vf) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; struct pvr2_ctrl *hcp, *vcp; int ret = pvr2_try_fmt_vid_cap(file, fh, vf); @@ -466,7 +469,7 @@ static int pvr2_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format static int pvr2_streamon(struct file *file, void *priv, enum v4l2_buf_type i) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; struct pvr2_v4l2_dev *pdi = fh->pdi; int ret; @@ -485,7 +488,7 @@ static int pvr2_streamon(struct file *file, void *priv, enum v4l2_buf_type i) static int pvr2_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; if (!fh->pdi->stream) { @@ -497,10 +500,10 @@ static int pvr2_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) return pvr2_hdw_set_streaming(hdw, 0); } -static int pvr2_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *vc) +static int pvr2_query_ext_ctrl(struct file *file, void *priv, + struct v4l2_query_ext_ctrl *vc) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; struct pvr2_ctrl *cptr; int val; @@ -521,13 +524,16 @@ static int pvr2_queryctrl(struct file *file, void *priv, } pvr2_trace(PVR2_TRACE_V4LIOCTL, - "QUERYCTRL id=0x%x mapping name=%s (%s)", + "QUERYEXTCTRL id=0x%x mapping name=%s (%s)", vc->id, pvr2_ctrl_get_name(cptr), pvr2_ctrl_get_desc(cptr)); strscpy(vc->name, pvr2_ctrl_get_desc(cptr), sizeof(vc->name)); vc->flags = pvr2_ctrl_get_v4lflags(cptr); pvr2_ctrl_get_def(cptr, &val); vc->default_value = val; + vc->nr_of_dims = 0; + vc->elems = 1; + vc->elem_size = 4; switch (pvr2_ctrl_get_type(cptr)) { case pvr2_ctl_enum: vc->type = V4L2_CTRL_TYPE_MENU; @@ -549,7 +555,7 @@ static int pvr2_queryctrl(struct file *file, void *priv, break; default: pvr2_trace(PVR2_TRACE_V4LIOCTL, - "QUERYCTRL id=0x%x name=%s not mappable", + "QUERYEXTCTRL id=0x%x name=%s not mappable", vc->id, pvr2_ctrl_get_name(cptr)); return -EINVAL; } @@ -558,7 +564,7 @@ static int pvr2_queryctrl(struct file *file, void *priv, static int pvr2_querymenu(struct file *file, void *priv, struct v4l2_querymenu *vm) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; unsigned int cnt = 0; int ret; @@ -571,35 +577,10 @@ static int pvr2_querymenu(struct file *file, void *priv, struct v4l2_querymenu * return ret; } -static int pvr2_g_ctrl(struct file *file, void *priv, struct v4l2_control *vc) -{ - struct pvr2_v4l2_fh *fh = file->private_data; - struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; - int val = 0; - int ret; - - ret = pvr2_ctrl_get_value(pvr2_hdw_get_ctrl_v4l(hdw, vc->id), - &val); - vc->value = val; - return ret; -} - -static int pvr2_s_ctrl(struct file *file, void *priv, struct v4l2_control *vc) -{ - struct pvr2_v4l2_fh *fh = file->private_data; - struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; - int ret; - - ret = pvr2_ctrl_set_value(pvr2_hdw_get_ctrl_v4l(hdw, vc->id), - vc->value); - pvr2_hdw_commit_ctl(hdw); - return ret; -} - static int pvr2_g_ext_ctrls(struct file *file, void *priv, struct v4l2_ext_controls *ctls) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; struct v4l2_ext_control *ctrl; struct pvr2_ctrl *cptr; @@ -634,7 +615,7 @@ static int pvr2_g_ext_ctrls(struct file *file, void *priv, static int pvr2_s_ext_ctrls(struct file *file, void *priv, struct v4l2_ext_controls *ctls) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; struct v4l2_ext_control *ctrl; unsigned int idx; @@ -659,7 +640,7 @@ commit: static int pvr2_try_ext_ctrls(struct file *file, void *priv, struct v4l2_ext_controls *ctls) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; struct v4l2_ext_control *ctrl; struct pvr2_ctrl *pctl; @@ -681,7 +662,7 @@ static int pvr2_try_ext_ctrls(struct file *file, void *priv, static int pvr2_g_pixelaspect(struct file *file, void *priv, int type, struct v4l2_fract *f) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; struct v4l2_cropcap cap = { .type = type }; int ret; @@ -697,7 +678,7 @@ static int pvr2_g_pixelaspect(struct file *file, void *priv, static int pvr2_g_selection(struct file *file, void *priv, struct v4l2_selection *sel) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; struct v4l2_cropcap cap; int val = 0; @@ -748,7 +729,7 @@ static int pvr2_g_selection(struct file *file, void *priv, static int pvr2_s_selection(struct file *file, void *priv, struct v4l2_selection *sel) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; int ret; @@ -780,7 +761,7 @@ commit: static int pvr2_log_status(struct file *file, void *priv) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; pvr2_hdw_trigger_module_log(hdw); @@ -812,10 +793,8 @@ static const struct v4l2_ioctl_ops pvr2_ioctl_ops = { .vidioc_try_fmt_vid_cap = pvr2_try_fmt_vid_cap, .vidioc_streamon = pvr2_streamon, .vidioc_streamoff = pvr2_streamoff, - .vidioc_queryctrl = pvr2_queryctrl, + .vidioc_query_ext_ctrl = pvr2_query_ext_ctrl, .vidioc_querymenu = pvr2_querymenu, - .vidioc_g_ctrl = pvr2_g_ctrl, - .vidioc_s_ctrl = pvr2_s_ctrl, .vidioc_g_ext_ctrls = pvr2_g_ext_ctrls, .vidioc_s_ext_ctrls = pvr2_s_ext_ctrls, .vidioc_try_ext_ctrls = pvr2_try_ext_ctrls, @@ -906,7 +885,7 @@ static void pvr2_v4l2_internal_check(struct pvr2_channel *chp) static int pvr2_v4l2_release(struct file *file) { - struct pvr2_v4l2_fh *fhp = file->private_data; + struct pvr2_v4l2_fh *fhp = to_pvr2_v4l2_fh(file); struct pvr2_v4l2 *vp = fhp->pdi->v4lp; struct pvr2_hdw *hdw = fhp->channel.mc_head->hdw; @@ -921,9 +900,8 @@ static int pvr2_v4l2_release(struct file *file) fhp->rhp = NULL; } - v4l2_fh_del(&fhp->fh); + v4l2_fh_del(&fhp->fh, file); v4l2_fh_exit(&fhp->fh); - file->private_data = NULL; pvr2_channel_done(&fhp->channel); pvr2_trace(PVR2_TRACE_STRUCT, @@ -1024,17 +1002,18 @@ static int pvr2_v4l2_open(struct file *file) } fhp->file = file; - file->private_data = fhp; fhp->fw_mode_flag = pvr2_hdw_cpufw_get_enabled(hdw); - v4l2_fh_add(&fhp->fh); + v4l2_fh_add(&fhp->fh, file); return 0; } -static void pvr2_v4l2_notify(struct pvr2_v4l2_fh *fhp) +static void pvr2_v4l2_notify(void *ptr) { + struct pvr2_v4l2_fh *fhp = ptr; + wake_up(&fhp->wait_data); } @@ -1067,7 +1046,7 @@ static int pvr2_v4l2_iosetup(struct pvr2_v4l2_fh *fh) hdw = fh->channel.mc_head->hdw; sp = fh->pdi->stream->stream; - pvr2_stream_set_callback(sp,(pvr2_stream_callback)pvr2_v4l2_notify,fh); + pvr2_stream_set_callback(sp, pvr2_v4l2_notify, fh); pvr2_hdw_set_stream_type(hdw,fh->pdi->config); if ((ret = pvr2_hdw_set_streaming(hdw,!0)) < 0) return ret; return pvr2_ioread_set_enabled(fh->rhp,!0); @@ -1077,7 +1056,7 @@ static int pvr2_v4l2_iosetup(struct pvr2_v4l2_fh *fh) static ssize_t pvr2_v4l2_read(struct file *file, char __user *buff, size_t count, loff_t *ppos) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); int ret; if (fh->fw_mode_flag) { @@ -1139,7 +1118,7 @@ static ssize_t pvr2_v4l2_read(struct file *file, static __poll_t pvr2_v4l2_poll(struct file *file, poll_table *wait) { __poll_t mask = 0; - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); int ret; if (fh->fw_mode_flag) { @@ -1198,11 +1177,6 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip, dip->minor_type = pvr2_v4l_type_video; nr_ptr = video_nr; caps |= V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_AUDIO; - if (!dip->stream) { - pr_err(KBUILD_MODNAME - ": Failed to set up pvrusb2 v4l video dev due to missing stream instance\n"); - return; - } break; case VFL_TYPE_VBI: dip->config = pvr2_config_vbi; diff --git a/drivers/media/usb/pwc/pwc-if.c b/drivers/media/usb/pwc/pwc-if.c index e342199711d3..c6e5d031f068 100644 --- a/drivers/media/usb/pwc/pwc-if.c +++ b/drivers/media/usb/pwc/pwc-if.c @@ -56,7 +56,6 @@ #endif #include <linux/vmalloc.h> #include <asm/io.h> -#include <linux/kernel.h> /* simple_strtol() */ #include "pwc.h" #include "pwc-kiara.h" @@ -760,8 +759,6 @@ static const struct vb2_ops pwc_vb_queue_ops = { .buf_queue = buffer_queue, .start_streaming = start_streaming, .stop_streaming = stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; /***************************************************************************/ @@ -1054,6 +1051,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id pdev->vb_queue.ops = &pwc_vb_queue_ops; pdev->vb_queue.mem_ops = &vb2_vmalloc_memops; pdev->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + pdev->vb_queue.lock = &pdev->vb_queue_lock; rc = vb2_queue_init(&pdev->vb_queue); if (rc < 0) { PWC_ERROR("Oops, could not initialize vb2 queue.\n"); @@ -1064,7 +1062,6 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id pdev->vdev = pwc_template; strscpy(pdev->vdev.name, name, sizeof(pdev->vdev.name)); pdev->vdev.queue = &pdev->vb_queue; - pdev->vdev.queue->lock = &pdev->vb_queue_lock; video_set_drvdata(&pdev->vdev, pdev); pdev->release = le16_to_cpu(udev->descriptor.bcdDevice); diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c index 3c2627712fe9..8332f2c5aed7 100644 --- a/drivers/media/usb/s2255/s2255drv.c +++ b/drivers/media/usb/s2255/s2255drv.c @@ -247,7 +247,7 @@ struct s2255_vc { struct s2255_dev { struct s2255_vc vc[MAX_CHANNELS]; struct v4l2_device v4l2_dev; - atomic_t num_channels; + refcount_t num_channels; int frames; struct mutex lock; /* channels[].vdev.lock */ struct mutex cmdlock; /* protects cmdbuf */ @@ -471,7 +471,7 @@ static void s2255_reset_dsppower(struct s2255_dev *dev) */ static void s2255_timer(struct timer_list *t) { - struct s2255_dev *dev = from_timer(dev, t, timer); + struct s2255_dev *dev = timer_container_of(dev, t, timer); struct s2255_fw *data = dev->fw_data; if (usb_submit_urb(data->fw_urb, GFP_ATOMIC) < 0) { pr_err("s2255: can't submit urb\n"); @@ -704,8 +704,6 @@ static const struct vb2_ops s2255_video_qops = { .buf_queue = buffer_queue, .start_streaming = start_streaming, .stop_streaming = stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int vidioc_querycap(struct file *file, void *priv, @@ -1550,11 +1548,11 @@ static void s2255_video_device_release(struct video_device *vdev) container_of(vdev, struct s2255_vc, vdev); dprintk(dev, 4, "%s, chnls: %d\n", __func__, - atomic_read(&dev->num_channels)); + refcount_read(&dev->num_channels)); v4l2_ctrl_handler_free(&vc->hdl); - if (atomic_dec_and_test(&dev->num_channels)) + if (refcount_dec_and_test(&dev->num_channels)) s2255_destroy(dev); return; } @@ -1659,7 +1657,7 @@ static int s2255_probe_v4l(struct s2255_dev *dev) "failed to register video device!\n"); break; } - atomic_inc(&dev->num_channels); + refcount_inc(&dev->num_channels); v4l2_info(&dev->v4l2_dev, "V4L2 device registered as %s\n", video_device_node_name(&vc->vdev)); @@ -1667,11 +1665,11 @@ static int s2255_probe_v4l(struct s2255_dev *dev) pr_info("Sensoray 2255 V4L driver Revision: %s\n", S2255_VERSION); /* if no channels registered, return error and probe will fail*/ - if (atomic_read(&dev->num_channels) == 0) { + if (refcount_read(&dev->num_channels) == 0) { v4l2_device_unregister(&dev->v4l2_dev); return ret; } - if (atomic_read(&dev->num_channels) != MAX_CHANNELS) + if (refcount_read(&dev->num_channels) != MAX_CHANNELS) pr_warn("s2255: Not all channels available.\n"); return 0; } @@ -1906,9 +1904,10 @@ static int s2255_get_fx2fw(struct s2255_dev *dev) { int fw; int ret; - unsigned char transBuffer[64]; - ret = s2255_vendor_req(dev, S2255_VR_FW, 0, 0, transBuffer, 2, - S2255_VR_IN); + u8 transBuffer[2] = {}; + + ret = s2255_vendor_req(dev, S2255_VR_FW, 0, 0, transBuffer, + sizeof(transBuffer), S2255_VR_IN); if (ret < 0) dprintk(dev, 2, "get fw error: %x\n", ret); fw = transBuffer[0] + (transBuffer[1] << 8); @@ -2220,7 +2219,7 @@ static int s2255_probe(struct usb_interface *interface, goto errorFWDATA1; } - atomic_set(&dev->num_channels, 0); + refcount_set(&dev->num_channels, 0); dev->pid = id->idProduct; dev->fw_data = kzalloc(sizeof(struct s2255_fw), GFP_KERNEL); if (!dev->fw_data) @@ -2340,12 +2339,12 @@ static void s2255_disconnect(struct usb_interface *interface) { struct s2255_dev *dev = to_s2255_dev(usb_get_intfdata(interface)); int i; - int channels = atomic_read(&dev->num_channels); + int channels = refcount_read(&dev->num_channels); mutex_lock(&dev->lock); v4l2_device_disconnect(&dev->v4l2_dev); mutex_unlock(&dev->lock); /*see comments in the uvc_driver.c usb disconnect function */ - atomic_inc(&dev->num_channels); + refcount_inc(&dev->num_channels); /* unregister each video device. */ for (i = 0; i < channels; i++) video_unregister_device(&dev->vc[i].vdev); @@ -2358,7 +2357,7 @@ static void s2255_disconnect(struct usb_interface *interface) dev->vc[i].vidstatus_ready = 1; wake_up(&dev->vc[i].wait_vidstatus); } - if (atomic_dec_and_test(&dev->num_channels)) + if (refcount_dec_and_test(&dev->num_channels)) s2255_destroy(dev); dev_info(&interface->dev, "%s\n", __func__); } diff --git a/drivers/media/usb/siano/smsusb.c b/drivers/media/usb/siano/smsusb.c index fe9c7b3a950e..2c8179a84991 100644 --- a/drivers/media/usb/siano/smsusb.c +++ b/drivers/media/usb/siano/smsusb.c @@ -40,7 +40,7 @@ struct smsusb_urb_t { struct smscore_buffer_t *cb; struct smsusb_device_t *dev; - struct urb urb; + struct urb *urb; /* For the bottom half */ struct work_struct wq; @@ -160,7 +160,7 @@ static int smsusb_submit_urb(struct smsusb_device_t *dev, } usb_fill_bulk_urb( - &surb->urb, + surb->urb, dev->udev, usb_rcvbulkpipe(dev->udev, dev->in_ep), surb->cb->p, @@ -168,9 +168,9 @@ static int smsusb_submit_urb(struct smsusb_device_t *dev, smsusb_onresponse, surb ); - surb->urb.transfer_flags |= URB_FREE_BUFFER; + surb->urb->transfer_flags |= URB_FREE_BUFFER; - return usb_submit_urb(&surb->urb, GFP_ATOMIC); + return usb_submit_urb(surb->urb, GFP_ATOMIC); } static void smsusb_stop_streaming(struct smsusb_device_t *dev) @@ -178,7 +178,9 @@ static void smsusb_stop_streaming(struct smsusb_device_t *dev) int i; for (i = 0; i < MAX_URBS; i++) { - usb_kill_urb(&dev->surbs[i].urb); + usb_kill_urb(dev->surbs[i].urb); + if (dev->surbs[i].wq.func) + cancel_work_sync(&dev->surbs[i].wq); if (dev->surbs[i].cb) { smscore_putbuffer(dev->coredev, dev->surbs[i].cb); @@ -277,10 +279,8 @@ static int smsusb1_load_firmware(struct usb_device *udev, int id, int board_id) } } - fw_buffer = kmalloc(fw->size, GFP_KERNEL); + fw_buffer = kmemdup(fw->data, fw->size, GFP_KERNEL); if (fw_buffer) { - memcpy(fw_buffer, fw->data, fw->size); - rc = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 2), fw_buffer, fw->size, &dummy, 1000); @@ -338,6 +338,8 @@ static void smsusb_term_device(struct usb_interface *intf) struct smsusb_device_t *dev = usb_get_intfdata(intf); if (dev) { + int i; + dev->state = SMSUSB_DISCONNECTED; smsusb_stop_streaming(dev); @@ -346,6 +348,9 @@ static void smsusb_term_device(struct usb_interface *intf) if (dev->coredev) smscore_unregister_device(dev->coredev); + for (i = 0; i < MAX_URBS; i++) + usb_free_urb(dev->surbs[i].urb); + pr_debug("device 0x%p destroyed\n", dev); kfree(dev); } @@ -453,12 +458,7 @@ static int smsusb_init_device(struct usb_interface *intf, int board_id) rc = smscore_register_device(¶ms, &dev->coredev, 0, mdev); if (rc < 0) { pr_err("smscore_register_device(...) failed, rc %d\n", rc); - smsusb_term_device(intf); -#ifdef CONFIG_MEDIA_CONTROLLER_DVB - media_device_unregister(mdev); -#endif - kfree(mdev); - return rc; + goto err_unregister_device; } smscore_set_board_id(dev->coredev, board_id); @@ -468,15 +468,16 @@ static int smsusb_init_device(struct usb_interface *intf, int board_id) /* initialize urbs */ for (i = 0; i < MAX_URBS; i++) { dev->surbs[i].dev = dev; - usb_init_urb(&dev->surbs[i].urb); + dev->surbs[i].urb = usb_alloc_urb(0, GFP_KERNEL); + if (!dev->surbs[i].urb) + goto err_unregister_device; } pr_debug("smsusb_start_streaming(...).\n"); rc = smsusb_start_streaming(dev); if (rc < 0) { pr_err("smsusb_start_streaming(...) failed\n"); - smsusb_term_device(intf); - return rc; + goto err_unregister_device; } dev->state = SMSUSB_ACTIVE; @@ -484,13 +485,21 @@ static int smsusb_init_device(struct usb_interface *intf, int board_id) rc = smscore_start_device(dev->coredev); if (rc < 0) { pr_err("smscore_start_device(...) failed\n"); - smsusb_term_device(intf); - return rc; + goto err_unregister_device; } pr_debug("device 0x%p created\n", dev); return rc; + +err_unregister_device: + /* smsusb_term_device() frees any allocated urb. */ + smsusb_term_device(intf); +#ifdef CONFIG_MEDIA_CONTROLLER_DVB + media_device_unregister(mdev); +#endif + kfree(mdev); + return rc; } static int smsusb_probe(struct usb_interface *intf, @@ -723,5 +732,5 @@ static struct usb_driver smsusb_driver = { module_usb_driver(smsusb_driver); MODULE_DESCRIPTION("Driver for the Siano SMS1xxx USB dongle"); -MODULE_AUTHOR("Siano Mobile Silicon, INC. (uris@siano-ms.com)"); +MODULE_AUTHOR("Siano Mobile Silicon, Inc. <uris@siano-ms.com>"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/usb/stk1160/Kconfig b/drivers/media/usb/stk1160/Kconfig index 4f50fb7db7b9..bf7c16baa9f8 100644 --- a/drivers/media/usb/stk1160/Kconfig +++ b/drivers/media/usb/stk1160/Kconfig @@ -1,8 +1,9 @@ # SPDX-License-Identifier: GPL-2.0-only -config VIDEO_STK1160_COMMON +config VIDEO_STK1160 tristate "STK1160 USB video capture support" depends on VIDEO_DEV && I2C - + select VIDEOBUF2_VMALLOC + select VIDEO_SAA711X help This is a video4linux driver for STK1160 based video capture devices. @@ -12,10 +13,3 @@ config VIDEO_STK1160_COMMON This driver only provides support for video capture. For audio capture, you need to select the snd-usb-audio driver (i.e. CONFIG_SND_USB_AUDIO). - -config VIDEO_STK1160 - tristate - depends on VIDEO_STK1160_COMMON - default y - select VIDEOBUF2_VMALLOC - select VIDEO_SAA711X diff --git a/drivers/media/usb/stk1160/stk1160-core.c b/drivers/media/usb/stk1160/stk1160-core.c index ce717502ea4c..25d725c2ab3c 100644 --- a/drivers/media/usb/stk1160/stk1160-core.c +++ b/drivers/media/usb/stk1160/stk1160-core.c @@ -195,8 +195,7 @@ static int stk1160_scan_usb(struct usb_interface *intf, struct usb_device *udev, if (udev->speed == USB_SPEED_HIGH) size = size * hb_mult(sizedescr); - if (usb_endpoint_xfer_isoc(desc) && - usb_endpoint_dir_in(desc)) { + if (usb_endpoint_is_isoc_in(desc)) { switch (desc->bEndpointAddress) { case STK1160_EP_AUDIO: has_audio = true; diff --git a/drivers/media/usb/stk1160/stk1160-v4l.c b/drivers/media/usb/stk1160/stk1160-v4l.c index a1f785a5ffd8..715ce1dcb304 100644 --- a/drivers/media/usb/stk1160/stk1160-v4l.c +++ b/drivers/media/usb/stk1160/stk1160-v4l.c @@ -232,10 +232,6 @@ static int stk1160_start_streaming(struct stk1160 *dev) /* submit urbs and enables IRQ */ for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { - struct stk1160_urb *stk_urb = &dev->isoc_ctl.urb_ctl[i]; - - dma_sync_sgtable_for_device(stk1160_get_dmadev(dev), stk_urb->sgt, - DMA_FROM_DEVICE); rc = usb_submit_urb(dev->isoc_ctl.urb_ctl[i].urb, GFP_KERNEL); if (rc) { stk1160_err("cannot submit urb[%d] (%d)\n", i, rc); @@ -734,8 +730,6 @@ static const struct vb2_ops stk1160_video_qops = { .buf_queue = buffer_queue, .start_streaming = start_streaming, .stop_streaming = stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static const struct video_device v4l_template = { diff --git a/drivers/media/usb/stk1160/stk1160-video.c b/drivers/media/usb/stk1160/stk1160-video.c index 4e966f6bf608..f4baf9263286 100644 --- a/drivers/media/usb/stk1160/stk1160-video.c +++ b/drivers/media/usb/stk1160/stk1160-video.c @@ -99,7 +99,7 @@ void stk1160_buffer_done(struct stk1160 *dev) static inline void stk1160_copy_video(struct stk1160 *dev, u8 *src, int len) { - int linesdone, lineoff, lencopy; + int linesdone, lineoff, lencopy, offset; int bytesperline = dev->width * 2; struct stk1160_buffer *buf = dev->isoc_ctl.buf; u8 *dst = buf->mem; @@ -107,8 +107,7 @@ void stk1160_copy_video(struct stk1160 *dev, u8 *src, int len) /* * TODO: These stk1160_dbg are very spammy! - * We should 1) check why we are getting them - * and 2) add ratelimit. + * We should check why we are getting them. * * UPDATE: One of the reasons (the only one?) for getting these * is incorrect standard (mismatch between expected and configured). @@ -131,17 +130,19 @@ void stk1160_copy_video(struct stk1160 *dev, u8 *src, int len) dst += linesdone * bytesperline * 2 + lineoff; /* Copy the remaining of current line */ - if (remain < (bytesperline - lineoff)) - lencopy = remain; - else - lencopy = bytesperline - lineoff; + lencopy = min(remain, bytesperline - lineoff); /* * Check if we have enough space left in the buffer. * In that case, we force loop exit after copy. */ - if (lencopy > buf->bytesused - buf->length) { - lencopy = buf->bytesused - buf->length; + offset = dst - (u8 *)buf->mem; + if (offset > buf->length) { + dev_warn_ratelimited(dev->dev, "out of bounds offset\n"); + return; + } + if (lencopy > buf->length - offset) { + lencopy = buf->length - offset; remain = lencopy; } @@ -151,7 +152,7 @@ void stk1160_copy_video(struct stk1160 *dev, u8 *src, int len) /* Let the bug hunt begin! sanity checks! */ if (lencopy < 0) { - stk1160_dbg("copy skipped: negative lencopy\n"); + printk_ratelimited(KERN_DEBUG "copy skipped: negative lencopy\n"); return; } @@ -174,17 +175,19 @@ void stk1160_copy_video(struct stk1160 *dev, u8 *src, int len) src += lencopy; /* Copy one line at a time */ - if (remain < bytesperline) - lencopy = remain; - else - lencopy = bytesperline; + lencopy = min(remain, bytesperline); /* * Check if we have enough space left in the buffer. * In that case, we force loop exit after copy. */ - if (lencopy > buf->bytesused - buf->length) { - lencopy = buf->bytesused - buf->length; + offset = dst - (u8 *)buf->mem; + if (offset > buf->length) { + dev_warn_ratelimited(dev->dev, "offset out of bounds\n"); + return; + } + if (lencopy > buf->length - offset) { + lencopy = buf->length - offset; remain = lencopy; } @@ -295,9 +298,7 @@ static void stk1160_process_isoc(struct stk1160 *dev, struct urb *urb) static void stk1160_isoc_irq(struct urb *urb) { int i, rc; - struct stk1160_urb *stk_urb = urb->context; - struct stk1160 *dev = stk_urb->dev; - struct device *dma_dev = stk1160_get_dmadev(dev); + struct stk1160 *dev = urb->context; switch (urb->status) { case 0: @@ -312,10 +313,6 @@ static void stk1160_isoc_irq(struct urb *urb) return; } - invalidate_kernel_vmap_range(stk_urb->transfer_buffer, - urb->transfer_buffer_length); - dma_sync_sgtable_for_cpu(dma_dev, stk_urb->sgt, DMA_FROM_DEVICE); - stk1160_process_isoc(dev, urb); /* Reset urb buffers */ @@ -324,7 +321,6 @@ static void stk1160_isoc_irq(struct urb *urb) urb->iso_frame_desc[i].actual_length = 0; } - dma_sync_sgtable_for_device(dma_dev, stk_urb->sgt, DMA_FROM_DEVICE); rc = usb_submit_urb(urb, GFP_ATOMIC); if (rc) stk1160_err("urb re-submit failed (%d)\n", rc); @@ -362,11 +358,9 @@ void stk1160_cancel_isoc(struct stk1160 *dev) static void stk_free_urb(struct stk1160 *dev, struct stk1160_urb *stk_urb) { - struct device *dma_dev = stk1160_get_dmadev(dev); - - dma_vunmap_noncontiguous(dma_dev, stk_urb->transfer_buffer); - dma_free_noncontiguous(dma_dev, stk_urb->urb->transfer_buffer_length, - stk_urb->sgt, DMA_FROM_DEVICE); + usb_free_noncoherent(dev->udev, stk_urb->urb->transfer_buffer_length, + stk_urb->transfer_buffer, DMA_FROM_DEVICE, + stk_urb->sgt); usb_free_urb(stk_urb->urb); stk_urb->transfer_buffer = NULL; @@ -407,32 +401,24 @@ void stk1160_uninit_isoc(struct stk1160 *dev) static int stk1160_fill_urb(struct stk1160 *dev, struct stk1160_urb *stk_urb, int sb_size, int max_packets) { - struct device *dma_dev = stk1160_get_dmadev(dev); - stk_urb->urb = usb_alloc_urb(max_packets, GFP_KERNEL); if (!stk_urb->urb) return -ENOMEM; - stk_urb->sgt = dma_alloc_noncontiguous(dma_dev, sb_size, - DMA_FROM_DEVICE, GFP_KERNEL, 0); - /* - * If the buffer allocation failed, we exit but return 0 since - * we allow the driver working with less buffers - */ - if (!stk_urb->sgt) + stk_urb->transfer_buffer = usb_alloc_noncoherent(dev->udev, sb_size, + GFP_KERNEL, &stk_urb->dma, + DMA_FROM_DEVICE, &stk_urb->sgt); + if (!stk_urb->transfer_buffer) { + /* + * If the buffer allocation failed, we exit but return 0 since + * we allow the driver working with less buffers. + */ goto free_urb; + } - stk_urb->transfer_buffer = dma_vmap_noncontiguous(dma_dev, sb_size, - stk_urb->sgt); - if (!stk_urb->transfer_buffer) - goto free_sgt; - - stk_urb->dma = stk_urb->sgt->sgl->dma_address; stk_urb->dev = dev; return 0; -free_sgt: - dma_free_noncontiguous(dma_dev, sb_size, stk_urb->sgt, DMA_FROM_DEVICE); - stk_urb->sgt = NULL; + free_urb: usb_free_urb(stk_urb->urb); stk_urb->urb = NULL; @@ -491,12 +477,13 @@ int stk1160_alloc_isoc(struct stk1160 *dev) urb->transfer_buffer = dev->isoc_ctl.urb_ctl[i].transfer_buffer; urb->transfer_buffer_length = sb_size; urb->complete = stk1160_isoc_irq; - urb->context = &dev->isoc_ctl.urb_ctl[i]; + urb->context = dev; urb->interval = 1; urb->start_frame = 0; urb->number_of_packets = max_packets; urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; urb->transfer_dma = dev->isoc_ctl.urb_ctl[i].dma; + urb->sgt = dev->isoc_ctl.urb_ctl[i].sgt; k = 0; for (j = 0; j < max_packets; j++) { diff --git a/drivers/media/usb/stk1160/stk1160.h b/drivers/media/usb/stk1160/stk1160.h index 7b498d14ed7a..4cbcb0a03bab 100644 --- a/drivers/media/usb/stk1160/stk1160.h +++ b/drivers/media/usb/stk1160/stk1160.h @@ -16,8 +16,6 @@ #include <media/videobuf2-v4l2.h> #include <media/v4l2-device.h> #include <media/v4l2-ctrls.h> -#include <linux/usb.h> -#include <linux/usb/hcd.h> #define STK1160_VERSION "0.9.5" #define STK1160_VERSION_NUM 0x000905 @@ -195,8 +193,3 @@ void stk1160_select_input(struct stk1160 *dev); /* Provided by stk1160-ac97.c */ void stk1160_ac97_setup(struct stk1160 *dev); - -static inline struct device *stk1160_get_dmadev(struct stk1160 *dev) -{ - return bus_to_hcd(dev->udev->bus)->self.sysdev; -} diff --git a/drivers/media/usb/ttusb-dec/ttusb_dec.c b/drivers/media/usb/ttusb-dec/ttusb_dec.c index 38822cedd93a..b4575fe89c95 100644 --- a/drivers/media/usb/ttusb-dec/ttusb_dec.c +++ b/drivers/media/usb/ttusb-dec/ttusb_dec.c @@ -19,6 +19,7 @@ #include <linux/input.h> #include <linux/mutex.h> +#include <linux/workqueue.h> #include <media/dmxdev.h> #include <media/dvb_demux.h> @@ -139,7 +140,7 @@ struct ttusb_dec { int v_pes_postbytes; struct list_head urb_frame_list; - struct tasklet_struct urb_tasklet; + struct work_struct urb_bh_work; spinlock_t urb_frame_list_lock; struct dvb_demux_filter *audio_filter; @@ -766,9 +767,9 @@ static void ttusb_dec_process_urb_frame(struct ttusb_dec *dec, u8 *b, } } -static void ttusb_dec_process_urb_frame_list(struct tasklet_struct *t) +static void ttusb_dec_process_urb_frame_list(struct work_struct *t) { - struct ttusb_dec *dec = from_tasklet(dec, t, urb_tasklet); + struct ttusb_dec *dec = from_work(dec, t, urb_bh_work); struct list_head *item; struct urb_frame *frame; unsigned long flags; @@ -822,7 +823,7 @@ static void ttusb_dec_process_urb(struct urb *urb) spin_unlock_irqrestore(&dec->urb_frame_list_lock, flags); - tasklet_schedule(&dec->urb_tasklet); + queue_work(system_bh_wq, &dec->urb_bh_work); } } } else { @@ -1128,7 +1129,7 @@ static int ttusb_dec_stop_sec_feed(struct dvb_demux_feed *dvbdmxfeed) { struct ttusb_dec *dec = dvbdmxfeed->demux->priv; u8 b0[] = { 0x00, 0x00 }; - struct filter_info *finfo = (struct filter_info *)dvbdmxfeed->priv; + struct filter_info *finfo = dvbdmxfeed->priv; unsigned long flags; b0[1] = finfo->stream_id; @@ -1198,11 +1199,11 @@ static int ttusb_dec_alloc_iso_urbs(struct ttusb_dec *dec) return 0; } -static void ttusb_dec_init_tasklet(struct ttusb_dec *dec) +static void ttusb_dec_init_bh_work(struct ttusb_dec *dec) { spin_lock_init(&dec->urb_frame_list_lock); INIT_LIST_HEAD(&dec->urb_frame_list); - tasklet_setup(&dec->urb_tasklet, ttusb_dec_process_urb_frame_list); + INIT_WORK(&dec->urb_bh_work, ttusb_dec_process_urb_frame_list); } static int ttusb_init_rc( struct ttusb_dec *dec) @@ -1544,8 +1545,7 @@ static void ttusb_dec_exit_dvb(struct ttusb_dec *dec) dvb_dmx_release(&dec->demux); if (dec->fe) { dvb_unregister_frontend(dec->fe); - if (dec->fe->ops.release) - dec->fe->ops.release(dec->fe); + dvb_frontend_detach(dec->fe); } dvb_unregister_adapter(&dec->adapter); } @@ -1589,12 +1589,12 @@ static void ttusb_dec_exit_usb(struct ttusb_dec *dec) ttusb_dec_free_iso_urbs(dec); } -static void ttusb_dec_exit_tasklet(struct ttusb_dec *dec) +static void ttusb_dec_exit_bh_work(struct ttusb_dec *dec) { struct list_head *item; struct urb_frame *frame; - tasklet_kill(&dec->urb_tasklet); + cancel_work_sync(&dec->urb_bh_work); while ((item = dec->urb_frame_list.next) != &dec->urb_frame_list) { frame = list_entry(item, struct urb_frame, urb_frame_list); @@ -1704,7 +1704,7 @@ static int ttusb_dec_probe(struct usb_interface *intf, ttusb_dec_init_v_pes(dec); ttusb_dec_init_filters(dec); - ttusb_dec_init_tasklet(dec); + ttusb_dec_init_bh_work(dec); dec->active = 1; @@ -1730,7 +1730,7 @@ static void ttusb_dec_disconnect(struct usb_interface *intf) dprintk("%s\n", __func__); if (dec->active) { - ttusb_dec_exit_tasklet(dec); + ttusb_dec_exit_bh_work(dec); ttusb_dec_exit_filters(dec); if(enable_rc) ttusb_dec_exit_rc(dec); diff --git a/drivers/media/usb/ttusb-dec/ttusbdecfe.c b/drivers/media/usb/ttusb-dec/ttusbdecfe.c index ea25b96b8bbf..dff6bf532ce3 100644 --- a/drivers/media/usb/ttusb-dec/ttusbdecfe.c +++ b/drivers/media/usb/ttusb-dec/ttusbdecfe.c @@ -76,7 +76,7 @@ static int ttusbdecfe_dvbt_read_status(struct dvb_frontend *fe, static int ttusbdecfe_dvbt_set_frontend(struct dvb_frontend *fe) { struct dtv_frontend_properties *p = &fe->dtv_property_cache; - struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv; + struct ttusbdecfe_state *state = fe->demodulator_priv; u8 b[] = { 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, @@ -103,7 +103,7 @@ static int ttusbdecfe_dvbt_get_tune_settings(struct dvb_frontend* fe, static int ttusbdecfe_dvbs_set_frontend(struct dvb_frontend *fe) { struct dtv_frontend_properties *p = &fe->dtv_property_cache; - struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv; + struct ttusbdecfe_state *state = fe->demodulator_priv; u8 b[] = { 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, @@ -137,7 +137,7 @@ static int ttusbdecfe_dvbs_set_frontend(struct dvb_frontend *fe) static int ttusbdecfe_dvbs_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd *cmd) { - struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv; + struct ttusbdecfe_state *state = fe->demodulator_priv; u8 b[] = { 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; @@ -158,7 +158,7 @@ static int ttusbdecfe_dvbs_diseqc_send_master_cmd(struct dvb_frontend* fe, struc static int ttusbdecfe_dvbs_set_tone(struct dvb_frontend *fe, enum fe_sec_tone_mode tone) { - struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv; + struct ttusbdecfe_state *state = fe->demodulator_priv; state->hi_band = (SEC_TONE_ON == tone); @@ -169,7 +169,7 @@ static int ttusbdecfe_dvbs_set_tone(struct dvb_frontend *fe, static int ttusbdecfe_dvbs_set_voltage(struct dvb_frontend *fe, enum fe_sec_voltage voltage) { - struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv; + struct ttusbdecfe_state *state = fe->demodulator_priv; switch (voltage) { case SEC_VOLTAGE_13: @@ -187,7 +187,7 @@ static int ttusbdecfe_dvbs_set_voltage(struct dvb_frontend *fe, static void ttusbdecfe_release(struct dvb_frontend* fe) { - struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv; + struct ttusbdecfe_state *state = fe->demodulator_priv; kfree(state); } diff --git a/drivers/media/usb/usbtv/usbtv-core.c b/drivers/media/usb/usbtv/usbtv-core.c index 2308c0b4f5e7..1f7620cd2996 100644 --- a/drivers/media/usb/usbtv/usbtv-core.c +++ b/drivers/media/usb/usbtv/usbtv-core.c @@ -47,7 +47,7 @@ int usbtv_set_regs(struct usbtv *usbtv, const u16 regs[][2], int size) { int ret; - int pipe = usb_rcvctrlpipe(usbtv->udev, 0); + int pipe = usb_sndctrlpipe(usbtv->udev, 0); int i; for (i = 0; i < size; i++) { diff --git a/drivers/media/usb/usbtv/usbtv-video.c b/drivers/media/usb/usbtv/usbtv-video.c index 1e30e05953dc..de0328100a60 100644 --- a/drivers/media/usb/usbtv/usbtv-video.c +++ b/drivers/media/usb/usbtv/usbtv-video.c @@ -73,6 +73,10 @@ static int usbtv_configure_for_norm(struct usbtv *usbtv, v4l2_std_id norm) } if (params) { + if (vb2_is_busy(&usbtv->vb2q) && + (usbtv->width != params->cap_width || + usbtv->height != params->cap_height)) + return -EBUSY; usbtv->width = params->cap_width; usbtv->height = params->cap_height; usbtv->n_chunks = usbtv->width * usbtv->height @@ -726,9 +730,10 @@ static int usbtv_queue_setup(struct vb2_queue *vq, { struct usbtv *usbtv = vb2_get_drv_priv(vq); unsigned size = USBTV_CHUNK * usbtv->n_chunks * 2 * sizeof(u32); + unsigned int q_num_bufs = vb2_get_num_buffers(vq); - if (vq->num_buffers + *nbuffers < 2) - *nbuffers = 2 - vq->num_buffers; + if (q_num_bufs + *nbuffers < 2) + *nbuffers = 2 - q_num_bufs; if (*nplanes) return sizes[0] < size ? -EINVAL : 0; *nplanes = 1; @@ -779,8 +784,6 @@ static const struct vb2_ops usbtv_vb2_ops = { .buf_queue = usbtv_buf_queue, .start_streaming = usbtv_start_streaming, .stop_streaming = usbtv_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int usbtv_s_ctrl(struct v4l2_ctrl *ctrl) @@ -962,15 +965,8 @@ ctrl_fail: void usbtv_video_free(struct usbtv *usbtv) { - mutex_lock(&usbtv->vb2q_lock); - mutex_lock(&usbtv->v4l2_lock); - - usbtv_stop(usbtv); vb2_video_unregister_device(&usbtv->vdev); v4l2_device_disconnect(&usbtv->v4l2_dev); - mutex_unlock(&usbtv->v4l2_lock); - mutex_unlock(&usbtv->vb2q_lock); - v4l2_device_put(&usbtv->v4l2_dev); } diff --git a/drivers/media/usb/uvc/Kconfig b/drivers/media/usb/uvc/Kconfig index ca51ee8e45f3..579532272fd6 100644 --- a/drivers/media/usb/uvc/Kconfig +++ b/drivers/media/usb/uvc/Kconfig @@ -3,6 +3,7 @@ config USB_VIDEO_CLASS tristate "USB Video Class (UVC)" depends on VIDEO_DEV select VIDEOBUF2_VMALLOC + select UVC_COMMON help Support for the USB Video Class (UVC). Currently only video input devices, such as webcams, are supported. diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c index c95a2229f4fa..2905505c240c 100644 --- a/drivers/media/usb/uvc/uvc_ctrl.c +++ b/drivers/media/usb/uvc/uvc_ctrl.c @@ -6,19 +6,21 @@ * Laurent Pinchart (laurent.pinchart@ideasonboard.com) */ +#include <asm/barrier.h> +#include <linux/bitops.h> #include <linux/kernel.h> #include <linux/list.h> #include <linux/module.h> #include <linux/slab.h> #include <linux/uaccess.h> #include <linux/usb.h> +#include <linux/usb/uvc.h> #include <linux/videodev2.h> #include <linux/vmalloc.h> #include <linux/wait.h> #include <linux/workqueue.h> #include <linux/atomic.h> #include <media/v4l2-ctrls.h> -#include <media/v4l2-uvc.h> #include "uvcvideo.h" @@ -356,6 +358,33 @@ static const struct uvc_control_info uvc_ctrls[] = { .flags = UVC_CTRL_FLAG_GET_CUR | UVC_CTRL_FLAG_AUTO_UPDATE, }, + /* + * UVC_CTRL_FLAG_AUTO_UPDATE is needed because the RoI may get updated + * by sensors. + * "This RoI should be the same as specified in most recent SET_CUR + * except in the case where the ‘Auto Detect and Track’ and/or + * ‘Image Stabilization’ bit have been set." + * 4.2.2.1.20 Digital Region of Interest (ROI) Control + */ + { + .entity = UVC_GUID_UVC_CAMERA, + .selector = UVC_CT_REGION_OF_INTEREST_CONTROL, + .index = 21, + .size = 10, + .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR + | UVC_CTRL_FLAG_GET_MIN | UVC_CTRL_FLAG_GET_MAX + | UVC_CTRL_FLAG_GET_DEF + | UVC_CTRL_FLAG_AUTO_UPDATE, + }, + { + .entity = UVC_GUID_CHROMEOS_XU, + .selector = UVC_CROSXU_CONTROL_IQ_PROFILE, + .index = 3, + .size = 1, + .flags = UVC_CTRL_FLAG_SET_CUR + | UVC_CTRL_FLAG_GET_RANGE + | UVC_CTRL_FLAG_RESTORE, + }, }; static const u32 uvc_control_classes[] = { @@ -363,72 +392,293 @@ static const u32 uvc_control_classes[] = { V4L2_CID_USER_CLASS, }; -static const struct uvc_menu_info power_line_frequency_controls[] = { - { 0, "Disabled" }, - { 1, "50 Hz" }, - { 2, "60 Hz" }, - { 3, "Auto" }, +static const int exposure_auto_mapping[] = { 2, 1, 4, 8 }; +static const int cros_colorfx_mapping[] = { + 1, /* V4L2_COLORFX_NONE */ + -1, /* V4L2_COLORFX_BW */ + -1, /* V4L2_COLORFX_SEPIA */ + -1, /* V4L2_COLORFX_NEGATIVE */ + -1, /* V4L2_COLORFX_EMBOSS */ + -1, /* V4L2_COLORFX_SKETCH */ + -1, /* V4L2_COLORFX_SKY_BLUE */ + -1, /* V4L2_COLORFX_GRASS_GREEN */ + -1, /* V4L2_COLORFX_SKIN_WHITEN */ + 0, /* V4L2_COLORFX_VIVID */ }; -static const struct uvc_menu_info exposure_auto_controls[] = { - { 2, "Auto Mode" }, - { 1, "Manual Mode" }, - { 4, "Shutter Priority Mode" }, - { 8, "Aperture Priority Mode" }, -}; -static s32 uvc_ctrl_get_zoom(struct uvc_control_mapping *mapping, - u8 query, const u8 *data) +static bool uvc_ctrl_mapping_is_compound(struct uvc_control_mapping *mapping) +{ + return mapping->v4l2_type >= V4L2_CTRL_COMPOUND_TYPES; +} + +static s32 uvc_mapping_get_s32(struct uvc_control_mapping *mapping, + u8 query, const void *data_in) +{ + s32 data_out = 0; + + mapping->get(mapping, query, data_in, sizeof(data_out), &data_out); + + return data_out; +} + +static void uvc_mapping_set_s32(struct uvc_control_mapping *mapping, + s32 data_in, void *data_out) +{ + mapping->set(mapping, sizeof(data_in), &data_in, data_out); +} + +/* + * This function translates the V4L2 menu index @idx, as exposed to userspace as + * the V4L2 control value, to the corresponding UVC control value used by the + * device. The custom menu_mapping in the control @mapping is used when + * available, otherwise the function assumes that the V4L2 and UVC values are + * identical. + * + * For controls of type UVC_CTRL_DATA_TYPE_BITMASK, the UVC control value is + * expressed as a bitmask and is thus guaranteed to have a single bit set. + * + * The function returns -EINVAL if the V4L2 menu index @idx isn't valid for the + * control, which includes all controls whose type isn't UVC_CTRL_DATA_TYPE_ENUM + * or UVC_CTRL_DATA_TYPE_BITMASK. + */ +static int uvc_mapping_get_menu_value(const struct uvc_control_mapping *mapping, + u32 idx) { - s8 zoom = (s8)data[0]; + if (!test_bit(idx, &mapping->menu_mask)) + return -EINVAL; + + if (mapping->menu_mapping) + return mapping->menu_mapping[idx]; + + return idx; +} + +static const char * +uvc_mapping_get_menu_name(const struct uvc_control_mapping *mapping, u32 idx) +{ + if (!test_bit(idx, &mapping->menu_mask)) + return NULL; + + if (mapping->menu_names) + return mapping->menu_names[idx]; + + return v4l2_ctrl_get_menu(mapping->id)[idx]; +} + +static int uvc_ctrl_get_zoom(struct uvc_control_mapping *mapping, u8 query, + const void *uvc_in, size_t v4l2_size, + void *v4l2_out) +{ + u8 value = ((u8 *)uvc_in)[2]; + s8 sign = ((s8 *)uvc_in)[0]; + s32 *out = v4l2_out; + + if (WARN_ON(v4l2_size != sizeof(s32))) + return -EINVAL; switch (query) { case UVC_GET_CUR: - return (zoom == 0) ? 0 : (zoom > 0 ? data[2] : -data[2]); + *out = (sign == 0) ? 0 : (sign > 0 ? value : -value); + return 0; case UVC_GET_MIN: case UVC_GET_MAX: case UVC_GET_RES: case UVC_GET_DEF: default: - return data[2]; + *out = value; + return 0; } } -static void uvc_ctrl_set_zoom(struct uvc_control_mapping *mapping, - s32 value, u8 *data) +static int uvc_ctrl_set_zoom(struct uvc_control_mapping *mapping, + size_t v4l2_size, const void *v4l2_in, + void *uvc_out) { - data[0] = value == 0 ? 0 : (value > 0) ? 1 : 0xff; - data[2] = min((int)abs(value), 0xff); + u8 *out = uvc_out; + s32 value; + + if (WARN_ON(v4l2_size != sizeof(s32))) + return -EINVAL; + + value = *(u32 *)v4l2_in; + out[0] = value == 0 ? 0 : (value > 0) ? 1 : 0xff; + out[2] = min_t(int, abs(value), 0xff); + + return 0; } -static s32 uvc_ctrl_get_rel_speed(struct uvc_control_mapping *mapping, - u8 query, const u8 *data) +static int uvc_ctrl_get_rel_speed(struct uvc_control_mapping *mapping, + u8 query, const void *uvc_in, + size_t v4l2_size, void *v4l2_out) { unsigned int first = mapping->offset / 8; - s8 rel = (s8)data[first]; + u8 value = ((u8 *)uvc_in)[first + 1]; + s8 sign = ((s8 *)uvc_in)[first]; + s32 *out = v4l2_out; + + if (WARN_ON(v4l2_size != sizeof(s32))) + return -EINVAL; switch (query) { case UVC_GET_CUR: - return (rel == 0) ? 0 : (rel > 0 ? data[first+1] - : -data[first+1]); + *out = (sign == 0) ? 0 : (sign > 0 ? value : -value); + return 0; case UVC_GET_MIN: - return -data[first+1]; + *out = -value; + return 0; case UVC_GET_MAX: case UVC_GET_RES: case UVC_GET_DEF: default: - return data[first+1]; + *out = value; + return 0; } } -static void uvc_ctrl_set_rel_speed(struct uvc_control_mapping *mapping, - s32 value, u8 *data) +static int uvc_ctrl_set_rel_speed(struct uvc_control_mapping *mapping, + size_t v4l2_size, const void *v4l2_in, + void *uvc_out) { unsigned int first = mapping->offset / 8; + u8 *out = uvc_out; + s32 value; - data[first] = value == 0 ? 0 : (value > 0) ? 1 : 0xff; - data[first+1] = min_t(int, abs(value), 0xff); + if (WARN_ON(v4l2_size != sizeof(s32))) + return -EINVAL; + + value = *(u32 *)v4l2_in; + out[first] = value == 0 ? 0 : (value > 0) ? 1 : 0xff; + out[first + 1] = min_t(int, abs(value), 0xff); + + return 0; +} + +static const struct uvc_control_mapping uvc_ctrl_power_line_mapping_limited = { + .id = V4L2_CID_POWER_LINE_FREQUENCY, + .entity = UVC_GUID_UVC_PROCESSING, + .selector = UVC_PU_POWER_LINE_FREQUENCY_CONTROL, + .size = 2, + .offset = 0, + .v4l2_type = V4L2_CTRL_TYPE_MENU, + .data_type = UVC_CTRL_DATA_TYPE_ENUM, + .menu_mask = GENMASK(V4L2_CID_POWER_LINE_FREQUENCY_60HZ, + V4L2_CID_POWER_LINE_FREQUENCY_50HZ), +}; + +static const struct uvc_control_mapping uvc_ctrl_power_line_mapping_uvc11 = { + .id = V4L2_CID_POWER_LINE_FREQUENCY, + .entity = UVC_GUID_UVC_PROCESSING, + .selector = UVC_PU_POWER_LINE_FREQUENCY_CONTROL, + .size = 2, + .offset = 0, + .v4l2_type = V4L2_CTRL_TYPE_MENU, + .data_type = UVC_CTRL_DATA_TYPE_ENUM, + .menu_mask = GENMASK(V4L2_CID_POWER_LINE_FREQUENCY_60HZ, + V4L2_CID_POWER_LINE_FREQUENCY_DISABLED), +}; + +static const struct uvc_control_mapping uvc_ctrl_power_line_mapping_uvc15 = { + .id = V4L2_CID_POWER_LINE_FREQUENCY, + .entity = UVC_GUID_UVC_PROCESSING, + .selector = UVC_PU_POWER_LINE_FREQUENCY_CONTROL, + .size = 2, + .offset = 0, + .v4l2_type = V4L2_CTRL_TYPE_MENU, + .data_type = UVC_CTRL_DATA_TYPE_ENUM, + .menu_mask = GENMASK(V4L2_CID_POWER_LINE_FREQUENCY_AUTO, + V4L2_CID_POWER_LINE_FREQUENCY_DISABLED), +}; + +static const struct uvc_control_mapping *uvc_ctrl_filter_plf_mapping( + struct uvc_video_chain *chain, struct uvc_control *ctrl) +{ + const struct uvc_control_mapping *out_mapping = + &uvc_ctrl_power_line_mapping_uvc11; + u8 *buf __free(kfree) = NULL; + u8 init_val; + int ret; + + buf = kmalloc(sizeof(*buf), GFP_KERNEL); + if (!buf) + return NULL; + + /* Save the current PLF value, so we can restore it. */ + ret = uvc_query_ctrl(chain->dev, UVC_GET_CUR, ctrl->entity->id, + chain->dev->intfnum, ctrl->info.selector, + buf, sizeof(*buf)); + /* If we cannot read the control skip it. */ + if (ret) + return NULL; + init_val = *buf; + + /* If PLF value cannot be set to off, it is limited. */ + *buf = V4L2_CID_POWER_LINE_FREQUENCY_DISABLED; + ret = uvc_query_ctrl(chain->dev, UVC_SET_CUR, ctrl->entity->id, + chain->dev->intfnum, ctrl->info.selector, + buf, sizeof(*buf)); + if (ret) + return &uvc_ctrl_power_line_mapping_limited; + + /* UVC 1.1 does not define auto, we can exit. */ + if (chain->dev->uvc_version < 0x150) + goto end; + + /* Check if the device supports auto. */ + *buf = V4L2_CID_POWER_LINE_FREQUENCY_AUTO; + ret = uvc_query_ctrl(chain->dev, UVC_SET_CUR, ctrl->entity->id, + chain->dev->intfnum, ctrl->info.selector, + buf, sizeof(*buf)); + if (!ret) + out_mapping = &uvc_ctrl_power_line_mapping_uvc15; + +end: + /* Restore initial value and add mapping. */ + *buf = init_val; + uvc_query_ctrl(chain->dev, UVC_SET_CUR, ctrl->entity->id, + chain->dev->intfnum, ctrl->info.selector, + buf, sizeof(*buf)); + + return out_mapping; +} + +static int uvc_get_rect(struct uvc_control_mapping *mapping, u8 query, + const void *uvc_in, size_t v4l2_size, void *v4l2_out) +{ + const struct uvc_rect *uvc_rect = uvc_in; + struct v4l2_rect *v4l2_rect = v4l2_out; + + if (WARN_ON(v4l2_size != sizeof(struct v4l2_rect))) + return -EINVAL; + + if (uvc_rect->left > uvc_rect->right || + uvc_rect->top > uvc_rect->bottom) + return -EIO; + + v4l2_rect->top = uvc_rect->top; + v4l2_rect->left = uvc_rect->left; + v4l2_rect->height = uvc_rect->bottom - uvc_rect->top + 1; + v4l2_rect->width = uvc_rect->right - uvc_rect->left + 1; + + return 0; +} + +static int uvc_set_rect(struct uvc_control_mapping *mapping, size_t v4l2_size, + const void *v4l2_in, void *uvc_out) +{ + struct uvc_rect *uvc_rect = uvc_out; + const struct v4l2_rect *v4l2_rect = v4l2_in; + + if (WARN_ON(v4l2_size != sizeof(struct v4l2_rect))) + return -EINVAL; + + uvc_rect->top = min(0xffff, v4l2_rect->top); + uvc_rect->left = min(0xffff, v4l2_rect->left); + uvc_rect->bottom = min(0xffff, v4l2_rect->top + v4l2_rect->height - 1); + uvc_rect->right = min(0xffff, v4l2_rect->left + v4l2_rect->width - 1); + + return 0; } static const struct uvc_control_mapping uvc_ctrl_mappings[] = { @@ -524,8 +774,9 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = { .offset = 0, .v4l2_type = V4L2_CTRL_TYPE_MENU, .data_type = UVC_CTRL_DATA_TYPE_BITMASK, - .menu_info = exposure_auto_controls, - .menu_count = ARRAY_SIZE(exposure_auto_controls), + .menu_mapping = exposure_auto_mapping, + .menu_mask = GENMASK(V4L2_EXPOSURE_APERTURE_PRIORITY, + V4L2_EXPOSURE_AUTO), .slave_ids = { V4L2_CID_EXPOSURE_ABSOLUTE, }, }, { @@ -719,33 +970,44 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = { .v4l2_type = V4L2_CTRL_TYPE_BOOLEAN, .data_type = UVC_CTRL_DATA_TYPE_BOOLEAN, }, -}; - -static const struct uvc_control_mapping uvc_ctrl_mappings_uvc11[] = { { - .id = V4L2_CID_POWER_LINE_FREQUENCY, .entity = UVC_GUID_UVC_PROCESSING, .selector = UVC_PU_POWER_LINE_FREQUENCY_CONTROL, - .size = 2, + .filter_mapping = uvc_ctrl_filter_plf_mapping, + }, + { + .id = V4L2_CID_UVC_REGION_OF_INTEREST_RECT, + .entity = UVC_GUID_UVC_CAMERA, + .selector = UVC_CT_REGION_OF_INTEREST_CONTROL, + .size = sizeof(struct uvc_rect) * 8, .offset = 0, - .v4l2_type = V4L2_CTRL_TYPE_MENU, - .data_type = UVC_CTRL_DATA_TYPE_ENUM, - .menu_info = power_line_frequency_controls, - .menu_count = ARRAY_SIZE(power_line_frequency_controls) - 1, + .v4l2_type = V4L2_CTRL_TYPE_RECT, + .data_type = UVC_CTRL_DATA_TYPE_RECT, + .get = uvc_get_rect, + .set = uvc_set_rect, + .name = "Region of Interest Rectangle", }, -}; - -static const struct uvc_control_mapping uvc_ctrl_mappings_uvc15[] = { { - .id = V4L2_CID_POWER_LINE_FREQUENCY, - .entity = UVC_GUID_UVC_PROCESSING, - .selector = UVC_PU_POWER_LINE_FREQUENCY_CONTROL, - .size = 2, + .id = V4L2_CID_UVC_REGION_OF_INTEREST_AUTO, + .entity = UVC_GUID_UVC_CAMERA, + .selector = UVC_CT_REGION_OF_INTEREST_CONTROL, + .size = 16, + .offset = 64, + .v4l2_type = V4L2_CTRL_TYPE_BITMASK, + .data_type = UVC_CTRL_DATA_TYPE_BITMASK, + .name = "Region of Interest Auto Ctrls", + }, + { + .id = V4L2_CID_COLORFX, + .entity = UVC_GUID_CHROMEOS_XU, + .selector = UVC_CROSXU_CONTROL_IQ_PROFILE, + .size = 8, .offset = 0, .v4l2_type = V4L2_CTRL_TYPE_MENU, .data_type = UVC_CTRL_DATA_TYPE_ENUM, - .menu_info = power_line_frequency_controls, - .menu_count = ARRAY_SIZE(power_line_frequency_controls), + .menu_mapping = cros_colorfx_mapping, + .menu_mask = BIT(V4L2_COLORFX_VIVID) | + BIT(V4L2_COLORFX_NONE), }, }; @@ -768,20 +1030,45 @@ static inline void uvc_clear_bit(u8 *data, int bit) data[bit >> 3] &= ~(1 << (bit & 7)); } +static s32 uvc_menu_to_v4l2_menu(struct uvc_control_mapping *mapping, s32 val) +{ + unsigned int i; + + for (i = 0; BIT(i) <= mapping->menu_mask; ++i) { + u32 menu_value; + + if (!test_bit(i, &mapping->menu_mask)) + continue; + + menu_value = uvc_mapping_get_menu_value(mapping, i); + + if (menu_value == val) + return i; + } + + return val; +} + /* * Extract the bit string specified by mapping->offset and mapping->size * from the little-endian data stored at 'data' and return the result as * a signed 32bit integer. Sign extension will be performed if the mapping * references a signed data type. */ -static s32 uvc_get_le_value(struct uvc_control_mapping *mapping, - u8 query, const u8 *data) +static int uvc_get_le_value(struct uvc_control_mapping *mapping, + u8 query, const void *uvc_in, size_t v4l2_size, + void *v4l2_out) { - int bits = mapping->size; int offset = mapping->offset; + int bits = mapping->size; + const u8 *data = uvc_in; + s32 *out = v4l2_out; s32 value = 0; u8 mask; + if (WARN_ON(v4l2_size != sizeof(s32))) + return -EINVAL; + data += offset / 8; offset &= 7; mask = ((1LL << bits) - 1) << offset; @@ -789,7 +1076,7 @@ static s32 uvc_get_le_value(struct uvc_control_mapping *mapping, while (1) { u8 byte = *data & mask; value |= offset > 0 ? (byte >> offset) : (byte << (-offset)); - bits -= 8 - (offset > 0 ? offset : 0); + bits -= 8 - max(offset, 0); if (bits <= 0) break; @@ -802,28 +1089,58 @@ static s32 uvc_get_le_value(struct uvc_control_mapping *mapping, if (mapping->data_type == UVC_CTRL_DATA_TYPE_SIGNED) value |= -(value & (1 << (mapping->size - 1))); - return value; + /* If it is a menu, convert from uvc to v4l2. */ + if (mapping->v4l2_type != V4L2_CTRL_TYPE_MENU) { + *out = value; + return 0; + } + + switch (query) { + case UVC_GET_CUR: + case UVC_GET_DEF: + *out = uvc_menu_to_v4l2_menu(mapping, value); + return 0; + } + + *out = value; + return 0; } /* * Set the bit string specified by mapping->offset and mapping->size * in the little-endian data stored at 'data' to the value 'value'. */ -static void uvc_set_le_value(struct uvc_control_mapping *mapping, - s32 value, u8 *data) +static int uvc_set_le_value(struct uvc_control_mapping *mapping, + size_t v4l2_size, const void *v4l2_in, + void *uvc_out) { - int bits = mapping->size; int offset = mapping->offset; + int bits = mapping->size; + u8 *data = uvc_out; + s32 value; u8 mask; - /* - * According to the v4l2 spec, writing any value to a button control - * should result in the action belonging to the button control being - * triggered. UVC devices however want to see a 1 written -> override - * value. - */ - if (mapping->v4l2_type == V4L2_CTRL_TYPE_BUTTON) + if (WARN_ON(v4l2_size != sizeof(s32))) + return -EINVAL; + + value = *(s32 *)v4l2_in; + + switch (mapping->v4l2_type) { + case V4L2_CTRL_TYPE_MENU: + value = uvc_mapping_get_menu_value(mapping, value); + break; + case V4L2_CTRL_TYPE_BUTTON: + /* + * According to the v4l2 spec, writing any value to a button + * control should result in the action belonging to the button + * control being triggered. UVC devices however want to see a 1 + * written -> override value. + */ value = -1; + break; + default: + break; + } data += offset / 8; offset &= 7; @@ -835,6 +1152,8 @@ static void uvc_set_le_value(struct uvc_control_mapping *mapping, bits -= 8 - offset; offset = 0; } + + return 0; } /* ------------------------------------------------------------------------ @@ -853,7 +1172,7 @@ static int uvc_entity_match_guid(const struct uvc_entity *entity, static void __uvc_find_control(struct uvc_entity *entity, u32 v4l2_id, struct uvc_control_mapping **mapping, struct uvc_control **control, - int next) + int next, int next_compound) { struct uvc_control *ctrl; struct uvc_control_mapping *map; @@ -868,14 +1187,16 @@ static void __uvc_find_control(struct uvc_entity *entity, u32 v4l2_id, continue; list_for_each_entry(map, &ctrl->info.mappings, list) { - if ((map->id == v4l2_id) && !next) { + if (map->id == v4l2_id && !next && !next_compound) { *control = ctrl; *mapping = map; return; } if ((*mapping == NULL || (*mapping)->id > map->id) && - (map->id > v4l2_id) && next) { + (map->id > v4l2_id) && + (uvc_ctrl_mapping_is_compound(map) ? + next_compound : next)) { *control = ctrl; *mapping = map; } @@ -889,6 +1210,7 @@ static struct uvc_control *uvc_find_control(struct uvc_video_chain *chain, struct uvc_control *ctrl = NULL; struct uvc_entity *entity; int next = v4l2_id & V4L2_CTRL_FLAG_NEXT_CTRL; + int next_compound = v4l2_id & V4L2_CTRL_FLAG_NEXT_COMPOUND; *mapping = NULL; @@ -897,12 +1219,13 @@ static struct uvc_control *uvc_find_control(struct uvc_video_chain *chain, /* Find the control. */ list_for_each_entry(entity, &chain->entities, chain) { - __uvc_find_control(entity, v4l2_id, mapping, &ctrl, next); - if (ctrl && !next) + __uvc_find_control(entity, v4l2_id, mapping, &ctrl, next, + next_compound); + if (ctrl && !next && !next_compound) return ctrl; } - if (ctrl == NULL && !next) + if (!ctrl && !next && !next_compound) uvc_dbg(chain->dev, CONTROL, "Control 0x%08x not found\n", v4l2_id); @@ -966,26 +1289,6 @@ static int uvc_ctrl_populate_cache(struct uvc_video_chain *chain, return 0; } -static s32 __uvc_ctrl_get_value(struct uvc_control_mapping *mapping, - const u8 *data) -{ - s32 value = mapping->get(mapping, UVC_GET_CUR, data); - - if (mapping->v4l2_type == V4L2_CTRL_TYPE_MENU) { - const struct uvc_menu_info *menu = mapping->menu_info; - unsigned int i; - - for (i = 0; i < mapping->menu_count; ++i, ++menu) { - if (menu->value == value) { - value = i; - break; - } - } - } - - return value; -} - static int __uvc_ctrl_load_cur(struct uvc_video_chain *chain, struct uvc_control *ctrl) { @@ -1036,8 +1339,8 @@ static int __uvc_ctrl_get(struct uvc_video_chain *chain, if (ret < 0) return ret; - *value = __uvc_ctrl_get_value(mapping, - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT)); + *value = uvc_mapping_get_s32(mapping, UVC_GET_CUR, + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT)); return 0; } @@ -1045,7 +1348,8 @@ static int __uvc_ctrl_get(struct uvc_video_chain *chain, static int __uvc_query_v4l2_class(struct uvc_video_chain *chain, u32 req_id, u32 found_id) { - bool find_next = req_id & V4L2_CTRL_FLAG_NEXT_CTRL; + bool find_next = req_id & + (V4L2_CTRL_FLAG_NEXT_CTRL | V4L2_CTRL_FLAG_NEXT_COMPOUND); unsigned int i; req_id &= V4L2_CTRL_ID_MASK; @@ -1067,7 +1371,8 @@ static int __uvc_query_v4l2_class(struct uvc_video_chain *chain, u32 req_id, } static int uvc_query_v4l2_class(struct uvc_video_chain *chain, u32 req_id, - u32 found_id, struct v4l2_queryctrl *v4l2_ctrl) + u32 found_id, + struct v4l2_query_ext_ctrl *v4l2_ctrl) { int idx; @@ -1085,11 +1390,58 @@ static int uvc_query_v4l2_class(struct uvc_video_chain *chain, u32 req_id, return 0; } +static bool uvc_ctrl_is_readable(u32 which, struct uvc_control *ctrl, + struct uvc_control_mapping *mapping) +{ + if (which == V4L2_CTRL_WHICH_CUR_VAL) + return !!(ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR); + + if (which == V4L2_CTRL_WHICH_DEF_VAL) + return !!(ctrl->info.flags & UVC_CTRL_FLAG_GET_DEF); + + /* Types with implicit boundaries. */ + switch (mapping->v4l2_type) { + case V4L2_CTRL_TYPE_MENU: + case V4L2_CTRL_TYPE_BOOLEAN: + case V4L2_CTRL_TYPE_BUTTON: + return true; + case V4L2_CTRL_TYPE_BITMASK: + return (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES) || + (ctrl->info.flags & UVC_CTRL_FLAG_GET_MAX); + default: + break; + } + + if (which == V4L2_CTRL_WHICH_MIN_VAL) + return !!(ctrl->info.flags & UVC_CTRL_FLAG_GET_MIN); + + if (which == V4L2_CTRL_WHICH_MAX_VAL) + return !!(ctrl->info.flags & UVC_CTRL_FLAG_GET_MAX); + + return false; +} + +/* + * Check if control @v4l2_id can be accessed by the given control @ioctl + * (VIDIOC_G_EXT_CTRLS, VIDIOC_TRY_EXT_CTRLS or VIDIOC_S_EXT_CTRLS). + * + * For set operations on slave controls, check if the master's value is set to + * manual, either in the others controls set in the same ioctl call, or from + * the master's current value. This catches VIDIOC_S_EXT_CTRLS calls that set + * both the master and slave control, such as for instance setting + * auto_exposure=1, exposure_time_absolute=251. + */ int uvc_ctrl_is_accessible(struct uvc_video_chain *chain, u32 v4l2_id, - bool read) + const struct v4l2_ext_controls *ctrls, + unsigned long ioctl) { + struct uvc_control_mapping *master_map = NULL; + struct uvc_control *master_ctrl = NULL; struct uvc_control_mapping *mapping; struct uvc_control *ctrl; + s32 val; + int ret; + int i; if (__uvc_query_v4l2_class(chain, v4l2_id, 0) >= 0) return -EACCES; @@ -1098,10 +1450,35 @@ int uvc_ctrl_is_accessible(struct uvc_video_chain *chain, u32 v4l2_id, if (!ctrl) return -EINVAL; - if (!(ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR) && read) + if (ioctl == VIDIOC_G_EXT_CTRLS) + return uvc_ctrl_is_readable(ctrls->which, ctrl, mapping); + + if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR)) return -EACCES; - if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR) && !read) + if (ioctl != VIDIOC_S_EXT_CTRLS || !mapping->master_id) + return 0; + + /* + * Iterate backwards in cases where the master control is accessed + * multiple times in the same ioctl. We want the last value. + */ + for (i = ctrls->count - 1; i >= 0; i--) { + if (ctrls->controls[i].id == mapping->master_id) + return ctrls->controls[i].value == + mapping->master_manual ? 0 : -EACCES; + } + + __uvc_find_control(ctrl->entity, mapping->master_id, &master_map, + &master_ctrl, 0, 0); + + if (!master_ctrl || !(master_ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR)) + return 0; + if (WARN_ON(uvc_ctrl_mapping_is_compound(master_map))) + return -EIO; + + ret = __uvc_ctrl_get(chain, master_ctrl, master_map, &val); + if (ret >= 0 && val != mapping->master_manual) return -EACCES; return 0; @@ -1121,66 +1498,60 @@ static const char *uvc_map_get_name(const struct uvc_control_mapping *map) return "Unknown Control"; } -static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, - struct uvc_control *ctrl, - struct uvc_control_mapping *mapping, - struct v4l2_queryctrl *v4l2_ctrl) +static u32 uvc_get_ctrl_bitmap(struct uvc_control *ctrl, + struct uvc_control_mapping *mapping) { - struct uvc_control_mapping *master_map = NULL; - struct uvc_control *master_ctrl = NULL; - const struct uvc_menu_info *menu; - unsigned int i; - - memset(v4l2_ctrl, 0, sizeof(*v4l2_ctrl)); - v4l2_ctrl->id = mapping->id; - v4l2_ctrl->type = mapping->v4l2_type; - strscpy(v4l2_ctrl->name, uvc_map_get_name(mapping), - sizeof(v4l2_ctrl->name)); - v4l2_ctrl->flags = 0; + /* + * Some controls, like CT_AE_MODE_CONTROL, use GET_RES to represent + * the number of bits supported. Those controls do not list GET_MAX + * as supported. + */ + if (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES) + return uvc_mapping_get_s32(mapping, UVC_GET_RES, + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES)); - if (!(ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR)) - v4l2_ctrl->flags |= V4L2_CTRL_FLAG_WRITE_ONLY; - if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR)) - v4l2_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MAX) + return uvc_mapping_get_s32(mapping, UVC_GET_MAX, + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX)); - if (mapping->master_id) - __uvc_find_control(ctrl->entity, mapping->master_id, - &master_map, &master_ctrl, 0); - if (master_ctrl && (master_ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR)) { - s32 val; - int ret = __uvc_ctrl_get(chain, master_ctrl, master_map, &val); - if (ret < 0) - return ret; + return ~0; +} - if (val != mapping->master_manual) - v4l2_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; - } +/* + * Maximum retry count to avoid spurious errors with controls. Increasing this + * value does no seem to produce better results in the tested hardware. + */ +#define MAX_QUERY_RETRIES 2 +static int __uvc_queryctrl_boundaries(struct uvc_video_chain *chain, + struct uvc_control *ctrl, + struct uvc_control_mapping *mapping, + struct v4l2_query_ext_ctrl *v4l2_ctrl) +{ if (!ctrl->cached) { - int ret = uvc_ctrl_populate_cache(chain, ctrl); - if (ret < 0) + unsigned int retries; + int ret; + + for (retries = 0; retries < MAX_QUERY_RETRIES; retries++) { + ret = uvc_ctrl_populate_cache(chain, ctrl); + if (ret != -EIO) + break; + } + + if (ret) return ret; } if (ctrl->info.flags & UVC_CTRL_FLAG_GET_DEF) { - v4l2_ctrl->default_value = mapping->get(mapping, UVC_GET_DEF, - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF)); + v4l2_ctrl->default_value = uvc_mapping_get_s32(mapping, + UVC_GET_DEF, uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF)); } switch (mapping->v4l2_type) { case V4L2_CTRL_TYPE_MENU: - v4l2_ctrl->minimum = 0; - v4l2_ctrl->maximum = mapping->menu_count - 1; + v4l2_ctrl->minimum = ffs(mapping->menu_mask) - 1; + v4l2_ctrl->maximum = fls(mapping->menu_mask) - 1; v4l2_ctrl->step = 1; - - menu = mapping->menu_info; - for (i = 0; i < mapping->menu_count; ++i, ++menu) { - if (menu->value == v4l2_ctrl->default_value) { - v4l2_ctrl->default_value = i; - break; - } - } - return 0; case V4L2_CTRL_TYPE_BOOLEAN: @@ -1195,27 +1566,131 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, v4l2_ctrl->step = 0; return 0; + case V4L2_CTRL_TYPE_BITMASK: + v4l2_ctrl->minimum = 0; + v4l2_ctrl->maximum = uvc_get_ctrl_bitmap(ctrl, mapping); + v4l2_ctrl->step = 0; + return 0; + default: break; } if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MIN) - v4l2_ctrl->minimum = mapping->get(mapping, UVC_GET_MIN, - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN)); + v4l2_ctrl->minimum = uvc_mapping_get_s32(mapping, UVC_GET_MIN, + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN)); + else + v4l2_ctrl->minimum = 0; if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MAX) - v4l2_ctrl->maximum = mapping->get(mapping, UVC_GET_MAX, - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX)); + v4l2_ctrl->maximum = uvc_mapping_get_s32(mapping, UVC_GET_MAX, + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX)); + else + v4l2_ctrl->maximum = 0; if (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES) - v4l2_ctrl->step = mapping->get(mapping, UVC_GET_RES, - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES)); + v4l2_ctrl->step = uvc_mapping_get_s32(mapping, UVC_GET_RES, + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES)); + else + v4l2_ctrl->step = 0; + + return 0; +} + +static size_t uvc_mapping_v4l2_size(struct uvc_control_mapping *mapping) +{ + if (mapping->v4l2_type == V4L2_CTRL_TYPE_RECT) + return sizeof(struct v4l2_rect); + + if (uvc_ctrl_mapping_is_compound(mapping)) + return DIV_ROUND_UP(mapping->size, 8); + + return sizeof(s32); +} + +static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, + struct uvc_control *ctrl, + struct uvc_control_mapping *mapping, + struct v4l2_query_ext_ctrl *v4l2_ctrl) +{ + struct uvc_control_mapping *master_map = NULL; + struct uvc_control *master_ctrl = NULL; + int ret; + + memset(v4l2_ctrl, 0, sizeof(*v4l2_ctrl)); + v4l2_ctrl->id = mapping->id; + v4l2_ctrl->type = mapping->v4l2_type; + strscpy(v4l2_ctrl->name, uvc_map_get_name(mapping), + sizeof(v4l2_ctrl->name)); + v4l2_ctrl->flags = 0; + + if (!(ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR)) + v4l2_ctrl->flags |= V4L2_CTRL_FLAG_WRITE_ONLY; + if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR)) + v4l2_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + if ((ctrl->info.flags & UVC_CTRL_FLAG_GET_MAX) && + (ctrl->info.flags & UVC_CTRL_FLAG_GET_MIN)) + v4l2_ctrl->flags |= V4L2_CTRL_FLAG_HAS_WHICH_MIN_MAX; + + if (mapping->master_id) + __uvc_find_control(ctrl->entity, mapping->master_id, + &master_map, &master_ctrl, 0, 0); + if (master_ctrl && (master_ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR)) { + unsigned int retries; + s32 val; + int ret; + + if (WARN_ON(uvc_ctrl_mapping_is_compound(master_map))) + return -EIO; + + for (retries = 0; retries < MAX_QUERY_RETRIES; retries++) { + ret = __uvc_ctrl_get(chain, master_ctrl, master_map, + &val); + if (!ret) + break; + if (ret < 0 && ret != -EIO) + return ret; + } + + if (ret == -EIO) { + dev_warn_ratelimited(&chain->dev->intf->dev, + "UVC non compliance: Error %d querying master control %x (%s)\n", + ret, master_map->id, + uvc_map_get_name(master_map)); + } else { + if (val != mapping->master_manual) + v4l2_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + } + } + + v4l2_ctrl->elem_size = uvc_mapping_v4l2_size(mapping); + v4l2_ctrl->elems = 1; + + if (v4l2_ctrl->type >= V4L2_CTRL_COMPOUND_TYPES) { + v4l2_ctrl->flags |= V4L2_CTRL_FLAG_HAS_PAYLOAD; + v4l2_ctrl->default_value = 0; + v4l2_ctrl->minimum = 0; + v4l2_ctrl->maximum = 0; + v4l2_ctrl->step = 0; + return 0; + } + + ret = __uvc_queryctrl_boundaries(chain, ctrl, mapping, v4l2_ctrl); + if (ret && !mapping->disabled) { + dev_warn(&chain->dev->intf->dev, + "UVC non compliance: permanently disabling control %x (%s), due to error %d\n", + mapping->id, uvc_map_get_name(mapping), ret); + mapping->disabled = true; + } + + if (mapping->disabled) + v4l2_ctrl->flags |= V4L2_CTRL_FLAG_DISABLED; return 0; } int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, - struct v4l2_queryctrl *v4l2_ctrl) + struct v4l2_query_ext_ctrl *v4l2_ctrl) { struct uvc_control *ctrl; struct uvc_control_mapping *mapping; @@ -1268,17 +1743,20 @@ done: int uvc_query_v4l2_menu(struct uvc_video_chain *chain, struct v4l2_querymenu *query_menu) { - const struct uvc_menu_info *menu_info; struct uvc_control_mapping *mapping; struct uvc_control *ctrl; u32 index = query_menu->index; u32 id = query_menu->id; + const char *name; int ret; memset(query_menu, 0, sizeof(*query_menu)); query_menu->id = id; query_menu->index = index; + if (index >= BITS_PER_TYPE(mapping->menu_mask)) + return -EINVAL; + ret = mutex_lock_interruptible(&chain->ctrl_mutex); if (ret < 0) return -ERESTARTSYS; @@ -1289,16 +1767,13 @@ int uvc_query_v4l2_menu(struct uvc_video_chain *chain, goto done; } - if (query_menu->index >= mapping->menu_count) { + if (!test_bit(query_menu->index, &mapping->menu_mask)) { ret = -EINVAL; goto done; } - menu_info = &mapping->menu_info[query_menu->index]; - - if (mapping->data_type == UVC_CTRL_DATA_TYPE_BITMASK && - (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES)) { - s32 bitmap; + if (mapping->data_type == UVC_CTRL_DATA_TYPE_BITMASK) { + int mask; if (!ctrl->cached) { ret = uvc_ctrl_populate_cache(chain, ctrl); @@ -1306,15 +1781,25 @@ int uvc_query_v4l2_menu(struct uvc_video_chain *chain, goto done; } - bitmap = mapping->get(mapping, UVC_GET_RES, - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES)); - if (!(bitmap & menu_info->value)) { + mask = uvc_mapping_get_menu_value(mapping, query_menu->index); + if (mask < 0) { + ret = mask; + goto done; + } + + if (!(uvc_get_ctrl_bitmap(ctrl, mapping) & mask)) { ret = -EINVAL; goto done; } } - strscpy(query_menu->name, menu_info->name, sizeof(query_menu->name)); + name = uvc_mapping_get_menu_name(mapping, query_menu->index); + if (!name) { + ret = -EINVAL; + goto done; + } + + strscpy(query_menu->name, name, sizeof(query_menu->name)); done: mutex_unlock(&chain->ctrl_mutex); @@ -1331,7 +1816,7 @@ static void uvc_ctrl_fill_event(struct uvc_video_chain *chain, struct uvc_control_mapping *mapping, s32 value, u32 changes) { - struct v4l2_queryctrl v4l2_ctrl; + struct v4l2_query_ext_ctrl v4l2_ctrl; __uvc_query_v4l2_ctrl(chain, ctrl, mapping, &v4l2_ctrl); @@ -1389,16 +1874,62 @@ static void uvc_ctrl_send_slave_event(struct uvc_video_chain *chain, u32 changes = V4L2_EVENT_CTRL_CH_FLAGS; s32 val = 0; - __uvc_find_control(master->entity, slave_id, &mapping, &ctrl, 0); + __uvc_find_control(master->entity, slave_id, &mapping, &ctrl, 0, 0); if (ctrl == NULL) return; - if (__uvc_ctrl_get(chain, ctrl, mapping, &val) == 0) + if (uvc_ctrl_mapping_is_compound(mapping) || + __uvc_ctrl_get(chain, ctrl, mapping, &val) == 0) changes |= V4L2_EVENT_CTRL_CH_VALUE; uvc_ctrl_send_event(chain, handle, ctrl, mapping, val, changes); } +static int uvc_ctrl_set_handle(struct uvc_control *ctrl, struct uvc_fh *handle) +{ + int ret; + + lockdep_assert_held(&handle->chain->ctrl_mutex); + + if (ctrl->handle) { + dev_warn_ratelimited(&handle->stream->dev->intf->dev, + "UVC non compliance: Setting an async control with a pending operation."); + + if (ctrl->handle == handle) + return 0; + + WARN_ON(!ctrl->handle->pending_async_ctrls); + if (ctrl->handle->pending_async_ctrls) + ctrl->handle->pending_async_ctrls--; + ctrl->handle = handle; + ctrl->handle->pending_async_ctrls++; + return 0; + } + + ret = uvc_pm_get(handle->chain->dev); + if (ret) + return ret; + + ctrl->handle = handle; + ctrl->handle->pending_async_ctrls++; + return 0; +} + +static int uvc_ctrl_clear_handle(struct uvc_control *ctrl) +{ + lockdep_assert_held(&ctrl->handle->chain->ctrl_mutex); + + if (WARN_ON(!ctrl->handle->pending_async_ctrls)) { + ctrl->handle = NULL; + return -EINVAL; + } + + ctrl->handle->pending_async_ctrls--; + uvc_pm_put(ctrl->handle->chain->dev); + ctrl->handle = NULL; + return 0; +} + void uvc_ctrl_status_event(struct uvc_video_chain *chain, struct uvc_control *ctrl, const u8 *data) { @@ -1408,11 +1939,20 @@ void uvc_ctrl_status_event(struct uvc_video_chain *chain, mutex_lock(&chain->ctrl_mutex); + /* Flush the control cache, the data might have changed. */ + ctrl->loaded = 0; + handle = ctrl->handle; - ctrl->handle = NULL; + if (handle) + uvc_ctrl_clear_handle(ctrl); list_for_each_entry(mapping, &ctrl->info.mappings, list) { - s32 value = __uvc_ctrl_get_value(mapping, data); + s32 value; + + if (uvc_ctrl_mapping_is_compound(mapping)) + value = 0; + else + value = uvc_mapping_get_s32(mapping, UVC_GET_CUR, data); /* * handle may be NULL here if the device sends auto-update @@ -1442,11 +1982,15 @@ static void uvc_ctrl_status_event_work(struct work_struct *work) uvc_ctrl_status_event(w->chain, w->ctrl, w->data); + /* The barrier is needed to synchronize with uvc_status_stop(). */ + if (smp_load_acquire(&dev->flush_status)) + return; + /* Resubmit the URB. */ w->urb->interval = dev->int_ep->desc.bInterval; ret = usb_submit_urb(w->urb, GFP_KERNEL); if (ret < 0) - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "Failed to resubmit status URB (%d).\n", ret); } @@ -1456,10 +2000,8 @@ bool uvc_ctrl_status_event_async(struct urb *urb, struct uvc_video_chain *chain, struct uvc_device *dev = chain->dev; struct uvc_ctrl_work *w = &dev->async_ctrl; - if (list_empty(&ctrl->info.mappings)) { - ctrl->handle = NULL; + if (list_empty(&ctrl->info.mappings)) return false; - } w->data = data; w->urb = urb; @@ -1485,16 +2027,22 @@ static bool uvc_ctrl_xctrls_has_control(const struct v4l2_ext_control *xctrls, } static void uvc_ctrl_send_events(struct uvc_fh *handle, - const struct v4l2_ext_control *xctrls, unsigned int xctrls_count) + struct uvc_entity *entity, + const struct v4l2_ext_control *xctrls, + unsigned int xctrls_count) { struct uvc_control_mapping *mapping; struct uvc_control *ctrl; - u32 changes = V4L2_EVENT_CTRL_CH_VALUE; unsigned int i; unsigned int j; for (i = 0; i < xctrls_count; ++i) { + u32 changes = V4L2_EVENT_CTRL_CH_VALUE; + s32 value; + ctrl = uvc_find_control(handle->chain, xctrls[i].id, &mapping); + if (ctrl->entity != entity) + continue; if (ctrl->info.flags & UVC_CTRL_FLAG_ASYNCHRONOUS) /* Notification will be sent from an Interrupt event. */ @@ -1518,6 +2066,10 @@ static void uvc_ctrl_send_events(struct uvc_fh *handle, slave_id); } + if (uvc_ctrl_mapping_is_compound(mapping)) + value = 0; + else + value = xctrls[i].value; /* * If the master is being modified in the same transaction * flags may change too. @@ -1528,7 +2080,7 @@ static void uvc_ctrl_send_events(struct uvc_fh *handle, changes |= V4L2_EVENT_CTRL_CH_FLAGS; uvc_ctrl_send_event(handle->chain, handle, ctrl, mapping, - xctrls[i].value, changes); + value, changes); } } @@ -1554,17 +2106,24 @@ static int uvc_ctrl_add_event(struct v4l2_subscribed_event *sev, unsigned elems) goto done; } - list_add_tail(&sev->node, &mapping->ev_subs); if (sev->flags & V4L2_EVENT_SUB_FL_SEND_INITIAL) { struct v4l2_event ev; u32 changes = V4L2_EVENT_CTRL_CH_FLAGS; s32 val = 0; - if (__uvc_ctrl_get(handle->chain, ctrl, mapping, &val) == 0) + ret = uvc_pm_get(handle->chain->dev); + if (ret) + goto done; + + if (uvc_ctrl_mapping_is_compound(mapping) || + __uvc_ctrl_get(handle->chain, ctrl, mapping, &val) == 0) changes |= V4L2_EVENT_CTRL_CH_VALUE; uvc_ctrl_fill_event(handle->chain, &ev, ctrl, mapping, val, changes); + + uvc_pm_put(handle->chain->dev); + /* * Mark the queue as active, allowing this initial event to be * accepted. @@ -1573,6 +2132,8 @@ static int uvc_ctrl_add_event(struct v4l2_subscribed_event *sev, unsigned elems) v4l2_event_queue_fh(sev->fh, &ev); } + list_add_tail(&sev->node, &mapping->ev_subs); + done: mutex_unlock(&handle->chain->ctrl_mutex); return ret; @@ -1626,12 +2187,20 @@ int uvc_ctrl_begin(struct uvc_video_chain *chain) return mutex_lock_interruptible(&chain->ctrl_mutex) ? -ERESTARTSYS : 0; } +/* + * Returns the number of uvc controls that have been correctly set, or a + * negative number if there has been an error. + */ static int uvc_ctrl_commit_entity(struct uvc_device *dev, - struct uvc_entity *entity, int rollback, struct uvc_control **err_ctrl) + struct uvc_fh *handle, + struct uvc_entity *entity, + int rollback, + struct uvc_control **err_ctrl) { + unsigned int processed_ctrls = 0; struct uvc_control *ctrl; unsigned int i; - int ret; + int ret = 0; if (entity == NULL) return 0; @@ -1660,8 +2229,9 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev, dev->intfnum, ctrl->info.selector, uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), ctrl->info.size); - else - ret = 0; + + if (!ret) + processed_ctrls++; if (rollback || ret < 0) memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), @@ -1670,14 +2240,25 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev, ctrl->dirty = 0; - if (ret < 0) { + if (!rollback && handle && !ret && + ctrl->info.flags & UVC_CTRL_FLAG_ASYNCHRONOUS) + ret = uvc_ctrl_set_handle(ctrl, handle); + + if (ret < 0 && !rollback) { if (err_ctrl) *err_ctrl = ctrl; - return ret; + /* + * If we fail to set a control, we need to rollback + * the next ones. + */ + rollback = 1; } } - return 0; + if (ret) + return ret; + + return processed_ctrls; } static int uvc_ctrl_find_ctrl_idx(struct uvc_entity *entity, @@ -1693,7 +2274,7 @@ static int uvc_ctrl_find_ctrl_idx(struct uvc_entity *entity, for (i = 0; i < ctrls->count; i++) { __uvc_find_control(entity, ctrls->controls[i].id, &mapping, - &ctrl_found, 0); + &ctrl_found, 0, 0); if (uvc_control == ctrl_found) return i; } @@ -1707,28 +2288,151 @@ int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback, struct uvc_video_chain *chain = handle->chain; struct uvc_control *err_ctrl; struct uvc_entity *entity; - int ret = 0; + int ret_out = 0; + int ret; /* Find the control. */ list_for_each_entry(entity, &chain->entities, chain) { - ret = uvc_ctrl_commit_entity(chain->dev, entity, rollback, - &err_ctrl); - if (ret < 0) - goto done; + ret = uvc_ctrl_commit_entity(chain->dev, handle, entity, + rollback, &err_ctrl); + if (ret < 0) { + if (ctrls) + ctrls->error_idx = + uvc_ctrl_find_ctrl_idx(entity, ctrls, + err_ctrl); + /* + * When we fail to commit an entity, we need to + * restore the UVC_CTRL_DATA_BACKUP for all the + * controls in the other entities, otherwise our cache + * and the hardware will be out of sync. + */ + rollback = 1; + + ret_out = ret; + } else if (ret > 0 && !rollback) { + uvc_ctrl_send_events(handle, entity, + ctrls->controls, ctrls->count); + } } - if (!rollback) - uvc_ctrl_send_events(handle, ctrls->controls, ctrls->count); -done: - if (ret < 0 && ctrls) - ctrls->error_idx = uvc_ctrl_find_ctrl_idx(entity, ctrls, - err_ctrl); mutex_unlock(&chain->ctrl_mutex); - return ret; + return ret_out; +} + +static int uvc_mapping_get_xctrl_compound(struct uvc_video_chain *chain, + struct uvc_control *ctrl, + struct uvc_control_mapping *mapping, + u32 which, + struct v4l2_ext_control *xctrl) +{ + u8 *data __free(kfree) = NULL; + size_t size; + u8 query; + int ret; + int id; + + switch (which) { + case V4L2_CTRL_WHICH_CUR_VAL: + id = UVC_CTRL_DATA_CURRENT; + query = UVC_GET_CUR; + break; + case V4L2_CTRL_WHICH_MIN_VAL: + id = UVC_CTRL_DATA_MIN; + query = UVC_GET_MIN; + break; + case V4L2_CTRL_WHICH_MAX_VAL: + id = UVC_CTRL_DATA_MAX; + query = UVC_GET_MAX; + break; + case V4L2_CTRL_WHICH_DEF_VAL: + id = UVC_CTRL_DATA_DEF; + query = UVC_GET_DEF; + break; + default: + return -EINVAL; + } + + size = uvc_mapping_v4l2_size(mapping); + if (xctrl->size < size) { + xctrl->size = size; + return -ENOSPC; + } + + data = kmalloc(size, GFP_KERNEL); + if (!data) + return -ENOMEM; + + if (which == V4L2_CTRL_WHICH_CUR_VAL) + ret = __uvc_ctrl_load_cur(chain, ctrl); + else + ret = uvc_ctrl_populate_cache(chain, ctrl); + + if (ret < 0) + return ret; + + ret = mapping->get(mapping, query, uvc_ctrl_data(ctrl, id), size, data); + if (ret < 0) + return ret; + + /* + * v4l2_ext_control does not have enough room to fit a compound control. + * Instead, the value is in the user memory at xctrl->ptr. The v4l2 + * ioctl helper does not copy it for us. + */ + return copy_to_user(xctrl->ptr, data, size) ? -EFAULT : 0; +} + +static int uvc_mapping_get_xctrl_std(struct uvc_video_chain *chain, + struct uvc_control *ctrl, + struct uvc_control_mapping *mapping, + u32 which, struct v4l2_ext_control *xctrl) +{ + struct v4l2_query_ext_ctrl qec; + int ret; + + switch (which) { + case V4L2_CTRL_WHICH_CUR_VAL: + return __uvc_ctrl_get(chain, ctrl, mapping, &xctrl->value); + case V4L2_CTRL_WHICH_DEF_VAL: + case V4L2_CTRL_WHICH_MIN_VAL: + case V4L2_CTRL_WHICH_MAX_VAL: + break; + default: + return -EINVAL; + } + + ret = __uvc_queryctrl_boundaries(chain, ctrl, mapping, &qec); + if (ret < 0) + return ret; + + switch (which) { + case V4L2_CTRL_WHICH_DEF_VAL: + xctrl->value = qec.default_value; + break; + case V4L2_CTRL_WHICH_MIN_VAL: + xctrl->value = qec.minimum; + break; + case V4L2_CTRL_WHICH_MAX_VAL: + xctrl->value = qec.maximum; + break; + } + + return 0; } -int uvc_ctrl_get(struct uvc_video_chain *chain, - struct v4l2_ext_control *xctrl) +static int uvc_mapping_get_xctrl(struct uvc_video_chain *chain, + struct uvc_control *ctrl, + struct uvc_control_mapping *mapping, + u32 which, struct v4l2_ext_control *xctrl) +{ + if (uvc_ctrl_mapping_is_compound(mapping)) + return uvc_mapping_get_xctrl_compound(chain, ctrl, mapping, + which, xctrl); + return uvc_mapping_get_xctrl_std(chain, ctrl, mapping, which, xctrl); +} + +int uvc_ctrl_get(struct uvc_video_chain *chain, u32 which, + struct v4l2_ext_control *xctrl) { struct uvc_control *ctrl; struct uvc_control_mapping *mapping; @@ -1737,34 +2441,23 @@ int uvc_ctrl_get(struct uvc_video_chain *chain, return -EACCES; ctrl = uvc_find_control(chain, xctrl->id, &mapping); - if (ctrl == NULL) + if (!ctrl) return -EINVAL; - return __uvc_ctrl_get(chain, ctrl, mapping, &xctrl->value); + return uvc_mapping_get_xctrl(chain, ctrl, mapping, which, xctrl); } -int uvc_ctrl_set(struct uvc_fh *handle, - struct v4l2_ext_control *xctrl) +static int uvc_ctrl_clamp(struct uvc_video_chain *chain, + struct uvc_control *ctrl, + struct uvc_control_mapping *mapping, + s32 *value_in_out) { - struct uvc_video_chain *chain = handle->chain; - struct uvc_control *ctrl; - struct uvc_control_mapping *mapping; - s32 value; + s32 value = *value_in_out; u32 step; s32 min; s32 max; int ret; - if (__uvc_query_v4l2_class(chain, xctrl->id, 0) >= 0) - return -EACCES; - - ctrl = uvc_find_control(chain, xctrl->id, &mapping); - if (ctrl == NULL) - return -EINVAL; - if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR)) - return -EACCES; - - /* Clamp out of range values. */ switch (mapping->v4l2_type) { case V4L2_CTRL_TYPE_INTEGER: if (!ctrl->cached) { @@ -1773,59 +2466,126 @@ int uvc_ctrl_set(struct uvc_fh *handle, return ret; } - min = mapping->get(mapping, UVC_GET_MIN, - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN)); - max = mapping->get(mapping, UVC_GET_MAX, - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX)); - step = mapping->get(mapping, UVC_GET_RES, - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES)); + min = uvc_mapping_get_s32(mapping, UVC_GET_MIN, + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN)); + max = uvc_mapping_get_s32(mapping, UVC_GET_MAX, + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX)); + step = uvc_mapping_get_s32(mapping, UVC_GET_RES, + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES)); if (step == 0) step = 1; - xctrl->value = min + DIV_ROUND_CLOSEST((u32)(xctrl->value - min), - step) * step; + value = min + DIV_ROUND_CLOSEST((u32)(value - min), step) * step; if (mapping->data_type == UVC_CTRL_DATA_TYPE_SIGNED) - xctrl->value = clamp(xctrl->value, min, max); + value = clamp(value, min, max); else - xctrl->value = clamp_t(u32, xctrl->value, min, max); - value = xctrl->value; - break; + value = clamp_t(u32, value, min, max); + *value_in_out = value; + return 0; + + case V4L2_CTRL_TYPE_BITMASK: + if (!ctrl->cached) { + ret = uvc_ctrl_populate_cache(chain, ctrl); + if (ret < 0) + return ret; + } + + value &= uvc_get_ctrl_bitmap(ctrl, mapping); + *value_in_out = value; + return 0; case V4L2_CTRL_TYPE_BOOLEAN: - xctrl->value = clamp(xctrl->value, 0, 1); - value = xctrl->value; - break; + *value_in_out = clamp(value, 0, 1); + return 0; case V4L2_CTRL_TYPE_MENU: - if (xctrl->value < 0 || xctrl->value >= mapping->menu_count) + if (value < (ffs(mapping->menu_mask) - 1) || + value > (fls(mapping->menu_mask) - 1)) return -ERANGE; - value = mapping->menu_info[xctrl->value].value; + + if (!test_bit(value, &mapping->menu_mask)) + return -EINVAL; /* * Valid menu indices are reported by the GET_RES request for * UVC controls that support it. */ - if (mapping->data_type == UVC_CTRL_DATA_TYPE_BITMASK && - (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES)) { + if (mapping->data_type == UVC_CTRL_DATA_TYPE_BITMASK) { + int val = uvc_mapping_get_menu_value(mapping, value); if (!ctrl->cached) { ret = uvc_ctrl_populate_cache(chain, ctrl); if (ret < 0) return ret; } - step = mapping->get(mapping, UVC_GET_RES, - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES)); - if (!(step & value)) + if (!(uvc_get_ctrl_bitmap(ctrl, mapping) & val)) return -EINVAL; } - - break; + return 0; default: - value = xctrl->value; - break; + return 0; } + return 0; +} + +static int uvc_mapping_set_xctrl_compound(struct uvc_control *ctrl, + struct uvc_control_mapping *mapping, + struct v4l2_ext_control *xctrl) +{ + u8 *data __free(kfree) = NULL; + size_t size = uvc_mapping_v4l2_size(mapping); + + if (xctrl->size != size) + return -EINVAL; + + /* + * v4l2_ext_control does not have enough room to fit a compound control. + * Instead, the value is in the user memory at xctrl->ptr. The v4l2 + * ioctl helper does not copy it for us. + */ + data = memdup_user(xctrl->ptr, size); + if (IS_ERR(data)) + return PTR_ERR(data); + + return mapping->set(mapping, size, data, + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT)); +} + +static int uvc_mapping_set_xctrl(struct uvc_control *ctrl, + struct uvc_control_mapping *mapping, + struct v4l2_ext_control *xctrl) +{ + if (uvc_ctrl_mapping_is_compound(mapping)) + return uvc_mapping_set_xctrl_compound(ctrl, mapping, xctrl); + + uvc_mapping_set_s32(mapping, xctrl->value, + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT)); + return 0; +} + +int uvc_ctrl_set(struct uvc_fh *handle, struct v4l2_ext_control *xctrl) +{ + struct uvc_video_chain *chain = handle->chain; + struct uvc_control_mapping *mapping; + struct uvc_control *ctrl; + int ret; + + lockdep_assert_held(&chain->ctrl_mutex); + + if (__uvc_query_v4l2_class(chain, xctrl->id, 0) >= 0) + return -EACCES; + + ctrl = uvc_find_control(chain, xctrl->id, &mapping); + if (!ctrl) + return -EINVAL; + if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR)) + return -EACCES; + + ret = uvc_ctrl_clamp(chain, ctrl, mapping, &xctrl->value); + if (ret) + return ret; /* * If the mapping doesn't span the whole UVC control, the current value * needs to be loaded from the device to perform the read-modify-write @@ -1844,11 +2604,9 @@ int uvc_ctrl_set(struct uvc_fh *handle, ctrl->info.size); } - mapping->set(mapping, value, - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT)); - - if (ctrl->info.flags & UVC_CTRL_FLAG_ASYNCHRONOUS) - ctrl->handle = handle; + ret = uvc_mapping_set_xctrl(ctrl, mapping, xctrl); + if (ret) + return ret; ctrl->dirty = 1; ctrl->modified = 1; @@ -1879,7 +2637,13 @@ static int uvc_ctrl_get_flags(struct uvc_device *dev, else ret = uvc_query_ctrl(dev, UVC_GET_INFO, ctrl->entity->id, dev->intfnum, info->selector, data, 1); - if (!ret) + + if (!ret) { + info->flags &= ~(UVC_CTRL_FLAG_GET_CUR | + UVC_CTRL_FLAG_SET_CUR | + UVC_CTRL_FLAG_AUTO_UPDATE | + UVC_CTRL_FLAG_ASYNCHRONOUS); + info->flags |= (data[0] & UVC_CONTROL_CAP_GET ? UVC_CTRL_FLAG_GET_CUR : 0) | (data[0] & UVC_CONTROL_CAP_SET ? @@ -1888,6 +2652,7 @@ static int uvc_ctrl_get_flags(struct uvc_device *dev, UVC_CTRL_FLAG_AUTO_UPDATE : 0) | (data[0] & UVC_CONTROL_CAP_ASYNCHRONOUS ? UVC_CTRL_FLAG_ASYNCHRONOUS : 0); + } kfree(data); return ret; @@ -2015,7 +2780,7 @@ static int uvc_ctrl_init_xu_ctrl(struct uvc_device *dev, int uvc_xu_ctrl_query(struct uvc_video_chain *chain, struct uvc_xu_control_query *xqry) { - struct uvc_entity *entity; + struct uvc_entity *entity, *iter; struct uvc_control *ctrl; unsigned int i; bool found; @@ -2025,16 +2790,16 @@ int uvc_xu_ctrl_query(struct uvc_video_chain *chain, int ret; /* Find the extension unit. */ - found = false; - list_for_each_entry(entity, &chain->entities, chain) { - if (UVC_ENTITY_TYPE(entity) == UVC_VC_EXTENSION_UNIT && - entity->id == xqry->unit) { - found = true; + entity = NULL; + list_for_each_entry(iter, &chain->entities, chain) { + if (UVC_ENTITY_TYPE(iter) == UVC_VC_EXTENSION_UNIT && + iter->id == xqry->unit) { + entity = iter; break; } } - if (!found) { + if (!entity) { uvc_dbg(chain->dev, CONTROL, "Extension unit %u not found\n", xqry->unit); return -ENOENT; @@ -2164,14 +2929,14 @@ int uvc_ctrl_restore_values(struct uvc_device *dev) if (!ctrl->initialized || !ctrl->modified || (ctrl->info.flags & UVC_CTRL_FLAG_RESTORE) == 0) continue; - dev_dbg(&dev->udev->dev, + dev_dbg(&dev->intf->dev, "restoring control %pUl/%u/%u\n", ctrl->info.entity, ctrl->info.index, ctrl->info.selector); ctrl->dirty = 1; } - ret = uvc_ctrl_commit_entity(dev, entity, 0, NULL); + ret = uvc_ctrl_commit_entity(dev, NULL, entity, 0, NULL); if (ret < 0) return ret; } @@ -2216,34 +2981,52 @@ static int __uvc_ctrl_add_mapping(struct uvc_video_chain *chain, struct uvc_control_mapping *map; unsigned int size; unsigned int i; + int ret; /* - * Most mappings come from static kernel data and need to be duplicated. + * Most mappings come from static kernel data, and need to be duplicated. * Mappings that come from userspace will be unnecessarily duplicated, * this could be optimized. */ map = kmemdup(mapping, sizeof(*mapping), GFP_KERNEL); - if (map == NULL) + if (!map) return -ENOMEM; + map->name = NULL; + map->menu_names = NULL; + map->menu_mapping = NULL; + /* For UVCIOC_CTRL_MAP custom control */ if (mapping->name) { map->name = kstrdup(mapping->name, GFP_KERNEL); - if (!map->name) { - kfree(map); - return -ENOMEM; - } + if (!map->name) + goto err_nomem; } INIT_LIST_HEAD(&map->ev_subs); - size = sizeof(*mapping->menu_info) * mapping->menu_count; - map->menu_info = kmemdup(mapping->menu_info, size, GFP_KERNEL); - if (map->menu_info == NULL) { - kfree(map->name); - kfree(map); - return -ENOMEM; - } + if (mapping->menu_mapping && mapping->menu_mask) { + size = sizeof(mapping->menu_mapping[0]) + * fls(mapping->menu_mask); + map->menu_mapping = kmemdup(mapping->menu_mapping, size, + GFP_KERNEL); + if (!map->menu_mapping) + goto err_nomem; + } + if (mapping->menu_names && mapping->menu_mask) { + size = sizeof(mapping->menu_names[0]) + * fls(mapping->menu_mask); + map->menu_names = kmemdup(mapping->menu_names, size, + GFP_KERNEL); + if (!map->menu_names) + goto err_nomem; + } + + if (uvc_ctrl_mapping_is_compound(map)) + if (WARN_ON(!map->set || !map->get)) { + ret = -EIO; + goto free_mem; + } if (map->get == NULL) map->get = uvc_get_le_value; @@ -2264,6 +3047,15 @@ static int __uvc_ctrl_add_mapping(struct uvc_video_chain *chain, ctrl->info.selector); return 0; + +err_nomem: + ret = -ENOMEM; +free_mem: + kfree(map->menu_names); + kfree(map->menu_mapping); + kfree(map->name); + kfree(map); + return ret; } int uvc_ctrl_add_mapping(struct uvc_video_chain *chain, @@ -2421,19 +3213,8 @@ static void uvc_ctrl_prune_entity(struct uvc_device *dev, static void uvc_ctrl_init_ctrl(struct uvc_video_chain *chain, struct uvc_control *ctrl) { - const struct uvc_control_mapping *mappings; - unsigned int num_mappings; unsigned int i; - /* - * XU controls initialization requires querying the device for control - * information. As some buggy UVC devices will crash when queried - * repeatedly in a tight loop, delay XU controls initialization until - * first use. - */ - if (UVC_ENTITY_TYPE(ctrl->entity) == UVC_VC_EXTENSION_UNIT) - return; - for (i = 0; i < ARRAY_SIZE(uvc_ctrls); ++i) { const struct uvc_control_info *info = &uvc_ctrls[i]; @@ -2454,55 +3235,22 @@ static void uvc_ctrl_init_ctrl(struct uvc_video_chain *chain, if (!ctrl->initialized) return; - /* - * First check if the device provides a custom mapping for this control, - * used to override standard mappings for non-conformant devices. Don't - * process standard mappings if a custom mapping is found. This - * mechanism doesn't support combining standard and custom mappings for - * a single control. - */ - if (chain->dev->info->mappings) { - bool custom = false; - - for (i = 0; chain->dev->info->mappings[i]; ++i) { - const struct uvc_control_mapping *mapping = - chain->dev->info->mappings[i]; - - if (uvc_entity_match_guid(ctrl->entity, mapping->entity) && - ctrl->info.selector == mapping->selector) { - __uvc_ctrl_add_mapping(chain, ctrl, mapping); - custom = true; - } - } - - if (custom) - return; - } - - /* Process common mappings next. */ + /* Process common mappings. */ for (i = 0; i < ARRAY_SIZE(uvc_ctrl_mappings); ++i) { const struct uvc_control_mapping *mapping = &uvc_ctrl_mappings[i]; - if (uvc_entity_match_guid(ctrl->entity, mapping->entity) && - ctrl->info.selector == mapping->selector) - __uvc_ctrl_add_mapping(chain, ctrl, mapping); - } - - /* Finally process version-specific mappings. */ - if (chain->dev->uvc_version < 0x0150) { - mappings = uvc_ctrl_mappings_uvc11; - num_mappings = ARRAY_SIZE(uvc_ctrl_mappings_uvc11); - } else { - mappings = uvc_ctrl_mappings_uvc15; - num_mappings = ARRAY_SIZE(uvc_ctrl_mappings_uvc15); - } + if (!uvc_entity_match_guid(ctrl->entity, mapping->entity) || + ctrl->info.selector != mapping->selector) + continue; - for (i = 0; i < num_mappings; ++i) { - const struct uvc_control_mapping *mapping = &mappings[i]; + /* Let the device provide a custom mapping. */ + if (mapping->filter_mapping) { + mapping = mapping->filter_mapping(chain, ctrl); + if (!mapping) + continue; + } - if (uvc_entity_match_guid(ctrl->entity, mapping->entity) && - ctrl->info.selector == mapping->selector) - __uvc_ctrl_add_mapping(chain, ctrl, mapping); + __uvc_ctrl_add_mapping(chain, ctrl, mapping); } } @@ -2581,6 +3329,30 @@ int uvc_ctrl_init_device(struct uvc_device *dev) return 0; } +void uvc_ctrl_cleanup_fh(struct uvc_fh *handle) +{ + struct uvc_entity *entity; + + guard(mutex)(&handle->chain->ctrl_mutex); + + if (!handle->pending_async_ctrls) + return; + + list_for_each_entry(entity, &handle->chain->dev->entities, list) { + for (unsigned int i = 0; i < entity->ncontrols; ++i) { + if (entity->controls[i].handle != handle) + continue; + uvc_ctrl_clear_handle(&entity->controls[i]); + } + } + + if (!WARN_ON(handle->pending_async_ctrls)) + return; + + for (unsigned int i = 0; i < handle->pending_async_ctrls; i++) + uvc_pm_put(handle->stream->dev); +} + /* * Cleanup device controls. */ @@ -2591,7 +3363,8 @@ static void uvc_ctrl_cleanup_mappings(struct uvc_device *dev, list_for_each_entry_safe(mapping, nm, &ctrl->info.mappings, list) { list_del(&mapping->list); - kfree(mapping->menu_info); + kfree(mapping->menu_names); + kfree(mapping->menu_mapping); kfree(mapping->name); kfree(mapping); } diff --git a/drivers/media/usb/uvc/uvc_debugfs.c b/drivers/media/usb/uvc/uvc_debugfs.c index 1a1258d4ffca..14fa41cb8148 100644 --- a/drivers/media/usb/uvc/uvc_debugfs.c +++ b/drivers/media/usb/uvc/uvc_debugfs.c @@ -59,7 +59,6 @@ static int uvc_debugfs_stats_release(struct inode *inode, struct file *file) static const struct file_operations uvc_debugfs_stats_fops = { .owner = THIS_MODULE, .open = uvc_debugfs_stats_open, - .llseek = no_llseek, .read = uvc_debugfs_stats_read, .release = uvc_debugfs_stats_release, }; diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index e4bcb5011360..ee4f54d68349 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -7,20 +7,22 @@ */ #include <linux/atomic.h> +#include <linux/bits.h> #include <linux/gpio/consumer.h> #include <linux/kernel.h> #include <linux/list.h> #include <linux/module.h> #include <linux/slab.h> #include <linux/usb.h> +#include <linux/usb/quirks.h> +#include <linux/usb/uvc.h> #include <linux/videodev2.h> #include <linux/vmalloc.h> #include <linux/wait.h> -#include <asm/unaligned.h> +#include <linux/unaligned.h> #include <media/v4l2-common.h> #include <media/v4l2-ioctl.h> -#include <media/v4l2-uvc.h> #include "uvcvideo.h" @@ -30,11 +32,13 @@ unsigned int uvc_clock_param = CLOCK_MONOTONIC; unsigned int uvc_hw_timestamps_param; -unsigned int uvc_no_drop_param; +unsigned int uvc_no_drop_param = 1; static unsigned int uvc_quirks_param = -1; unsigned int uvc_dbg_param; unsigned int uvc_timeout_param = UVC_CTRL_STREAMING_TIMEOUT; +static struct usb_driver uvc_driver; + /* ------------------------------------------------------------------------ * Utility functions */ @@ -133,6 +137,9 @@ struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id) { struct uvc_entity *entity; + if (id == UVC_INVALID_ENTITY_ID) + return NULL; + list_for_each_entry(entity, &dev->entities, list) { if (entity->id == id) return entity; @@ -160,13 +167,26 @@ static struct uvc_entity *uvc_entity_by_reference(struct uvc_device *dev, static struct uvc_streaming *uvc_stream_by_id(struct uvc_device *dev, int id) { - struct uvc_streaming *stream; + struct uvc_streaming *stream, *last_stream; + unsigned int count = 0; list_for_each_entry(stream, &dev->streams, list) { + count += 1; + last_stream = stream; if (stream->header.bTerminalLink == id) return stream; } + /* + * If the streaming entity is referenced by an invalid ID, notify the + * user and use heuristics to guess the correct entity. + */ + if (count == 1 && id == UVC_INVALID_ENTITY_ID) { + dev_warn(&dev->intf->dev, + "UVC non compliance: Invalid USB header. The streaming entity has an invalid ID, guessing the correct one."); + return last_stream; + } + return NULL; } @@ -179,11 +199,9 @@ static void uvc_stream_delete(struct uvc_streaming *stream) if (stream->async_wq) destroy_workqueue(stream->async_wq); - mutex_destroy(&stream->mutex); - usb_put_intf(stream->intf); - kfree(stream->format); + kfree(stream->formats); kfree(stream->header.bmaControls); kfree(stream); } @@ -197,8 +215,6 @@ static struct uvc_streaming *uvc_stream_new(struct uvc_device *dev, if (stream == NULL) return NULL; - mutex_init(&stream->mutex); - stream->dev = dev; stream->intf = usb_get_intf(intf); stream->intfnum = intf->cur_altsetting->desc.bInterfaceNumber; @@ -218,22 +234,134 @@ static struct uvc_streaming *uvc_stream_new(struct uvc_device *dev, * Descriptors parsing */ +static int uvc_parse_frame(struct uvc_device *dev, + struct uvc_streaming *streaming, + struct uvc_format *format, struct uvc_frame *frame, + u32 **intervals, u8 ftype, int width_multiplier, + const unsigned char *buffer, int buflen) +{ + struct usb_host_interface *alts = streaming->intf->cur_altsetting; + unsigned int maxIntervalIndex; + unsigned int interval; + unsigned int i, n; + + if (ftype != UVC_VS_FRAME_FRAME_BASED) + n = buflen > 25 ? buffer[25] : 0; + else + n = buflen > 21 ? buffer[21] : 0; + + n = n ? n : 3; + + if (buflen < 26 + 4 * n) { + uvc_dbg(dev, DESCR, + "device %d videostreaming interface %d FRAME error\n", + dev->udev->devnum, alts->desc.bInterfaceNumber); + return -EINVAL; + } + + frame->bFrameIndex = buffer[3]; + frame->bmCapabilities = buffer[4]; + frame->wWidth = get_unaligned_le16(&buffer[5]) * width_multiplier; + frame->wHeight = get_unaligned_le16(&buffer[7]); + frame->dwMinBitRate = get_unaligned_le32(&buffer[9]); + frame->dwMaxBitRate = get_unaligned_le32(&buffer[13]); + if (ftype != UVC_VS_FRAME_FRAME_BASED) { + frame->dwMaxVideoFrameBufferSize = + get_unaligned_le32(&buffer[17]); + frame->dwDefaultFrameInterval = + get_unaligned_le32(&buffer[21]); + frame->bFrameIntervalType = buffer[25]; + } else { + frame->dwMaxVideoFrameBufferSize = 0; + frame->dwDefaultFrameInterval = + get_unaligned_le32(&buffer[17]); + frame->bFrameIntervalType = buffer[21]; + } + + /* + * Copy the frame intervals. + * + * Some bogus devices report dwMinFrameInterval equal to + * dwMaxFrameInterval and have dwFrameIntervalStep set to zero. Setting + * all null intervals to 1 fixes the problem and some other divisions + * by zero that could happen. + */ + frame->dwFrameInterval = *intervals; + + for (i = 0; i < n; ++i) { + interval = get_unaligned_le32(&buffer[26 + 4 * i]); + (*intervals)[i] = interval ? interval : 1; + } + + /* + * Apply more fixes, quirks and workarounds to handle incorrect or + * broken descriptors. + */ + + /* + * Several UVC chipsets screw up dwMaxVideoFrameBufferSize completely. + * Observed behaviours range from setting the value to 1.1x the actual + * frame size to hardwiring the 16 low bits to 0. This results in a + * higher than necessary memory usage as well as a wrong image size + * information. For uncompressed formats this can be fixed by computing + * the value from the frame size. + */ + if (!(format->flags & UVC_FMT_FLAG_COMPRESSED)) + frame->dwMaxVideoFrameBufferSize = format->bpp * frame->wWidth + * frame->wHeight / 8; + + /* + * Clamp the default frame interval to the boundaries. A zero + * bFrameIntervalType value indicates a continuous frame interval + * range, with dwFrameInterval[0] storing the minimum value and + * dwFrameInterval[1] storing the maximum value. + */ + maxIntervalIndex = frame->bFrameIntervalType ? n - 1 : 1; + frame->dwDefaultFrameInterval = + clamp(frame->dwDefaultFrameInterval, + frame->dwFrameInterval[0], + frame->dwFrameInterval[maxIntervalIndex]); + + /* + * Some devices report frame intervals that are not functional. If the + * corresponding quirk is set, restrict operation to the first interval + * only. + */ + if (dev->quirks & UVC_QUIRK_RESTRICT_FRAME_RATE) { + frame->bFrameIntervalType = 1; + (*intervals)[0] = frame->dwDefaultFrameInterval; + } + + uvc_dbg(dev, DESCR, "- %ux%u (%u.%u fps)\n", + frame->wWidth, frame->wHeight, + 10000000 / frame->dwDefaultFrameInterval, + (100000000 / frame->dwDefaultFrameInterval) % 10); + + *intervals += n; + + return buffer[0]; +} + static int uvc_parse_format(struct uvc_device *dev, struct uvc_streaming *streaming, struct uvc_format *format, - u32 **intervals, unsigned char *buffer, int buflen) + struct uvc_frame *frames, u32 **intervals, const unsigned char *buffer, + int buflen) { - struct usb_interface *intf = streaming->intf; - struct usb_host_interface *alts = intf->cur_altsetting; - struct uvc_format_desc *fmtdesc; + struct usb_host_interface *alts = streaming->intf->cur_altsetting; + const struct uvc_format_desc *fmtdesc; struct uvc_frame *frame; const unsigned char *start = buffer; unsigned int width_multiplier = 1; - unsigned int interval; unsigned int i, n; u8 ftype; + int ret; + + if (buflen < 4) + return -EINVAL; format->type = buffer[2]; format->index = buffer[3]; + format->frames = frames; switch (buffer[2]) { case UVC_VS_FORMAT_UNCOMPRESSED: @@ -250,18 +378,17 @@ static int uvc_parse_format(struct uvc_device *dev, /* Find the format descriptor from its GUID. */ fmtdesc = uvc_format_by_guid(&buffer[5]); - if (fmtdesc != NULL) { - strscpy(format->name, fmtdesc->name, - sizeof(format->name)); - format->fcc = fmtdesc->fcc; - } else { + if (!fmtdesc) { + /* + * Unknown video formats are not fatal errors, the + * caller will skip this descriptor. + */ dev_info(&streaming->intf->dev, "Unknown video format %pUl\n", &buffer[5]); - snprintf(format->name, sizeof(format->name), "%pUl\n", - &buffer[5]); - format->fcc = 0; + return 0; } + format->fcc = fmtdesc->fcc; format->bpp = buffer[21]; /* @@ -270,8 +397,6 @@ static int uvc_parse_format(struct uvc_device *dev, */ if (dev->quirks & UVC_QUIRK_FORCE_Y8) { if (format->fcc == V4L2_PIX_FMT_YUYV) { - strscpy(format->name, "Greyscale 8-bit (Y8 )", - sizeof(format->name)); format->fcc = V4L2_PIX_FMT_GREY; format->bpp = 8; width_multiplier = 2; @@ -312,7 +437,6 @@ static int uvc_parse_format(struct uvc_device *dev, return -EINVAL; } - strscpy(format->name, "MJPEG", sizeof(format->name)); format->fcc = V4L2_PIX_FMT_MJPEG; format->flags = UVC_FMT_FLAG_COMPRESSED; format->bpp = 0; @@ -328,17 +452,7 @@ static int uvc_parse_format(struct uvc_device *dev, return -EINVAL; } - switch (buffer[8] & 0x7f) { - case 0: - strscpy(format->name, "SD-DV", sizeof(format->name)); - break; - case 1: - strscpy(format->name, "SDL-DV", sizeof(format->name)); - break; - case 2: - strscpy(format->name, "HD-DV", sizeof(format->name)); - break; - default: + if ((buffer[8] & 0x7f) > 2) { uvc_dbg(dev, DESCR, "device %d videostreaming interface %d: unknown DV format %u\n", dev->udev->devnum, @@ -346,17 +460,14 @@ static int uvc_parse_format(struct uvc_device *dev, return -EINVAL; } - strlcat(format->name, buffer[8] & (1 << 7) ? " 60Hz" : " 50Hz", - sizeof(format->name)); - format->fcc = V4L2_PIX_FMT_DV; format->flags = UVC_FMT_FLAG_COMPRESSED | UVC_FMT_FLAG_STREAM; format->bpp = 0; ftype = 0; /* Create a dummy frame descriptor. */ - frame = &format->frame[0]; - memset(&format->frame[0], 0, sizeof(format->frame[0])); + frame = &frames[0]; + memset(frame, 0, sizeof(*frame)); frame->bFrameIntervalType = 1; frame->dwDefaultFrameInterval = 1; frame->dwFrameInterval = *intervals; @@ -375,7 +486,7 @@ static int uvc_parse_format(struct uvc_device *dev, return -EINVAL; } - uvc_dbg(dev, DESCR, "Found format %s\n", format->name); + uvc_dbg(dev, DESCR, "Found format %p4cc", &format->fcc); buflen -= buffer[0]; buffer += buffer[0]; @@ -384,93 +495,19 @@ static int uvc_parse_format(struct uvc_device *dev, * Parse the frame descriptors. Only uncompressed, MJPEG and frame * based formats have frame descriptors. */ - while (buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE && - buffer[2] == ftype) { - frame = &format->frame[format->nframes]; - if (ftype != UVC_VS_FRAME_FRAME_BASED) - n = buflen > 25 ? buffer[25] : 0; - else - n = buflen > 21 ? buffer[21] : 0; - - n = n ? n : 3; - - if (buflen < 26 + 4*n) { - uvc_dbg(dev, DESCR, - "device %d videostreaming interface %d FRAME error\n", - dev->udev->devnum, - alts->desc.bInterfaceNumber); - return -EINVAL; - } - - frame->bFrameIndex = buffer[3]; - frame->bmCapabilities = buffer[4]; - frame->wWidth = get_unaligned_le16(&buffer[5]) - * width_multiplier; - frame->wHeight = get_unaligned_le16(&buffer[7]); - frame->dwMinBitRate = get_unaligned_le32(&buffer[9]); - frame->dwMaxBitRate = get_unaligned_le32(&buffer[13]); - if (ftype != UVC_VS_FRAME_FRAME_BASED) { - frame->dwMaxVideoFrameBufferSize = - get_unaligned_le32(&buffer[17]); - frame->dwDefaultFrameInterval = - get_unaligned_le32(&buffer[21]); - frame->bFrameIntervalType = buffer[25]; - } else { - frame->dwMaxVideoFrameBufferSize = 0; - frame->dwDefaultFrameInterval = - get_unaligned_le32(&buffer[17]); - frame->bFrameIntervalType = buffer[21]; - } - frame->dwFrameInterval = *intervals; - - /* - * Several UVC chipsets screw up dwMaxVideoFrameBufferSize - * completely. Observed behaviours range from setting the - * value to 1.1x the actual frame size to hardwiring the - * 16 low bits to 0. This results in a higher than necessary - * memory usage as well as a wrong image size information. For - * uncompressed formats this can be fixed by computing the - * value from the frame size. - */ - if (!(format->flags & UVC_FMT_FLAG_COMPRESSED)) - frame->dwMaxVideoFrameBufferSize = format->bpp - * frame->wWidth * frame->wHeight / 8; - - /* - * Some bogus devices report dwMinFrameInterval equal to - * dwMaxFrameInterval and have dwFrameIntervalStep set to - * zero. Setting all null intervals to 1 fixes the problem and - * some other divisions by zero that could happen. - */ - for (i = 0; i < n; ++i) { - interval = get_unaligned_le32(&buffer[26+4*i]); - *(*intervals)++ = interval ? interval : 1; - } - - /* - * Make sure that the default frame interval stays between - * the boundaries. - */ - n -= frame->bFrameIntervalType ? 1 : 2; - frame->dwDefaultFrameInterval = - min(frame->dwFrameInterval[n], - max(frame->dwFrameInterval[0], - frame->dwDefaultFrameInterval)); - - if (dev->quirks & UVC_QUIRK_RESTRICT_FRAME_RATE) { - frame->bFrameIntervalType = 1; - frame->dwFrameInterval[0] = - frame->dwDefaultFrameInterval; + if (ftype) { + while (buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE && + buffer[2] == ftype) { + frame = &frames[format->nframes]; + ret = uvc_parse_frame(dev, streaming, format, frame, + intervals, ftype, width_multiplier, + buffer, buflen); + if (ret < 0) + return ret; + format->nframes++; + buflen -= ret; + buffer += ret; } - - uvc_dbg(dev, DESCR, "- %ux%u (%u.%u fps)\n", - frame->wWidth, frame->wHeight, - 10000000 / frame->dwDefaultFrameInterval, - (100000000 / frame->dwDefaultFrameInterval) % 10); - - format->nframes++; - buflen -= buffer[0]; - buffer += buffer[0]; } if (buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE && @@ -509,12 +546,12 @@ static int uvc_parse_streaming(struct uvc_device *dev, struct uvc_format *format; struct uvc_frame *frame; struct usb_host_interface *alts = &intf->altsetting[0]; - unsigned char *_buffer, *buffer = alts->extra; + const unsigned char *_buffer, *buffer = alts->extra; int _buflen, buflen = alts->extralen; unsigned int nformats = 0, nframes = 0, nintervals = 0; unsigned int size, i, n, p; u32 *interval; - u16 psize; + u32 psize; int ret = -EINVAL; if (intf->cur_altsetting->desc.bInterfaceSubClass @@ -526,7 +563,7 @@ static int uvc_parse_streaming(struct uvc_device *dev, return -EINVAL; } - if (usb_driver_claim_interface(&uvc_driver.driver, intf, dev)) { + if (usb_driver_claim_interface(&uvc_driver, intf, dev)) { uvc_dbg(dev, DESCR, "device %d interface %d is already claimed\n", dev->udev->devnum, @@ -536,7 +573,7 @@ static int uvc_parse_streaming(struct uvc_device *dev, streaming = uvc_stream_new(dev, intf); if (streaming == NULL) { - usb_driver_release_interface(&uvc_driver.driver, intf); + usb_driver_release_interface(&uvc_driver, intf); return -ENOMEM; } @@ -682,19 +719,29 @@ static int uvc_parse_streaming(struct uvc_device *dev, goto error; } - size = nformats * sizeof(*format) + nframes * sizeof(*frame) + /* + * Allocate memory for the formats, the frames and the intervals, + * plus any required padding to guarantee that everything has the + * correct alignment. + */ + size = nformats * sizeof(*format); + size = ALIGN(size, __alignof__(*frame)) + nframes * sizeof(*frame); + size = ALIGN(size, __alignof__(*interval)) + nintervals * sizeof(*interval); + format = kzalloc(size, GFP_KERNEL); - if (format == NULL) { + if (!format) { ret = -ENOMEM; goto error; } - frame = (struct uvc_frame *)&format[nformats]; - interval = (u32 *)&frame[nframes]; + frame = (void *)format + nformats * sizeof(*format); + frame = PTR_ALIGN(frame, __alignof__(*frame)); + interval = (void *)frame + nframes * sizeof(*frame); + interval = PTR_ALIGN(interval, __alignof__(*interval)); - streaming->format = format; - streaming->nformats = nformats; + streaming->formats = format; + streaming->nformats = 0; /* Parse the format descriptors. */ while (buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE) { @@ -703,12 +750,14 @@ static int uvc_parse_streaming(struct uvc_device *dev, case UVC_VS_FORMAT_MJPEG: case UVC_VS_FORMAT_DV: case UVC_VS_FORMAT_FRAME_BASED: - format->frame = frame; - ret = uvc_parse_format(dev, streaming, format, + ret = uvc_parse_format(dev, streaming, format, frame, &interval, buffer, buflen); if (ret < 0) goto error; + if (!ret) + break; + streaming->nformats++; frame += format->nframes; format++; @@ -732,12 +781,13 @@ static int uvc_parse_streaming(struct uvc_device *dev, /* Parse the alternate settings to find the maximum bandwidth. */ for (i = 0; i < intf->num_altsetting; ++i) { struct usb_host_endpoint *ep; + alts = &intf->altsetting[i]; ep = uvc_find_endpoint(alts, streaming->header.bEndpointAddress); if (ep == NULL) continue; - psize = uvc_endpoint_max_bpi(dev->udev, ep); + psize = usb_endpoint_max_periodic_payload(dev->udev, ep); if (psize > streaming->maxpsize) streaming->maxpsize = psize; } @@ -746,7 +796,7 @@ static int uvc_parse_streaming(struct uvc_device *dev, return 0; error: - usb_driver_release_interface(&uvc_driver.driver, intf); + usb_driver_release_interface(&uvc_driver, intf); uvc_stream_delete(streaming); return ret; } @@ -757,14 +807,27 @@ static const u8 uvc_media_transport_input_guid[16] = UVC_GUID_UVC_MEDIA_TRANSPORT_INPUT; static const u8 uvc_processing_guid[16] = UVC_GUID_UVC_PROCESSING; -static struct uvc_entity *uvc_alloc_entity(u16 type, u16 id, - unsigned int num_pads, unsigned int extra_size) +static struct uvc_entity *uvc_alloc_new_entity(struct uvc_device *dev, u16 type, + u16 id, unsigned int num_pads, + unsigned int extra_size) { struct uvc_entity *entity; unsigned int num_inputs; unsigned int size; unsigned int i; + /* Per UVC 1.1+ spec 3.7.2, the ID should be non-zero. */ + if (id == 0) { + dev_err(&dev->intf->dev, "Found Unit with invalid ID 0\n"); + id = UVC_INVALID_ENTITY_ID; + } + + /* Per UVC 1.1+ spec 3.7.2, the ID is unique. */ + if (uvc_entity_by_id(dev, id)) { + dev_err(&dev->intf->dev, "Found multiple Units with ID %u\n", id); + id = UVC_INVALID_ENTITY_ID; + } + extra_size = roundup(extra_size, sizeof(*entity->pads)); if (num_pads) num_inputs = type & UVC_TERM_OUTPUT ? num_pads : num_pads - 1; @@ -774,7 +837,7 @@ static struct uvc_entity *uvc_alloc_entity(u16 type, u16 id, + num_inputs; entity = kzalloc(size, GFP_KERNEL); if (entity == NULL) - return NULL; + return ERR_PTR(-ENOMEM); entity->id = id; entity->type = type; @@ -813,6 +876,27 @@ static struct uvc_entity *uvc_alloc_entity(u16 type, u16 id, return entity; } +static void uvc_entity_set_name(struct uvc_device *dev, struct uvc_entity *entity, + const char *type_name, u8 string_id) +{ + int ret; + + /* + * First attempt to read the entity name from the device. If the entity + * has no associated string, or if reading the string fails (most + * likely due to a buggy firmware), fall back to default names based on + * the entity type. + */ + if (string_id) { + ret = usb_string(dev->udev, string_id, entity->name, + sizeof(entity->name)); + if (!ret) + return; + } + + sprintf(entity->name, "%s %u", type_name, entity->id); +} + /* Parse vendor-specific extensions. */ static int uvc_parse_vendor_control(struct uvc_device *dev, const unsigned char *buffer, int buflen) @@ -823,7 +907,7 @@ static int uvc_parse_vendor_control(struct uvc_device *dev, unsigned int n, p; int handled = 0; - switch (le16_to_cpu(dev->udev->descriptor.idVendor)) { + switch (le16_to_cpu(udev->descriptor.idVendor)) { case 0x046d: /* Logitech */ if (buffer[1] != 0x41 || buffer[2] != 0x01) break; @@ -865,10 +949,10 @@ static int uvc_parse_vendor_control(struct uvc_device *dev, break; } - unit = uvc_alloc_entity(UVC_VC_EXTENSION_UNIT, buffer[3], - p + 1, 2*n); - if (unit == NULL) - return -ENOMEM; + unit = uvc_alloc_new_entity(dev, UVC_VC_EXTENSION_UNIT, + buffer[3], p + 1, 2 * n); + if (IS_ERR(unit)) + return PTR_ERR(unit); memcpy(unit->guid, &buffer[4], 16); unit->extension.bNumControls = buffer[20]; @@ -879,11 +963,7 @@ static int uvc_parse_vendor_control(struct uvc_device *dev, + n; memcpy(unit->extension.bmControls, &buffer[23+p], 2*n); - if (buffer[24+p+2*n] != 0) - usb_string(udev, buffer[24+p+2*n], unit->name, - sizeof(unit->name)); - else - sprintf(unit->name, "Extension %u", buffer[3]); + uvc_entity_set_name(dev, unit, "Extension", buffer[24+p+2*n]); list_add_tail(&unit->list, &dev->entities); handled = 1; @@ -901,6 +981,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev, struct usb_interface *intf; struct usb_host_interface *alts = dev->intf->cur_altsetting; unsigned int i, n, p, len; + const char *type_name; u16 type; switch (buffer[2]) { @@ -980,10 +1061,10 @@ static int uvc_parse_standard_control(struct uvc_device *dev, return -EINVAL; } - term = uvc_alloc_entity(type | UVC_TERM_INPUT, buffer[3], - 1, n + p); - if (term == NULL) - return -ENOMEM; + term = uvc_alloc_new_entity(dev, type | UVC_TERM_INPUT, + buffer[3], 1, n + p); + if (IS_ERR(term)) + return PTR_ERR(term); if (UVC_ENTITY_TYPE(term) == UVC_ITT_CAMERA) { term->camera.bControlSize = n; @@ -1006,15 +1087,14 @@ static int uvc_parse_standard_control(struct uvc_device *dev, memcpy(term->media.bmTransportModes, &buffer[10+n], p); } - if (buffer[7] != 0) - usb_string(udev, buffer[7], term->name, - sizeof(term->name)); - else if (UVC_ENTITY_TYPE(term) == UVC_ITT_CAMERA) - sprintf(term->name, "Camera %u", buffer[3]); + if (UVC_ENTITY_TYPE(term) == UVC_ITT_CAMERA) + type_name = "Camera"; else if (UVC_ENTITY_TYPE(term) == UVC_ITT_MEDIA_TRANSPORT_INPUT) - sprintf(term->name, "Media %u", buffer[3]); + type_name = "Media"; else - sprintf(term->name, "Input %u", buffer[3]); + type_name = "Input"; + + uvc_entity_set_name(dev, term, type_name, buffer[7]); list_add_tail(&term->list, &dev->entities); break; @@ -1040,18 +1120,14 @@ static int uvc_parse_standard_control(struct uvc_device *dev, return 0; } - term = uvc_alloc_entity(type | UVC_TERM_OUTPUT, buffer[3], - 1, 0); - if (term == NULL) - return -ENOMEM; + term = uvc_alloc_new_entity(dev, type | UVC_TERM_OUTPUT, + buffer[3], 1, 0); + if (IS_ERR(term)) + return PTR_ERR(term); memcpy(term->baSourceID, &buffer[7], 1); - if (buffer[8] != 0) - usb_string(udev, buffer[8], term->name, - sizeof(term->name)); - else - sprintf(term->name, "Output %u", buffer[3]); + uvc_entity_set_name(dev, term, "Output", buffer[8]); list_add_tail(&term->list, &dev->entities); break; @@ -1066,17 +1142,14 @@ static int uvc_parse_standard_control(struct uvc_device *dev, return -EINVAL; } - unit = uvc_alloc_entity(buffer[2], buffer[3], p + 1, 0); - if (unit == NULL) - return -ENOMEM; + unit = uvc_alloc_new_entity(dev, buffer[2], buffer[3], + p + 1, 0); + if (IS_ERR(unit)) + return PTR_ERR(unit); memcpy(unit->baSourceID, &buffer[5], p); - if (buffer[5+p] != 0) - usb_string(udev, buffer[5+p], unit->name, - sizeof(unit->name)); - else - sprintf(unit->name, "Selector %u", buffer[3]); + uvc_entity_set_name(dev, unit, "Selector", buffer[5+p]); list_add_tail(&unit->list, &dev->entities); break; @@ -1092,9 +1165,9 @@ static int uvc_parse_standard_control(struct uvc_device *dev, return -EINVAL; } - unit = uvc_alloc_entity(buffer[2], buffer[3], 2, n); - if (unit == NULL) - return -ENOMEM; + unit = uvc_alloc_new_entity(dev, buffer[2], buffer[3], 2, n); + if (IS_ERR(unit)) + return PTR_ERR(unit); memcpy(unit->baSourceID, &buffer[4], 1); unit->processing.wMaxMultiplier = @@ -1105,11 +1178,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev, if (dev->uvc_version >= 0x0110) unit->processing.bmVideoStandards = buffer[9+n]; - if (buffer[8+n] != 0) - usb_string(udev, buffer[8+n], unit->name, - sizeof(unit->name)); - else - sprintf(unit->name, "Processing %u", buffer[3]); + uvc_entity_set_name(dev, unit, "Processing", buffer[8+n]); list_add_tail(&unit->list, &dev->entities); break; @@ -1125,9 +1194,10 @@ static int uvc_parse_standard_control(struct uvc_device *dev, return -EINVAL; } - unit = uvc_alloc_entity(buffer[2], buffer[3], p + 1, n); - if (unit == NULL) - return -ENOMEM; + unit = uvc_alloc_new_entity(dev, buffer[2], buffer[3], + p + 1, n); + if (IS_ERR(unit)) + return PTR_ERR(unit); memcpy(unit->guid, &buffer[4], 16); unit->extension.bNumControls = buffer[20]; @@ -1136,11 +1206,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev, unit->extension.bmControls = (u8 *)unit + sizeof(*unit); memcpy(unit->extension.bmControls, &buffer[23+p], n); - if (buffer[23+p+n] != 0) - usb_string(udev, buffer[23+p+n], unit->name, - sizeof(unit->name)); - else - sprintf(unit->name, "Extension %u", buffer[3]); + uvc_entity_set_name(dev, unit, "Extension", buffer[23+p+n]); list_add_tail(&unit->list, &dev->entities); break; @@ -1158,7 +1224,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev, static int uvc_parse_control(struct uvc_device *dev) { struct usb_host_interface *alts = dev->intf->cur_altsetting; - unsigned char *buffer = alts->extra; + const unsigned char *buffer = alts->extra; int buflen = alts->extralen; int ret; @@ -1173,7 +1239,8 @@ static int uvc_parse_control(struct uvc_device *dev) buffer[1] != USB_DT_CS_INTERFACE) goto next_descriptor; - if ((ret = uvc_parse_standard_control(dev, buffer, buflen)) < 0) + ret = uvc_parse_standard_control(dev, buffer, buflen); + if (ret < 0) return ret; next_descriptor: @@ -1260,19 +1327,25 @@ static int uvc_gpio_parse(struct uvc_device *dev) struct gpio_desc *gpio_privacy; int irq; - gpio_privacy = devm_gpiod_get_optional(&dev->udev->dev, "privacy", + gpio_privacy = devm_gpiod_get_optional(&dev->intf->dev, "privacy", GPIOD_IN); - if (IS_ERR_OR_NULL(gpio_privacy)) - return PTR_ERR_OR_ZERO(gpio_privacy); + if (!gpio_privacy) + return 0; + + if (IS_ERR(gpio_privacy)) + return dev_err_probe(&dev->intf->dev, + PTR_ERR(gpio_privacy), + "Can't get privacy GPIO\n"); irq = gpiod_to_irq(gpio_privacy); if (irq < 0) - return dev_err_probe(&dev->udev->dev, irq, + return dev_err_probe(&dev->intf->dev, irq, "No IRQ for privacy GPIO\n"); - unit = uvc_alloc_entity(UVC_EXT_GPIO_UNIT, UVC_EXT_GPIO_UNIT_ID, 0, 1); - if (!unit) - return -ENOMEM; + unit = uvc_alloc_new_entity(dev, UVC_EXT_GPIO_UNIT, + UVC_EXT_GPIO_UNIT_ID, 0, 1); + if (IS_ERR(unit)) + return PTR_ERR(unit); unit->gpio.gpio_privacy = gpio_privacy; unit->gpio.irq = irq; @@ -1293,15 +1366,27 @@ static int uvc_gpio_parse(struct uvc_device *dev) static int uvc_gpio_init_irq(struct uvc_device *dev) { struct uvc_entity *unit = dev->gpio_unit; + int ret; if (!unit || unit->gpio.irq < 0) return 0; - return devm_request_threaded_irq(&dev->udev->dev, unit->gpio.irq, NULL, - uvc_gpio_irq, - IRQF_ONESHOT | IRQF_TRIGGER_FALLING | - IRQF_TRIGGER_RISING, - "uvc_privacy_gpio", dev); + ret = request_threaded_irq(unit->gpio.irq, NULL, uvc_gpio_irq, + IRQF_ONESHOT | IRQF_TRIGGER_FALLING | + IRQF_TRIGGER_RISING, + "uvc_privacy_gpio", dev); + + unit->gpio.initialized = !ret; + + return ret; +} + +static void uvc_gpio_deinit(struct uvc_device *dev) +{ + if (!dev->gpio_unit || !dev->gpio_unit->gpio.initialized) + return; + + free_irq(dev->gpio_unit->gpio.irq, dev); } /* ------------------------------------------------------------------------ @@ -1811,8 +1896,8 @@ static int uvc_scan_device(struct uvc_device *dev) uvc_scan_fallback(dev); if (list_empty(&dev->chains)) { - dev_info(&dev->udev->dev, "No valid video chain found.\n"); - return -1; + dev_info(&dev->intf->dev, "No valid video chain found.\n"); + return -ENODEV; } /* Add GPIO entity to the first chain. */ @@ -1856,12 +1941,14 @@ static void uvc_delete(struct kref *kref) list_for_each_safe(p, n, &dev->chains) { struct uvc_video_chain *chain; + chain = list_entry(p, struct uvc_video_chain, list); kfree(chain); } list_for_each_safe(p, n, &dev->entities) { struct uvc_entity *entity; + entity = list_entry(p, struct uvc_entity, list); #ifdef CONFIG_MEDIA_CONTROLLER uvc_mc_cleanup_entity(entity); @@ -1871,9 +1958,9 @@ static void uvc_delete(struct kref *kref) list_for_each_safe(p, n, &dev->streams) { struct uvc_streaming *streaming; + streaming = list_entry(p, struct uvc_streaming, list); - usb_driver_release_interface(&uvc_driver.driver, - streaming->intf); + usb_driver_release_interface(&uvc_driver, streaming->intf); uvc_stream_delete(streaming); } @@ -1895,12 +1982,20 @@ static void uvc_unregister_video(struct uvc_device *dev) { struct uvc_streaming *stream; + uvc_gpio_deinit(dev); + list_for_each_entry(stream, &dev->streams, list) { - if (!video_is_registered(&stream->vdev)) + /* Nothing to do here, continue. */ + if (!video_is_registered(&stream->queue.vdev)) continue; - video_unregister_device(&stream->vdev); - video_unregister_device(&stream->meta.vdev); + vb2_video_unregister_device(&stream->queue.vdev); + vb2_video_unregister_device(&stream->meta.queue.vdev); + + /* + * Now both vdevs are not streaming and all the ioctls will + * return -ENODEV. + */ uvc_debugfs_cleanup_stream(stream); } @@ -1917,16 +2012,16 @@ static void uvc_unregister_video(struct uvc_device *dev) int uvc_register_video_device(struct uvc_device *dev, struct uvc_streaming *stream, - struct video_device *vdev, struct uvc_video_queue *queue, enum v4l2_buf_type type, const struct v4l2_file_operations *fops, const struct v4l2_ioctl_ops *ioctl_ops) { + struct video_device *vdev = &queue->vdev; int ret; /* Initialize the video buffers queue. */ - ret = uvc_queue_init(queue, type, !uvc_no_drop_param); + ret = uvc_queue_init(queue, type); if (ret) return ret; @@ -1942,6 +2037,8 @@ int uvc_register_video_device(struct uvc_device *dev, vdev->ioctl_ops = ioctl_ops; vdev->release = uvc_release; vdev->prio = &stream->chain->prio; + vdev->queue = &queue->queue; + vdev->lock = &queue->mutex; if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT) vdev->vfl_dir = VFL_DIR_TX; else @@ -2002,9 +2099,9 @@ static int uvc_register_video(struct uvc_device *dev, uvc_debugfs_init_stream(stream); /* Register the device with V4L. */ - return uvc_register_video_device(dev, stream, &stream->vdev, - &stream->queue, stream->type, - &uvc_fops, &uvc_ioctl_ops); + return uvc_register_video_device(dev, stream, &stream->queue, + stream->type, &uvc_fops, + &uvc_ioctl_ops); } /* @@ -2023,7 +2120,7 @@ static int uvc_register_terms(struct uvc_device *dev, stream = uvc_stream_by_id(dev, term->id); if (stream == NULL) { - dev_info(&dev->udev->dev, + dev_info(&dev->intf->dev, "No streaming interface found for terminal %u.", term->id); continue; @@ -2040,7 +2137,7 @@ static int uvc_register_terms(struct uvc_device *dev, */ uvc_meta_register(stream); - term->vdev = &stream->vdev; + term->vdev = &stream->queue.vdev; } return 0; @@ -2059,7 +2156,7 @@ static int uvc_register_chains(struct uvc_device *dev) #ifdef CONFIG_MEDIA_CONTROLLER ret = uvc_mc_register_entities(chain); if (ret < 0) - dev_info(&dev->udev->dev, + dev_info(&dev->intf->dev, "Failed to register entities (%d).\n", ret); #endif } @@ -2093,7 +2190,6 @@ static int uvc_probe(struct usb_interface *intf, INIT_LIST_HEAD(&dev->streams); kref_init(&dev->ref); atomic_set(&dev->nmappings, 0); - mutex_init(&dev->lock); dev->udev = usb_get_dev(udev); dev->intf = usb_get_intf(intf); @@ -2150,83 +2246,102 @@ static int uvc_probe(struct usb_interface *intf, #endif /* Parse the Video Class control descriptor. */ - if (uvc_parse_control(dev) < 0) { + ret = uvc_parse_control(dev); + if (ret < 0) { uvc_dbg(dev, PROBE, "Unable to parse UVC descriptors\n"); goto error; } /* Parse the associated GPIOs. */ - if (uvc_gpio_parse(dev) < 0) { - uvc_dbg(dev, PROBE, "Unable to parse UVC GPIOs\n"); + ret = uvc_gpio_parse(dev); + if (ret < 0) goto error; - } - dev_info(&dev->udev->dev, "Found UVC %u.%02x device %s (%04x:%04x)\n", + dev_info(&dev->intf->dev, "Found UVC %u.%02x device %s (%04x:%04x)\n", dev->uvc_version >> 8, dev->uvc_version & 0xff, udev->product ? udev->product : "<unnamed>", le16_to_cpu(udev->descriptor.idVendor), le16_to_cpu(udev->descriptor.idProduct)); if (dev->quirks != dev->info->quirks) { - dev_info(&dev->udev->dev, + dev_info(&dev->intf->dev, "Forcing device quirks to 0x%x by module parameter for testing purpose.\n", dev->quirks); - dev_info(&dev->udev->dev, + dev_info(&dev->intf->dev, "Please report required quirks to the linux-media mailing list.\n"); } if (dev->info->uvc_version) { dev->uvc_version = dev->info->uvc_version; - dev_info(&dev->udev->dev, "Forcing UVC version to %u.%02x\n", + dev_info(&dev->intf->dev, "Forcing UVC version to %u.%02x\n", dev->uvc_version >> 8, dev->uvc_version & 0xff); } /* Register the V4L2 device. */ - if (v4l2_device_register(&intf->dev, &dev->vdev) < 0) + ret = v4l2_device_register(&intf->dev, &dev->vdev); + if (ret < 0) goto error; /* Scan the device for video chains. */ - if (uvc_scan_device(dev) < 0) + ret = uvc_scan_device(dev); + if (ret < 0) goto error; /* Initialize controls. */ - if (uvc_ctrl_init_device(dev) < 0) + ret = uvc_ctrl_init_device(dev); + if (ret < 0) goto error; /* Register video device nodes. */ - if (uvc_register_chains(dev) < 0) + ret = uvc_register_chains(dev); + if (ret < 0) goto error; #ifdef CONFIG_MEDIA_CONTROLLER /* Register the media device node */ - if (media_device_register(&dev->mdev) < 0) + ret = media_device_register(&dev->mdev); + if (ret < 0) goto error; #endif /* Save our data pointer in the interface data. */ usb_set_intfdata(intf, dev); /* Initialize the interrupt URB. */ - if ((ret = uvc_status_init(dev)) < 0) { - dev_info(&dev->udev->dev, + ret = uvc_status_init(dev); + if (ret < 0) { + dev_info(&dev->intf->dev, "Unable to initialize the status endpoint (%d), status interrupt will not be supported.\n", ret); } ret = uvc_gpio_init_irq(dev); if (ret < 0) { - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "Unable to request privacy GPIO IRQ (%d)\n", ret); goto error; } + ret = uvc_meta_init(dev); + if (ret < 0) { + dev_err(&dev->intf->dev, + "Error initializing the metadata formats (%d)\n", ret); + goto error; + } + + if (dev->quirks & UVC_QUIRK_NO_RESET_RESUME) + udev->quirks &= ~USB_QUIRK_RESET_RESUME; + + if (!(dev->quirks & UVC_QUIRK_DISABLE_AUTOSUSPEND)) + usb_enable_autosuspend(udev); + uvc_dbg(dev, PROBE, "UVC device initialized\n"); - usb_enable_autosuspend(udev); + return 0; error: uvc_unregister_video(dev); kref_put(&dev->ref, uvc_delete); - return -ENODEV; + return ret; } static void uvc_disconnect(struct usb_interface *intf) @@ -2258,10 +2373,7 @@ static int uvc_suspend(struct usb_interface *intf, pm_message_t message) /* Controls are cached on the fly so they don't need to be saved. */ if (intf->cur_altsetting->desc.bInterfaceSubClass == UVC_SC_VIDEOCONTROL) { - mutex_lock(&dev->lock); - if (dev->users) - uvc_status_stop(dev); - mutex_unlock(&dev->lock); + uvc_status_suspend(dev); return 0; } @@ -2292,20 +2404,18 @@ static int __uvc_resume(struct usb_interface *intf, int reset) return ret; } - mutex_lock(&dev->lock); - if (dev->users) - ret = uvc_status_start(dev, GFP_NOIO); - mutex_unlock(&dev->lock); - - return ret; + return uvc_status_resume(dev); } list_for_each_entry(stream, &dev->streams, list) { if (stream->intf == intf) { ret = uvc_video_resume(stream, reset); - if (ret < 0) - uvc_queue_streamoff(&stream->queue, - stream->queue.queue.type); + if (ret < 0) { + mutex_lock(&stream->queue.mutex); + vb2_streamoff(&stream->queue.queue, + stream->queue.queue.type); + mutex_unlock(&stream->queue.mutex); + } return ret; } } @@ -2353,47 +2463,40 @@ static int uvc_clock_param_set(const char *val, const struct kernel_param *kp) } module_param_call(clock, uvc_clock_param_set, uvc_clock_param_get, - &uvc_clock_param, S_IRUGO|S_IWUSR); + &uvc_clock_param, 0644); MODULE_PARM_DESC(clock, "Video buffers timestamp clock"); -module_param_named(hwtimestamps, uvc_hw_timestamps_param, uint, S_IRUGO|S_IWUSR); +module_param_named(hwtimestamps, uvc_hw_timestamps_param, uint, 0644); MODULE_PARM_DESC(hwtimestamps, "Use hardware timestamps"); -module_param_named(nodrop, uvc_no_drop_param, uint, S_IRUGO|S_IWUSR); + +static int param_set_nodrop(const char *val, const struct kernel_param *kp) +{ + pr_warn_once("uvcvideo: " + DEPRECATED + "nodrop parameter will be eventually removed.\n"); + return param_set_bool(val, kp); +} + +static const struct kernel_param_ops param_ops_nodrop = { + .set = param_set_nodrop, + .get = param_get_uint, +}; + +param_check_uint(nodrop, &uvc_no_drop_param); +module_param_cb(nodrop, ¶m_ops_nodrop, &uvc_no_drop_param, 0644); +__MODULE_PARM_TYPE(nodrop, "uint"); MODULE_PARM_DESC(nodrop, "Don't drop incomplete frames"); -module_param_named(quirks, uvc_quirks_param, uint, S_IRUGO|S_IWUSR); + +module_param_named(quirks, uvc_quirks_param, uint, 0644); MODULE_PARM_DESC(quirks, "Forced device quirks"); -module_param_named(trace, uvc_dbg_param, uint, S_IRUGO|S_IWUSR); +module_param_named(trace, uvc_dbg_param, uint, 0644); MODULE_PARM_DESC(trace, "Trace level bitmask"); -module_param_named(timeout, uvc_timeout_param, uint, S_IRUGO|S_IWUSR); +module_param_named(timeout, uvc_timeout_param, uint, 0644); MODULE_PARM_DESC(timeout, "Streaming control requests timeout"); /* ------------------------------------------------------------------------ * Driver initialization and cleanup */ -static const struct uvc_menu_info power_line_frequency_controls_limited[] = { - { 1, "50 Hz" }, - { 2, "60 Hz" }, -}; - -static const struct uvc_control_mapping uvc_ctrl_power_line_mapping_limited = { - .id = V4L2_CID_POWER_LINE_FREQUENCY, - .entity = UVC_GUID_UVC_PROCESSING, - .selector = UVC_PU_POWER_LINE_FREQUENCY_CONTROL, - .size = 2, - .offset = 0, - .v4l2_type = V4L2_CTRL_TYPE_MENU, - .data_type = UVC_CTRL_DATA_TYPE_ENUM, - .menu_info = power_line_frequency_controls_limited, - .menu_count = ARRAY_SIZE(power_line_frequency_controls_limited), -}; - -static const struct uvc_device_info uvc_ctrl_power_line_limited = { - .mappings = (const struct uvc_control_mapping *[]) { - &uvc_ctrl_power_line_mapping_limited, - NULL, /* Sentinel */ - }, -}; - static const struct uvc_device_info uvc_quirk_probe_minmax = { .quirks = UVC_QUIRK_PROBE_MINMAX, }; @@ -2422,35 +2525,41 @@ static const struct uvc_device_info uvc_quirk_force_y8 = { * The Logitech cameras listed below have their interface class set to * VENDOR_SPEC because they don't announce themselves as UVC devices, even * though they are compliant. + * + * Sort these by vendor/product ID. */ static const struct usb_device_id uvc_ids[] = { - /* Quanta USB2.0 HD UVC Webcam */ + /* HP Webcam HD 2300 */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x0408, - .idProduct = 0x3090, + .idVendor = 0x03f0, + .idProduct = 0xe207, .bInterfaceClass = USB_CLASS_VIDEO, .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, - .driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_limited }, - /* Quanta USB2.0 HD UVC Webcam */ + .driver_info = (kernel_ulong_t)&uvc_quirk_stream_no_fid }, + /* Quanta ACER HD User Facing */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, .idVendor = 0x0408, - .idProduct = 0x4030, + .idProduct = 0x4033, .bInterfaceClass = USB_CLASS_VIDEO, .bInterfaceSubClass = 1, - .bInterfaceProtocol = 0, - .driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_limited }, - /* Quanta USB2.0 HD UVC Webcam */ + .bInterfaceProtocol = UVC_PC_PROTOCOL_15, + .driver_info = (kernel_ulong_t)&(const struct uvc_device_info){ + .uvc_version = 0x010a, + } }, + /* Quanta ACER HD User Facing */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, .idVendor = 0x0408, - .idProduct = 0x4034, + .idProduct = 0x4035, .bInterfaceClass = USB_CLASS_VIDEO, .bInterfaceSubClass = 1, .bInterfaceProtocol = UVC_PC_PROTOCOL_15, - .driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_limited }, + .driver_info = (kernel_ulong_t)&(const struct uvc_device_info){ + .uvc_version = 0x010a, + } }, /* LogiLink Wireless Webcam */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, @@ -2496,6 +2605,24 @@ static const struct usb_device_id uvc_ids[] = { .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, .driver_info = (kernel_ulong_t)&uvc_quirk_probe_minmax }, + /* Logitech, Webcam C910 */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x046d, + .idProduct = 0x0821, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_WAKE_AUTOSUSPEND)}, + /* Logitech, Webcam B910 */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x046d, + .idProduct = 0x0823, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_WAKE_AUTOSUSPEND)}, /* Logitech Quickcam Fusion */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, @@ -2552,43 +2679,53 @@ static const struct usb_device_id uvc_ids[] = { .bInterfaceClass = USB_CLASS_VIDEO, .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, - .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_RESTORE_CTRLS_ON_INIT) }, - /* Chicony CNF7129 (Asus EEE 100HE) */ + .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_RESTORE_CTRLS_ON_INIT + | UVC_QUIRK_INVALID_DEVICE_SOF) }, + /* Logitech HD Pro Webcam C922 */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x04f2, - .idProduct = 0xb071, + .idVendor = 0x046d, + .idProduct = 0x085c, .bInterfaceClass = USB_CLASS_VIDEO, .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, - .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_RESTRICT_FRAME_RATE) }, - /* Chicony EasyCamera */ + .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_INVALID_DEVICE_SOF) }, + /* Logitech Rally Bar Huddle */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x04f2, - .idProduct = 0xb5eb, + .idVendor = 0x046d, + .idProduct = 0x087c, .bInterfaceClass = USB_CLASS_VIDEO, .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, - .driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_limited }, - /* Chicony EasyCamera */ + .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_NO_RESET_RESUME) }, + /* Logitech Rally Bar */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x04f2, - .idProduct = 0xb6ba, + .idVendor = 0x046d, + .idProduct = 0x089b, .bInterfaceClass = USB_CLASS_VIDEO, .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, - .driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_limited }, - /* Chicony EasyCamera */ + .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_NO_RESET_RESUME) }, + /* Logitech Rally Bar Mini */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x046d, + .idProduct = 0x08d3, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_NO_RESET_RESUME) }, + /* Chicony CNF7129 (Asus EEE 100HE) */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, .idVendor = 0x04f2, - .idProduct = 0xb746, + .idProduct = 0xb071, .bInterfaceClass = USB_CLASS_VIDEO, .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, - .driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_limited }, + .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_RESTRICT_FRAME_RATE) }, /* Alcor Micro AU3820 (Future Boy PC USB Webcam) */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, @@ -2734,6 +2871,15 @@ static const struct usb_device_id uvc_ids[] = { .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, .driver_info = (kernel_ulong_t)&uvc_quirk_probe_minmax }, + /* Sonix Technology Co. Ltd. - 292A IPC AR0330 */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x0c45, + .idProduct = 0x6366, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_MJPEG_NO_EOF) }, /* MT6227 */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, @@ -2762,6 +2908,15 @@ static const struct usb_device_id uvc_ids[] = { .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, .driver_info = (kernel_ulong_t)&uvc_quirk_probe_minmax }, + /* Kurokesu C1 PRO */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x16d0, + .idProduct = 0x0ed1, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_MJPEG_NO_EOF) }, /* Syntek (HP Spartan) */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, @@ -2946,6 +3101,24 @@ static const struct usb_device_id uvc_ids[] = { .bInterfaceProtocol = 0, .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_PROBE_MINMAX | UVC_QUIRK_IGNORE_SELECTOR_UNIT) }, + /* Actions Microelectronics Co. Display capture-UVC05 */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x1de1, + .idProduct = 0xf105, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_DISABLE_AUTOSUSPEND) }, + /* NXP Semiconductors IR VIDEO */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x1fc9, + .idProduct = 0x009b, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = (kernel_ulong_t)&uvc_quirk_probe_minmax }, /* Oculus VR Positional Tracker DK2 */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, @@ -2973,24 +3146,42 @@ static const struct usb_device_id uvc_ids[] = { .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_FORCE_BPP) }, - /* Sonix Technology USB 2.0 Camera */ + /* Insta360 Link */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x2e1a, + .idProduct = 0x4c01, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_DISABLE_AUTOSUSPEND) }, + /* Intel D410/ASR depth camera */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x8086, + .idProduct = 0x0ad2, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_INFO_META(V4L2_META_FMT_D4XX) }, + /* Intel D415/ASRC depth camera */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x3277, - .idProduct = 0x0072, + .idVendor = 0x8086, + .idProduct = 0x0ad3, .bInterfaceClass = USB_CLASS_VIDEO, .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, - .driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_limited }, - /* Acer EasyCamera */ + .driver_info = UVC_INFO_META(V4L2_META_FMT_D4XX) }, + /* Intel D430/AWG depth camera */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x5986, - .idProduct = 0x1172, + .idVendor = 0x8086, + .idProduct = 0x0ad4, .bInterfaceClass = USB_CLASS_VIDEO, .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, - .driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_limited }, + .driver_info = UVC_INFO_META(V4L2_META_FMT_D4XX) }, /* Intel RealSense D4M */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, @@ -3000,6 +3191,51 @@ static const struct usb_device_id uvc_ids[] = { .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, .driver_info = UVC_INFO_META(V4L2_META_FMT_D4XX) }, + /* Intel D435/AWGC depth camera */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x8086, + .idProduct = 0x0b07, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_INFO_META(V4L2_META_FMT_D4XX) }, + /* Intel D435i depth camera */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x8086, + .idProduct = 0x0b3a, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_INFO_META(V4L2_META_FMT_D4XX) }, + /* Intel D405 Depth Camera */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x8086, + .idProduct = 0x0b5b, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_INFO_META(V4L2_META_FMT_D4XX) }, + /* Intel D455 Depth Camera */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x8086, + .idProduct = 0x0b5c, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_INFO_META(V4L2_META_FMT_D4XX) }, + /* Intel D421 Depth Module */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x8086, + .idProduct = 0x1155, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_INFO_META(V4L2_META_FMT_D4XX) }, /* Generic USB Video Class */ { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, UVC_PC_PROTOCOL_UNDEFINED) }, { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, UVC_PC_PROTOCOL_15) }, @@ -3008,17 +3244,15 @@ static const struct usb_device_id uvc_ids[] = { MODULE_DEVICE_TABLE(usb, uvc_ids); -struct uvc_driver uvc_driver = { - .driver = { - .name = "uvcvideo", - .probe = uvc_probe, - .disconnect = uvc_disconnect, - .suspend = uvc_suspend, - .resume = uvc_resume, - .reset_resume = uvc_reset_resume, - .id_table = uvc_ids, - .supports_autosuspend = 1, - }, +static struct usb_driver uvc_driver = { + .name = "uvcvideo", + .probe = uvc_probe, + .disconnect = uvc_disconnect, + .suspend = uvc_suspend, + .resume = uvc_resume, + .reset_resume = uvc_reset_resume, + .id_table = uvc_ids, + .supports_autosuspend = 1, }; static int __init uvc_init(void) @@ -3027,7 +3261,7 @@ static int __init uvc_init(void) uvc_debugfs_init(); - ret = usb_register(&uvc_driver.driver); + ret = usb_register(&uvc_driver); if (ret < 0) { uvc_debugfs_cleanup(); return ret; @@ -3038,7 +3272,7 @@ static int __init uvc_init(void) static void __exit uvc_cleanup(void) { - usb_deregister(&uvc_driver.driver); + usb_deregister(&uvc_driver); uvc_debugfs_cleanup(); } diff --git a/drivers/media/usb/uvc/uvc_entity.c b/drivers/media/usb/uvc/uvc_entity.c index 7c4d2f93d351..3823ac9c8045 100644 --- a/drivers/media/usb/uvc/uvc_entity.c +++ b/drivers/media/usb/uvc/uvc_entity.c @@ -37,7 +37,7 @@ static int uvc_mc_create_links(struct uvc_video_chain *chain, continue; remote = uvc_entity_by_id(chain->dev, entity->baSourceID[i]); - if (remote == NULL) + if (remote == NULL || remote->num_pads == 0) return -EINVAL; source = (UVC_ENTITY_TYPE(remote) == UVC_TT_STREAMING) @@ -140,7 +140,7 @@ int uvc_mc_register_entities(struct uvc_video_chain *chain) list_for_each_entry(entity, &chain->entities, chain) { ret = uvc_mc_init_entity(chain, entity); if (ret < 0) { - dev_info(&chain->dev->udev->dev, + dev_info(&chain->dev->intf->dev, "Failed to initialize entity for entity %u\n", entity->id); return ret; @@ -150,7 +150,7 @@ int uvc_mc_register_entities(struct uvc_video_chain *chain) list_for_each_entry(entity, &chain->entities, chain) { ret = uvc_mc_create_links(chain, entity); if (ret < 0) { - dev_info(&chain->dev->udev->dev, + dev_info(&chain->dev->intf->dev, "Failed to create links for entity %u\n", entity->id); return ret; diff --git a/drivers/media/usb/uvc/uvc_metadata.c b/drivers/media/usb/uvc/uvc_metadata.c index 82de7781f5b6..c23b174965c3 100644 --- a/drivers/media/usb/uvc/uvc_metadata.c +++ b/drivers/media/usb/uvc/uvc_metadata.c @@ -10,6 +10,7 @@ #include <linux/list.h> #include <linux/module.h> #include <linux/usb.h> +#include <linux/usb/uvc.h> #include <linux/videodev2.h> #include <media/v4l2-ioctl.h> @@ -22,10 +23,10 @@ * V4L2 ioctls */ -static int uvc_meta_v4l2_querycap(struct file *file, void *fh, +static int uvc_meta_v4l2_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct uvc_streaming *stream = video_get_drvdata(vfh->vdev); struct uvc_video_chain *chain = stream->chain; @@ -38,54 +39,58 @@ static int uvc_meta_v4l2_querycap(struct file *file, void *fh, return 0; } -static int uvc_meta_v4l2_get_format(struct file *file, void *fh, +static int uvc_meta_v4l2_get_format(struct file *file, void *priv, struct v4l2_format *format) { - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct uvc_streaming *stream = video_get_drvdata(vfh->vdev); struct v4l2_meta_format *fmt = &format->fmt.meta; if (format->type != vfh->vdev->queue->type) return -EINVAL; - memset(fmt, 0, sizeof(*fmt)); - fmt->dataformat = stream->meta.format; fmt->buffersize = UVC_METADATA_BUF_SIZE; return 0; } -static int uvc_meta_v4l2_try_format(struct file *file, void *fh, +static int uvc_meta_v4l2_try_format(struct file *file, void *priv, struct v4l2_format *format) { - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct uvc_streaming *stream = video_get_drvdata(vfh->vdev); struct uvc_device *dev = stream->dev; struct v4l2_meta_format *fmt = &format->fmt.meta; - u32 fmeta = fmt->dataformat; + u32 fmeta = V4L2_META_FMT_UVC; if (format->type != vfh->vdev->queue->type) return -EINVAL; + for (unsigned int i = 0; i < dev->nmeta_formats; i++) { + if (dev->meta_formats[i] == fmt->dataformat) { + fmeta = fmt->dataformat; + break; + } + } + memset(fmt, 0, sizeof(*fmt)); - fmt->dataformat = fmeta == dev->info->meta_format - ? fmeta : V4L2_META_FMT_UVC; + fmt->dataformat = fmeta; fmt->buffersize = UVC_METADATA_BUF_SIZE; return 0; } -static int uvc_meta_v4l2_set_format(struct file *file, void *fh, +static int uvc_meta_v4l2_set_format(struct file *file, void *priv, struct v4l2_format *format) { - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct uvc_streaming *stream = video_get_drvdata(vfh->vdev); struct v4l2_meta_format *fmt = &format->fmt.meta; int ret; - ret = uvc_meta_v4l2_try_format(file, fh, format); + ret = uvc_meta_v4l2_try_format(file, priv, format); if (ret < 0) return ret; @@ -94,35 +99,28 @@ static int uvc_meta_v4l2_set_format(struct file *file, void *fh, * Metadata buffers would still be perfectly parseable, but it's more * consistent and cleaner to disallow that. */ - mutex_lock(&stream->mutex); + if (vb2_is_busy(&stream->meta.queue.queue)) + return -EBUSY; - if (uvc_queue_allocated(&stream->queue)) - ret = -EBUSY; - else - stream->meta.format = fmt->dataformat; + stream->meta.format = fmt->dataformat; - mutex_unlock(&stream->mutex); - - return ret; + return 0; } -static int uvc_meta_v4l2_enum_formats(struct file *file, void *fh, +static int uvc_meta_v4l2_enum_formats(struct file *file, void *priv, struct v4l2_fmtdesc *fdesc) { - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct uvc_streaming *stream = video_get_drvdata(vfh->vdev); struct uvc_device *dev = stream->dev; - u32 index = fdesc->index; - if (fdesc->type != vfh->vdev->queue->type || - index > 1U || (index && !dev->info->meta_format)) + if (fdesc->type != vfh->vdev->queue->type) return -EINVAL; - memset(fdesc, 0, sizeof(*fdesc)); + if (fdesc->index >= dev->nmeta_formats) + return -EINVAL; - fdesc->type = vfh->vdev->queue->type; - fdesc->index = index; - fdesc->pixelformat = index ? dev->info->meta_format : V4L2_META_FMT_UVC; + fdesc->pixelformat = dev->meta_formats[fdesc->index]; return 0; } @@ -156,21 +154,108 @@ static const struct v4l2_file_operations uvc_meta_fops = { .mmap = vb2_fop_mmap, }; +static struct uvc_entity *uvc_meta_find_msxu(struct uvc_device *dev) +{ + static const u8 uvc_msxu_guid[16] = UVC_GUID_MSXU_1_5; + struct uvc_entity *entity; + + list_for_each_entry(entity, &dev->entities, list) { + if (!memcmp(entity->guid, uvc_msxu_guid, sizeof(entity->guid))) + return entity; + } + + return NULL; +} + +static int uvc_meta_detect_msxu(struct uvc_device *dev) +{ + u32 *data __free(kfree) = NULL; + struct uvc_entity *entity; + int ret; + + entity = uvc_meta_find_msxu(dev); + if (!entity) + return 0; + + /* + * USB requires buffers aligned in a special way, simplest way is to + * make sure that query_ctrl will work is to kmalloc() them. + */ + data = kmalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + /* + * Check if the metadata is already enabled, or if the device always + * returns metadata. + */ + ret = uvc_query_ctrl(dev, UVC_GET_CUR, entity->id, dev->intfnum, + UVC_MSXU_CONTROL_METADATA, data, sizeof(*data)); + if (ret) + return 0; + + if (*data) { + dev->quirks |= UVC_QUIRK_MSXU_META; + return 0; + } + + /* + * Set the value of UVC_MSXU_CONTROL_METADATA to the value reported by + * GET_MAX to enable production of MSXU metadata. The GET_MAX request + * reports the maximum size of the metadata, if its value is 0 then MSXU + * metadata is not supported. For more information, see + * https://learn.microsoft.com/en-us/windows-hardware/drivers/stream/uvc-extensions-1-5#2229-metadata-control + */ + ret = uvc_query_ctrl(dev, UVC_GET_MAX, entity->id, dev->intfnum, + UVC_MSXU_CONTROL_METADATA, data, sizeof(*data)); + if (ret || !*data) + return 0; + + /* + * If we can set UVC_MSXU_CONTROL_METADATA, the device will report + * metadata. + */ + ret = uvc_query_ctrl(dev, UVC_SET_CUR, entity->id, dev->intfnum, + UVC_MSXU_CONTROL_METADATA, data, sizeof(*data)); + if (!ret) + dev->quirks |= UVC_QUIRK_MSXU_META; + + return 0; +} + int uvc_meta_register(struct uvc_streaming *stream) { struct uvc_device *dev = stream->dev; - struct video_device *vdev = &stream->meta.vdev; struct uvc_video_queue *queue = &stream->meta.queue; stream->meta.format = V4L2_META_FMT_UVC; - /* - * The video interface queue uses manual locking and thus does not set - * the queue pointer. Set it manually here. - */ - vdev->queue = &queue->queue; - - return uvc_register_video_device(dev, stream, vdev, queue, + return uvc_register_video_device(dev, stream, queue, V4L2_BUF_TYPE_META_CAPTURE, &uvc_meta_fops, &uvc_meta_ioctl_ops); } + +int uvc_meta_init(struct uvc_device *dev) +{ + unsigned int i = 0; + int ret; + + ret = uvc_meta_detect_msxu(dev); + if (ret) + return ret; + + dev->meta_formats[i++] = V4L2_META_FMT_UVC; + + if (dev->info->meta_format && + !WARN_ON(dev->info->meta_format == V4L2_META_FMT_UVC)) + dev->meta_formats[i++] = dev->info->meta_format; + + if (dev->quirks & UVC_QUIRK_MSXU_META && + !WARN_ON(dev->info->meta_format == V4L2_META_FMT_UVC_MSXU_1_5)) + dev->meta_formats[i++] = V4L2_META_FMT_UVC_MSXU_1_5; + + /* IMPORTANT: for new meta-formats update UVC_MAX_META_DATA_FORMATS. */ + dev->nmeta_formats = i; + + return 0; +} diff --git a/drivers/media/usb/uvc/uvc_queue.c b/drivers/media/usb/uvc/uvc_queue.c index 16fa17bbd15e..790184c9843d 100644 --- a/drivers/media/usb/uvc/uvc_queue.c +++ b/drivers/media/usb/uvc/uvc_queue.c @@ -42,13 +42,15 @@ static inline struct uvc_buffer *uvc_vbuf_to_buffer(struct vb2_v4l2_buffer *buf) * * This function must be called with the queue spinlock held. */ -static void uvc_queue_return_buffers(struct uvc_video_queue *queue, - enum uvc_buffer_state state) +static void __uvc_queue_return_buffers(struct uvc_video_queue *queue, + enum uvc_buffer_state state) { enum vb2_buffer_state vb2_state = state == UVC_BUF_STATE_ERROR ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_QUEUED; + lockdep_assert_held(&queue->irqlock); + while (!list_empty(&queue->irqqueue)) { struct uvc_buffer *buf = list_first_entry(&queue->irqqueue, struct uvc_buffer, @@ -59,6 +61,14 @@ static void uvc_queue_return_buffers(struct uvc_video_queue *queue, } } +static void uvc_queue_return_buffers(struct uvc_video_queue *queue, + enum uvc_buffer_state state) +{ + spin_lock_irq(&queue->irqlock); + __uvc_queue_return_buffers(queue, state); + spin_unlock_irq(&queue->irqlock); +} + /* ----------------------------------------------------------------------------- * videobuf2 queue operations */ @@ -157,7 +167,7 @@ static void uvc_buffer_finish(struct vb2_buffer *vb) uvc_video_clock_update(stream, vbuf, buf); } -static int uvc_start_streaming(struct vb2_queue *vq, unsigned int count) +static int uvc_start_streaming_video(struct vb2_queue *vq, unsigned int count) { struct uvc_video_queue *queue = vb2_get_drv_priv(vq); struct uvc_streaming *stream = uvc_queue_to_stream(queue); @@ -165,31 +175,44 @@ static int uvc_start_streaming(struct vb2_queue *vq, unsigned int count) lockdep_assert_irqs_enabled(); + ret = uvc_pm_get(stream->dev); + if (ret) + return ret; + queue->buf_used = 0; ret = uvc_video_start_streaming(stream); if (ret == 0) return 0; - spin_lock_irq(&queue->irqlock); + uvc_pm_put(stream->dev); + uvc_queue_return_buffers(queue, UVC_BUF_STATE_QUEUED); - spin_unlock_irq(&queue->irqlock); return ret; } -static void uvc_stop_streaming(struct vb2_queue *vq) +static void uvc_stop_streaming_video(struct vb2_queue *vq) { struct uvc_video_queue *queue = vb2_get_drv_priv(vq); + struct uvc_streaming *stream = uvc_queue_to_stream(queue); lockdep_assert_irqs_enabled(); - if (vq->type != V4L2_BUF_TYPE_META_CAPTURE) - uvc_video_stop_streaming(uvc_queue_to_stream(queue)); + uvc_video_stop_streaming(uvc_queue_to_stream(queue)); + + uvc_pm_put(stream->dev); + + uvc_queue_return_buffers(queue, UVC_BUF_STATE_ERROR); +} + +static void uvc_stop_streaming_meta(struct vb2_queue *vq) +{ + struct uvc_video_queue *queue = vb2_get_drv_priv(vq); + + lockdep_assert_irqs_enabled(); - spin_lock_irq(&queue->irqlock); uvc_queue_return_buffers(queue, UVC_BUF_STATE_ERROR); - spin_unlock_irq(&queue->irqlock); } static const struct vb2_ops uvc_queue_qops = { @@ -197,23 +220,23 @@ static const struct vb2_ops uvc_queue_qops = { .buf_prepare = uvc_buffer_prepare, .buf_queue = uvc_buffer_queue, .buf_finish = uvc_buffer_finish, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, - .start_streaming = uvc_start_streaming, - .stop_streaming = uvc_stop_streaming, + .start_streaming = uvc_start_streaming_video, + .stop_streaming = uvc_stop_streaming_video, }; static const struct vb2_ops uvc_meta_queue_qops = { .queue_setup = uvc_queue_setup, .buf_prepare = uvc_buffer_prepare, .buf_queue = uvc_buffer_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, - .stop_streaming = uvc_stop_streaming, + /* + * .start_streaming is not provided here. Metadata relies on video + * streaming being active. If video isn't streaming, then no metadata + * will arrive either. + */ + .stop_streaming = uvc_stop_streaming_meta, }; -int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type, - int drop_corrupted) +int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type) { int ret; @@ -243,159 +266,15 @@ int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type, mutex_init(&queue->mutex); spin_lock_init(&queue->irqlock); INIT_LIST_HEAD(&queue->irqqueue); - queue->flags = drop_corrupted ? UVC_QUEUE_DROP_CORRUPTED : 0; return 0; } -void uvc_queue_release(struct uvc_video_queue *queue) -{ - mutex_lock(&queue->mutex); - vb2_queue_release(&queue->queue); - mutex_unlock(&queue->mutex); -} - -/* ----------------------------------------------------------------------------- - * V4L2 queue operations - */ - -int uvc_request_buffers(struct uvc_video_queue *queue, - struct v4l2_requestbuffers *rb) -{ - int ret; - - mutex_lock(&queue->mutex); - ret = vb2_reqbufs(&queue->queue, rb); - mutex_unlock(&queue->mutex); - - return ret ? ret : rb->count; -} - -int uvc_query_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf) -{ - int ret; - - mutex_lock(&queue->mutex); - ret = vb2_querybuf(&queue->queue, buf); - mutex_unlock(&queue->mutex); - - return ret; -} - -int uvc_create_buffers(struct uvc_video_queue *queue, - struct v4l2_create_buffers *cb) -{ - int ret; - - mutex_lock(&queue->mutex); - ret = vb2_create_bufs(&queue->queue, cb); - mutex_unlock(&queue->mutex); - - return ret; -} - -int uvc_queue_buffer(struct uvc_video_queue *queue, - struct media_device *mdev, struct v4l2_buffer *buf) -{ - int ret; - - mutex_lock(&queue->mutex); - ret = vb2_qbuf(&queue->queue, mdev, buf); - mutex_unlock(&queue->mutex); - - return ret; -} - -int uvc_export_buffer(struct uvc_video_queue *queue, - struct v4l2_exportbuffer *exp) -{ - int ret; - - mutex_lock(&queue->mutex); - ret = vb2_expbuf(&queue->queue, exp); - mutex_unlock(&queue->mutex); - - return ret; -} - -int uvc_dequeue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf, - int nonblocking) -{ - int ret; - - mutex_lock(&queue->mutex); - ret = vb2_dqbuf(&queue->queue, buf, nonblocking); - mutex_unlock(&queue->mutex); - - return ret; -} - -int uvc_queue_streamon(struct uvc_video_queue *queue, enum v4l2_buf_type type) -{ - int ret; - - mutex_lock(&queue->mutex); - ret = vb2_streamon(&queue->queue, type); - mutex_unlock(&queue->mutex); - - return ret; -} - -int uvc_queue_streamoff(struct uvc_video_queue *queue, enum v4l2_buf_type type) -{ - int ret; - - mutex_lock(&queue->mutex); - ret = vb2_streamoff(&queue->queue, type); - mutex_unlock(&queue->mutex); - - return ret; -} - -int uvc_queue_mmap(struct uvc_video_queue *queue, struct vm_area_struct *vma) -{ - return vb2_mmap(&queue->queue, vma); -} - -#ifndef CONFIG_MMU -unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue, - unsigned long pgoff) -{ - return vb2_get_unmapped_area(&queue->queue, 0, 0, pgoff, 0); -} -#endif - -__poll_t uvc_queue_poll(struct uvc_video_queue *queue, struct file *file, - poll_table *wait) -{ - __poll_t ret; - - mutex_lock(&queue->mutex); - ret = vb2_poll(&queue->queue, file, wait); - mutex_unlock(&queue->mutex); - - return ret; -} - /* ----------------------------------------------------------------------------- * */ /* - * Check if buffers have been allocated. - */ -int uvc_queue_allocated(struct uvc_video_queue *queue) -{ - int allocated; - - mutex_lock(&queue->mutex); - allocated = vb2_is_busy(&queue->queue); - mutex_unlock(&queue->mutex); - - return allocated; -} - -/* * Cancel the video buffers queue. * * Cancelling the queue marks all buffers on the irq queue as erroneous, @@ -412,7 +291,7 @@ void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect) unsigned long flags; spin_lock_irqsave(&queue->irqlock, flags); - uvc_queue_return_buffers(queue, UVC_BUF_STATE_ERROR); + __uvc_queue_return_buffers(queue, UVC_BUF_STATE_ERROR); /* * This must be protected by the irqlock spinlock to avoid race * conditions between uvc_buffer_queue and the disconnection event that @@ -476,14 +355,15 @@ static void uvc_queue_buffer_complete(struct kref *ref) struct vb2_buffer *vb = &buf->buf.vb2_buf; struct uvc_video_queue *queue = vb2_get_drv_priv(vb->vb2_queue); - if ((queue->flags & UVC_QUEUE_DROP_CORRUPTED) && buf->error) { + if (buf->error && !uvc_no_drop_param) { uvc_queue_buffer_requeue(queue, buf); return; } buf->state = buf->error ? UVC_BUF_STATE_ERROR : UVC_BUF_STATE_DONE; vb2_set_plane_payload(&buf->buf.vb2_buf, 0, buf->bytesused); - vb2_buffer_done(&buf->buf.vb2_buf, VB2_BUF_STATE_DONE); + vb2_buffer_done(&buf->buf.vb2_buf, buf->error ? VB2_BUF_STATE_ERROR : + VB2_BUF_STATE_DONE); } /* diff --git a/drivers/media/usb/uvc/uvc_status.c b/drivers/media/usb/uvc/uvc_status.c index 7518ffce22ed..231cfee8e7c2 100644 --- a/drivers/media/usb/uvc/uvc_status.c +++ b/drivers/media/usb/uvc/uvc_status.c @@ -6,6 +6,7 @@ * Laurent Pinchart (laurent.pinchart@ideasonboard.com) */ +#include <asm/barrier.h> #include <linux/kernel.h> #include <linux/input.h> #include <linux/slab.h> @@ -18,11 +19,34 @@ * Input device */ #ifdef CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV + +static bool uvc_input_has_button(struct uvc_device *dev) +{ + struct uvc_streaming *stream; + + /* + * The device has button events if both bTriggerSupport and + * bTriggerUsage are one. Otherwise the camera button does not + * exist or is handled automatically by the camera without host + * driver or client application intervention. + */ + list_for_each_entry(stream, &dev->streams, list) { + if (stream->header.bTriggerSupport == 1 && + stream->header.bTriggerUsage == 1) + return true; + } + + return false; +} + static int uvc_input_init(struct uvc_device *dev) { struct input_dev *input; int ret; + if (!uvc_input_has_button(dev)) + return 0; + input = input_allocate_device(); if (input == NULL) return -ENOMEM; @@ -38,7 +62,8 @@ static int uvc_input_init(struct uvc_device *dev) __set_bit(EV_KEY, input->evbit); __set_bit(KEY_CAMERA, input->keybit); - if ((ret = input_register_device(input)) < 0) + ret = input_register_device(input); + if (ret < 0) goto error; dev->input = input; @@ -73,38 +98,23 @@ static void uvc_input_report_key(struct uvc_device *dev, unsigned int code, /* -------------------------------------------------------------------------- * Status interrupt endpoint */ -struct uvc_streaming_status { - u8 bStatusType; - u8 bOriginator; - u8 bEvent; - u8 bValue[]; -} __packed; - -struct uvc_control_status { - u8 bStatusType; - u8 bOriginator; - u8 bEvent; - u8 bSelector; - u8 bAttribute; - u8 bValue[]; -} __packed; - static void uvc_event_streaming(struct uvc_device *dev, - struct uvc_streaming_status *status, int len) + struct uvc_status *status, int len) { - if (len < 3) { + if (len <= offsetof(struct uvc_status, bEvent)) { uvc_dbg(dev, STATUS, "Invalid streaming status event received\n"); return; } if (status->bEvent == 0) { - if (len < 4) + if (len <= offsetof(struct uvc_status, streaming)) return; + uvc_dbg(dev, STATUS, "Button (intf %u) %s len %d\n", status->bOriginator, - status->bValue[0] ? "pressed" : "released", len); - uvc_input_report_key(dev, KEY_CAMERA, status->bValue[0]); + status->streaming.button ? "pressed" : "released", len); + uvc_input_report_key(dev, KEY_CAMERA, status->streaming.button); } else { uvc_dbg(dev, STATUS, "Stream %u error event %02x len %d\n", status->bOriginator, status->bEvent, len); @@ -131,7 +141,7 @@ static struct uvc_control *uvc_event_entity_find_ctrl(struct uvc_entity *entity, } static struct uvc_control *uvc_event_find_ctrl(struct uvc_device *dev, - const struct uvc_control_status *status, + const struct uvc_status *status, struct uvc_video_chain **chain) { list_for_each_entry((*chain), &dev->chains, list) { @@ -143,7 +153,7 @@ static struct uvc_control *uvc_event_find_ctrl(struct uvc_device *dev, continue; ctrl = uvc_event_entity_find_ctrl(entity, - status->bSelector); + status->control.bSelector); if (ctrl) return ctrl; } @@ -153,7 +163,7 @@ static struct uvc_control *uvc_event_find_ctrl(struct uvc_device *dev, } static bool uvc_event_control(struct urb *urb, - const struct uvc_control_status *status, int len) + const struct uvc_status *status, int len) { static const char *attrs[] = { "value", "info", "failure", "min", "max" }; struct uvc_device *dev = urb->context; @@ -161,24 +171,24 @@ static bool uvc_event_control(struct urb *urb, struct uvc_control *ctrl; if (len < 6 || status->bEvent != 0 || - status->bAttribute >= ARRAY_SIZE(attrs)) { + status->control.bAttribute >= ARRAY_SIZE(attrs)) { uvc_dbg(dev, STATUS, "Invalid control status event received\n"); return false; } uvc_dbg(dev, STATUS, "Control %u/%u %s change len %d\n", - status->bOriginator, status->bSelector, - attrs[status->bAttribute], len); + status->bOriginator, status->control.bSelector, + attrs[status->control.bAttribute], len); /* Find the control. */ ctrl = uvc_event_find_ctrl(dev, status, &chain); if (!ctrl) return false; - switch (status->bAttribute) { + switch (status->control.bAttribute) { case UVC_CTRL_VALUE_CHANGE: return uvc_ctrl_status_event_async(urb, chain, ctrl, - status->bValue); + status->control.bValue); case UVC_CTRL_INFO_CHANGE: case UVC_CTRL_FAILURE_CHANGE: @@ -206,7 +216,7 @@ static void uvc_status_complete(struct urb *urb) return; default: - dev_warn(&dev->udev->dev, + dev_warn(&dev->intf->dev, "Non-zero status (%d) in status completion handler.\n", urb->status); return; @@ -214,28 +224,22 @@ static void uvc_status_complete(struct urb *urb) len = urb->actual_length; if (len > 0) { - switch (dev->status[0] & 0x0f) { + switch (dev->status->bStatusType & 0x0f) { case UVC_STATUS_TYPE_CONTROL: { - struct uvc_control_status *status = - (struct uvc_control_status *)dev->status; - - if (uvc_event_control(urb, status, len)) + if (uvc_event_control(urb, dev->status, len)) /* The URB will be resubmitted in work context. */ return; break; } case UVC_STATUS_TYPE_STREAMING: { - struct uvc_streaming_status *status = - (struct uvc_streaming_status *)dev->status; - - uvc_event_streaming(dev, status, len); + uvc_event_streaming(dev, dev->status, len); break; } default: uvc_dbg(dev, STATUS, "Unknown status event type %u\n", - dev->status[0]); + dev->status->bStatusType); break; } } @@ -244,7 +248,7 @@ static void uvc_status_complete(struct urb *urb) urb->interval = dev->int_ep->desc.bInterval; ret = usb_submit_urb(urb, GFP_ATOMIC); if (ret < 0) - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "Failed to resubmit status URB (%d).\n", ret); } @@ -254,18 +258,19 @@ int uvc_status_init(struct uvc_device *dev) unsigned int pipe; int interval; + mutex_init(&dev->status_lock); + if (ep == NULL) return 0; - uvc_input_init(dev); - - dev->status = kzalloc(UVC_MAX_STATUS_SIZE, GFP_KERNEL); - if (dev->status == NULL) + dev->status = kzalloc(sizeof(*dev->status), GFP_KERNEL); + if (!dev->status) return -ENOMEM; dev->int_urb = usb_alloc_urb(0, GFP_KERNEL); - if (dev->int_urb == NULL) { + if (!dev->int_urb) { kfree(dev->status); + dev->status = NULL; return -ENOMEM; } @@ -281,15 +286,20 @@ int uvc_status_init(struct uvc_device *dev) interval = fls(interval) - 1; usb_fill_int_urb(dev->int_urb, dev->udev, pipe, - dev->status, UVC_MAX_STATUS_SIZE, uvc_status_complete, + dev->status, sizeof(*dev->status), uvc_status_complete, dev, interval); + uvc_input_init(dev); + return 0; } void uvc_status_unregister(struct uvc_device *dev) { - usb_kill_urb(dev->int_urb); + if (!dev->status) + return; + + uvc_status_suspend(dev); uvc_input_unregister(dev); } @@ -299,15 +309,104 @@ void uvc_status_cleanup(struct uvc_device *dev) kfree(dev->status); } -int uvc_status_start(struct uvc_device *dev, gfp_t flags) +static int uvc_status_start(struct uvc_device *dev, gfp_t flags) { - if (dev->int_urb == NULL) + lockdep_assert_held(&dev->status_lock); + + if (!dev->int_urb) return 0; return usb_submit_urb(dev->int_urb, flags); } -void uvc_status_stop(struct uvc_device *dev) +static void uvc_status_stop(struct uvc_device *dev) { + struct uvc_ctrl_work *w = &dev->async_ctrl; + + lockdep_assert_held(&dev->status_lock); + + if (!dev->int_urb) + return; + + /* + * Prevent the asynchronous control handler from requeing the URB. The + * barrier is needed so the flush_status change is visible to other + * CPUs running the asynchronous handler before usb_kill_urb() is + * called below. + */ + smp_store_release(&dev->flush_status, true); + + /* + * Cancel any pending asynchronous work. If any status event was queued, + * process it synchronously. + */ + if (cancel_work_sync(&w->work)) + uvc_ctrl_status_event(w->chain, w->ctrl, w->data); + + /* Kill the urb. */ usb_kill_urb(dev->int_urb); + + /* + * The URB completion handler may have queued asynchronous work. This + * won't resubmit the URB as flush_status is set, but it needs to be + * cancelled before returning or it could then race with a future + * uvc_status_start() call. + */ + if (cancel_work_sync(&w->work)) + uvc_ctrl_status_event(w->chain, w->ctrl, w->data); + + /* + * From this point, there are no events on the queue and the status URB + * is dead. No events will be queued until uvc_status_start() is called. + * The barrier is needed to make sure that flush_status is visible to + * uvc_ctrl_status_event_work() when uvc_status_start() will be called + * again. + */ + smp_store_release(&dev->flush_status, false); +} + +int uvc_status_resume(struct uvc_device *dev) +{ + guard(mutex)(&dev->status_lock); + + if (dev->status_users) + return uvc_status_start(dev, GFP_NOIO); + + return 0; +} + +void uvc_status_suspend(struct uvc_device *dev) +{ + guard(mutex)(&dev->status_lock); + + if (dev->status_users) + uvc_status_stop(dev); +} + +int uvc_status_get(struct uvc_device *dev) +{ + int ret; + + guard(mutex)(&dev->status_lock); + + if (!dev->status_users) { + ret = uvc_status_start(dev, GFP_KERNEL); + if (ret) + return ret; + } + + dev->status_users++; + + return 0; +} + +void uvc_status_put(struct uvc_device *dev) +{ + guard(mutex)(&dev->status_lock); + + if (dev->status_users == 1) + uvc_status_stop(dev); + WARN_ON(!dev->status_users); + if (dev->status_users) + dev->status_users--; } diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c index f4d4c33b6dfb..9e4a251eca88 100644 --- a/drivers/media/usb/uvc/uvc_v4l2.c +++ b/drivers/media/usb/uvc/uvc_v4l2.c @@ -6,6 +6,7 @@ * Laurent Pinchart (laurent.pinchart@ideasonboard.com) */ +#include <linux/bits.h> #include <linux/compat.h> #include <linux/kernel.h> #include <linux/list.h> @@ -25,16 +26,113 @@ #include "uvcvideo.h" +int uvc_pm_get(struct uvc_device *dev) +{ + int ret; + + ret = usb_autopm_get_interface(dev->intf); + if (ret) + return ret; + + ret = uvc_status_get(dev); + if (ret) + usb_autopm_put_interface(dev->intf); + + return ret; +} + +void uvc_pm_put(struct uvc_device *dev) +{ + uvc_status_put(dev); + usb_autopm_put_interface(dev->intf); +} + +static int uvc_control_add_xu_mapping(struct uvc_video_chain *chain, + struct uvc_control_mapping *map, + const struct uvc_xu_control_mapping *xmap) +{ + unsigned int i; + size_t size; + int ret; + + /* + * Prevent excessive memory consumption, as well as integer + * overflows. + */ + if (xmap->menu_count == 0 || + xmap->menu_count > UVC_MAX_CONTROL_MENU_ENTRIES) + return -EINVAL; + + map->menu_names = NULL; + map->menu_mapping = NULL; + + map->menu_mask = GENMASK(xmap->menu_count - 1, 0); + + size = xmap->menu_count * sizeof(*map->menu_mapping); + map->menu_mapping = kzalloc(size, GFP_KERNEL); + if (!map->menu_mapping) { + ret = -ENOMEM; + goto done; + } + + for (i = 0; i < xmap->menu_count ; i++) { + if (copy_from_user((u32 *)&map->menu_mapping[i], + &xmap->menu_info[i].value, + sizeof(map->menu_mapping[i]))) { + ret = -EACCES; + goto done; + } + } + + /* + * Always use the standard naming if available, otherwise copy the + * names supplied by userspace. + */ + if (!v4l2_ctrl_get_menu(map->id)) { + size = xmap->menu_count * sizeof(map->menu_names[0]); + map->menu_names = kzalloc(size, GFP_KERNEL); + if (!map->menu_names) { + ret = -ENOMEM; + goto done; + } + + for (i = 0; i < xmap->menu_count ; i++) { + /* sizeof(names[i]) - 1: to take care of \0 */ + if (copy_from_user((char *)map->menu_names[i], + xmap->menu_info[i].name, + sizeof(map->menu_names[i]) - 1)) { + ret = -EACCES; + goto done; + } + } + } + + ret = uvc_ctrl_add_mapping(chain, map); + +done: + kfree(map->menu_names); + map->menu_names = NULL; + kfree(map->menu_mapping); + map->menu_mapping = NULL; + + return ret; +} + /* ------------------------------------------------------------------------ * UVC ioctls */ -static int uvc_ioctl_ctrl_map(struct uvc_video_chain *chain, - struct uvc_xu_control_mapping *xmap) +static int uvc_ioctl_xu_ctrl_map(struct uvc_video_chain *chain, + struct uvc_xu_control_mapping *xmap) { struct uvc_control_mapping *map; - unsigned int size; int ret; + if (xmap->data_type > UVC_CTRL_DATA_TYPE_BITMASK) { + uvc_dbg(chain->dev, CONTROL, + "Unsupported UVC data type %u\n", xmap->data_type); + return -EINVAL; + } + map = kzalloc(sizeof(*map), GFP_KERNEL); if (map == NULL) return -ENOMEM; @@ -60,39 +158,20 @@ static int uvc_ioctl_ctrl_map(struct uvc_video_chain *chain, case V4L2_CTRL_TYPE_INTEGER: case V4L2_CTRL_TYPE_BOOLEAN: case V4L2_CTRL_TYPE_BUTTON: + ret = uvc_ctrl_add_mapping(chain, map); break; case V4L2_CTRL_TYPE_MENU: - /* - * Prevent excessive memory consumption, as well as integer - * overflows. - */ - if (xmap->menu_count == 0 || - xmap->menu_count > UVC_MAX_CONTROL_MENU_ENTRIES) { - ret = -EINVAL; - goto free_map; - } - - size = xmap->menu_count * sizeof(*map->menu_info); - map->menu_info = memdup_user(xmap->menu_info, size); - if (IS_ERR(map->menu_info)) { - ret = PTR_ERR(map->menu_info); - goto free_map; - } - - map->menu_count = xmap->menu_count; + ret = uvc_control_add_xu_mapping(chain, map, xmap); break; default: uvc_dbg(chain->dev, CONTROL, "Unsupported V4L2 control type %u\n", xmap->v4l2_type); ret = -ENOTTY; - goto free_map; + break; } - ret = uvc_ctrl_add_mapping(chain, map); - - kfree(map->menu_info); free_map: kfree(map); @@ -109,7 +188,7 @@ free_map: * the Video Probe and Commit negotiation, but some hardware don't implement * that feature. */ -static u32 uvc_try_frame_interval(struct uvc_frame *frame, u32 interval) +static u32 uvc_try_frame_interval(const struct uvc_frame *frame, u32 interval) { unsigned int i; @@ -158,10 +237,11 @@ static u32 uvc_v4l2_get_bytesperline(const struct uvc_format *format, static int uvc_v4l2_try_format(struct uvc_streaming *stream, struct v4l2_format *fmt, struct uvc_streaming_control *probe, - struct uvc_format **uvc_format, struct uvc_frame **uvc_frame) + const struct uvc_format **uvc_format, + const struct uvc_frame **uvc_frame) { - struct uvc_format *format = NULL; - struct uvc_frame *frame = NULL; + const struct uvc_format *format = NULL; + const struct uvc_frame *frame = NULL; u16 rw, rh; unsigned int d, maxd; unsigned int i; @@ -183,7 +263,7 @@ static int uvc_v4l2_try_format(struct uvc_streaming *stream, * format otherwise. */ for (i = 0; i < stream->nformats; ++i) { - format = &stream->format[i]; + format = &stream->formats[i]; if (format->fcc == fmt->fmt.pix.pixelformat) break; } @@ -203,14 +283,14 @@ static int uvc_v4l2_try_format(struct uvc_streaming *stream, maxd = (unsigned int)-1; for (i = 0; i < format->nframes; ++i) { - u16 w = format->frame[i].wWidth; - u16 h = format->frame[i].wHeight; + u16 w = format->frames[i].wWidth; + u16 h = format->frames[i].wHeight; d = min(w, rw) * min(h, rh); d = w*h + rw*rh - 2*d; if (d < maxd) { maxd = d; - frame = &format->frame[i]; + frame = &format->frames[i]; } if (maxd == 0) @@ -249,14 +329,12 @@ static int uvc_v4l2_try_format(struct uvc_streaming *stream, * developers test their webcams with the Linux driver as well as with * the Windows driver). */ - mutex_lock(&stream->mutex); if (stream->dev->quirks & UVC_QUIRK_PROBE_EXTRAFIELDS) probe->dwMaxVideoFrameSize = stream->ctrl.dwMaxVideoFrameSize; /* Probe the device. */ ret = uvc_probe_video(stream, probe); - mutex_unlock(&stream->mutex); if (ret < 0) return ret; @@ -267,8 +345,8 @@ static int uvc_v4l2_try_format(struct uvc_streaming *stream, * accepted the requested format as-is. */ for (i = 0; i < stream->nformats; ++i) { - if (probe->bFormatIndex == stream->format[i].index) { - format = &stream->format[i]; + if (probe->bFormatIndex == stream->formats[i].index) { + format = &stream->formats[i]; break; } } @@ -279,8 +357,8 @@ static int uvc_v4l2_try_format(struct uvc_streaming *stream, probe->bFormatIndex); for (i = 0; i < format->nframes; ++i) { - if (probe->bFrameIndex == format->frame[i].bFrameIndex) { - frame = &format->frame[i]; + if (probe->bFrameIndex == format->frames[i].bFrameIndex) { + frame = &format->frames[i]; break; } } @@ -308,24 +386,22 @@ static int uvc_v4l2_try_format(struct uvc_streaming *stream, return ret; } -static int uvc_v4l2_get_format(struct uvc_streaming *stream, - struct v4l2_format *fmt) +static int uvc_ioctl_g_fmt(struct file *file, void *priv, + struct v4l2_format *fmt) { - struct uvc_format *format; - struct uvc_frame *frame; - int ret = 0; + struct uvc_fh *handle = to_uvc_fh(file); + struct uvc_streaming *stream = handle->stream; + const struct uvc_format *format; + const struct uvc_frame *frame; if (fmt->type != stream->type) return -EINVAL; - mutex_lock(&stream->mutex); format = stream->cur_format; frame = stream->cur_frame; - if (format == NULL || frame == NULL) { - ret = -EINVAL; - goto done; - } + if (!format || !frame) + return -EINVAL; fmt->fmt.pix.pixelformat = format->fcc; fmt->fmt.pix.width = frame->wWidth; @@ -337,17 +413,17 @@ static int uvc_v4l2_get_format(struct uvc_streaming *stream, fmt->fmt.pix.xfer_func = format->xfer_func; fmt->fmt.pix.ycbcr_enc = format->ycbcr_enc; -done: - mutex_unlock(&stream->mutex); - return ret; + return 0; } -static int uvc_v4l2_set_format(struct uvc_streaming *stream, - struct v4l2_format *fmt) +static int uvc_ioctl_s_fmt(struct file *file, void *priv, + struct v4l2_format *fmt) { + struct uvc_fh *handle = to_uvc_fh(file); + struct uvc_streaming *stream = handle->stream; struct uvc_streaming_control probe; - struct uvc_format *format; - struct uvc_frame *frame; + const struct uvc_format *format; + const struct uvc_frame *frame; int ret; if (fmt->type != stream->type) @@ -357,34 +433,27 @@ static int uvc_v4l2_set_format(struct uvc_streaming *stream, if (ret < 0) return ret; - mutex_lock(&stream->mutex); - - if (uvc_queue_allocated(&stream->queue)) { - ret = -EBUSY; - goto done; - } + if (vb2_is_busy(&stream->queue.queue)) + return -EBUSY; stream->ctrl = probe; stream->cur_format = format; stream->cur_frame = frame; -done: - mutex_unlock(&stream->mutex); - return ret; + return 0; } -static int uvc_v4l2_get_streamparm(struct uvc_streaming *stream, - struct v4l2_streamparm *parm) +static int uvc_ioctl_g_parm(struct file *file, void *priv, + struct v4l2_streamparm *parm) { u32 numerator, denominator; + struct uvc_fh *handle = to_uvc_fh(file); + struct uvc_streaming *stream = handle->stream; if (parm->type != stream->type) return -EINVAL; - mutex_lock(&stream->mutex); numerator = stream->ctrl.dwFrameInterval; - mutex_unlock(&stream->mutex); - denominator = 10000000; v4l2_simplify_fraction(&numerator, &denominator, 8, 333); @@ -408,13 +477,15 @@ static int uvc_v4l2_get_streamparm(struct uvc_streaming *stream, return 0; } -static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream, - struct v4l2_streamparm *parm) +static int uvc_ioctl_s_parm(struct file *file, void *priv, + struct v4l2_streamparm *parm) { + struct uvc_fh *handle = to_uvc_fh(file); + struct uvc_streaming *stream = handle->stream; struct uvc_streaming_control probe; struct v4l2_fract timeperframe; - struct uvc_format *format; - struct uvc_frame *frame; + const struct uvc_format *format; + const struct uvc_frame *frame; u32 interval, maxd; unsigned int i; int ret; @@ -432,12 +503,8 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream, uvc_dbg(stream->dev, FORMAT, "Setting frame interval to %u/%u (%u)\n", timeperframe.numerator, timeperframe.denominator, interval); - mutex_lock(&stream->mutex); - - if (uvc_queue_streaming(&stream->queue)) { - mutex_unlock(&stream->mutex); + if (uvc_queue_streaming(&stream->queue)) return -EBUSY; - } format = stream->cur_format; frame = stream->cur_frame; @@ -449,19 +516,19 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream, for (i = 0; i < format->nframes && maxd != 0; i++) { u32 d, ival; - if (&format->frame[i] == stream->cur_frame) + if (&format->frames[i] == stream->cur_frame) continue; - if (format->frame[i].wWidth != stream->cur_frame->wWidth || - format->frame[i].wHeight != stream->cur_frame->wHeight) + if (format->frames[i].wWidth != stream->cur_frame->wWidth || + format->frames[i].wHeight != stream->cur_frame->wHeight) continue; - ival = uvc_try_frame_interval(&format->frame[i], interval); + ival = uvc_try_frame_interval(&format->frames[i], interval); d = abs((s32)ival - interval); if (d >= maxd) continue; - frame = &format->frame[i]; + frame = &format->frames[i]; probe.bFrameIndex = frame->bFrameIndex; probe.dwFrameInterval = ival; maxd = d; @@ -469,14 +536,11 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream, /* Probe the device with the new settings. */ ret = uvc_probe_video(stream, &probe); - if (ret < 0) { - mutex_unlock(&stream->mutex); + if (ret < 0) return ret; - } stream->ctrl = probe; stream->cur_frame = frame; - mutex_unlock(&stream->mutex); /* Return the actual frame period. */ timeperframe.numerator = probe.dwFrameInterval; @@ -496,62 +560,6 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream, } /* ------------------------------------------------------------------------ - * Privilege management - */ - -/* - * Privilege management is the multiple-open implementation basis. The current - * implementation is completely transparent for the end-user and doesn't - * require explicit use of the VIDIOC_G_PRIORITY and VIDIOC_S_PRIORITY ioctls. - * Those ioctls enable finer control on the device (by making possible for a - * user to request exclusive access to a device), but are not mature yet. - * Switching to the V4L2 priority mechanism might be considered in the future - * if this situation changes. - * - * Each open instance of a UVC device can either be in a privileged or - * unprivileged state. Only a single instance can be in a privileged state at - * a given time. Trying to perform an operation that requires privileges will - * automatically acquire the required privileges if possible, or return -EBUSY - * otherwise. Privileges are dismissed when closing the instance or when - * freeing the video buffers using VIDIOC_REQBUFS. - * - * Operations that require privileges are: - * - * - VIDIOC_S_INPUT - * - VIDIOC_S_PARM - * - VIDIOC_S_FMT - * - VIDIOC_REQBUFS - */ -static int uvc_acquire_privileges(struct uvc_fh *handle) -{ - /* Always succeed if the handle is already privileged. */ - if (handle->state == UVC_HANDLE_ACTIVE) - return 0; - - /* Check if the device already has a privileged handle. */ - if (atomic_inc_return(&handle->stream->active) != 1) { - atomic_dec(&handle->stream->active); - return -EBUSY; - } - - handle->state = UVC_HANDLE_ACTIVE; - return 0; -} - -static void uvc_dismiss_privileges(struct uvc_fh *handle) -{ - if (handle->state == UVC_HANDLE_ACTIVE) - atomic_dec(&handle->stream->active); - - handle->state = UVC_HANDLE_PASSIVE; -} - -static int uvc_has_privileges(struct uvc_fh *handle) -{ - return handle->state == UVC_HANDLE_ACTIVE; -} - -/* ------------------------------------------------------------------------ * V4L2 file operations */ @@ -559,77 +567,42 @@ static int uvc_v4l2_open(struct file *file) { struct uvc_streaming *stream; struct uvc_fh *handle; - int ret = 0; stream = video_drvdata(file); uvc_dbg(stream->dev, CALLS, "%s\n", __func__); - ret = usb_autopm_get_interface(stream->dev->intf); - if (ret < 0) - return ret; - /* Create the device handle. */ handle = kzalloc(sizeof(*handle), GFP_KERNEL); - if (handle == NULL) { - usb_autopm_put_interface(stream->dev->intf); + if (!handle) return -ENOMEM; - } - mutex_lock(&stream->dev->lock); - if (stream->dev->users == 0) { - ret = uvc_status_start(stream->dev, GFP_KERNEL); - if (ret < 0) { - mutex_unlock(&stream->dev->lock); - usb_autopm_put_interface(stream->dev->intf); - kfree(handle); - return ret; - } - } - - stream->dev->users++; - mutex_unlock(&stream->dev->lock); - - v4l2_fh_init(&handle->vfh, &stream->vdev); - v4l2_fh_add(&handle->vfh); + v4l2_fh_init(&handle->vfh, &stream->queue.vdev); + v4l2_fh_add(&handle->vfh, file); handle->chain = stream->chain; handle->stream = stream; - handle->state = UVC_HANDLE_PASSIVE; - file->private_data = handle; return 0; } static int uvc_v4l2_release(struct file *file) { - struct uvc_fh *handle = file->private_data; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_streaming *stream = handle->stream; uvc_dbg(stream->dev, CALLS, "%s\n", __func__); - /* Only free resources if this is a privileged handle. */ - if (uvc_has_privileges(handle)) - uvc_queue_release(&stream->queue); + uvc_ctrl_cleanup_fh(handle); /* Release the file handle. */ - uvc_dismiss_privileges(handle); - v4l2_fh_del(&handle->vfh); - v4l2_fh_exit(&handle->vfh); - kfree(handle); - file->private_data = NULL; - - mutex_lock(&stream->dev->lock); - if (--stream->dev->users == 0) - uvc_status_stop(stream->dev); - mutex_unlock(&stream->dev->lock); - - usb_autopm_put_interface(stream->dev->intf); + vb2_fop_release(file); + return 0; } -static int uvc_ioctl_querycap(struct file *file, void *fh, +static int uvc_ioctl_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct uvc_fh *handle = file->private_data; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_video_chain *chain = handle->chain; struct uvc_streaming *stream = handle->stream; @@ -642,11 +615,13 @@ static int uvc_ioctl_querycap(struct file *file, void *fh, return 0; } -static int uvc_ioctl_enum_fmt(struct uvc_streaming *stream, +static int uvc_ioctl_enum_fmt(struct file *file, void *priv, struct v4l2_fmtdesc *fmt) { - struct uvc_format *format; + struct uvc_fh *handle = to_uvc_fh(file); + struct uvc_streaming *stream = handle->stream; enum v4l2_buf_type type = fmt->type; + const struct uvc_format *format; u32 index = fmt->index; if (fmt->type != stream->type || fmt->index >= stream->nformats) @@ -656,222 +631,28 @@ static int uvc_ioctl_enum_fmt(struct uvc_streaming *stream, fmt->index = index; fmt->type = type; - format = &stream->format[fmt->index]; + format = &stream->formats[fmt->index]; fmt->flags = 0; if (format->flags & UVC_FMT_FLAG_COMPRESSED) fmt->flags |= V4L2_FMT_FLAG_COMPRESSED; - strscpy(fmt->description, format->name, sizeof(fmt->description)); - fmt->description[sizeof(fmt->description) - 1] = 0; fmt->pixelformat = format->fcc; return 0; } -static int uvc_ioctl_enum_fmt_vid_cap(struct file *file, void *fh, - struct v4l2_fmtdesc *fmt) -{ - struct uvc_fh *handle = fh; - struct uvc_streaming *stream = handle->stream; - - return uvc_ioctl_enum_fmt(stream, fmt); -} - -static int uvc_ioctl_enum_fmt_vid_out(struct file *file, void *fh, - struct v4l2_fmtdesc *fmt) +static int uvc_ioctl_try_fmt(struct file *file, void *priv, + struct v4l2_format *fmt) { - struct uvc_fh *handle = fh; - struct uvc_streaming *stream = handle->stream; - - return uvc_ioctl_enum_fmt(stream, fmt); -} - -static int uvc_ioctl_g_fmt_vid_cap(struct file *file, void *fh, - struct v4l2_format *fmt) -{ - struct uvc_fh *handle = fh; - struct uvc_streaming *stream = handle->stream; - - return uvc_v4l2_get_format(stream, fmt); -} - -static int uvc_ioctl_g_fmt_vid_out(struct file *file, void *fh, - struct v4l2_format *fmt) -{ - struct uvc_fh *handle = fh; - struct uvc_streaming *stream = handle->stream; - - return uvc_v4l2_get_format(stream, fmt); -} - -static int uvc_ioctl_s_fmt_vid_cap(struct file *file, void *fh, - struct v4l2_format *fmt) -{ - struct uvc_fh *handle = fh; - struct uvc_streaming *stream = handle->stream; - int ret; - - ret = uvc_acquire_privileges(handle); - if (ret < 0) - return ret; - - return uvc_v4l2_set_format(stream, fmt); -} - -static int uvc_ioctl_s_fmt_vid_out(struct file *file, void *fh, - struct v4l2_format *fmt) -{ - struct uvc_fh *handle = fh; - struct uvc_streaming *stream = handle->stream; - int ret; - - ret = uvc_acquire_privileges(handle); - if (ret < 0) - return ret; - - return uvc_v4l2_set_format(stream, fmt); -} - -static int uvc_ioctl_try_fmt_vid_cap(struct file *file, void *fh, - struct v4l2_format *fmt) -{ - struct uvc_fh *handle = fh; - struct uvc_streaming *stream = handle->stream; - struct uvc_streaming_control probe; - - return uvc_v4l2_try_format(stream, fmt, &probe, NULL, NULL); -} - -static int uvc_ioctl_try_fmt_vid_out(struct file *file, void *fh, - struct v4l2_format *fmt) -{ - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_streaming *stream = handle->stream; struct uvc_streaming_control probe; return uvc_v4l2_try_format(stream, fmt, &probe, NULL, NULL); } -static int uvc_ioctl_reqbufs(struct file *file, void *fh, - struct v4l2_requestbuffers *rb) -{ - struct uvc_fh *handle = fh; - struct uvc_streaming *stream = handle->stream; - int ret; - - ret = uvc_acquire_privileges(handle); - if (ret < 0) - return ret; - - mutex_lock(&stream->mutex); - ret = uvc_request_buffers(&stream->queue, rb); - mutex_unlock(&stream->mutex); - if (ret < 0) - return ret; - - if (ret == 0) - uvc_dismiss_privileges(handle); - - return 0; -} - -static int uvc_ioctl_querybuf(struct file *file, void *fh, - struct v4l2_buffer *buf) -{ - struct uvc_fh *handle = fh; - struct uvc_streaming *stream = handle->stream; - - if (!uvc_has_privileges(handle)) - return -EBUSY; - - return uvc_query_buffer(&stream->queue, buf); -} - -static int uvc_ioctl_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf) -{ - struct uvc_fh *handle = fh; - struct uvc_streaming *stream = handle->stream; - - if (!uvc_has_privileges(handle)) - return -EBUSY; - - return uvc_queue_buffer(&stream->queue, - stream->vdev.v4l2_dev->mdev, buf); -} - -static int uvc_ioctl_expbuf(struct file *file, void *fh, - struct v4l2_exportbuffer *exp) -{ - struct uvc_fh *handle = fh; - struct uvc_streaming *stream = handle->stream; - - if (!uvc_has_privileges(handle)) - return -EBUSY; - - return uvc_export_buffer(&stream->queue, exp); -} - -static int uvc_ioctl_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf) -{ - struct uvc_fh *handle = fh; - struct uvc_streaming *stream = handle->stream; - - if (!uvc_has_privileges(handle)) - return -EBUSY; - - return uvc_dequeue_buffer(&stream->queue, buf, - file->f_flags & O_NONBLOCK); -} - -static int uvc_ioctl_create_bufs(struct file *file, void *fh, - struct v4l2_create_buffers *cb) -{ - struct uvc_fh *handle = fh; - struct uvc_streaming *stream = handle->stream; - int ret; - - ret = uvc_acquire_privileges(handle); - if (ret < 0) - return ret; - - return uvc_create_buffers(&stream->queue, cb); -} - -static int uvc_ioctl_streamon(struct file *file, void *fh, - enum v4l2_buf_type type) -{ - struct uvc_fh *handle = fh; - struct uvc_streaming *stream = handle->stream; - int ret; - - if (!uvc_has_privileges(handle)) - return -EBUSY; - - mutex_lock(&stream->mutex); - ret = uvc_queue_streamon(&stream->queue, type); - mutex_unlock(&stream->mutex); - - return ret; -} - -static int uvc_ioctl_streamoff(struct file *file, void *fh, - enum v4l2_buf_type type) -{ - struct uvc_fh *handle = fh; - struct uvc_streaming *stream = handle->stream; - - if (!uvc_has_privileges(handle)) - return -EBUSY; - - mutex_lock(&stream->mutex); - uvc_queue_streamoff(&stream->queue, type); - mutex_unlock(&stream->mutex); - - return 0; -} - -static int uvc_ioctl_enum_input(struct file *file, void *fh, +static int uvc_ioctl_enum_input(struct file *file, void *priv, struct v4l2_input *input) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_video_chain *chain = handle->chain; const struct uvc_entity *selector = chain->selector; struct uvc_entity *iterm = NULL; @@ -911,9 +692,9 @@ static int uvc_ioctl_enum_input(struct file *file, void *fh, return 0; } -static int uvc_ioctl_g_input(struct file *file, void *fh, unsigned int *input) +static int uvc_ioctl_g_input(struct file *file, void *priv, unsigned int *input) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_video_chain *chain = handle->chain; u8 *buf; int ret; @@ -939,16 +720,16 @@ static int uvc_ioctl_g_input(struct file *file, void *fh, unsigned int *input) return ret; } -static int uvc_ioctl_s_input(struct file *file, void *fh, unsigned int input) +static int uvc_ioctl_s_input(struct file *file, void *priv, unsigned int input) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); + struct uvc_streaming *stream = handle->stream; struct uvc_video_chain *chain = handle->chain; u8 *buf; int ret; - ret = uvc_acquire_privileges(handle); - if (ret < 0) - return ret; + if (vb2_is_busy(&stream->queue.queue)) + return -EBUSY; if (chain->selector == NULL || (chain->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) { @@ -973,42 +754,13 @@ static int uvc_ioctl_s_input(struct file *file, void *fh, unsigned int input) return ret; } -static int uvc_ioctl_queryctrl(struct file *file, void *fh, - struct v4l2_queryctrl *qc) -{ - struct uvc_fh *handle = fh; - struct uvc_video_chain *chain = handle->chain; - - return uvc_query_v4l2_ctrl(chain, qc); -} - -static int uvc_ioctl_query_ext_ctrl(struct file *file, void *fh, +static int uvc_ioctl_query_ext_ctrl(struct file *file, void *priv, struct v4l2_query_ext_ctrl *qec) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_video_chain *chain = handle->chain; - struct v4l2_queryctrl qc = { qec->id }; - int ret; - - ret = uvc_query_v4l2_ctrl(chain, &qc); - if (ret) - return ret; - - qec->id = qc.id; - qec->type = qc.type; - strscpy(qec->name, qc.name, sizeof(qec->name)); - qec->minimum = qc.minimum; - qec->maximum = qc.maximum; - qec->step = qc.step; - qec->default_value = qc.default_value; - qec->flags = qc.flags; - qec->elem_size = 4; - qec->elems = 1; - qec->nr_of_dims = 0; - memset(qec->dims, 0, sizeof(qec->dims)); - memset(qec->reserved, 0, sizeof(qec->reserved)); - return 0; + return uvc_query_v4l2_ctrl(chain, qec); } static int uvc_ctrl_check_access(struct uvc_video_chain *chain, @@ -1020,8 +772,7 @@ static int uvc_ctrl_check_access(struct uvc_video_chain *chain, int ret = 0; for (i = 0; i < ctrls->count; ++ctrl, ++i) { - ret = uvc_ctrl_is_accessible(chain, ctrl->id, - ioctl == VIDIOC_G_EXT_CTRLS); + ret = uvc_ctrl_is_accessible(chain, ctrl->id, ctrls, ioctl); if (ret) break; } @@ -1031,41 +782,40 @@ static int uvc_ctrl_check_access(struct uvc_video_chain *chain, return ret; } -static int uvc_ioctl_g_ext_ctrls(struct file *file, void *fh, +static int uvc_ioctl_g_ext_ctrls(struct file *file, void *priv, struct v4l2_ext_controls *ctrls) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_video_chain *chain = handle->chain; struct v4l2_ext_control *ctrl = ctrls->controls; unsigned int i; + u32 which; int ret; + if (!ctrls->count) + return 0; + + switch (ctrls->which) { + case V4L2_CTRL_WHICH_DEF_VAL: + case V4L2_CTRL_WHICH_CUR_VAL: + case V4L2_CTRL_WHICH_MAX_VAL: + case V4L2_CTRL_WHICH_MIN_VAL: + which = ctrls->which; + break; + default: + which = V4L2_CTRL_WHICH_CUR_VAL; + } + ret = uvc_ctrl_check_access(chain, ctrls, VIDIOC_G_EXT_CTRLS); if (ret < 0) return ret; - if (ctrls->which == V4L2_CTRL_WHICH_DEF_VAL) { - for (i = 0; i < ctrls->count; ++ctrl, ++i) { - struct v4l2_queryctrl qc = { .id = ctrl->id }; - - ret = uvc_query_v4l2_ctrl(chain, &qc); - if (ret < 0) { - ctrls->error_idx = i; - return ret; - } - - ctrl->value = qc.default_value; - } - - return 0; - } - ret = uvc_ctrl_begin(chain); if (ret < 0) return ret; for (i = 0; i < ctrls->count; ++ctrl, ++i) { - ret = uvc_ctrl_get(chain, ctrl); + ret = uvc_ctrl_get(chain, which, ctrl); if (ret < 0) { uvc_ctrl_rollback(handle); ctrls->error_idx = i; @@ -1087,6 +837,9 @@ static int uvc_ioctl_s_try_ext_ctrls(struct uvc_fh *handle, unsigned int i; int ret; + if (!ctrls->count) + return 0; + ret = uvc_ctrl_check_access(chain, ctrls, ioctl); if (ret < 0) return ret; @@ -1113,35 +866,35 @@ static int uvc_ioctl_s_try_ext_ctrls(struct uvc_fh *handle, return uvc_ctrl_rollback(handle); } -static int uvc_ioctl_s_ext_ctrls(struct file *file, void *fh, +static int uvc_ioctl_s_ext_ctrls(struct file *file, void *priv, struct v4l2_ext_controls *ctrls) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); return uvc_ioctl_s_try_ext_ctrls(handle, ctrls, VIDIOC_S_EXT_CTRLS); } -static int uvc_ioctl_try_ext_ctrls(struct file *file, void *fh, +static int uvc_ioctl_try_ext_ctrls(struct file *file, void *priv, struct v4l2_ext_controls *ctrls) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); return uvc_ioctl_s_try_ext_ctrls(handle, ctrls, VIDIOC_TRY_EXT_CTRLS); } -static int uvc_ioctl_querymenu(struct file *file, void *fh, +static int uvc_ioctl_querymenu(struct file *file, void *priv, struct v4l2_querymenu *qm) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_video_chain *chain = handle->chain; return uvc_query_v4l2_menu(chain, qm); } -static int uvc_ioctl_g_selection(struct file *file, void *fh, +static int uvc_ioctl_g_selection(struct file *file, void *priv, struct v4l2_selection *sel) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_streaming *stream = handle->stream; if (sel->type != stream->type) @@ -1164,51 +917,26 @@ static int uvc_ioctl_g_selection(struct file *file, void *fh, sel->r.left = 0; sel->r.top = 0; - mutex_lock(&stream->mutex); sel->r.width = stream->cur_frame->wWidth; sel->r.height = stream->cur_frame->wHeight; - mutex_unlock(&stream->mutex); return 0; } -static int uvc_ioctl_g_parm(struct file *file, void *fh, - struct v4l2_streamparm *parm) -{ - struct uvc_fh *handle = fh; - struct uvc_streaming *stream = handle->stream; - - return uvc_v4l2_get_streamparm(stream, parm); -} - -static int uvc_ioctl_s_parm(struct file *file, void *fh, - struct v4l2_streamparm *parm) -{ - struct uvc_fh *handle = fh; - struct uvc_streaming *stream = handle->stream; - int ret; - - ret = uvc_acquire_privileges(handle); - if (ret < 0) - return ret; - - return uvc_v4l2_set_streamparm(stream, parm); -} - -static int uvc_ioctl_enum_framesizes(struct file *file, void *fh, +static int uvc_ioctl_enum_framesizes(struct file *file, void *priv, struct v4l2_frmsizeenum *fsize) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_streaming *stream = handle->stream; - struct uvc_format *format = NULL; - struct uvc_frame *frame = NULL; + const struct uvc_format *format = NULL; + const struct uvc_frame *frame = NULL; unsigned int index; unsigned int i; /* Look for the given pixel format */ for (i = 0; i < stream->nformats; i++) { - if (stream->format[i].fcc == fsize->pixel_format) { - format = &stream->format[i]; + if (stream->formats[i].fcc == fsize->pixel_format) { + format = &stream->formats[i]; break; } } @@ -1217,10 +945,10 @@ static int uvc_ioctl_enum_framesizes(struct file *file, void *fh, /* Skip duplicate frame sizes */ for (i = 0, index = 0; i < format->nframes; i++) { - if (frame && frame->wWidth == format->frame[i].wWidth && - frame->wHeight == format->frame[i].wHeight) + if (frame && frame->wWidth == format->frames[i].wWidth && + frame->wHeight == format->frames[i].wHeight) continue; - frame = &format->frame[i]; + frame = &format->frames[i]; if (index == fsize->index) break; index++; @@ -1235,21 +963,21 @@ static int uvc_ioctl_enum_framesizes(struct file *file, void *fh, return 0; } -static int uvc_ioctl_enum_frameintervals(struct file *file, void *fh, +static int uvc_ioctl_enum_frameintervals(struct file *file, void *priv, struct v4l2_frmivalenum *fival) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_streaming *stream = handle->stream; - struct uvc_format *format = NULL; - struct uvc_frame *frame = NULL; + const struct uvc_format *format = NULL; + const struct uvc_frame *frame = NULL; unsigned int nintervals; unsigned int index; unsigned int i; /* Look for the given pixel format and frame size */ for (i = 0; i < stream->nformats; i++) { - if (stream->format[i].fcc == fival->pixel_format) { - format = &stream->format[i]; + if (stream->formats[i].fcc == fival->pixel_format) { + format = &stream->formats[i]; break; } } @@ -1258,9 +986,9 @@ static int uvc_ioctl_enum_frameintervals(struct file *file, void *fh, index = fival->index; for (i = 0; i < format->nframes; i++) { - if (format->frame[i].wWidth == fival->width && - format->frame[i].wHeight == fival->height) { - frame = &format->frame[i]; + if (format->frames[i].wWidth == fival->width && + format->frames[i].wHeight == fival->height) { + frame = &format->frames[i]; nintervals = frame->bFrameIntervalType ?: 1; if (index < nintervals) break; @@ -1307,16 +1035,16 @@ static int uvc_ioctl_subscribe_event(struct v4l2_fh *fh, } } -static long uvc_ioctl_default(struct file *file, void *fh, bool valid_prio, +static long uvc_ioctl_default(struct file *file, void *priv, bool valid_prio, unsigned int cmd, void *arg) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_video_chain *chain = handle->chain; switch (cmd) { /* Dynamic controls. */ case UVCIOC_CTRL_MAP: - return uvc_ioctl_ctrl_map(chain, arg); + return uvc_ioctl_xu_ctrl_map(chain, arg); case UVCIOC_CTRL_QUERY: return uvc_xu_ctrl_query(chain, arg); @@ -1416,7 +1144,7 @@ static int uvc_v4l2_put_xu_query(const struct uvc_xu_control_query *kp, static long uvc_v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) { - struct uvc_fh *handle = file->private_data; + struct uvc_fh *handle = to_uvc_fh(file); union { struct uvc_xu_control_mapping xmap; struct uvc_xu_control_query xqry; @@ -1424,114 +1152,112 @@ static long uvc_v4l2_compat_ioctl32(struct file *file, void __user *up = compat_ptr(arg); long ret; + ret = uvc_pm_get(handle->stream->dev); + if (ret) + return ret; + switch (cmd) { case UVCIOC_CTRL_MAP32: ret = uvc_v4l2_get_xu_mapping(&karg.xmap, up); if (ret) - return ret; - ret = uvc_ioctl_ctrl_map(handle->chain, &karg.xmap); + break; + ret = uvc_ioctl_xu_ctrl_map(handle->chain, &karg.xmap); if (ret) - return ret; + break; ret = uvc_v4l2_put_xu_mapping(&karg.xmap, up); if (ret) - return ret; - + break; break; case UVCIOC_CTRL_QUERY32: ret = uvc_v4l2_get_xu_query(&karg.xqry, up); if (ret) - return ret; + break; ret = uvc_xu_ctrl_query(handle->chain, &karg.xqry); if (ret) - return ret; + break; ret = uvc_v4l2_put_xu_query(&karg.xqry, up); if (ret) - return ret; + break; break; default: - return -ENOIOCTLCMD; + ret = -ENOIOCTLCMD; + break; } + uvc_pm_put(handle->stream->dev); + return ret; } #endif -static ssize_t uvc_v4l2_read(struct file *file, char __user *data, - size_t count, loff_t *ppos) +static long uvc_v4l2_unlocked_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) { - struct uvc_fh *handle = file->private_data; - struct uvc_streaming *stream = handle->stream; - - uvc_dbg(stream->dev, CALLS, "%s: not implemented\n", __func__); - return -EINVAL; -} - -static int uvc_v4l2_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct uvc_fh *handle = file->private_data; - struct uvc_streaming *stream = handle->stream; - - uvc_dbg(stream->dev, CALLS, "%s\n", __func__); - - return uvc_queue_mmap(&stream->queue, vma); -} - -static __poll_t uvc_v4l2_poll(struct file *file, poll_table *wait) -{ - struct uvc_fh *handle = file->private_data; - struct uvc_streaming *stream = handle->stream; - - uvc_dbg(stream->dev, CALLS, "%s\n", __func__); - - return uvc_queue_poll(&stream->queue, file, wait); -} - -#ifndef CONFIG_MMU -static unsigned long uvc_v4l2_get_unmapped_area(struct file *file, - unsigned long addr, unsigned long len, unsigned long pgoff, - unsigned long flags) -{ - struct uvc_fh *handle = file->private_data; - struct uvc_streaming *stream = handle->stream; + struct uvc_fh *handle = to_uvc_fh(file); + unsigned int converted_cmd = v4l2_translate_cmd(cmd); + int ret; - uvc_dbg(stream->dev, CALLS, "%s\n", __func__); + /* The following IOCTLs need to turn on the camera. */ + switch (converted_cmd) { + case UVCIOC_CTRL_MAP: + case UVCIOC_CTRL_QUERY: + case VIDIOC_G_CTRL: + case VIDIOC_G_EXT_CTRLS: + case VIDIOC_G_INPUT: + case VIDIOC_QUERYCTRL: + case VIDIOC_QUERYMENU: + case VIDIOC_QUERY_EXT_CTRL: + case VIDIOC_S_CTRL: + case VIDIOC_S_EXT_CTRLS: + case VIDIOC_S_FMT: + case VIDIOC_S_INPUT: + case VIDIOC_S_PARM: + case VIDIOC_TRY_EXT_CTRLS: + case VIDIOC_TRY_FMT: + ret = uvc_pm_get(handle->stream->dev); + if (ret) + return ret; + ret = video_ioctl2(file, cmd, arg); + uvc_pm_put(handle->stream->dev); + return ret; + } - return uvc_queue_get_unmapped_area(&stream->queue, pgoff); + /* The other IOCTLs can run with the camera off. */ + return video_ioctl2(file, cmd, arg); } -#endif const struct v4l2_ioctl_ops uvc_ioctl_ops = { + .vidioc_g_fmt_vid_cap = uvc_ioctl_g_fmt, + .vidioc_g_fmt_vid_out = uvc_ioctl_g_fmt, + .vidioc_s_fmt_vid_cap = uvc_ioctl_s_fmt, + .vidioc_s_fmt_vid_out = uvc_ioctl_s_fmt, + .vidioc_g_parm = uvc_ioctl_g_parm, + .vidioc_s_parm = uvc_ioctl_s_parm, .vidioc_querycap = uvc_ioctl_querycap, - .vidioc_enum_fmt_vid_cap = uvc_ioctl_enum_fmt_vid_cap, - .vidioc_enum_fmt_vid_out = uvc_ioctl_enum_fmt_vid_out, - .vidioc_g_fmt_vid_cap = uvc_ioctl_g_fmt_vid_cap, - .vidioc_g_fmt_vid_out = uvc_ioctl_g_fmt_vid_out, - .vidioc_s_fmt_vid_cap = uvc_ioctl_s_fmt_vid_cap, - .vidioc_s_fmt_vid_out = uvc_ioctl_s_fmt_vid_out, - .vidioc_try_fmt_vid_cap = uvc_ioctl_try_fmt_vid_cap, - .vidioc_try_fmt_vid_out = uvc_ioctl_try_fmt_vid_out, - .vidioc_reqbufs = uvc_ioctl_reqbufs, - .vidioc_querybuf = uvc_ioctl_querybuf, - .vidioc_qbuf = uvc_ioctl_qbuf, - .vidioc_expbuf = uvc_ioctl_expbuf, - .vidioc_dqbuf = uvc_ioctl_dqbuf, - .vidioc_create_bufs = uvc_ioctl_create_bufs, - .vidioc_streamon = uvc_ioctl_streamon, - .vidioc_streamoff = uvc_ioctl_streamoff, + .vidioc_enum_fmt_vid_cap = uvc_ioctl_enum_fmt, + .vidioc_enum_fmt_vid_out = uvc_ioctl_enum_fmt, + .vidioc_try_fmt_vid_cap = uvc_ioctl_try_fmt, + .vidioc_try_fmt_vid_out = uvc_ioctl_try_fmt, + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, .vidioc_enum_input = uvc_ioctl_enum_input, .vidioc_g_input = uvc_ioctl_g_input, .vidioc_s_input = uvc_ioctl_s_input, - .vidioc_queryctrl = uvc_ioctl_queryctrl, .vidioc_query_ext_ctrl = uvc_ioctl_query_ext_ctrl, .vidioc_g_ext_ctrls = uvc_ioctl_g_ext_ctrls, .vidioc_s_ext_ctrls = uvc_ioctl_s_ext_ctrls, .vidioc_try_ext_ctrls = uvc_ioctl_try_ext_ctrls, .vidioc_querymenu = uvc_ioctl_querymenu, .vidioc_g_selection = uvc_ioctl_g_selection, - .vidioc_g_parm = uvc_ioctl_g_parm, - .vidioc_s_parm = uvc_ioctl_s_parm, .vidioc_enum_framesizes = uvc_ioctl_enum_framesizes, .vidioc_enum_frameintervals = uvc_ioctl_enum_frameintervals, .vidioc_subscribe_event = uvc_ioctl_subscribe_event, @@ -1543,15 +1269,14 @@ const struct v4l2_file_operations uvc_fops = { .owner = THIS_MODULE, .open = uvc_v4l2_open, .release = uvc_v4l2_release, - .unlocked_ioctl = video_ioctl2, + .unlocked_ioctl = uvc_v4l2_unlocked_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl32 = uvc_v4l2_compat_ioctl32, #endif - .read = uvc_v4l2_read, - .mmap = uvc_v4l2_mmap, - .poll = uvc_v4l2_poll, + .mmap = vb2_fop_mmap, + .poll = vb2_fop_poll, #ifndef CONFIG_MMU - .get_unmapped_area = uvc_v4l2_get_unmapped_area, + .get_unmapped_area = vb2_fop_get_unmapped_area, #endif }; diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c index d2eb9066e4dc..2094e059d7d3 100644 --- a/drivers/media/usb/uvc/uvc_video.c +++ b/drivers/media/usb/uvc/uvc_video.c @@ -18,8 +18,9 @@ #include <linux/vmalloc.h> #include <linux/wait.h> #include <linux/atomic.h> -#include <asm/unaligned.h> +#include <linux/unaligned.h> +#include <media/jpeg.h> #include <media/v4l2-common.h> #include "uvcvideo.h" @@ -79,13 +80,35 @@ int uvc_query_ctrl(struct uvc_device *dev, u8 query, u8 unit, if (likely(ret == size)) return 0; - dev_err(&dev->udev->dev, - "Failed to query (%s) UVC control %u on unit %u: %d (exp. %u).\n", - uvc_query_name(query), cs, unit, ret, size); + /* + * Some devices return shorter USB control packets than expected if the + * returned value can fit in less bytes. Zero all the bytes that the + * device has not written. + * + * This quirk is applied to all controls, regardless of their data type. + * Most controls are little-endian integers, in which case the missing + * bytes become 0 MSBs. For other data types, a different heuristic + * could be implemented if a device is found needing it. + * + * We exclude UVC_GET_INFO from the quirk. UVC_GET_LEN does not need + * to be excluded because its size is always 1. + */ + if (ret > 0 && query != UVC_GET_INFO) { + memset(data + ret, 0, size - ret); + dev_warn_once(&dev->intf->dev, + "UVC non compliance: %s control %u on unit %u returned %d bytes when we expected %u.\n", + uvc_query_name(query), cs, unit, ret, size); + return 0; + } - if (ret != -EPIPE) - return ret; + if (ret != -EPIPE) { + dev_err(&dev->intf->dev, + "Failed to query (%s) UVC control %u on unit %u: %d (exp. %u).\n", + uvc_query_name(query), cs, unit, ret, size); + return ret < 0 ? ret : -EPIPE; + } + /* Reuse data[0] to request the error code. */ tmp = *(u8 *)data; ret = __uvc_query_ctrl(dev, UVC_GET_CUR, 0, intfnum, @@ -95,8 +118,12 @@ int uvc_query_ctrl(struct uvc_device *dev, u8 query, u8 unit, error = *(u8 *)data; *(u8 *)data = tmp; - if (ret != 1) + if (ret != 1) { + dev_err_ratelimited(&dev->intf->dev, + "Failed to query (%s) UVC error code control %u on unit %u: %d (exp. 1).\n", + uvc_query_name(query), cs, unit, ret); return ret < 0 ? ret : -EPIPE; + } uvc_dbg(dev, CONTROL, "Control error %u\n", error); @@ -107,7 +134,7 @@ int uvc_query_ctrl(struct uvc_device *dev, u8 query, u8 unit, case 1: /* Not ready */ return -EBUSY; case 2: /* Wrong state */ - return -EILSEQ; + return -EACCES; case 3: /* Power */ return -EREMOTE; case 4: /* Out of range */ @@ -129,14 +156,15 @@ int uvc_query_ctrl(struct uvc_device *dev, u8 query, u8 unit, return -EPIPE; } +static const struct usb_device_id elgato_cam_link_4k = { + USB_DEVICE(0x0fd9, 0x0066) +}; + static void uvc_fixup_video_ctrl(struct uvc_streaming *stream, struct uvc_streaming_control *ctrl) { - static const struct usb_device_id elgato_cam_link_4k = { - USB_DEVICE(0x0fd9, 0x0066) - }; - struct uvc_format *format = NULL; - struct uvc_frame *frame = NULL; + const struct uvc_format *format = NULL; + const struct uvc_frame *frame = NULL; unsigned int i; /* @@ -164,8 +192,8 @@ static void uvc_fixup_video_ctrl(struct uvc_streaming *stream, } for (i = 0; i < stream->nformats; ++i) { - if (stream->format[i].index == ctrl->bFormatIndex) { - format = &stream->format[i]; + if (stream->formats[i].index == ctrl->bFormatIndex) { + format = &stream->formats[i]; break; } } @@ -174,8 +202,8 @@ static void uvc_fixup_video_ctrl(struct uvc_streaming *stream, return; for (i = 0; i < format->nframes; ++i) { - if (format->frame[i].bFrameIndex == ctrl->bFrameIndex) { - frame = &format->frame[i]; + if (format->frames[i].bFrameIndex == ctrl->bFrameIndex) { + frame = &format->frames[i]; break; } } @@ -212,13 +240,13 @@ static void uvc_fixup_video_ctrl(struct uvc_streaming *stream, * Compute a bandwidth estimation by multiplying the frame * size by the number of video frames per second, divide the * result by the number of USB frames (or micro-frames for - * high-speed devices) per second and add the UVC header size - * (assumed to be 12 bytes long). + * high- and super-speed devices) per second and add the UVC + * header size (assumed to be 12 bytes long). */ bandwidth = frame->wWidth * frame->wHeight / 8 * format->bpp; bandwidth *= 10000000 / interval + 1; bandwidth /= 1000; - if (stream->dev->udev->speed == USB_SPEED_HIGH) + if (stream->dev->udev->speed >= USB_SPEED_HIGH) bandwidth /= 8; bandwidth += 12; @@ -234,6 +262,15 @@ static void uvc_fixup_video_ctrl(struct uvc_streaming *stream, ctrl->dwMaxPayloadTransferSize = bandwidth; } + + if (stream->intf->num_altsetting > 1 && + ctrl->dwMaxPayloadTransferSize > stream->maxpsize) { + dev_warn_ratelimited(&stream->intf->dev, + "UVC non compliance: Reducing max payload transfer size (%u) to fit endpoint limit (%u).\n", + ctrl->dwMaxPayloadTransferSize, + stream->maxpsize); + ctrl->dwMaxPayloadTransferSize = stream->maxpsize; + } } static size_t uvc_video_ctrl_size(struct uvc_streaming *stream) @@ -295,9 +332,10 @@ static int uvc_get_video_ctrl(struct uvc_streaming *stream, goto out; } else if (ret != size) { dev_err(&stream->intf->dev, - "Failed to query (%u) UVC %s control : %d (exp. %u).\n", - query, probe ? "probe" : "commit", ret, size); - ret = -EIO; + "Failed to query (%s) UVC %s control : %d (exp. %u).\n", + uvc_query_name(query), probe ? "probe" : "commit", + ret, size); + ret = (ret == -EPROTO) ? -EPROTO : -EIO; goto out; } @@ -464,18 +502,49 @@ static inline ktime_t uvc_video_get_time(void) return ktime_get_real(); } +static void uvc_video_clock_add_sample(struct uvc_clock *clock, + const struct uvc_clock_sample *sample) +{ + unsigned long flags; + + /* + * If we write new data on the position where we had the last + * overflow, remove the overflow pointer. There is no SOF overflow + * in the whole circular buffer. + */ + if (clock->head == clock->last_sof_overflow) + clock->last_sof_overflow = -1; + + spin_lock_irqsave(&clock->lock, flags); + + if (clock->count > 0 && clock->last_sof > sample->dev_sof) { + /* + * Remove data from the circular buffer that is older than the + * last SOF overflow. We only support one SOF overflow per + * circular buffer. + */ + if (clock->last_sof_overflow != -1) + clock->count = (clock->head - clock->last_sof_overflow + + clock->size) % clock->size; + clock->last_sof_overflow = clock->head; + } + + /* Add sample. */ + clock->samples[clock->head] = *sample; + clock->head = (clock->head + 1) % clock->size; + clock->count = min(clock->count + 1, clock->size); + + spin_unlock_irqrestore(&clock->lock, flags); +} + static void uvc_video_clock_decode(struct uvc_streaming *stream, struct uvc_buffer *buf, const u8 *data, int len) { - struct uvc_clock_sample *sample; + struct uvc_clock_sample sample; unsigned int header_size; bool has_pts = false; bool has_scr = false; - unsigned long flags; - ktime_t time; - u16 host_sof; - u16 dev_sof; switch (data[1] & (UVC_STREAM_PTS | UVC_STREAM_SCR)) { case UVC_STREAM_PTS | UVC_STREAM_SCR: @@ -516,16 +585,55 @@ uvc_video_clock_decode(struct uvc_streaming *stream, struct uvc_buffer *buf, /* * To limit the amount of data, drop SCRs with an SOF identical to the - * previous one. + * previous one. This filtering is also needed to support UVC 1.5, where + * all the data packets of the same frame contains the same SOF. In that + * case only the first one will match the host_sof. */ - dev_sof = get_unaligned_le16(&data[header_size - 2]); - if (dev_sof == stream->clock.last_sof) + sample.dev_sof = get_unaligned_le16(&data[header_size - 2]); + if (sample.dev_sof == stream->clock.last_sof) return; - stream->clock.last_sof = dev_sof; + sample.dev_stc = get_unaligned_le32(&data[header_size - 6]); - host_sof = usb_get_current_frame_number(stream->dev->udev); - time = uvc_video_get_time(); + /* + * STC (Source Time Clock) is the clock used by the camera. The UVC 1.5 + * standard states that it "must be captured when the first video data + * of a video frame is put on the USB bus". This is generally understood + * as requiring devices to clear the payload header's SCR bit before + * the first packet containing video data. + * + * Most vendors follow that interpretation, but some (namely SunplusIT + * on some devices) always set the `UVC_STREAM_SCR` bit, fill the SCR + * field with 0's,and expect that the driver only processes the SCR if + * there is data in the packet. + * + * Ignore all the hardware timestamp information if we haven't received + * any data for this frame yet, the packet contains no data, and both + * STC and SOF are zero. This heuristics should be safe on compliant + * devices. This should be safe with compliant devices, as in the very + * unlikely case where a UVC 1.1 device would send timing information + * only before the first packet containing data, and both STC and SOF + * happen to be zero for a particular frame, we would only miss one + * clock sample from many and the clock recovery algorithm wouldn't + * suffer from this condition. + */ + if (buf && buf->bytesused == 0 && len == header_size && + sample.dev_stc == 0 && sample.dev_sof == 0) + return; + + sample.host_sof = usb_get_current_frame_number(stream->dev->udev); + + /* + * On some devices, like the Logitech C922, the device SOF does not run + * at a stable rate of 1kHz. For those devices use the host SOF instead. + * In the tests performed so far, this improves the timestamp precision. + * This is probably explained by a small packet handling jitter from the + * host, but the exact reason hasn't been fully determined. + */ + if (stream->dev->quirks & UVC_QUIRK_INVALID_DEVICE_SOF) + sample.dev_sof = sample.host_sof; + + sample.host_time = uvc_video_get_time(); /* * The UVC specification allows device implementations that can't obtain @@ -548,46 +656,29 @@ uvc_video_clock_decode(struct uvc_streaming *stream, struct uvc_buffer *buf, * the 8 LSBs of the delta are kept. */ if (stream->clock.sof_offset == (u16)-1) { - u16 delta_sof = (host_sof - dev_sof) & 255; + u16 delta_sof = (sample.host_sof - sample.dev_sof) & 255; if (delta_sof >= 10) stream->clock.sof_offset = delta_sof; else stream->clock.sof_offset = 0; } - dev_sof = (dev_sof + stream->clock.sof_offset) & 2047; - - spin_lock_irqsave(&stream->clock.lock, flags); - - sample = &stream->clock.samples[stream->clock.head]; - sample->dev_stc = get_unaligned_le32(&data[header_size - 6]); - sample->dev_sof = dev_sof; - sample->host_sof = host_sof; - sample->host_time = time; - - /* Update the sliding window head and count. */ - stream->clock.head = (stream->clock.head + 1) % stream->clock.size; - - if (stream->clock.count < stream->clock.size) - stream->clock.count++; - - spin_unlock_irqrestore(&stream->clock.lock, flags); + sample.dev_sof = (sample.dev_sof + stream->clock.sof_offset) & 2047; + uvc_video_clock_add_sample(&stream->clock, &sample); + stream->clock.last_sof = sample.dev_sof; } -static void uvc_video_clock_reset(struct uvc_streaming *stream) +static void uvc_video_clock_reset(struct uvc_clock *clock) { - struct uvc_clock *clock = &stream->clock; - clock->head = 0; clock->count = 0; clock->last_sof = -1; + clock->last_sof_overflow = -1; clock->sof_offset = -1; } -static int uvc_video_clock_init(struct uvc_streaming *stream) +static int uvc_video_clock_init(struct uvc_clock *clock) { - struct uvc_clock *clock = &stream->clock; - spin_lock_init(&clock->lock); clock->size = 32; @@ -596,15 +687,15 @@ static int uvc_video_clock_init(struct uvc_streaming *stream) if (clock->samples == NULL) return -ENOMEM; - uvc_video_clock_reset(stream); + uvc_video_clock_reset(clock); return 0; } -static void uvc_video_clock_cleanup(struct uvc_streaming *stream) +static void uvc_video_clock_cleanup(struct uvc_clock *clock) { - kfree(stream->clock.samples); - stream->clock.samples = NULL; + kfree(clock->samples); + clock->samples = NULL; } /* @@ -705,11 +796,11 @@ void uvc_video_clock_update(struct uvc_streaming *stream, unsigned long flags; u64 timestamp; u32 delta_stc; - u32 y1, y2; + u32 y1; u32 x1, x2; u32 mean; u32 sof; - u64 y; + u64 y, y2; if (!uvc_hw_timestamps_param) return; @@ -724,11 +815,11 @@ void uvc_video_clock_update(struct uvc_streaming *stream, spin_lock_irqsave(&clock->lock, flags); - if (clock->count < clock->size) + if (clock->count < 2) goto done; - first = &clock->samples[clock->head]; - last = &clock->samples[(clock->head - 1) % clock->size]; + first = &clock->samples[(clock->head - clock->count + clock->size) % clock->size]; + last = &clock->samples[(clock->head - 1 + clock->size) % clock->size]; /* First step, PTS to SOF conversion. */ delta_stc = buf->pts - (1UL << 31); @@ -742,6 +833,18 @@ void uvc_video_clock_update(struct uvc_streaming *stream, if (y2 < y1) y2 += 2048 << 16; + /* + * Have at least 1/4 of a second of timestamps before we + * try to do any calculation. Otherwise we do not have enough + * precision. This value was determined by running Android CTS + * on different devices. + * + * dev_sof runs at 1KHz, and we have a fixed point precision of + * 16 bits. + */ + if ((y2 - y1) < ((1000 / 4) << 16)) + goto done; + y = (u64)(y2 - y1) * (1ULL << 31) + (u64)y1 * (u64)x2 - (u64)y2 * (u64)x1; y = div_u64(y, x2 - x1); @@ -749,7 +852,7 @@ void uvc_video_clock_update(struct uvc_streaming *stream, sof = y; uvc_dbg(stream->dev, CLOCK, - "%s: PTS %u y %llu.%06llu SOF %u.%06llu (x1 %u x2 %u y1 %u y2 %u SOF offset %u)\n", + "%s: PTS %u y %llu.%06llu SOF %u.%06llu (x1 %u x2 %u y1 %u y2 %llu SOF offset %u)\n", stream->dev->name, buf->pts, y >> 16, div_u64((y & 0xffff) * 1000000, 65536), sof >> 16, div_u64(((u64)sof & 0xffff) * 1000000LLU, 65536), @@ -764,7 +867,7 @@ void uvc_video_clock_update(struct uvc_streaming *stream, goto done; y1 = NSEC_PER_SEC; - y2 = (u32)ktime_to_ns(ktime_sub(last->host_time, first->host_time)) + y1; + y2 = ktime_to_ns(ktime_sub(last->host_time, first->host_time)) + y1; /* * Interpolated and host SOF timestamps can wrap around at slightly @@ -785,7 +888,7 @@ void uvc_video_clock_update(struct uvc_streaming *stream, timestamp = ktime_to_ns(first->host_time) + y - y1; uvc_dbg(stream->dev, CLOCK, - "%s: SOF %u.%06llu y %llu ts %llu buf ts %llu (x1 %u/%u/%u x2 %u/%u/%u y1 %u y2 %u)\n", + "%s: SOF %u.%06llu y %llu ts %llu buf ts %llu (x1 %u/%u/%u x2 %u/%u/%u y1 %u y2 %llu)\n", stream->dev->name, sof >> 16, div_u64(((u64)sof & 0xffff) * 1000000LLU, 65536), y, timestamp, vbuf->vb2_buf.timestamp, @@ -1049,6 +1152,7 @@ static void uvc_video_stats_stop(struct uvc_streaming *stream) static int uvc_video_decode_start(struct uvc_streaming *stream, struct uvc_buffer *buf, const u8 *data, int len) { + u8 header_len; u8 fid; /* @@ -1062,6 +1166,7 @@ static int uvc_video_decode_start(struct uvc_streaming *stream, return -EINVAL; } + header_len = data[0]; fid = data[1] & UVC_STREAM_FID; /* @@ -1143,9 +1248,31 @@ static int uvc_video_decode_start(struct uvc_streaming *stream, return -EAGAIN; } + /* + * Some cameras, when running two parallel streams (one MJPEG alongside + * another non-MJPEG stream), are known to lose the EOF packet for a frame. + * We can detect the end of a frame by checking for a new SOI marker, as + * the SOI always lies on the packet boundary between two frames for + * these devices. + */ + if (stream->dev->quirks & UVC_QUIRK_MJPEG_NO_EOF && + (stream->cur_format->fcc == V4L2_PIX_FMT_MJPEG || + stream->cur_format->fcc == V4L2_PIX_FMT_JPEG)) { + const u8 *packet = data + header_len; + + if (len >= header_len + 2 && + packet[0] == 0xff && packet[1] == JPEG_MARKER_SOI && + buf->bytesused != 0) { + buf->state = UVC_BUF_STATE_READY; + buf->error = 1; + stream->last_fid ^= UVC_STREAM_FID; + return -EAGAIN; + } + } + stream->last_fid = fid; - return data[0]; + return header_len; } static inline enum dma_data_direction uvc_stream_dir( @@ -1157,20 +1284,6 @@ static inline enum dma_data_direction uvc_stream_dir( return DMA_TO_DEVICE; } -static inline struct device *uvc_stream_to_dmadev(struct uvc_streaming *stream) -{ - return bus_to_hcd(stream->dev->udev->bus)->self.sysdev; -} - -static int uvc_submit_urb(struct uvc_urb *uvc_urb, gfp_t mem_flags) -{ - /* Sync DMA. */ - dma_sync_sgtable_for_device(uvc_stream_to_dmadev(uvc_urb->stream), - uvc_urb->sgt, - uvc_stream_dir(uvc_urb->stream)); - return usb_submit_urb(uvc_urb->urb, mem_flags); -} - /* * uvc_video_decode_data_work: Asynchronous memcpy processing * @@ -1192,7 +1305,7 @@ static void uvc_video_copy_data_work(struct work_struct *work) uvc_queue_buffer_release(op->buf); } - ret = uvc_submit_urb(uvc_urb, GFP_KERNEL); + ret = usb_submit_urb(uvc_urb->urb, GFP_KERNEL); if (ret < 0) dev_err(&uvc_urb->stream->intf->dev, "Failed to resubmit video URB (%d).\n", ret); @@ -1315,12 +1428,6 @@ static void uvc_video_decode_meta(struct uvc_streaming *stream, if (!meta_buf || length == 2) return; - if (meta_buf->length - meta_buf->bytesused < - length + sizeof(meta->ns) + sizeof(meta->sof)) { - meta_buf->error = 1; - return; - } - has_pts = mem[1] & UVC_STREAM_PTS; has_scr = mem[1] & UVC_STREAM_SCR; @@ -1341,6 +1448,12 @@ static void uvc_video_decode_meta(struct uvc_streaming *stream, !memcmp(scr, stream->clock.last_scr, 6))) return; + if (meta_buf->length - meta_buf->bytesused < + length + sizeof(meta->ns) + sizeof(meta->sof)) { + meta_buf->error = 1; + return; + } + meta = (struct uvc_meta_buf *)((u8 *)meta_buf->mem + meta_buf->bytesused); local_irq_save(flags); time = uvc_video_get_time(); @@ -1352,7 +1465,9 @@ static void uvc_video_decode_meta(struct uvc_streaming *stream, if (has_scr) memcpy(stream->clock.last_scr, scr, 6); - memcpy(&meta->length, mem, length); + meta->length = mem[0]; + meta->flags = mem[1]; + memcpy(meta->buf, &mem[2], length - 2); meta_buf->bytesused += length + sizeof(meta->ns) + sizeof(meta->sof); uvc_dbg(stream->dev, FRAME, @@ -1576,7 +1691,7 @@ static void uvc_video_complete(struct urb *urb) struct uvc_streaming *stream = uvc_urb->stream; struct uvc_video_queue *queue = &stream->queue; struct uvc_video_queue *qmeta = &stream->meta.queue; - struct vb2_queue *vb2_qmeta = stream->meta.vdev.queue; + struct vb2_queue *vb2_qmeta = stream->meta.queue.vdev.queue; struct uvc_buffer *buf = NULL; struct uvc_buffer *buf_meta = NULL; unsigned long flags; @@ -1616,12 +1731,6 @@ static void uvc_video_complete(struct urb *urb) /* Re-initialise the URB async work. */ uvc_urb->async_operations = 0; - /* Sync DMA and invalidate vmap range. */ - dma_sync_sgtable_for_cpu(uvc_stream_to_dmadev(uvc_urb->stream), - uvc_urb->sgt, uvc_stream_dir(stream)); - invalidate_kernel_vmap_range(uvc_urb->buffer, - uvc_urb->stream->urb_size); - /* * Process the URB headers, and optionally queue expensive memcpy tasks * to be deferred to a work queue. @@ -1630,7 +1739,7 @@ static void uvc_video_complete(struct urb *urb) /* If no async work is needed, resubmit the URB immediately. */ if (!uvc_urb->async_operations) { - ret = uvc_submit_urb(uvc_urb, GFP_ATOMIC); + ret = usb_submit_urb(uvc_urb->urb, GFP_ATOMIC); if (ret < 0) dev_err(&stream->intf->dev, "Failed to resubmit video URB (%d).\n", ret); @@ -1645,17 +1754,15 @@ static void uvc_video_complete(struct urb *urb) */ static void uvc_free_urb_buffers(struct uvc_streaming *stream) { - struct device *dma_dev = uvc_stream_to_dmadev(stream); + struct usb_device *udev = stream->dev->udev; struct uvc_urb *uvc_urb; for_each_uvc_urb(uvc_urb, stream) { if (!uvc_urb->buffer) continue; - dma_vunmap_noncontiguous(dma_dev, uvc_urb->buffer); - dma_free_noncontiguous(dma_dev, stream->urb_size, uvc_urb->sgt, - uvc_stream_dir(stream)); - + usb_free_noncoherent(udev, stream->urb_size, uvc_urb->buffer, + uvc_stream_dir(stream), uvc_urb->sgt); uvc_urb->buffer = NULL; uvc_urb->sgt = NULL; } @@ -1666,26 +1773,13 @@ static void uvc_free_urb_buffers(struct uvc_streaming *stream) static bool uvc_alloc_urb_buffer(struct uvc_streaming *stream, struct uvc_urb *uvc_urb, gfp_t gfp_flags) { - struct device *dma_dev = uvc_stream_to_dmadev(stream); - - uvc_urb->sgt = dma_alloc_noncontiguous(dma_dev, stream->urb_size, - uvc_stream_dir(stream), - gfp_flags, 0); - if (!uvc_urb->sgt) - return false; - uvc_urb->dma = uvc_urb->sgt->sgl->dma_address; - - uvc_urb->buffer = dma_vmap_noncontiguous(dma_dev, stream->urb_size, - uvc_urb->sgt); - if (!uvc_urb->buffer) { - dma_free_noncontiguous(dma_dev, stream->urb_size, - uvc_urb->sgt, - uvc_stream_dir(stream)); - uvc_urb->sgt = NULL; - return false; - } + struct usb_device *udev = stream->dev->udev; - return true; + uvc_urb->buffer = usb_alloc_noncoherent(udev, stream->urb_size, + gfp_flags, &uvc_urb->dma, + uvc_stream_dir(stream), + &uvc_urb->sgt); + return !!uvc_urb->buffer; } /* @@ -1776,24 +1870,6 @@ static void uvc_video_stop_transfer(struct uvc_streaming *stream, } /* - * Compute the maximum number of bytes per interval for an endpoint. - */ -u16 uvc_endpoint_max_bpi(struct usb_device *dev, struct usb_host_endpoint *ep) -{ - u16 psize; - - switch (dev->speed) { - case USB_SPEED_SUPER: - case USB_SPEED_SUPER_PLUS: - return le16_to_cpu(ep->ss_ep_comp.wBytesPerInterval); - default: - psize = usb_endpoint_maxp(&ep->desc); - psize *= usb_endpoint_maxp_mult(&ep->desc); - return psize; - } -} - -/* * Initialize isochronous URBs and allocate transfer buffers. The packet size * is given by the endpoint. */ @@ -1803,10 +1879,10 @@ static int uvc_init_video_isoc(struct uvc_streaming *stream, struct urb *urb; struct uvc_urb *uvc_urb; unsigned int npackets, i; - u16 psize; + u32 psize; u32 size; - psize = uvc_endpoint_max_bpi(stream->dev->udev, ep); + psize = usb_endpoint_max_periodic_payload(stream->dev->udev, ep); size = stream->ctrl.dwMaxVideoFrameSize; npackets = uvc_alloc_urb_buffers(stream, size, psize, gfp_flags); @@ -1833,6 +1909,7 @@ static int uvc_init_video_isoc(struct uvc_streaming *stream, urb->complete = uvc_video_complete; urb->number_of_packets = npackets; urb->transfer_buffer_length = size; + urb->sgt = uvc_urb->sgt; for (i = 0; i < npackets; ++i) { urb->iso_frame_desc[i].offset = i * psize; @@ -1889,6 +1966,7 @@ static int uvc_init_video_bulk(struct uvc_streaming *stream, size, uvc_video_complete, uvc_urb); urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; urb->transfer_dma = uvc_urb->dma; + urb->sgt = uvc_urb->sgt; uvc_urb->urb = urb; } @@ -1947,8 +2025,8 @@ static int uvc_video_start_transfer(struct uvc_streaming *stream, continue; /* Check if the bandwidth is high enough. */ - psize = uvc_endpoint_max_bpi(stream->dev->udev, ep); - if (psize >= bandwidth && psize <= best_psize) { + psize = usb_endpoint_max_periodic_payload(stream->dev->udev, ep); + if (psize >= bandwidth && psize < best_psize) { altsetting = alts->desc.bAlternateSetting; best_psize = psize; best_ep = ep; @@ -1965,6 +2043,17 @@ static int uvc_video_start_transfer(struct uvc_streaming *stream, "Selecting alternate setting %u (%u B/frame bandwidth)\n", altsetting, best_psize); + /* + * Some devices, namely the Logitech C910 and B910, are unable + * to recover from a USB autosuspend, unless the alternate + * setting of the streaming interface is toggled. + */ + if (stream->dev->quirks & UVC_QUIRK_WAKE_AUTOSUSPEND) { + usb_set_interface(stream->dev->udev, intfnum, + altsetting); + usb_set_interface(stream->dev->udev, intfnum, 0); + } + ret = usb_set_interface(stream->dev->udev, intfnum, altsetting); if (ret < 0) return ret; @@ -1989,7 +2078,7 @@ static int uvc_video_start_transfer(struct uvc_streaming *stream, /* Submit the URBs. */ for_each_uvc_urb(uvc_urb, stream) { - ret = uvc_submit_urb(uvc_urb, gfp_flags); + ret = usb_submit_urb(uvc_urb->urb, gfp_flags); if (ret < 0) { dev_err(&stream->intf->dev, "Failed to submit URB %u (%d).\n", @@ -2054,7 +2143,7 @@ int uvc_video_resume(struct uvc_streaming *stream, int reset) stream->frozen = 0; - uvc_video_clock_reset(stream); + uvc_video_clock_reset(&stream->clock); if (!uvc_queue_streaming(&stream->queue)) return 0; @@ -2083,8 +2172,8 @@ int uvc_video_resume(struct uvc_streaming *stream, int reset) int uvc_video_init(struct uvc_streaming *stream) { struct uvc_streaming_control *probe = &stream->ctrl; - struct uvc_format *format = NULL; - struct uvc_frame *frame = NULL; + const struct uvc_format *format = NULL; + const struct uvc_frame *frame = NULL; struct uvc_urb *uvc_urb; unsigned int i; int ret; @@ -2121,6 +2210,21 @@ int uvc_video_init(struct uvc_streaming *stream) * request on the probe control, as required by the UVC specification. */ ret = uvc_get_video_ctrl(stream, probe, 1, UVC_GET_CUR); + + /* + * Elgato Cam Link 4k can be in a stalled state if the resolution of + * the external source has changed while the firmware initializes. + * Once in this state, the device is useless until it receives a + * USB reset. It has even been observed that the stalled state will + * continue even after unplugging the device. + */ + if (ret == -EPROTO && + usb_match_one_id(stream->dev->intf, &elgato_cam_link_4k)) { + dev_err(&stream->intf->dev, "Elgato Cam Link 4K firmware crash detected\n"); + dev_err(&stream->intf->dev, "Resetting the device, unplug and replug to recover\n"); + usb_reset_device(stream->dev->udev); + } + if (ret < 0) return ret; @@ -2129,7 +2233,7 @@ int uvc_video_init(struct uvc_streaming *stream) * available format otherwise. */ for (i = stream->nformats; i > 0; --i) { - format = &stream->format[i-1]; + format = &stream->formats[i-1]; if (format->index == probe->bFormatIndex) break; } @@ -2147,7 +2251,7 @@ int uvc_video_init(struct uvc_streaming *stream) * descriptor is not found, use the first available frame. */ for (i = format->nframes; i > 0; --i) { - frame = &format->frame[i-1]; + frame = &format->frames[i-1]; if (frame->bFrameIndex == probe->bFrameIndex) break; } @@ -2188,7 +2292,7 @@ int uvc_video_start_streaming(struct uvc_streaming *stream) { int ret; - ret = uvc_video_clock_init(stream); + ret = uvc_video_clock_init(&stream->clock); if (ret < 0) return ret; @@ -2206,7 +2310,7 @@ int uvc_video_start_streaming(struct uvc_streaming *stream) error_video: usb_set_interface(stream->dev->udev, stream->intfnum, 0); error_commit: - uvc_video_clock_cleanup(stream); + uvc_video_clock_cleanup(&stream->clock); return ret; } @@ -2234,5 +2338,5 @@ void uvc_video_stop_streaming(struct uvc_streaming *stream) usb_clear_halt(stream->dev->udev, pipe); } - uvc_video_clock_cleanup(stream); + uvc_video_clock_cleanup(&stream->clock); } diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index df93db259312..ed7bad31f75c 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -41,6 +41,8 @@ #define UVC_EXT_GPIO_UNIT 0x7ffe #define UVC_EXT_GPIO_UNIT_ID 0x100 +#define UVC_INVALID_ENTITY_ID 0xffff + /* ------------------------------------------------------------------------ * Driver specific constants. */ @@ -51,8 +53,6 @@ #define UVC_URBS 5 /* Maximum number of packets per URB. */ #define UVC_MAX_PACKETS 32 -/* Maximum status buffer size in bytes of interrupt URB. */ -#define UVC_MAX_STATUS_SIZE 16 #define UVC_CTRL_CONTROL_TIMEOUT 5000 #define UVC_CTRL_STREAMING_TIMEOUT 5000 @@ -74,6 +74,12 @@ #define UVC_QUIRK_RESTORE_CTRLS_ON_INIT 0x00000400 #define UVC_QUIRK_FORCE_Y8 0x00000800 #define UVC_QUIRK_FORCE_BPP 0x00001000 +#define UVC_QUIRK_WAKE_AUTOSUSPEND 0x00002000 +#define UVC_QUIRK_NO_RESET_RESUME 0x00004000 +#define UVC_QUIRK_DISABLE_AUTOSUSPEND 0x00008000 +#define UVC_QUIRK_INVALID_DEVICE_SOF 0x00010000 +#define UVC_QUIRK_MJPEG_NO_EOF 0x00020000 +#define UVC_QUIRK_MSXU_META 0x00040000 /* Format flags */ #define UVC_FMT_FLAG_COMPRESSED 0x00000001 @@ -85,7 +91,9 @@ struct gpio_desc; struct sg_table; +struct uvc_control; struct uvc_device; +struct uvc_video_chain; /* * TODO: Put the most frequently accessed fields at the beginning of @@ -111,22 +119,33 @@ struct uvc_control_mapping { u8 entity[16]; u8 selector; + /* + * Size of the control data in the payload of the UVC control GET and + * SET requests, expressed in bits. + */ u8 size; + u8 offset; enum v4l2_ctrl_type v4l2_type; u32 data_type; - const struct uvc_menu_info *menu_info; - u32 menu_count; + const u32 *menu_mapping; + const char (*menu_names)[UVC_MENU_NAME_LEN]; + unsigned long menu_mask; u32 master_id; s32 master_manual; u32 slave_ids[2]; - s32 (*get)(struct uvc_control_mapping *mapping, u8 query, - const u8 *data); - void (*set)(struct uvc_control_mapping *mapping, s32 value, - u8 *data); + bool disabled; + + const struct uvc_control_mapping *(*filter_mapping) + (struct uvc_video_chain *chain, + struct uvc_control *ctrl); + int (*get)(struct uvc_control_mapping *mapping, u8 query, + const void *uvc_in, size_t v4l2_size, void *v4l2_out); + int (*set)(struct uvc_control_mapping *mapping, size_t v4l2_size, + const void *v4l2_in, void *uvc_out); }; struct uvc_control { @@ -226,6 +245,7 @@ struct uvc_entity { u8 *bmControls; struct gpio_desc *gpio_privacy; int irq; + bool initialized; } gpio; }; @@ -251,7 +271,7 @@ struct uvc_frame { u32 dwMaxVideoFrameBufferSize; u8 bFrameIntervalType; u32 dwDefaultFrameInterval; - u32 *dwFrameInterval; + const u32 *dwFrameInterval; }; struct uvc_format { @@ -264,10 +284,8 @@ struct uvc_format { u32 fcc; u32 flags; - char name[32]; - unsigned int nframes; - struct uvc_frame *frame; + const struct uvc_frame *frames; }; struct uvc_streaming_header { @@ -310,11 +328,14 @@ struct uvc_buffer { }; #define UVC_QUEUE_DISCONNECTED (1 << 0) -#define UVC_QUEUE_DROP_CORRUPTED (1 << 1) struct uvc_video_queue { + struct video_device vdev; struct vb2_queue queue; - struct mutex mutex; /* Protects queue */ + struct mutex mutex; /* + * Serializes vb2_queue and + * fops + */ unsigned int flags; unsigned int buf_used; @@ -331,7 +352,11 @@ struct uvc_video_chain { struct uvc_entity *processing; /* Processing unit */ struct uvc_entity *selector; /* Selector unit */ - struct mutex ctrl_mutex; /* Protects ctrl.info */ + struct mutex ctrl_mutex; /* + * Protects ctrl.info, + * ctrl.handle and + * uvc_fh.pending_async_ctrls + */ struct v4l2_prio_state prio; /* V4L2 priority state */ u32 caps; /* V4L2 chain-wide caps */ @@ -428,30 +453,23 @@ struct uvc_urb { struct uvc_streaming { struct list_head list; struct uvc_device *dev; - struct video_device vdev; struct uvc_video_chain *chain; atomic_t active; struct usb_interface *intf; int intfnum; - u16 maxpsize; + u32 maxpsize; struct uvc_streaming_header header; enum v4l2_buf_type type; unsigned int nformats; - struct uvc_format *format; + const struct uvc_format *formats; struct uvc_streaming_control ctrl; - struct uvc_format *def_format; - struct uvc_format *cur_format; - struct uvc_frame *cur_frame; - - /* - * Protect access to ctrl, cur_format, cur_frame and hardware video - * probe control. - */ - struct mutex mutex; + const struct uvc_format *def_format; + const struct uvc_format *cur_format; + const struct uvc_frame *cur_frame; /* Buffers queue. */ unsigned int frozen : 1; @@ -461,7 +479,6 @@ struct uvc_streaming { struct uvc_buffer *meta_buf); struct { - struct video_device vdev; struct uvc_video_queue queue; u32 format; } meta; @@ -500,6 +517,7 @@ struct uvc_streaming { unsigned int head; unsigned int count; unsigned int size; + unsigned int last_sof_overflow; u16 last_sof; u16 sof_offset; @@ -524,9 +542,37 @@ struct uvc_device_info { u32 quirks; u32 meta_format; u16 uvc_version; - const struct uvc_control_mapping **mappings; }; +struct uvc_rect { + u16 top; + u16 left; + u16 bottom; + u16 right; +} __packed; + +struct uvc_status_streaming { + u8 button; +} __packed; + +struct uvc_status_control { + u8 bSelector; + u8 bAttribute; + u8 bValue[11]; +} __packed; + +struct uvc_status { + u8 bStatusType; + u8 bOriginator; + u8 bEvent; + union { + struct uvc_status_control control; + struct uvc_status_streaming streaming; + }; +} __packed; + +#define UVC_MAX_META_DATA_FORMATS 3 + struct uvc_device { struct usb_device *udev; struct usb_interface *intf; @@ -537,8 +583,9 @@ struct uvc_device { const struct uvc_device_info *info; - struct mutex lock; /* Protects users */ - unsigned int users; + u32 meta_formats[UVC_MAX_META_DATA_FORMATS]; + unsigned int nmeta_formats; + atomic_t nmappings; /* Video control interface */ @@ -559,7 +606,11 @@ struct uvc_device { /* Status Interrupt Endpoint */ struct usb_host_endpoint *int_ep; struct urb *int_urb; - u8 *status; + struct uvc_status *status; + struct mutex status_lock; /* Protects status_users */ + unsigned int status_users; + bool flush_status; + struct input_dev *input; char input_phys[64]; @@ -574,21 +625,17 @@ struct uvc_device { struct uvc_entity *gpio_unit; }; -enum uvc_handle_state { - UVC_HANDLE_PASSIVE = 0, - UVC_HANDLE_ACTIVE = 1, -}; - struct uvc_fh { struct v4l2_fh vfh; struct uvc_video_chain *chain; struct uvc_streaming *stream; - enum uvc_handle_state state; + unsigned int pending_async_ctrls; }; -struct uvc_driver { - struct usb_driver driver; -}; +static inline struct uvc_fh *to_uvc_fh(struct file *filp) +{ + return container_of(file_to_v4l2_fh(filp), struct uvc_fh, vfh); +} /* ------------------------------------------------------------------------ * Debugging, printing and logging @@ -620,7 +667,7 @@ extern unsigned int uvc_hw_timestamps_param; #define uvc_dbg(_dev, flag, fmt, ...) \ do { \ if (uvc_dbg_param & UVC_DBG_##flag) \ - dev_printk(KERN_DEBUG, &(_dev)->udev->dev, fmt, \ + dev_printk(KERN_DEBUG, &(_dev)->intf->dev, fmt, \ ##__VA_ARGS__); \ } while (0) @@ -633,51 +680,22 @@ do { \ #define uvc_warn_once(_dev, warn, fmt, ...) \ do { \ if (!test_and_set_bit(warn, &(_dev)->warnings)) \ - dev_info(&(_dev)->udev->dev, fmt, ##__VA_ARGS__); \ + dev_info(&(_dev)->intf->dev, fmt, ##__VA_ARGS__); \ } while (0) /* -------------------------------------------------------------------------- * Internal functions. */ -/* Core driver */ -extern struct uvc_driver uvc_driver; - struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id); /* Video buffers queue management. */ -int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type, - int drop_corrupted); -void uvc_queue_release(struct uvc_video_queue *queue); -int uvc_request_buffers(struct uvc_video_queue *queue, - struct v4l2_requestbuffers *rb); -int uvc_query_buffer(struct uvc_video_queue *queue, - struct v4l2_buffer *v4l2_buf); -int uvc_create_buffers(struct uvc_video_queue *queue, - struct v4l2_create_buffers *v4l2_cb); -int uvc_queue_buffer(struct uvc_video_queue *queue, - struct media_device *mdev, - struct v4l2_buffer *v4l2_buf); -int uvc_export_buffer(struct uvc_video_queue *queue, - struct v4l2_exportbuffer *exp); -int uvc_dequeue_buffer(struct uvc_video_queue *queue, - struct v4l2_buffer *v4l2_buf, int nonblocking); -int uvc_queue_streamon(struct uvc_video_queue *queue, enum v4l2_buf_type type); -int uvc_queue_streamoff(struct uvc_video_queue *queue, enum v4l2_buf_type type); +int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type); void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect); struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue, struct uvc_buffer *buf); struct uvc_buffer *uvc_queue_get_current_buffer(struct uvc_video_queue *queue); void uvc_queue_buffer_release(struct uvc_buffer *buf); -int uvc_queue_mmap(struct uvc_video_queue *queue, - struct vm_area_struct *vma); -__poll_t uvc_queue_poll(struct uvc_video_queue *queue, struct file *file, - poll_table *wait); -#ifndef CONFIG_MMU -unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue, - unsigned long pgoff); -#endif -int uvc_queue_allocated(struct uvc_video_queue *queue); static inline int uvc_queue_streaming(struct uvc_video_queue *queue) { return vb2_is_streaming(&queue->queue); @@ -710,11 +728,11 @@ int uvc_query_ctrl(struct uvc_device *dev, u8 query, u8 unit, void uvc_video_clock_update(struct uvc_streaming *stream, struct vb2_v4l2_buffer *vbuf, struct uvc_buffer *buf); +int uvc_meta_init(struct uvc_device *dev); int uvc_meta_register(struct uvc_streaming *stream); int uvc_register_video_device(struct uvc_device *dev, struct uvc_streaming *stream, - struct video_device *vdev, struct uvc_video_queue *queue, enum v4l2_buf_type type, const struct v4l2_file_operations *fops, @@ -724,14 +742,20 @@ int uvc_register_video_device(struct uvc_device *dev, int uvc_status_init(struct uvc_device *dev); void uvc_status_unregister(struct uvc_device *dev); void uvc_status_cleanup(struct uvc_device *dev); -int uvc_status_start(struct uvc_device *dev, gfp_t flags); -void uvc_status_stop(struct uvc_device *dev); +int uvc_status_resume(struct uvc_device *dev); +void uvc_status_suspend(struct uvc_device *dev); +int uvc_status_get(struct uvc_device *dev); +void uvc_status_put(struct uvc_device *dev); + +/* PM */ +int uvc_pm_get(struct uvc_device *dev); +void uvc_pm_put(struct uvc_device *dev); /* Controls */ extern const struct v4l2_subscribed_event_ops uvc_ctrl_sub_ev_ops; int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, - struct v4l2_queryctrl *v4l2_ctrl); + struct v4l2_query_ext_ctrl *v4l2_ctrl); int uvc_query_v4l2_menu(struct uvc_video_chain *chain, struct v4l2_querymenu *query_menu); @@ -758,19 +782,21 @@ static inline int uvc_ctrl_rollback(struct uvc_fh *handle) return __uvc_ctrl_commit(handle, 1, NULL); } -int uvc_ctrl_get(struct uvc_video_chain *chain, struct v4l2_ext_control *xctrl); +int uvc_ctrl_get(struct uvc_video_chain *chain, u32 which, + struct v4l2_ext_control *xctrl); int uvc_ctrl_set(struct uvc_fh *handle, struct v4l2_ext_control *xctrl); int uvc_ctrl_is_accessible(struct uvc_video_chain *chain, u32 v4l2_id, - bool read); + const struct v4l2_ext_controls *ctrls, + unsigned long ioctl); int uvc_xu_ctrl_query(struct uvc_video_chain *chain, struct uvc_xu_control_query *xqry); +void uvc_ctrl_cleanup_fh(struct uvc_fh *handle); + /* Utility functions */ struct usb_host_endpoint *uvc_find_endpoint(struct usb_host_interface *alts, u8 epaddr); -u16 uvc_endpoint_max_bpi(struct usb_device *dev, struct usb_host_endpoint *ep); - /* Quirks support */ void uvc_video_decode_isight(struct uvc_urb *uvc_urb, struct uvc_buffer *buf, |
