diff options
Diffstat (limited to 'drivers/media/usb')
92 files changed, 2230 insertions, 1641 deletions
diff --git a/drivers/media/usb/airspy/airspy.c b/drivers/media/usb/airspy/airspy.c index e24e655fb1db..08f0920cf6ca 100644 --- a/drivers/media/usb/airspy/airspy.c +++ b/drivers/media/usb/airspy/airspy.c @@ -603,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, @@ -1017,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"); @@ -1026,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 6b380144d6c2..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; diff --git a/drivers/media/usb/au0828/au0828-dvb.c b/drivers/media/usb/au0828/au0828-dvb.c index 09f9948c6f8e..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; 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..e5dff969ed57 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) 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 343a4433ed24..e585c8f6e4c5 100644 --- a/drivers/media/usb/cx231xx/cx231xx-417.c +++ b/drivers/media/usb/cx231xx/cx231xx-417.c @@ -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, }; /* ------------------------------------------------------------------ */ @@ -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); 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-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 8f347bbeeb32..2cd4e333bc4b 100644 --- a/drivers/media/usb/cx231xx/cx231xx-video.c +++ b/drivers/media/usb/cx231xx/cx231xx-video.c @@ -795,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 **************************************/ diff --git a/drivers/media/usb/cx231xx/cx231xx.h b/drivers/media/usb/cx231xx/cx231xx.h index 74339a6a2f71..19f5036a78d7 100644 --- a/drivers/media/usb/cx231xx/cx231xx.h +++ b/drivers/media/usb/cx231xx/cx231xx.h @@ -790,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); @@ -905,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); @@ -916,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); @@ -949,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 4014f7d07330..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, }; diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index 4eb7dd4599b7..17062672ea06 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.c +++ b/drivers/media/usb/dvb-usb-v2/af9035.c @@ -322,13 +322,16 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap, ret = -EOPNOTSUPP; } 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; + if (msg[0].len < 3 || msg[1].len < 1) { ret = -EOPNOTSUPP; goto unlock; } - /* demod access via firmware interface */ - u32 reg = msg[0].buf[0] << 16 | msg[0].buf[1] << 8 | - msg[0].buf[2]; + + 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; @@ -385,13 +388,16 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap, ret = -EOPNOTSUPP; } 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; + if (msg[0].len < 3) { ret = -EOPNOTSUPP; goto unlock; } - /* demod access via firmware interface */ - u32 reg = msg[0].buf[0] << 16 | msg[0].buf[1] << 8 | - msg[0].buf[2]; + + 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; @@ -477,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, }; @@ -868,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; } @@ -2066,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, @@ -2157,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 a1235d0cce92..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 2410054ddb2c..65ef045b74ca 100644 --- a/drivers/media/usb/dvb-usb-v2/az6007.c +++ b/drivers/media/usb/dvb-usb-v2/az6007.c @@ -838,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 d3b5cb4a24da..7ebaf3ee4491 100644 --- a/drivers/media/usb/dvb-usb-v2/ce6230.c +++ b/drivers/media/usb/dvb-usb-v2/ce6230.c @@ -154,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 0e4773fc025c..973b32356b17 100644 --- a/drivers/media/usb/dvb-usb-v2/ec168.c +++ b/drivers/media/usb/dvb-usb-v2/ec168.c @@ -176,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 c71e7b93476d..0538170ccf29 100644 --- a/drivers/media/usb/dvb-usb-v2/gl861.c +++ b/drivers/media/usb/dvb-usb-v2/gl861.c @@ -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..0c510035805b 100644 --- a/drivers/media/usb/dvb-usb-v2/lmedm04.c +++ b/drivers/media/usb/dvb-usb-v2/lmedm04.c @@ -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 f7884bb56fcc..487c6ab784ab 100644 --- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c +++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c @@ -290,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.c b/drivers/media/usb/dvb-usb/af9005.c index 13604e6acdb8..a4bede7e8a1d 100644 --- a/drivers/media/usb/dvb-usb/af9005.c +++ b/drivers/media/usb/dvb-usb/af9005.c @@ -445,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, }; @@ -1005,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 2bc27710427d..056935d3cbd6 100644 --- a/drivers/media/usb/dvb-usb/az6027.c +++ b/drivers/media/usb/dvb-usb/az6027.c @@ -1062,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, }; @@ -1107,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 b5d8c6b75ae1..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 | 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 32134be16914..ab229ab1a858 100644 --- a/drivers/media/usb/dvb-usb/digitv.c +++ b/drivers/media/usb/dvb-usb/digitv.c @@ -88,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, }; @@ -299,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.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..3d85c6f7f6ec 100644 --- a/drivers/media/usb/dvb-usb/dtv5100.c +++ b/drivers/media/usb/dvb-usb/dtv5100.c @@ -97,7 +97,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 +166,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 cbb0541d4dc1..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) @@ -309,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 b3bb1805829a..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; @@ -136,7 +134,7 @@ static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], 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; @@ -152,7 +150,7 @@ static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], 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) { @@ -169,7 +167,7 @@ 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; @@ -177,7 +175,7 @@ static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], } /* 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; @@ -187,7 +185,7 @@ static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], 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; @@ -199,7 +197,7 @@ static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], 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; } @@ -211,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}; @@ -242,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; @@ -264,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; @@ -276,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; @@ -320,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; @@ -345,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: { @@ -363,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; } } @@ -406,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 */ @@ -436,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]; @@ -454,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); @@ -476,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; @@ -492,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; @@ -525,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; @@ -550,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; } } @@ -567,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; @@ -578,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; @@ -594,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; } @@ -605,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): { @@ -618,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 */ @@ -639,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; @@ -655,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); @@ -677,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 */ @@ -696,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; @@ -712,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; @@ -729,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; @@ -810,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, }; @@ -852,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 -EIO; } else { - eepromline[i%16] = ibuf[0]; + eepromline[i % 16] = ibuf[0]; eeprom[i] = ibuf[0]; } if ((i % 16) == 15) { @@ -963,7 +992,6 @@ static int su3000_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) .flags = I2C_M_RD, .buf = ibuf, .len = 1, - } }; @@ -983,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; } @@ -1003,6 +1029,7 @@ static int dw210x_set_voltage(struct dvb_frontend *fe, }; struct dvb_usb_adapter *udev_adap = fe->dvb->priv; + if (voltage == SEC_VOLTAGE_18) msg.buf = command_18v; else if (voltage == SEC_VOLTAGE_13) @@ -1206,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; @@ -1225,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; @@ -1239,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; @@ -1248,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; @@ -1269,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; @@ -1279,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; @@ -1293,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; @@ -1306,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; } @@ -1317,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; @@ -1335,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; @@ -1350,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) @@ -1359,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; @@ -1382,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; @@ -1439,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; @@ -1499,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; } @@ -1527,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; @@ -1701,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; } @@ -1726,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); } } @@ -1747,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); } @@ -1769,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); } @@ -1807,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), @@ -1840,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), { } }; @@ -1848,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; @@ -1875,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; @@ -1906,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; } @@ -2551,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", @@ -2562,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, @@ -2586,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; } diff --git a/drivers/media/usb/dvb-usb/gp8psk.c b/drivers/media/usb/dvb-usb/gp8psk.c index 4cd21bb8805e..96a255500b38 100644 --- a/drivers/media/usb/dvb-usb/gp8psk.c +++ b/drivers/media/usb/dvb-usb/gp8psk.c @@ -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 c88a202daf5f..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; @@ -319,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, }; @@ -909,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 d269f8bb2dee..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, }; @@ -429,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), { } diff --git a/drivers/media/usb/dvb-usb/pctv452e.c b/drivers/media/usb/dvb-usb/pctv452e.c index 2aab49003493..5094de9a312e 100644 --- a/drivers/media/usb/dvb-usb/pctv452e.c +++ b/drivers/media/usb/dvb-usb/pctv452e.c @@ -906,14 +906,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); @@ -959,7 +959,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/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index bae76023cf71..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 */ 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-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 4aef584e21da..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) 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/go7007-driver.c b/drivers/media/usb/go7007/go7007-driver.c index eb03f98b2ef1..468406302cd5 100644 --- a/drivers/media/usb/go7007/go7007-driver.c +++ b/drivers/media/usb/go7007/go7007-driver.c @@ -736,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 2880370e45c8..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; } diff --git a/drivers/media/usb/go7007/go7007-usb.c b/drivers/media/usb/go7007/go7007-usb.c index 762c13e49bfa..334cdde81a5c 100644 --- a/drivers/media/usb/go7007/go7007-usb.c +++ b/drivers/media/usb/go7007/go7007-usb.c @@ -1352,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 13256565b034..2087ffcb85a5 100644 --- a/drivers/media/usb/go7007/go7007-v4l2.c +++ b/drivers/media/usb/go7007/go7007-v4l2.c @@ -452,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 db1fab96d529..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); diff --git a/drivers/media/usb/gspca/cpia1.c b/drivers/media/usb/gspca/cpia1.c index 5f5fa851ca64..14aaf36cde6e 100644 --- a/drivers/media/usb/gspca/cpia1.c +++ b/drivers/media/usb/gspca/cpia1.c @@ -604,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; } diff --git a/drivers/media/usb/gspca/gspca.c b/drivers/media/usb/gspca/gspca.c index e8c8bdb9c40b..25edd2189654 100644 --- a/drivers/media/usb/gspca/gspca.c +++ b/drivers/media/usb/gspca/gspca.c @@ -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 = { 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/hackrf/hackrf.c b/drivers/media/usb/hackrf/hackrf.c index 9c0ecd5f056c..0b50de8775a3 100644 --- a/drivers/media/usb/hackrf/hackrf.c +++ b/drivers/media/usb/hackrf/hackrf.c @@ -888,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, @@ -1398,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"); @@ -1413,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"); @@ -1474,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; @@ -1494,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/msi2500/msi2500.c b/drivers/media/usb/msi2500/msi2500.c index 5138486abfa0..33099f39146a 100644 --- a/drivers/media/usb/msi2500/msi2500.c +++ b/drivers/media/usb/msi2500/msi2500.c @@ -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, @@ -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,8 +1217,8 @@ static int msi2500_probe(struct usb_interface *intf, goto err_free_mem; } - /* SPI master adapter */ - ctlr = spi_alloc_master(dev->dev, 0); + /* SPI host adapter */ + ctlr = spi_alloc_host(dev->dev, 0); if (ctlr == NULL) { ret = -ENOMEM; goto err_unregister_v4l2_dev; 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-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 29cc207194b9..f21c2806eb9f 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); @@ -3562,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) { @@ -3724,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; @@ -3806,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; } @@ -4248,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) || @@ -4261,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 @@ -4399,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; @@ -4421,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; @@ -4432,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; @@ -4443,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; @@ -4454,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); @@ -4479,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) { @@ -4517,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-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-v4l2.c b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c index d608b793fa84..ad38e1240541 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c @@ -497,8 +497,8 @@ 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_hdw *hdw = fh->channel.mc_head->hdw; @@ -521,13 +521,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 +552,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; } @@ -571,31 +574,6 @@ 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) { @@ -812,10 +790,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, 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 8e1de1e8bd12..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; } @@ -2221,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) @@ -2341,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); @@ -2359,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 723510520d09..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,7 @@ 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); @@ -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); } @@ -463,7 +468,9 @@ 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"); @@ -486,6 +493,7 @@ static int smsusb_init_device(struct usb_interface *intf, int board_id) 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); diff --git a/drivers/media/usb/stk1160/stk1160-v4l.c b/drivers/media/usb/stk1160/stk1160-v4l.c index a1f785a5ffd8..5ba3d9c4b3fb 100644 --- a/drivers/media/usb/stk1160/stk1160-v4l.c +++ b/drivers/media/usb/stk1160/stk1160-v4l.c @@ -734,8 +734,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 366f0e4a5dc0..9cbd957ecc90 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; @@ -130,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; } @@ -173,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; } diff --git a/drivers/media/usb/ttusb-dec/ttusb_dec.c b/drivers/media/usb/ttusb-dec/ttusb_dec.c index 79faa2560613..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 { @@ -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) @@ -1588,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); @@ -1703,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; @@ -1729,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/usbtv/usbtv-video.c b/drivers/media/usb/usbtv/usbtv-video.c index 702f1c8bd2ab..be22a9697197 100644 --- a/drivers/media/usb/usbtv/usbtv-video.c +++ b/drivers/media/usb/usbtv/usbtv-video.c @@ -780,8 +780,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) diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c index e59a463c2761..44b6513c5264 100644 --- a/drivers/media/usb/uvc/uvc_ctrl.c +++ b/drivers/media/usb/uvc/uvc_ctrl.c @@ -358,6 +358,24 @@ 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, + }, }; static const u32 uvc_control_classes[] = { @@ -367,6 +385,27 @@ static const u32 uvc_control_classes[] = { static const int exposure_auto_mapping[] = { 2, 1, 4, 8 }; +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 @@ -405,58 +444,219 @@ uvc_mapping_get_menu_name(const struct uvc_control_mapping *mapping, u32 idx) return v4l2_ctrl_get_menu(mapping->id)[idx]; } -static s32 uvc_ctrl_get_zoom(struct uvc_control_mapping *mapping, - u8 query, const u8 *data) +static int uvc_ctrl_get_zoom(struct uvc_control_mapping *mapping, u8 query, + const void *uvc_in, size_t v4l2_size, + void *v4l2_out) { - s8 zoom = (s8)data[0]; + 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; + + if (WARN_ON(v4l2_size != sizeof(s32))) + return -EINVAL; - data[first] = value == 0 ? 0 : (value > 0) ? 1 : 0xff; - data[first+1] = min_t(int, abs(value), 0xff); + 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[] = { @@ -748,52 +948,33 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = { .v4l2_type = V4L2_CTRL_TYPE_BOOLEAN, .data_type = UVC_CTRL_DATA_TYPE_BOOLEAN, }, -}; - -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), -}; - -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_mappings_uvc11[] = { - &uvc_ctrl_power_line_mapping_uvc11, - NULL, /* Sentinel */ -}; - -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_mappings_uvc15[] = { - &uvc_ctrl_power_line_mapping_uvc15, - NULL, /* Sentinel */ + { + .entity = UVC_GUID_UVC_PROCESSING, + .selector = UVC_PU_POWER_LINE_FREQUENCY_CONTROL, + .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_RECT, + .data_type = UVC_CTRL_DATA_TYPE_RECT, + .get = uvc_get_rect, + .set = uvc_set_rect, + .name = "Region of Interest Rectangle", + }, + { + .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", + }, }; /* ------------------------------------------------------------------------ @@ -815,20 +996,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; @@ -836,7 +1042,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; @@ -849,28 +1055,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; @@ -882,6 +1118,8 @@ static void uvc_set_le_value(struct uvc_control_mapping *mapping, bits -= 8 - offset; offset = 0; } + + return 0; } /* ------------------------------------------------------------------------ @@ -900,7 +1138,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; @@ -915,14 +1153,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; } @@ -936,6 +1176,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; @@ -944,12 +1185,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); @@ -1013,32 +1255,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) { - 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 == value) { - value = i; - break; - } - } - } - - return value; -} - static int __uvc_ctrl_load_cur(struct uvc_video_chain *chain, struct uvc_control *ctrl) { @@ -1089,8 +1305,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; } @@ -1098,7 +1314,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; @@ -1120,7 +1337,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; @@ -1138,6 +1356,37 @@ 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). @@ -1156,7 +1405,6 @@ int uvc_ctrl_is_accessible(struct uvc_video_chain *chain, u32 v4l2_id, struct uvc_control *master_ctrl = NULL; struct uvc_control_mapping *mapping; struct uvc_control *ctrl; - bool read = ioctl == VIDIOC_G_EXT_CTRLS; s32 val; int ret; int i; @@ -1168,10 +1416,10 @@ 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) - return -EACCES; + if (ioctl == VIDIOC_G_EXT_CTRLS) + return uvc_ctrl_is_readable(ctrls->which, ctrl, mapping); - if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR) && !read) + if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR)) return -EACCES; if (ioctl != VIDIOC_S_EXT_CTRLS || !mapping->master_id) @@ -1188,10 +1436,12 @@ int uvc_ctrl_is_accessible(struct uvc_video_chain *chain, u32 v4l2_id, } __uvc_find_control(ctrl->entity, mapping->master_id, &master_map, - &master_ctrl, 0); + &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) @@ -1223,50 +1473,21 @@ static u32 uvc_get_ctrl_bitmap(struct uvc_control *ctrl, * as supported. */ if (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES) - return mapping->get(mapping, UVC_GET_RES, - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_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_MAX) - return mapping->get(mapping, UVC_GET_MAX, - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX)); + return uvc_mapping_get_s32(mapping, UVC_GET_MAX, + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX)); return ~0; } -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 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) { - struct uvc_control_mapping *master_map = NULL; - struct uvc_control *master_ctrl = NULL; - 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; - - 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 (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; - - if (val != mapping->master_manual) - v4l2_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; - } - if (!ctrl->cached) { int ret = uvc_ctrl_populate_cache(chain, ctrl); if (ret < 0) @@ -1274,8 +1495,8 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, } 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) { @@ -1283,21 +1504,6 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, v4l2_ctrl->minimum = ffs(mapping->menu_mask) - 1; v4l2_ctrl->maximum = fls(mapping->menu_mask) - 1; v4l2_ctrl->step = 1; - - 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 == v4l2_ctrl->default_value) { - v4l2_ctrl->default_value = i; - break; - } - } - return 0; case V4L2_CTRL_TYPE_BOOLEAN: @@ -1323,22 +1529,95 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, } 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; + + 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)) { + s32 val; + int ret; + + 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) + return ret; + + 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; + } + + return __uvc_queryctrl_boundaries(chain, ctrl, mapping, v4l2_ctrl); +} + 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; @@ -1464,7 +1743,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); @@ -1522,16 +1801,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_fh *handle, struct uvc_control *ctrl, + struct uvc_fh *new_handle) +{ + lockdep_assert_held(&handle->chain->ctrl_mutex); + + if (new_handle) { + int ret; + + if (ctrl->handle) + dev_warn_ratelimited(&handle->stream->dev->udev->dev, + "UVC non compliance: Setting an async control with a pending operation."); + + if (new_handle == ctrl->handle) + return 0; + + if (ctrl->handle) { + WARN_ON(!ctrl->handle->pending_async_ctrls); + if (ctrl->handle->pending_async_ctrls) + ctrl->handle->pending_async_ctrls--; + ctrl->handle = new_handle; + handle->pending_async_ctrls++; + return 0; + } + + ret = uvc_pm_get(handle->chain->dev); + if (ret) + return ret; + + ctrl->handle = new_handle; + handle->pending_async_ctrls++; + return 0; + } + + /* Cannot clear the handle for a control not owned by us.*/ + if (WARN_ON(ctrl->handle != handle)) + return -EINVAL; + + ctrl->handle = NULL; + if (WARN_ON(!handle->pending_async_ctrls)) + return -EINVAL; + handle->pending_async_ctrls--; + uvc_pm_put(handle->chain->dev); + return 0; +} + void uvc_ctrl_status_event(struct uvc_video_chain *chain, struct uvc_control *ctrl, const u8 *data) { @@ -1541,11 +1866,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_set_handle(handle, ctrl, NULL); 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 @@ -1593,10 +1927,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; @@ -1622,16 +1954,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. */ @@ -1655,6 +1993,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. @@ -1665,7 +2007,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); } } @@ -1697,7 +2039,8 @@ static int uvc_ctrl_add_event(struct v4l2_subscribed_event *sev, unsigned elems) u32 changes = V4L2_EVENT_CTRL_CH_FLAGS; s32 val = 0; - if (__uvc_ctrl_get(handle->chain, ctrl, mapping, &val) == 0) + 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, @@ -1763,12 +2106,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; @@ -1797,8 +2148,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), @@ -1807,14 +2159,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(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, @@ -1830,7 +2193,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; } @@ -1844,28 +2207,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; @@ -1874,34 +2360,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) { @@ -1910,23 +2385,22 @@ 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) { @@ -1935,47 +2409,102 @@ int uvc_ctrl_set(struct uvc_fh *handle, return ret; } - xctrl->value &= uvc_get_ctrl_bitmap(ctrl, mapping); - value = xctrl->value; - break; + 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 < (ffs(mapping->menu_mask) - 1) || - xctrl->value > (fls(mapping->menu_mask) - 1)) + if (value < (ffs(mapping->menu_mask) - 1) || + value > (fls(mapping->menu_mask) - 1)) return -ERANGE; - if (!test_bit(xctrl->value, &mapping->menu_mask)) + if (!test_bit(value, &mapping->menu_mask)) return -EINVAL; - value = uvc_mapping_get_menu_value(mapping, xctrl->value); - /* * 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) { + int val = uvc_mapping_get_menu_value(mapping, value); if (!ctrl->cached) { ret = uvc_ctrl_populate_cache(chain, ctrl); if (ret < 0) return ret; } - if (!(uvc_get_ctrl_bitmap(ctrl, mapping) & 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 @@ -1994,11 +2523,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; @@ -2029,7 +2556,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 ? @@ -2038,6 +2571,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; @@ -2165,7 +2699,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; @@ -2175,16 +2709,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; @@ -2321,7 +2855,7 @@ int uvc_ctrl_restore_values(struct uvc_device *dev) 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; } @@ -2366,6 +2900,7 @@ 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. @@ -2406,6 +2941,12 @@ static int __uvc_ctrl_add_mapping(struct uvc_video_chain *chain, 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; if (map->set == NULL) @@ -2427,11 +2968,13 @@ static int __uvc_ctrl_add_mapping(struct uvc_video_chain *chain, return 0; err_nomem: + ret = -ENOMEM; +free_mem: kfree(map->menu_names); kfree(map->menu_mapping); kfree(map->name); kfree(map); - return -ENOMEM; + return ret; } int uvc_ctrl_add_mapping(struct uvc_video_chain *chain, @@ -2589,7 +3132,6 @@ 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 i; /* @@ -2621,50 +3163,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. */ - mappings = chain->dev->uvc_version < 0x0150 - ? uvc_ctrl_mappings_uvc11 : uvc_ctrl_mappings_uvc15; + if (!uvc_entity_match_guid(ctrl->entity, mapping->entity) || + ctrl->info.selector != mapping->selector) + continue; - for (i = 0; mappings[i]; ++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); } } @@ -2743,6 +3257,31 @@ int uvc_ctrl_init_device(struct uvc_device *dev) return 0; } +void uvc_ctrl_cleanup_fh(struct uvc_fh *handle) +{ + struct uvc_entity *entity; + int i; + + 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_set_handle(handle, &entity->controls[i], NULL); + } + } + + if (!WARN_ON(handle->pending_async_ctrls)) + return; + + for (i = 0; i < handle->pending_async_ctrls; i++) + uvc_pm_put(handle->stream->dev); +} + /* * Cleanup device controls. */ 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 bbd90123a4e7..da24a655ab68 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -14,11 +14,12 @@ #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> @@ -31,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 */ @@ -219,20 +222,127 @@ 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, 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 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; format->type = buffer[2]; format->index = buffer[3]; @@ -370,111 +480,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) { - unsigned int maxIntervalIndex; - - frame = &frames[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]; - } - - /* - * 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; + 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++; - *intervals += n; - - buflen -= buffer[0]; - buffer += buffer[0]; } if (buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE && @@ -530,7 +548,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, @@ -540,7 +558,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; } @@ -686,16 +704,26 @@ 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->formats = format; streaming->nformats = 0; @@ -753,7 +781,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; } @@ -1269,14 +1297,19 @@ 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); @@ -1302,15 +1335,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); } /* ------------------------------------------------------------------------ @@ -1884,8 +1929,7 @@ static void uvc_delete(struct kref *kref) 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); } @@ -1907,12 +1951,44 @@ 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) { + /* Nothing to do here, continue. */ if (!video_is_registered(&stream->vdev)) continue; + /* + * For stream->vdev we follow the same logic as: + * vb2_video_unregister_device(). + */ + + /* 1. Take a reference to vdev */ + get_device(&stream->vdev.dev); + + /* 2. Ensure that no new ioctls can be called. */ video_unregister_device(&stream->vdev); - video_unregister_device(&stream->meta.vdev); + + /* 3. Wait for old ioctls to finish. */ + mutex_lock(&stream->mutex); + + /* 4. Stop streaming. */ + uvc_queue_release(&stream->queue); + + mutex_unlock(&stream->mutex); + + put_device(&stream->vdev.dev); + + /* + * For stream->meta.vdev we can directly call: + * vb2_video_unregister_device(). + */ + vb2_video_unregister_device(&stream->meta.vdev); + + /* + * Now both vdevs are not streaming and all the ioctls will + * return -ENODEV. + */ uvc_debugfs_cleanup_stream(stream); } @@ -1938,7 +2014,7 @@ int uvc_register_video_device(struct uvc_device *dev, 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; @@ -2105,7 +2181,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); @@ -2162,16 +2237,17 @@ 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) { + ret = -ENODEV; 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->uvc_version >> 8, dev->uvc_version & 0xff, @@ -2194,24 +2270,32 @@ static int uvc_probe(struct usb_interface *intf, } /* 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) + if (uvc_scan_device(dev) < 0) { + ret = -ENODEV; goto error; + } /* Initialize controls. */ - if (uvc_ctrl_init_device(dev) < 0) + if (uvc_ctrl_init_device(dev) < 0) { + ret = -ENODEV; goto error; + } /* Register video device nodes. */ - if (uvc_register_chains(dev) < 0) + if (uvc_register_chains(dev) < 0) { + ret = -ENODEV; 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. */ @@ -2232,14 +2316,20 @@ static int uvc_probe(struct usb_interface *intf, 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) @@ -2271,10 +2361,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; } @@ -2305,12 +2392,7 @@ 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) { @@ -2370,8 +2452,25 @@ module_param_call(clock, uvc_clock_param_set, uvc_clock_param_get, MODULE_PARM_DESC(clock, "Video buffers timestamp clock"); 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, 0644); + +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, 0644); MODULE_PARM_DESC(quirks, "Forced device quirks"); module_param_named(trace, uvc_dbg_param, uint, 0644); @@ -2383,20 +2482,6 @@ MODULE_PARM_DESC(timeout, "Streaming control requests timeout"); * Driver initialization and cleanup */ -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_ctrl_power_line_uvc11 = { - .mappings = (const struct uvc_control_mapping *[]) { - &uvc_ctrl_power_line_mapping_uvc11, - NULL, /* Sentinel */ - }, -}; - static const struct uvc_device_info uvc_quirk_probe_minmax = { .quirks = UVC_QUIRK_PROBE_MINMAX, }; @@ -2425,35 +2510,32 @@ 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 */ - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE - | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x0408, - .idProduct = 0x3090, - .bInterfaceClass = USB_CLASS_VIDEO, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 0, - .driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_limited }, - /* Quanta USB2.0 HD UVC Webcam */ + /* 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, @@ -2573,52 +2655,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 Electronics Co., Ltd Integrated Camera */ + .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 = 0xb67c, + .idVendor = 0x046d, + .idProduct = 0x089b, .bInterfaceClass = USB_CLASS_VIDEO, .bInterfaceSubClass = 1, - .bInterfaceProtocol = UVC_PC_PROTOCOL_15, - .driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_uvc11 }, - /* Chicony EasyCamera */ + .bInterfaceProtocol = 0, + .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 = 0x04f2, - .idProduct = 0xb6ba, + .idVendor = 0x046d, + .idProduct = 0x08d3, .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) }, + /* 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, @@ -2764,6 +2847,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, @@ -2792,6 +2884,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, @@ -2976,6 +3077,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, @@ -3003,51 +3122,15 @@ static const struct usb_device_id uvc_ids[] = { .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_FORCE_BPP) }, - /* SunplusIT Inc HD Camera */ + /* Insta360 Link */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x2b7e, - .idProduct = 0xb752, - .bInterfaceClass = USB_CLASS_VIDEO, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = UVC_PC_PROTOCOL_15, - .driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_uvc11 }, - /* Lenovo Integrated Camera */ - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE - | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x30c9, - .idProduct = 0x0093, - .bInterfaceClass = USB_CLASS_VIDEO, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = UVC_PC_PROTOCOL_15, - .driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_uvc11 }, - /* Sonix Technology USB 2.0 Camera */ - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE - | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x3277, - .idProduct = 0x0072, + .idVendor = 0x2e1a, + .idProduct = 0x4c01, .bInterfaceClass = USB_CLASS_VIDEO, .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, - .driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_limited }, - /* Acer EasyCamera */ - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE - | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x5986, - .idProduct = 0x1172, - .bInterfaceClass = USB_CLASS_VIDEO, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 0, - .driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_limited }, - /* Acer EasyCamera */ - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE - | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x5986, - .idProduct = 0x1180, - .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_DISABLE_AUTOSUSPEND) }, /* Intel D410/ASR depth camera */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, @@ -3120,6 +3203,15 @@ static const struct usb_device_id uvc_ids[] = { .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) }, @@ -3128,17 +3220,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) @@ -3147,7 +3237,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; @@ -3158,7 +3248,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_queue.c b/drivers/media/usb/uvc/uvc_queue.c index 16fa17bbd15e..2ee142621042 100644 --- a/drivers/media/usb/uvc/uvc_queue.c +++ b/drivers/media/usb/uvc/uvc_queue.c @@ -197,8 +197,6 @@ 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, }; @@ -207,13 +205,10 @@ 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, }; -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,7 +238,6 @@ 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; } @@ -476,14 +470,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 a78a88c710e2..ee01dce4b783 100644 --- a/drivers/media/usb/uvc/uvc_status.c +++ b/drivers/media/usb/uvc/uvc_status.c @@ -257,11 +257,11 @@ 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(sizeof(*dev->status), GFP_KERNEL); if (!dev->status) return -ENOMEM; @@ -269,6 +269,7 @@ int uvc_status_init(struct uvc_device *dev) dev->int_urb = usb_alloc_urb(0, GFP_KERNEL); if (!dev->int_urb) { kfree(dev->status); + dev->status = NULL; return -ENOMEM; } @@ -287,12 +288,17 @@ int uvc_status_init(struct uvc_device *dev) 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); } @@ -302,18 +308,25 @@ 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 @@ -350,3 +363,49 @@ void uvc_status_stop(struct uvc_device *dev) */ 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 f4988f03640a..668a4e9d772c 100644 --- a/drivers/media/usb/uvc/uvc_v4l2.c +++ b/drivers/media/usb/uvc/uvc_v4l2.c @@ -26,6 +26,29 @@ #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_acquire_privileges(struct uvc_fh *handle); + static int uvc_control_add_xu_mapping(struct uvc_video_chain *chain, struct uvc_control_mapping *map, const struct uvc_xu_control_mapping *xmap) @@ -106,6 +129,12 @@ static int uvc_ioctl_xu_ctrl_map(struct uvc_video_chain *chain, struct uvc_control_mapping *map; 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; @@ -361,9 +390,11 @@ 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 *fh, + struct v4l2_format *fmt) { + struct uvc_fh *handle = fh; + struct uvc_streaming *stream = handle->stream; const struct uvc_format *format; const struct uvc_frame *frame; int ret = 0; @@ -395,14 +426,20 @@ done: return ret; } -static int uvc_v4l2_set_format(struct uvc_streaming *stream, - struct v4l2_format *fmt) +static int uvc_ioctl_s_fmt(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; const struct uvc_format *format; const struct uvc_frame *frame; int ret; + ret = uvc_acquire_privileges(handle); + if (ret < 0) + return ret; + if (fmt->type != stream->type) return -EINVAL; @@ -426,10 +463,12 @@ done: return ret; } -static int uvc_v4l2_get_streamparm(struct uvc_streaming *stream, - struct v4l2_streamparm *parm) +static int uvc_ioctl_g_parm(struct file *file, void *fh, + struct v4l2_streamparm *parm) { u32 numerator, denominator; + struct uvc_fh *handle = fh; + struct uvc_streaming *stream = handle->stream; if (parm->type != stream->type) return -EINVAL; @@ -461,9 +500,11 @@ 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 *fh, + struct v4l2_streamparm *parm) { + struct uvc_fh *handle = fh; + struct uvc_streaming *stream = handle->stream; struct uvc_streaming_control probe; struct v4l2_fract timeperframe; const struct uvc_format *format; @@ -472,6 +513,10 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream, unsigned int i; int ret; + ret = uvc_acquire_privileges(handle); + if (ret < 0) + return ret; + if (parm->type != stream->type) return -EINVAL; @@ -573,6 +618,7 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream, * - VIDIOC_S_INPUT * - VIDIOC_S_PARM * - VIDIOC_S_FMT + * - VIDIOC_CREATE_BUFS * - VIDIOC_REQBUFS */ static int uvc_acquire_privileges(struct uvc_fh *handle) @@ -612,35 +658,14 @@ 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); @@ -659,10 +684,15 @@ static int uvc_v4l2_release(struct file *file) uvc_dbg(stream->dev, CALLS, "%s\n", __func__); + uvc_ctrl_cleanup_fh(handle); + /* Only free resources if this is a privileged handle. */ if (uvc_has_privileges(handle)) uvc_queue_release(&stream->queue); + if (handle->is_streaming) + uvc_pm_put(stream->dev); + /* Release the file handle. */ uvc_dismiss_privileges(handle); v4l2_fh_del(&handle->vfh); @@ -670,12 +700,6 @@ static int uvc_v4l2_release(struct file *file) 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); return 0; } @@ -695,11 +719,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 *fh, struct v4l2_fmtdesc *fmt) { - const struct uvc_format *format; + struct uvc_fh *handle = fh; + 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) @@ -717,82 +743,8 @@ static int uvc_ioctl_enum_fmt(struct uvc_streaming *stream, 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) -{ - 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) +static int uvc_ioctl_try_fmt(struct file *file, void *fh, + struct v4l2_format *fmt) { struct uvc_fh *handle = fh; struct uvc_streaming *stream = handle->stream; @@ -896,11 +848,23 @@ static int uvc_ioctl_streamon(struct file *file, void *fh, if (!uvc_has_privileges(handle)) return -EBUSY; - mutex_lock(&stream->mutex); + guard(mutex)(&stream->mutex); + + if (handle->is_streaming) + return 0; + ret = uvc_queue_streamon(&stream->queue, type); - mutex_unlock(&stream->mutex); + if (ret) + return ret; - return ret; + ret = uvc_pm_get(stream->dev); + if (ret) { + uvc_queue_streamoff(&stream->queue, type); + return ret; + } + handle->is_streaming = true; + + return 0; } static int uvc_ioctl_streamoff(struct file *file, void *fh, @@ -912,9 +876,13 @@ static int uvc_ioctl_streamoff(struct file *file, void *fh, if (!uvc_has_privileges(handle)) return -EBUSY; - mutex_lock(&stream->mutex); + guard(mutex)(&stream->mutex); + uvc_queue_streamoff(&stream->queue, type); - mutex_unlock(&stream->mutex); + if (handle->is_streaming) { + handle->is_streaming = false; + uvc_pm_put(stream->dev); + } return 0; } @@ -1024,42 +992,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, struct v4l2_query_ext_ctrl *qec) { struct uvc_fh *handle = fh; 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, @@ -1088,34 +1027,33 @@ static int uvc_ioctl_g_ext_ctrls(struct file *file, void *fh, 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; @@ -1137,6 +1075,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; @@ -1222,29 +1163,6 @@ static int uvc_ioctl_g_selection(struct file *file, void *fh, 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, struct v4l2_frmsizeenum *fsize) { @@ -1463,9 +1381,11 @@ static int uvc_v4l2_put_xu_query(const struct uvc_xu_control_query *kp, #define UVCIOC_CTRL_MAP32 _IOWR('u', 0x20, struct uvc_xu_control_mapping32) #define UVCIOC_CTRL_QUERY32 _IOWR('u', 0x21, struct uvc_xu_control_query32) +DEFINE_FREE(uvc_pm_put, struct uvc_device *, if (_T) uvc_pm_put(_T)) static long uvc_v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) { + struct uvc_device *uvc_device __free(uvc_pm_put) = NULL; struct uvc_fh *handle = file->private_data; union { struct uvc_xu_control_mapping xmap; @@ -1474,6 +1394,12 @@ 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; + + uvc_device = handle->stream->dev; + switch (cmd) { case UVCIOC_CTRL_MAP32: ret = uvc_v4l2_get_xu_mapping(&karg.xmap, up); @@ -1508,6 +1434,42 @@ static long uvc_v4l2_compat_ioctl32(struct file *file, } #endif +static long uvc_v4l2_unlocked_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct uvc_fh *handle = file->private_data; + int ret; + + /* The following IOCTLs do not need to turn on the camera. */ + switch (cmd) { + case VIDIOC_CREATE_BUFS: + case VIDIOC_DQBUF: + case VIDIOC_ENUM_FMT: + case VIDIOC_ENUM_FRAMEINTERVALS: + case VIDIOC_ENUM_FRAMESIZES: + case VIDIOC_ENUMINPUT: + case VIDIOC_EXPBUF: + case VIDIOC_G_FMT: + case VIDIOC_G_PARM: + case VIDIOC_G_SELECTION: + case VIDIOC_QBUF: + case VIDIOC_QUERYCAP: + case VIDIOC_REQBUFS: + case VIDIOC_SUBSCRIBE_EVENT: + case VIDIOC_UNSUBSCRIBE_EVENT: + return video_ioctl2(file, cmd, arg); + } + + 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; +} + static ssize_t uvc_v4l2_read(struct file *file, char __user *data, size_t count, loff_t *ppos) { @@ -1553,15 +1515,17 @@ static unsigned long uvc_v4l2_get_unmapped_area(struct file *file, #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_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 = uvc_ioctl_reqbufs, .vidioc_querybuf = uvc_ioctl_querybuf, .vidioc_qbuf = uvc_ioctl_qbuf, @@ -1573,15 +1537,12 @@ const struct v4l2_ioctl_ops uvc_ioctl_ops = { .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, @@ -1593,7 +1554,7 @@ 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 diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c index 7cbf4692bd87..e3567aeb0007 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,6 +80,27 @@ int uvc_query_ctrl(struct uvc_device *dev, u8 query, u8 unit, if (likely(ret == size)) return 0; + /* + * 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->udev->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) { dev_err(&dev->udev->dev, "Failed to query (%s) UVC control %u on unit %u: %d (exp. %u).\n", @@ -96,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->udev->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); @@ -214,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; @@ -297,8 +323,9 @@ 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); + "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; } @@ -466,18 +493,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: @@ -522,14 +580,51 @@ uvc_video_clock_decode(struct uvc_streaming *stream, struct uvc_buffer *buf, * 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 @@ -552,46 +647,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; @@ -600,15 +678,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; } /* @@ -709,11 +787,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; @@ -728,11 +806,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); @@ -746,6 +824,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); @@ -753,7 +843,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), @@ -768,7 +858,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 @@ -789,7 +879,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, @@ -1053,6 +1143,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; /* @@ -1066,6 +1157,7 @@ static int uvc_video_decode_start(struct uvc_streaming *stream, return -EINVAL; } + header_len = data[0]; fid = data[1] & UVC_STREAM_FID; /* @@ -1147,9 +1239,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( @@ -2071,7 +2185,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; @@ -2220,7 +2334,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; @@ -2238,7 +2352,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; } @@ -2266,5 +2380,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 6fb0a78b1b00..b9f8eb62ba1d 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -73,6 +73,10 @@ #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 /* Format flags */ #define UVC_FMT_FLAG_COMPRESSED 0x00000001 @@ -84,7 +88,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 @@ -110,7 +116,12 @@ 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; @@ -123,10 +134,13 @@ struct uvc_control_mapping { 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); + 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 +240,7 @@ struct uvc_entity { u8 *bmControls; struct gpio_desc *gpio_privacy; int irq; + bool initialized; } gpio; }; @@ -308,7 +323,6 @@ struct uvc_buffer { }; #define UVC_QUEUE_DISCONNECTED (1 << 0) -#define UVC_QUEUE_DROP_CORRUPTED (1 << 1) struct uvc_video_queue { struct vb2_queue queue; @@ -329,7 +343,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 */ @@ -498,6 +516,7 @@ struct uvc_streaming { unsigned int head; unsigned int count; unsigned int size; + unsigned int last_sof_overflow; u16 last_sof; u16 sof_offset; @@ -522,9 +541,15 @@ 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; @@ -555,8 +580,6 @@ struct uvc_device { const struct uvc_device_info *info; - struct mutex lock; /* Protects users */ - unsigned int users; atomic_t nmappings; /* Video control interface */ @@ -578,6 +601,8 @@ struct uvc_device { struct usb_host_endpoint *int_ep; struct urb *int_urb; struct uvc_status *status; + struct mutex status_lock; /* Protects status_users */ + unsigned int status_users; bool flush_status; struct input_dev *input; @@ -604,10 +629,8 @@ struct uvc_fh { struct uvc_video_chain *chain; struct uvc_streaming *stream; enum uvc_handle_state state; -}; - -struct uvc_driver { - struct usb_driver driver; + unsigned int pending_async_ctrls; + bool is_streaming; }; /* ------------------------------------------------------------------------ @@ -660,14 +683,10 @@ do { \ * 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); +int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type); void uvc_queue_release(struct uvc_video_queue *queue); int uvc_request_buffers(struct uvc_video_queue *queue, struct v4l2_requestbuffers *rb); @@ -744,16 +763,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 uvc_control_mapping uvc_ctrl_power_line_mapping_limited; -extern const struct uvc_control_mapping uvc_ctrl_power_line_mapping_uvc11; 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); @@ -780,7 +803,8 @@ 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, const struct v4l2_ext_controls *ctrls, @@ -789,6 +813,8 @@ int uvc_ctrl_is_accessible(struct uvc_video_chain *chain, u32 v4l2_id, 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); |