diff options
Diffstat (limited to 'drivers/media/usb')
70 files changed, 1894 insertions, 1775 deletions
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-video.c b/drivers/media/usb/au0828/au0828-video.c index e9cd2a335f7f..fbaa542c8259 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -857,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) { @@ -905,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 = { @@ -948,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; @@ -972,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; @@ -1040,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)) @@ -1694,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) @@ -1921,9 +1921,8 @@ int au0828_analog_register(struct au0828_dev *dev, iface_desc = interface->cur_altsetting; for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) { endpoint = &iface_desc->endpoint[i].desc; - if (((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) - == USB_DIR_IN) && - ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) + if (usb_endpoint_dir_in(endpoint) && + (usb_endpoint_type(endpoint) == USB_ENDPOINT_XFER_ISOC)) { /* we find our isoc in endpoint */ diff --git a/drivers/media/usb/cx231xx/cx231xx-417.c b/drivers/media/usb/cx231xx/cx231xx-417.c index a4a9781328c5..c695a97e202b 100644 --- a/drivers/media/usb/cx231xx/cx231xx-417.c +++ b/drivers/media/usb/cx231xx/cx231xx-417.c @@ -1499,7 +1499,7 @@ static int vidioc_g_selection(struct file *file, void *priv, return 0; } -static int vidioc_g_std(struct file *file, void *fh0, v4l2_std_id *norm) +static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *norm) { struct cx231xx *dev = video_drvdata(file); @@ -1538,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) { @@ -1627,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, @@ -1720,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 6139ef5d891d..1cfec76b72f3 100644 --- a/drivers/media/usb/cx231xx/cx231xx-avcore.c +++ b/drivers/media/usb/cx231xx/cx231xx-avcore.c @@ -2704,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-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/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 0d2c42819d39..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, }; diff --git a/drivers/media/usb/dvb-usb-v2/anysee.c b/drivers/media/usb/dvb-usb-v2/anysee.c index bea12cdc85e8..64bddca5303c 100644 --- a/drivers/media/usb/dvb-usb-v2/anysee.c +++ b/drivers/media/usb/dvb-usb-v2/anysee.c @@ -235,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..05c18b6de5c6 100644 --- a/drivers/media/usb/dvb-usb-v2/lmedm04.c +++ b/drivers/media/usb/dvb-usb-v2/lmedm04.c @@ -70,12 +70,12 @@ #include "ts2020.h" -#define LME2510_C_S7395 "dvb-usb-lme2510c-s7395.fw"; -#define LME2510_C_LG "dvb-usb-lme2510c-lg.fw"; -#define LME2510_C_S0194 "dvb-usb-lme2510c-s0194.fw"; -#define LME2510_C_RS2000 "dvb-usb-lme2510c-rs2000.fw"; -#define LME2510_LG "dvb-usb-lme2510-lg.fw"; -#define LME2510_S0194 "dvb-usb-lme2510-s0194.fw"; +#define LME2510_C_S7395 "dvb-usb-lme2510c-s7395.fw" +#define LME2510_C_LG "dvb-usb-lme2510c-lg.fw" +#define LME2510_C_S0194 "dvb-usb-lme2510c-s0194.fw" +#define LME2510_C_RS2000 "dvb-usb-lme2510c-rs2000.fw" +#define LME2510_LG "dvb-usb-lme2510-lg.fw" +#define LME2510_S0194 "dvb-usb-lme2510-s0194.fw" /* debug */ static int dvb_usb_lme2510_debug; @@ -373,6 +373,7 @@ static int lme2510_int_read(struct dvb_usb_adapter *adap) struct dvb_usb_device *d = adap_to_d(adap); struct lme2510_state *lme_int = adap_to_priv(adap); struct usb_host_endpoint *ep; + int ret; lme_int->lme_urb = usb_alloc_urb(0, GFP_KERNEL); @@ -390,11 +391,20 @@ static int lme2510_int_read(struct dvb_usb_adapter *adap) /* Quirk of pipe reporting PIPE_BULK but behaves as interrupt */ ep = usb_pipe_endpoint(d->udev, lme_int->lme_urb->pipe); + if (!ep) { + usb_free_urb(lme_int->lme_urb); + return -ENODEV; + } if (usb_endpoint_type(&ep->desc) == USB_ENDPOINT_XFER_BULK) lme_int->lme_urb->pipe = usb_rcvbulkpipe(d->udev, 0xa); - usb_submit_urb(lme_int->lme_urb, GFP_KERNEL); + ret = usb_submit_urb(lme_int->lme_urb, GFP_KERNEL); + if (ret) { + usb_free_urb(lme_int->lme_urb); + return ret; + } + info("INT Interrupt Service Started"); return 0; @@ -549,7 +559,7 @@ static u32 lme2510_i2c_func(struct i2c_adapter *adapter) return I2C_FUNC_I2C; } -static struct i2c_algorithm lme2510_i2c_algo = { +static const struct i2c_algorithm lme2510_i2c_algo = { .master_xfer = lme2510_i2c_xfer, .functionality = lme2510_i2c_func, }; diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf.c b/drivers/media/usb/dvb-usb-v2/mxl111sf.c index cd5861a30b6f..870ac3c8b085 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf.c +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf.c @@ -911,7 +911,7 @@ static u32 mxl111sf_i2c_func(struct i2c_adapter *adapter) return I2C_FUNC_I2C; } -static struct i2c_algorithm mxl111sf_i2c_algo = { +static const struct i2c_algorithm mxl111sf_i2c_algo = { .master_xfer = mxl111sf_i2c_xfer, .functionality = mxl111sf_i2c_func, #ifdef NEED_ALGO_CONTROL diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c index 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 8253046cd6e6..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; 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/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.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..c448e2ebda1a 100644 --- a/drivers/media/usb/dvb-usb/dtv5100.c +++ b/drivers/media/usb/dvb-usb/dtv5100.c @@ -55,6 +55,11 @@ static int dtv5100_i2c_msg(struct dvb_usb_device *d, u8 addr, } index = (addr << 8) + wbuf[0]; + if (rlen > sizeof(st->data)) { + warn("rlen = %x is too big!\n", rlen); + return -EINVAL; + } + memcpy(st->data, rbuf, rlen); msleep(1); /* avoid I2C errors */ return usb_control_msg(d->udev, pipe, request, @@ -97,7 +102,7 @@ static u32 dtv5100_i2c_func(struct i2c_adapter *adapter) return I2C_FUNC_I2C; } -static struct i2c_algorithm dtv5100_i2c_algo = { +static const struct i2c_algorithm dtv5100_i2c_algo = { .master_xfer = dtv5100_i2c_xfer, .functionality = dtv5100_i2c_func, }; @@ -166,7 +171,7 @@ enum { AME_DTV5100, }; -static struct usb_device_id dtv5100_table[] = { +static const struct usb_device_id dtv5100_table[] = { DVB_USB_DEV(AME, AME_DTV5100), { } }; diff --git a/drivers/media/usb/dvb-usb/dvb-usb.h b/drivers/media/usb/dvb-usb/dvb-usb.h index 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 79e2ccf974c9..4fecf2f965e9 100644 --- a/drivers/media/usb/dvb-usb/dw2102.c +++ b/drivers/media/usb/dvb-usb/dw2102.c @@ -839,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, }; @@ -1836,7 +1836,7 @@ enum dw2102_table_entry { 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), 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 a2054b1b100f..45337ba0a0a3 100644 --- a/drivers/media/usb/dvb-usb/m920x.c +++ b/drivers/media/usb/dvb-usb/m920x.c @@ -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 268f05fc8691..3c79cc6848b4 100644 --- a/drivers/media/usb/dvb-usb/opera1.c +++ b/drivers/media/usb/dvb-usb/opera1.c @@ -155,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, }; @@ -425,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..bc7a224d829e 100644 --- a/drivers/media/usb/dvb-usb/pctv452e.c +++ b/drivers/media/usb/dvb-usb/pctv452e.c @@ -422,16 +422,15 @@ static int pctv452e_i2c_msg(struct dvb_usb_device *d, u8 addr, u8 id; int ret; + if (snd_len > 64 - 7 || rcv_len > 64 - 7) + return -EINVAL; + buf = kmalloc(64, GFP_KERNEL); if (!buf) return -ENOMEM; id = state->c++; - ret = -EINVAL; - if (snd_len > 64 - 7 || rcv_len > 64 - 7) - goto failed; - buf[0] = SYNC_BYTE_OUT; buf[1] = id; buf[2] = PCTV_CMD_I2C; @@ -906,14 +905,14 @@ static struct stb6100_config stb6100_config = { }; -static struct i2c_algorithm pctv452e_i2c_algo = { +static const struct i2c_algorithm pctv452e_i2c_algo = { .master_xfer = pctv452e_i2c_xfer, .functionality = pctv452e_i2c_func }; static int pctv452e_frontend_attach(struct dvb_usb_adapter *a) { - struct usb_device_id *id; + const struct usb_device_id *id; a->fe_adap[0].fe = dvb_attach(stb0899_attach, &stb0899_config, &a->dev->i2c_adap); @@ -959,7 +958,7 @@ enum { TECHNOTREND_CONNECT_S2_3650_CI, }; -static struct usb_device_id pctv452e_usb_table[] = { +static const struct usb_device_id pctv452e_usb_table[] = { DVB_USB_DEV(PINNACLE, PINNACLE_PCTV_452E), DVB_USB_DEV(TECHNOTREND, TECHNOTREND_CONNECT_S2_3600), DVB_USB_DEV(TECHNOTREND, TECHNOTREND_CONNECT_S2_3650_CI), diff --git a/drivers/media/usb/dvb-usb/technisat-usb2.c b/drivers/media/usb/dvb-usb/technisat-usb2.c index df90c6c5f3b9..1e43aab2bc27 100644 --- a/drivers/media/usb/dvb-usb/technisat-usb2.c +++ b/drivers/media/usb/dvb-usb/technisat-usb2.c @@ -199,7 +199,7 @@ static u32 technisat_usb2_i2c_func(struct i2c_adapter *adapter) return I2C_FUNC_I2C; } -static struct i2c_algorithm technisat_usb2_i2c_algo = { +static const struct i2c_algorithm technisat_usb2_i2c_algo = { .master_xfer = technisat_usb2_i2c_xfer, .functionality = technisat_usb2_i2c_func, }; @@ -693,7 +693,7 @@ enum { TECHNISAT_USB2_DVB_S2, }; -static struct usb_device_id technisat_usb2_id_table[] = { +static const struct usb_device_id technisat_usb2_id_table[] = { DVB_USB_DEV(TECHNISAT, TECHNISAT_USB2_DVB_S2), { } }; diff --git a/drivers/media/usb/dvb-usb/ttusb2.c b/drivers/media/usb/dvb-usb/ttusb2.c index 373ffa7f641e..acde6149d278 100644 --- a/drivers/media/usb/dvb-usb/ttusb2.c +++ b/drivers/media/usb/dvb-usb/ttusb2.c @@ -434,7 +434,7 @@ static u32 ttusb2_i2c_func(struct i2c_adapter *adapter) return I2C_FUNC_I2C; } -static struct i2c_algorithm ttusb2_i2c_algo = { +static const struct i2c_algorithm ttusb2_i2c_algo = { .master_xfer = ttusb2_i2c_xfer, .functionality = ttusb2_i2c_func, }; @@ -638,7 +638,7 @@ enum { TECHNOTREND_CONNECT_S2400_8KEEPROM, }; -static struct usb_device_id ttusb2_table[] = { +static const struct usb_device_id ttusb2_table[] = { DVB_USB_DEV(PINNACLE, PINNACLE_PCTV_400E), DVB_USB_DEV(PINNACLE, PINNACLE_PCTV_450E), DVB_USB_DEV(TECHNOTREND, TECHNOTREND_CONNECT_S2400), diff --git a/drivers/media/usb/dvb-usb/umt-010.c b/drivers/media/usb/dvb-usb/umt-010.c index 464699b0b75b..8f23f92946d4 100644 --- a/drivers/media/usb/dvb-usb/umt-010.c +++ b/drivers/media/usb/dvb-usb/umt-010.c @@ -86,7 +86,7 @@ enum { HANFTEK_UMT_010_WARM, }; -static struct usb_device_id umt_table[] = { +static const struct usb_device_id umt_table[] = { DVB_USB_DEV(HANFTEK, HANFTEK_UMT_010_COLD), DVB_USB_DEV(HANFTEK, HANFTEK_UMT_010_WARM), { } diff --git a/drivers/media/usb/dvb-usb/vp702x.c b/drivers/media/usb/dvb-usb/vp702x.c index 5b6740cbd1d1..034b0652b9a1 100644 --- a/drivers/media/usb/dvb-usb/vp702x.c +++ b/drivers/media/usb/dvb-usb/vp702x.c @@ -375,7 +375,7 @@ enum { VISIONPLUS_VP7020_WARM, }; -static struct usb_device_id vp702x_usb_table[] = { +static const struct usb_device_id vp702x_usb_table[] = { DVB_USB_DEV(VISIONPLUS, VISIONPLUS_VP7021_COLD), // DVB_USB_DEV(VISIONPLUS, VISIONPLUS_VP7020_COLD), // DVB_USB_DEV(VISIONPLUS, VISIONPLUS_VP7020_WARM), diff --git a/drivers/media/usb/dvb-usb/vp7045.c b/drivers/media/usb/dvb-usb/vp7045.c index 1dc2b18d44d8..5224c3233f8c 100644 --- a/drivers/media/usb/dvb-usb/vp7045.c +++ b/drivers/media/usb/dvb-usb/vp7045.c @@ -179,7 +179,7 @@ enum { VISIONPLUS_TINYUSB2_WARM, }; -static struct usb_device_id vp7045_usb_table[] = { +static const struct usb_device_id vp7045_usb_table[] = { DVB_USB_DEV(VISIONPLUS, VISIONPLUS_VP7045_COLD), DVB_USB_DEV(VISIONPLUS, VISIONPLUS_VP7045_WARM), DVB_USB_DEV(VISIONPLUS, VISIONPLUS_TINYUSB2_COLD), diff --git a/drivers/media/usb/em28xx/Kconfig b/drivers/media/usb/em28xx/Kconfig index cb61fd6cc6c6..3122d4bdfc59 100644 --- a/drivers/media/usb/em28xx/Kconfig +++ b/drivers/media/usb/em28xx/Kconfig @@ -68,6 +68,7 @@ config VIDEO_EM28XX_DVB select MEDIA_TUNER_XC5000 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT select DVB_MXL692 if MEDIA_SUBDRV_AUTOSELECT + select GPIOLIB_LEGACY if GPIOLIB && DVB_CXD2820R help This adds support for DVB cards based on the Empiatech em28xx chips. diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c index 9fce59979e3b..b94f5c70ab75 100644 --- a/drivers/media/usb/em28xx/em28xx-dvb.c +++ b/drivers/media/usb/em28xx/em28xx-dvb.c @@ -727,7 +727,7 @@ static int em28xx_pctv_290e_set_lna(struct dvb_frontend *fe) struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct em28xx_i2c_bus *i2c_bus = fe->dvb->priv; struct em28xx *dev = i2c_bus->dev; -#ifdef CONFIG_GPIOLIB +#ifdef CONFIG_GPIOLIB_LEGACY struct em28xx_dvb *dvb = dev->dvb; int ret; unsigned long flags; @@ -1705,7 +1705,7 @@ static int em28xx_dvb_init(struct em28xx *dev) goto out_free; } -#ifdef CONFIG_GPIOLIB +#ifdef CONFIG_GPIOLIB_LEGACY /* enable LNA for DVB-T, DVB-T2 and DVB-C */ result = gpio_request_one(dvb->lna_gpio, GPIOF_OUT_INIT_LOW, NULL); diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 66c09bc6d59e..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)); diff --git a/drivers/media/usb/gspca/gspca.c b/drivers/media/usb/gspca/gspca.c index 25edd2189654..3fc15d16df8e 100644 --- a/drivers/media/usb/gspca/gspca.c +++ b/drivers/media/usb/gspca/gspca.c @@ -1029,15 +1029,15 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, return 0; } -static int vidioc_g_fmt_vid_cap(struct file *file, void *_priv, +static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *fmt) { struct gspca_dev *gspca_dev = video_drvdata(file); - u32 priv = fmt->fmt.pix.priv; + u32 fmt_priv = fmt->fmt.pix.priv; fmt->fmt.pix = gspca_dev->pixfmt; /* some drivers use priv internally, so keep the original value */ - fmt->fmt.pix.priv = priv; + fmt->fmt.pix.priv = fmt_priv; return 0; } @@ -1075,24 +1075,24 @@ static int try_fmt_vid_cap(struct gspca_dev *gspca_dev, return mode; /* used when s_fmt */ } -static int vidioc_try_fmt_vid_cap(struct file *file, void *_priv, +static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *fmt) { struct gspca_dev *gspca_dev = video_drvdata(file); - u32 priv = fmt->fmt.pix.priv; + u32 fmt_priv = fmt->fmt.pix.priv; if (try_fmt_vid_cap(gspca_dev, fmt) < 0) return -EINVAL; /* some drivers use priv internally, so keep the original value */ - fmt->fmt.pix.priv = priv; + fmt->fmt.pix.priv = fmt_priv; return 0; } -static int vidioc_s_fmt_vid_cap(struct file *file, void *_priv, +static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *fmt) { struct gspca_dev *gspca_dev = video_drvdata(file); - u32 priv = fmt->fmt.pix.priv; + u32 fmt_priv = fmt->fmt.pix.priv; int mode; if (vb2_is_busy(&gspca_dev->queue)) @@ -1109,7 +1109,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *_priv, else gspca_dev->pixfmt = gspca_dev->cam.cam_mode[mode]; /* some drivers use priv internally, so keep the original value */ - fmt->fmt.pix.priv = priv; + fmt->fmt.pix.priv = fmt_priv; return 0; } diff --git a/drivers/media/usb/gspca/stv06xx/stv06xx_hdcs.c b/drivers/media/usb/gspca/stv06xx/stv06xx_hdcs.c index 5a47dcbf1c8e..303b055fefea 100644 --- a/drivers/media/usb/gspca/stv06xx/stv06xx_hdcs.c +++ b/drivers/media/usb/gspca/stv06xx/stv06xx_hdcs.c @@ -520,12 +520,13 @@ static int hdcs_init(struct sd *sd) static int hdcs_dump(struct sd *sd) { u16 reg, val; + int err = 0; pr_info("Dumping sensor registers:\n"); - for (reg = HDCS_IDENT; reg <= HDCS_ROWEXPH; reg++) { - stv06xx_read_sensor(sd, reg, &val); + for (reg = HDCS_IDENT; reg <= HDCS_ROWEXPH && !err; reg++) { + err = stv06xx_read_sensor(sd, reg, &val); pr_info("reg 0x%02x = 0x%02x\n", reg, val); } - return 0; + return (err < 0) ? err : 0; } diff --git a/drivers/media/usb/gspca/vicam.c b/drivers/media/usb/gspca/vicam.c index d98343fd33fe..91e177aa8136 100644 --- a/drivers/media/usb/gspca/vicam.c +++ b/drivers/media/usb/gspca/vicam.c @@ -227,6 +227,7 @@ static int sd_init(struct gspca_dev *gspca_dev) const struct ihex_binrec *rec; const struct firmware *fw; u8 *firmware_buf; + int len; ret = request_ihex_firmware(&fw, VICAM_FIRMWARE, &gspca_dev->dev->dev); @@ -241,9 +242,14 @@ static int sd_init(struct gspca_dev *gspca_dev) goto exit; } for (rec = (void *)fw->data; rec; rec = ihex_next_binrec(rec)) { - memcpy(firmware_buf, rec->data, be16_to_cpu(rec->len)); + len = be16_to_cpu(rec->len); + if (len > PAGE_SIZE) { + ret = -EINVAL; + break; + } + memcpy(firmware_buf, rec->data, len); ret = vicam_control_msg(gspca_dev, 0xff, 0, 0, firmware_buf, - be16_to_cpu(rec->len)); + len); if (ret < 0) break; } diff --git a/drivers/media/usb/hdpvr/hdpvr-i2c.c b/drivers/media/usb/hdpvr/hdpvr-i2c.c index 070559b01b01..9eacc85e3f11 100644 --- a/drivers/media/usb/hdpvr/hdpvr-i2c.c +++ b/drivers/media/usb/hdpvr/hdpvr-i2c.c @@ -124,32 +124,12 @@ static int hdpvr_transfer(struct i2c_adapter *i2c_adapter, struct i2c_msg *msgs, else retval = hdpvr_i2c_write(dev, 1, addr, msgs[0].buf, msgs[0].len); - } else if (num == 2) { - if (msgs[0].addr != msgs[1].addr) { - v4l2_warn(&dev->v4l2_dev, "refusing 2-phase i2c xfer with conflicting target addresses\n"); - retval = -EINVAL; - goto out; - } - - if ((msgs[0].flags & I2C_M_RD) || !(msgs[1].flags & I2C_M_RD)) { - v4l2_warn(&dev->v4l2_dev, "refusing complex xfer with r0=%d, r1=%d\n", - msgs[0].flags & I2C_M_RD, - msgs[1].flags & I2C_M_RD); - retval = -EINVAL; - goto out; - } - - /* - * Write followed by atomic read is the only complex xfer that - * we actually support here. - */ + } else { + /* do write-then-read */ retval = hdpvr_i2c_read(dev, 1, addr, msgs[0].buf, msgs[0].len, msgs[1].buf, msgs[1].len); - } else { - v4l2_warn(&dev->v4l2_dev, "refusing %d-phase i2c xfer\n", num); } -out: mutex_unlock(&dev->i2c_mutex); return retval ? retval : num; @@ -165,10 +145,16 @@ static const struct i2c_algorithm hdpvr_algo = { .functionality = hdpvr_functionality, }; +/* prevent invalid 0-length usb_control_msg and support only write-then-read */ +static const struct i2c_adapter_quirks hdpvr_quirks = { + .flags = I2C_AQ_NO_ZERO_LEN_READ | I2C_AQ_COMB_WRITE_THEN_READ, +}; + static const struct i2c_adapter hdpvr_i2c_adapter_template = { .name = "Hauppauge HD PVR I2C", .owner = THIS_MODULE, .algo = &hdpvr_algo, + .quirks = &hdpvr_quirks, }; static int hdpvr_activate_ir(struct hdpvr_device *dev) diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c index fd7d2a9d0449..8c7ae362d992 100644 --- a/drivers/media/usb/hdpvr/hdpvr-video.c +++ b/drivers/media/usb/hdpvr/hdpvr-video.c @@ -52,6 +52,11 @@ struct hdpvr_fh { bool legacy_mode; }; +static inline struct hdpvr_fh *file_to_hdpvr_fh(struct file *file) +{ + return container_of(file_to_v4l2_fh(file), struct hdpvr_fh, fh); +} + static uint list_size(struct list_head *list) { struct list_head *tmp; @@ -380,8 +385,7 @@ static int hdpvr_open(struct file *file) return -ENOMEM; fh->legacy_mode = true; v4l2_fh_init(&fh->fh, video_devdata(file)); - v4l2_fh_add(&fh->fh); - file->private_data = fh; + v4l2_fh_add(&fh->fh, file); return 0; } @@ -390,7 +394,7 @@ static int hdpvr_release(struct file *file) struct hdpvr_device *dev = video_drvdata(file); mutex_lock(&dev->io_mutex); - if (file->private_data == dev->owner) { + if (file_to_v4l2_fh(file) == dev->owner) { hdpvr_stop_streaming(dev); dev->owner = NULL; } @@ -426,7 +430,7 @@ static ssize_t hdpvr_read(struct file *file, char __user *buffer, size_t count, mutex_unlock(&dev->io_mutex); goto err; } - dev->owner = file->private_data; + dev->owner = file_to_v4l2_fh(file); print_buffer_status(); } mutex_unlock(&dev->io_mutex); @@ -541,7 +545,7 @@ static __poll_t hdpvr_poll(struct file *filp, poll_table *wait) "start_streaming failed\n"); dev->status = STATUS_IDLE; } else { - dev->owner = filp->private_data; + dev->owner = file_to_v4l2_fh(filp); } print_buffer_status(); @@ -586,11 +590,11 @@ static int vidioc_querycap(struct file *file, void *priv, return 0; } -static int vidioc_s_std(struct file *file, void *_fh, +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id std) { struct hdpvr_device *dev = video_drvdata(file); - struct hdpvr_fh *fh = _fh; + struct hdpvr_fh *fh = file_to_hdpvr_fh(file); u8 std_type = 1; if (!fh->legacy_mode && dev->options.video_input == HDPVR_COMPONENT) @@ -606,11 +610,12 @@ static int vidioc_s_std(struct file *file, void *_fh, return hdpvr_config_call(dev, CTRL_VIDEO_STD_TYPE, std_type); } -static int vidioc_g_std(struct file *file, void *_fh, +static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *std) { struct hdpvr_device *dev = video_drvdata(file); - struct hdpvr_fh *fh = _fh; + struct hdpvr_fh *fh = file_to_hdpvr_fh(file); + if (!fh->legacy_mode && dev->options.video_input == HDPVR_COMPONENT) return -ENODATA; @@ -618,11 +623,11 @@ static int vidioc_g_std(struct file *file, void *_fh, return 0; } -static int vidioc_querystd(struct file *file, void *_fh, v4l2_std_id *a) +static int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *a) { struct hdpvr_device *dev = video_drvdata(file); + struct hdpvr_fh *fh = file_to_hdpvr_fh(file); struct hdpvr_video_info vid_info; - struct hdpvr_fh *fh = _fh; int ret; *a = V4L2_STD_UNKNOWN; @@ -637,11 +642,11 @@ static int vidioc_querystd(struct file *file, void *_fh, v4l2_std_id *a) return ret; } -static int vidioc_s_dv_timings(struct file *file, void *_fh, +static int vidioc_s_dv_timings(struct file *file, void *priv, struct v4l2_dv_timings *timings) { struct hdpvr_device *dev = video_drvdata(file); - struct hdpvr_fh *fh = _fh; + struct hdpvr_fh *fh = file_to_hdpvr_fh(file); int i; fh->legacy_mode = false; @@ -660,11 +665,11 @@ static int vidioc_s_dv_timings(struct file *file, void *_fh, return 0; } -static int vidioc_g_dv_timings(struct file *file, void *_fh, +static int vidioc_g_dv_timings(struct file *file, void *priv, struct v4l2_dv_timings *timings) { struct hdpvr_device *dev = video_drvdata(file); - struct hdpvr_fh *fh = _fh; + struct hdpvr_fh *fh = file_to_hdpvr_fh(file); fh->legacy_mode = false; if (dev->options.video_input) @@ -673,11 +678,11 @@ static int vidioc_g_dv_timings(struct file *file, void *_fh, return 0; } -static int vidioc_query_dv_timings(struct file *file, void *_fh, +static int vidioc_query_dv_timings(struct file *file, void *priv, struct v4l2_dv_timings *timings) { struct hdpvr_device *dev = video_drvdata(file); - struct hdpvr_fh *fh = _fh; + struct hdpvr_fh *fh = file_to_hdpvr_fh(file); struct hdpvr_video_info vid_info; bool interlaced; int ret = 0; @@ -715,11 +720,11 @@ static int vidioc_query_dv_timings(struct file *file, void *_fh, return ret; } -static int vidioc_enum_dv_timings(struct file *file, void *_fh, +static int vidioc_enum_dv_timings(struct file *file, void *priv, struct v4l2_enum_dv_timings *timings) { struct hdpvr_device *dev = video_drvdata(file); - struct hdpvr_fh *fh = _fh; + struct hdpvr_fh *fh = file_to_hdpvr_fh(file); fh->legacy_mode = false; memset(timings->reserved, 0, sizeof(timings->reserved)); @@ -731,11 +736,11 @@ static int vidioc_enum_dv_timings(struct file *file, void *_fh, return 0; } -static int vidioc_dv_timings_cap(struct file *file, void *_fh, +static int vidioc_dv_timings_cap(struct file *file, void *priv, struct v4l2_dv_timings_cap *cap) { struct hdpvr_device *dev = video_drvdata(file); - struct hdpvr_fh *fh = _fh; + struct hdpvr_fh *fh = file_to_hdpvr_fh(file); fh->legacy_mode = false; if (dev->options.video_input) @@ -758,7 +763,7 @@ static const char *iname[] = { [HDPVR_COMPOSITE] = "Composite", }; -static int vidioc_enum_input(struct file *file, void *_fh, struct v4l2_input *i) +static int vidioc_enum_input(struct file *file, void *priv, struct v4l2_input *i) { unsigned int n; @@ -778,7 +783,7 @@ static int vidioc_enum_input(struct file *file, void *_fh, struct v4l2_input *i) return 0; } -static int vidioc_s_input(struct file *file, void *_fh, +static int vidioc_s_input(struct file *file, void *priv, unsigned int index) { struct hdpvr_device *dev = video_drvdata(file); @@ -812,7 +817,7 @@ static int vidioc_s_input(struct file *file, void *_fh, return retval; } -static int vidioc_g_input(struct file *file, void *private_data, +static int vidioc_g_input(struct file *file, void *priv, unsigned int *index) { struct hdpvr_device *dev = video_drvdata(file); @@ -844,7 +849,7 @@ static int vidioc_enumaudio(struct file *file, void *priv, return 0; } -static int vidioc_s_audio(struct file *file, void *private_data, +static int vidioc_s_audio(struct file *file, void *priv, const struct v4l2_audio *audio) { struct hdpvr_device *dev = video_drvdata(file); @@ -863,7 +868,7 @@ static int vidioc_s_audio(struct file *file, void *private_data, return retval; } -static int vidioc_g_audio(struct file *file, void *private_data, +static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *audio) { struct hdpvr_device *dev = video_drvdata(file); @@ -980,7 +985,7 @@ static int hdpvr_s_ctrl(struct v4l2_ctrl *ctrl) return ret; } -static int vidioc_enum_fmt_vid_cap(struct file *file, void *private_data, +static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { if (f->index != 0) @@ -991,11 +996,11 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *private_data, return 0; } -static int vidioc_g_fmt_vid_cap(struct file *file, void *_fh, +static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct hdpvr_device *dev = video_drvdata(file); - struct hdpvr_fh *fh = _fh; + struct hdpvr_fh *fh = file_to_hdpvr_fh(file); int ret; /* @@ -1048,7 +1053,7 @@ static int vidioc_encoder_cmd(struct file *filp, void *priv, switch (a->cmd) { case V4L2_ENC_CMD_START: - if (dev->owner && filp->private_data != dev->owner) { + if (dev->owner && file_to_v4l2_fh(filp) != dev->owner) { res = -EBUSY; break; } @@ -1056,12 +1061,12 @@ static int vidioc_encoder_cmd(struct file *filp, void *priv, break; res = hdpvr_start_streaming(dev); if (!res) - dev->owner = filp->private_data; + dev->owner = file_to_v4l2_fh(filp); else dev->status = STATUS_IDLE; break; case V4L2_ENC_CMD_STOP: - if (dev->owner && filp->private_data != dev->owner) { + if (dev->owner && file_to_v4l2_fh(filp) != dev->owner) { res = -EBUSY; break; } diff --git a/drivers/media/usb/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..b32bb906a9de 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c @@ -1527,7 +1527,7 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw) /* Encoder is about to be reset so note that as far as we're concerned now, the encoder has never been run. */ - del_timer_sync(&hdw->encoder_run_timer); + timer_delete_sync(&hdw->encoder_run_timer); if (hdw->state_encoder_runok) { hdw->state_encoder_runok = 0; trace_stbit("state_encoder_runok",hdw->state_encoder_runok); @@ -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) { @@ -3622,7 +3622,7 @@ static int pvr2_send_request_ex(struct pvr2_hdw *hdw, pvr2_trace( PVR2_TRACE_ERROR_LEGS, "Attempted to execute %d byte control-read transfer (limit=%d)", - write_len,PVR2_CTL_BUFFSIZE); + read_len, PVR2_CTL_BUFFSIZE); return -EINVAL; } if ((!write_len) && (!read_len)) { @@ -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-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..f9535a484738 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c @@ -21,8 +21,6 @@ #include <media/v4l2-common.h> #include <media/v4l2-ioctl.h> -struct pvr2_v4l2_dev; -struct pvr2_v4l2_fh; struct pvr2_v4l2; struct pvr2_v4l2_dev { @@ -48,6 +46,11 @@ struct pvr2_v4l2_fh { unsigned int input_cnt; }; +static inline struct pvr2_v4l2_fh *to_pvr2_v4l2_fh(struct file *filp) +{ + return container_of(file_to_v4l2_fh(filp), struct pvr2_v4l2_fh, fh); +} + struct pvr2_v4l2 { struct pvr2_channel channel; @@ -108,7 +111,7 @@ static struct v4l2_format pvr_format [] = { */ static int pvr2_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; strscpy(cap->driver, "pvrusb2", sizeof(cap->driver)); @@ -123,7 +126,7 @@ static int pvr2_querycap(struct file *file, void *priv, struct v4l2_capability * static int pvr2_g_std(struct file *file, void *priv, v4l2_std_id *std) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; int val = 0; int ret; @@ -136,7 +139,7 @@ static int pvr2_g_std(struct file *file, void *priv, v4l2_std_id *std) static int pvr2_s_std(struct file *file, void *priv, v4l2_std_id std) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; int ret; @@ -148,7 +151,7 @@ static int pvr2_s_std(struct file *file, void *priv, v4l2_std_id std) static int pvr2_querystd(struct file *file, void *priv, v4l2_std_id *std) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; int val = 0; int ret; @@ -161,7 +164,7 @@ static int pvr2_querystd(struct file *file, void *priv, v4l2_std_id *std) static int pvr2_enum_input(struct file *file, void *priv, struct v4l2_input *vi) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; struct pvr2_ctrl *cptr; struct v4l2_input tmp; @@ -209,7 +212,7 @@ static int pvr2_enum_input(struct file *file, void *priv, struct v4l2_input *vi) static int pvr2_g_input(struct file *file, void *priv, unsigned int *i) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; unsigned int idx; struct pvr2_ctrl *cptr; @@ -231,7 +234,7 @@ static int pvr2_g_input(struct file *file, void *priv, unsigned int *i) static int pvr2_s_input(struct file *file, void *priv, unsigned int inp) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; int ret; @@ -286,7 +289,7 @@ static int pvr2_s_audio(struct file *file, void *priv, const struct v4l2_audio * static int pvr2_g_tuner(struct file *file, void *priv, struct v4l2_tuner *vt) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; if (vt->index != 0) @@ -298,7 +301,7 @@ static int pvr2_g_tuner(struct file *file, void *priv, struct v4l2_tuner *vt) static int pvr2_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *vt) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; int ret; @@ -314,7 +317,7 @@ static int pvr2_s_tuner(struct file *file, void *priv, const struct v4l2_tuner * static int pvr2_s_frequency(struct file *file, void *priv, const struct v4l2_frequency *vf) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; unsigned long fv; struct v4l2_tuner vt; @@ -349,7 +352,7 @@ static int pvr2_s_frequency(struct file *file, void *priv, const struct v4l2_fre static int pvr2_g_frequency(struct file *file, void *priv, struct v4l2_frequency *vf) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; int val = 0; int cur_input; @@ -391,7 +394,7 @@ static int pvr2_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtd static int pvr2_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *vf) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; int val; @@ -411,7 +414,7 @@ static int pvr2_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format static int pvr2_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *vf) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; int lmin, lmax, ldef; struct pvr2_ctrl *hcp, *vcp; @@ -449,7 +452,7 @@ static int pvr2_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_forma static int pvr2_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *vf) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; struct pvr2_ctrl *hcp, *vcp; int ret = pvr2_try_fmt_vid_cap(file, fh, vf); @@ -466,7 +469,7 @@ static int pvr2_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format static int pvr2_streamon(struct file *file, void *priv, enum v4l2_buf_type i) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; struct pvr2_v4l2_dev *pdi = fh->pdi; int ret; @@ -485,7 +488,7 @@ static int pvr2_streamon(struct file *file, void *priv, enum v4l2_buf_type i) static int pvr2_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; if (!fh->pdi->stream) { @@ -497,10 +500,10 @@ static int pvr2_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) return pvr2_hdw_set_streaming(hdw, 0); } -static int pvr2_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *vc) +static int pvr2_query_ext_ctrl(struct file *file, void *priv, + struct v4l2_query_ext_ctrl *vc) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; struct pvr2_ctrl *cptr; int val; @@ -521,13 +524,16 @@ static int pvr2_queryctrl(struct file *file, void *priv, } pvr2_trace(PVR2_TRACE_V4LIOCTL, - "QUERYCTRL id=0x%x mapping name=%s (%s)", + "QUERYEXTCTRL id=0x%x mapping name=%s (%s)", vc->id, pvr2_ctrl_get_name(cptr), pvr2_ctrl_get_desc(cptr)); strscpy(vc->name, pvr2_ctrl_get_desc(cptr), sizeof(vc->name)); vc->flags = pvr2_ctrl_get_v4lflags(cptr); pvr2_ctrl_get_def(cptr, &val); vc->default_value = val; + vc->nr_of_dims = 0; + vc->elems = 1; + vc->elem_size = 4; switch (pvr2_ctrl_get_type(cptr)) { case pvr2_ctl_enum: vc->type = V4L2_CTRL_TYPE_MENU; @@ -549,7 +555,7 @@ static int pvr2_queryctrl(struct file *file, void *priv, break; default: pvr2_trace(PVR2_TRACE_V4LIOCTL, - "QUERYCTRL id=0x%x name=%s not mappable", + "QUERYEXTCTRL id=0x%x name=%s not mappable", vc->id, pvr2_ctrl_get_name(cptr)); return -EINVAL; } @@ -558,7 +564,7 @@ static int pvr2_queryctrl(struct file *file, void *priv, static int pvr2_querymenu(struct file *file, void *priv, struct v4l2_querymenu *vm) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; unsigned int cnt = 0; int ret; @@ -571,35 +577,10 @@ static int pvr2_querymenu(struct file *file, void *priv, struct v4l2_querymenu * return ret; } -static int pvr2_g_ctrl(struct file *file, void *priv, struct v4l2_control *vc) -{ - struct pvr2_v4l2_fh *fh = file->private_data; - struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; - int val = 0; - int ret; - - ret = pvr2_ctrl_get_value(pvr2_hdw_get_ctrl_v4l(hdw, vc->id), - &val); - vc->value = val; - return ret; -} - -static int pvr2_s_ctrl(struct file *file, void *priv, struct v4l2_control *vc) -{ - struct pvr2_v4l2_fh *fh = file->private_data; - struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; - int ret; - - ret = pvr2_ctrl_set_value(pvr2_hdw_get_ctrl_v4l(hdw, vc->id), - vc->value); - pvr2_hdw_commit_ctl(hdw); - return ret; -} - static int pvr2_g_ext_ctrls(struct file *file, void *priv, struct v4l2_ext_controls *ctls) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; struct v4l2_ext_control *ctrl; struct pvr2_ctrl *cptr; @@ -634,7 +615,7 @@ static int pvr2_g_ext_ctrls(struct file *file, void *priv, static int pvr2_s_ext_ctrls(struct file *file, void *priv, struct v4l2_ext_controls *ctls) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; struct v4l2_ext_control *ctrl; unsigned int idx; @@ -659,7 +640,7 @@ commit: static int pvr2_try_ext_ctrls(struct file *file, void *priv, struct v4l2_ext_controls *ctls) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; struct v4l2_ext_control *ctrl; struct pvr2_ctrl *pctl; @@ -681,7 +662,7 @@ static int pvr2_try_ext_ctrls(struct file *file, void *priv, static int pvr2_g_pixelaspect(struct file *file, void *priv, int type, struct v4l2_fract *f) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; struct v4l2_cropcap cap = { .type = type }; int ret; @@ -697,7 +678,7 @@ static int pvr2_g_pixelaspect(struct file *file, void *priv, static int pvr2_g_selection(struct file *file, void *priv, struct v4l2_selection *sel) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; struct v4l2_cropcap cap; int val = 0; @@ -748,7 +729,7 @@ static int pvr2_g_selection(struct file *file, void *priv, static int pvr2_s_selection(struct file *file, void *priv, struct v4l2_selection *sel) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; int ret; @@ -780,7 +761,7 @@ commit: static int pvr2_log_status(struct file *file, void *priv) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; pvr2_hdw_trigger_module_log(hdw); @@ -812,10 +793,8 @@ static const struct v4l2_ioctl_ops pvr2_ioctl_ops = { .vidioc_try_fmt_vid_cap = pvr2_try_fmt_vid_cap, .vidioc_streamon = pvr2_streamon, .vidioc_streamoff = pvr2_streamoff, - .vidioc_queryctrl = pvr2_queryctrl, + .vidioc_query_ext_ctrl = pvr2_query_ext_ctrl, .vidioc_querymenu = pvr2_querymenu, - .vidioc_g_ctrl = pvr2_g_ctrl, - .vidioc_s_ctrl = pvr2_s_ctrl, .vidioc_g_ext_ctrls = pvr2_g_ext_ctrls, .vidioc_s_ext_ctrls = pvr2_s_ext_ctrls, .vidioc_try_ext_ctrls = pvr2_try_ext_ctrls, @@ -906,7 +885,7 @@ static void pvr2_v4l2_internal_check(struct pvr2_channel *chp) static int pvr2_v4l2_release(struct file *file) { - struct pvr2_v4l2_fh *fhp = file->private_data; + struct pvr2_v4l2_fh *fhp = to_pvr2_v4l2_fh(file); struct pvr2_v4l2 *vp = fhp->pdi->v4lp; struct pvr2_hdw *hdw = fhp->channel.mc_head->hdw; @@ -921,9 +900,8 @@ static int pvr2_v4l2_release(struct file *file) fhp->rhp = NULL; } - v4l2_fh_del(&fhp->fh); + v4l2_fh_del(&fhp->fh, file); v4l2_fh_exit(&fhp->fh); - file->private_data = NULL; pvr2_channel_done(&fhp->channel); pvr2_trace(PVR2_TRACE_STRUCT, @@ -1024,10 +1002,9 @@ static int pvr2_v4l2_open(struct file *file) } fhp->file = file; - file->private_data = fhp; fhp->fw_mode_flag = pvr2_hdw_cpufw_get_enabled(hdw); - v4l2_fh_add(&fhp->fh); + v4l2_fh_add(&fhp->fh, file); return 0; } @@ -1079,7 +1056,7 @@ static int pvr2_v4l2_iosetup(struct pvr2_v4l2_fh *fh) static ssize_t pvr2_v4l2_read(struct file *file, char __user *buff, size_t count, loff_t *ppos) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); int ret; if (fh->fw_mode_flag) { @@ -1141,7 +1118,7 @@ static ssize_t pvr2_v4l2_read(struct file *file, static __poll_t pvr2_v4l2_poll(struct file *file, poll_table *wait) { __poll_t mask = 0; - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); int ret; if (fh->fw_mode_flag) { diff --git a/drivers/media/usb/pwc/pwc-if.c b/drivers/media/usb/pwc/pwc-if.c index 3ec9eb5956ed..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" diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c index 899a7a67e2ba..8332f2c5aed7 100644 --- a/drivers/media/usb/s2255/s2255drv.c +++ b/drivers/media/usb/s2255/s2255drv.c @@ -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"); diff --git a/drivers/media/usb/stk1160/stk1160-core.c b/drivers/media/usb/stk1160/stk1160-core.c index ce717502ea4c..25d725c2ab3c 100644 --- a/drivers/media/usb/stk1160/stk1160-core.c +++ b/drivers/media/usb/stk1160/stk1160-core.c @@ -195,8 +195,7 @@ static int stk1160_scan_usb(struct usb_interface *intf, struct usb_device *udev, if (udev->speed == USB_SPEED_HIGH) size = size * hb_mult(sizedescr); - if (usb_endpoint_xfer_isoc(desc) && - usb_endpoint_dir_in(desc)) { + if (usb_endpoint_is_isoc_in(desc)) { switch (desc->bEndpointAddress) { case STK1160_EP_AUDIO: has_audio = true; diff --git a/drivers/media/usb/stk1160/stk1160-v4l.c b/drivers/media/usb/stk1160/stk1160-v4l.c index 5ba3d9c4b3fb..715ce1dcb304 100644 --- a/drivers/media/usb/stk1160/stk1160-v4l.c +++ b/drivers/media/usb/stk1160/stk1160-v4l.c @@ -232,10 +232,6 @@ static int stk1160_start_streaming(struct stk1160 *dev) /* submit urbs and enables IRQ */ for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { - struct stk1160_urb *stk_urb = &dev->isoc_ctl.urb_ctl[i]; - - dma_sync_sgtable_for_device(stk1160_get_dmadev(dev), stk_urb->sgt, - DMA_FROM_DEVICE); rc = usb_submit_urb(dev->isoc_ctl.urb_ctl[i].urb, GFP_KERNEL); if (rc) { stk1160_err("cannot submit urb[%d] (%d)\n", i, rc); diff --git a/drivers/media/usb/stk1160/stk1160-video.c b/drivers/media/usb/stk1160/stk1160-video.c index 9cbd957ecc90..f4baf9263286 100644 --- a/drivers/media/usb/stk1160/stk1160-video.c +++ b/drivers/media/usb/stk1160/stk1160-video.c @@ -298,9 +298,7 @@ static void stk1160_process_isoc(struct stk1160 *dev, struct urb *urb) static void stk1160_isoc_irq(struct urb *urb) { int i, rc; - struct stk1160_urb *stk_urb = urb->context; - struct stk1160 *dev = stk_urb->dev; - struct device *dma_dev = stk1160_get_dmadev(dev); + struct stk1160 *dev = urb->context; switch (urb->status) { case 0: @@ -315,10 +313,6 @@ static void stk1160_isoc_irq(struct urb *urb) return; } - invalidate_kernel_vmap_range(stk_urb->transfer_buffer, - urb->transfer_buffer_length); - dma_sync_sgtable_for_cpu(dma_dev, stk_urb->sgt, DMA_FROM_DEVICE); - stk1160_process_isoc(dev, urb); /* Reset urb buffers */ @@ -327,7 +321,6 @@ static void stk1160_isoc_irq(struct urb *urb) urb->iso_frame_desc[i].actual_length = 0; } - dma_sync_sgtable_for_device(dma_dev, stk_urb->sgt, DMA_FROM_DEVICE); rc = usb_submit_urb(urb, GFP_ATOMIC); if (rc) stk1160_err("urb re-submit failed (%d)\n", rc); @@ -365,11 +358,9 @@ void stk1160_cancel_isoc(struct stk1160 *dev) static void stk_free_urb(struct stk1160 *dev, struct stk1160_urb *stk_urb) { - struct device *dma_dev = stk1160_get_dmadev(dev); - - dma_vunmap_noncontiguous(dma_dev, stk_urb->transfer_buffer); - dma_free_noncontiguous(dma_dev, stk_urb->urb->transfer_buffer_length, - stk_urb->sgt, DMA_FROM_DEVICE); + usb_free_noncoherent(dev->udev, stk_urb->urb->transfer_buffer_length, + stk_urb->transfer_buffer, DMA_FROM_DEVICE, + stk_urb->sgt); usb_free_urb(stk_urb->urb); stk_urb->transfer_buffer = NULL; @@ -410,32 +401,24 @@ void stk1160_uninit_isoc(struct stk1160 *dev) static int stk1160_fill_urb(struct stk1160 *dev, struct stk1160_urb *stk_urb, int sb_size, int max_packets) { - struct device *dma_dev = stk1160_get_dmadev(dev); - stk_urb->urb = usb_alloc_urb(max_packets, GFP_KERNEL); if (!stk_urb->urb) return -ENOMEM; - stk_urb->sgt = dma_alloc_noncontiguous(dma_dev, sb_size, - DMA_FROM_DEVICE, GFP_KERNEL, 0); - /* - * If the buffer allocation failed, we exit but return 0 since - * we allow the driver working with less buffers - */ - if (!stk_urb->sgt) + stk_urb->transfer_buffer = usb_alloc_noncoherent(dev->udev, sb_size, + GFP_KERNEL, &stk_urb->dma, + DMA_FROM_DEVICE, &stk_urb->sgt); + if (!stk_urb->transfer_buffer) { + /* + * If the buffer allocation failed, we exit but return 0 since + * we allow the driver working with less buffers. + */ goto free_urb; + } - stk_urb->transfer_buffer = dma_vmap_noncontiguous(dma_dev, sb_size, - stk_urb->sgt); - if (!stk_urb->transfer_buffer) - goto free_sgt; - - stk_urb->dma = stk_urb->sgt->sgl->dma_address; stk_urb->dev = dev; return 0; -free_sgt: - dma_free_noncontiguous(dma_dev, sb_size, stk_urb->sgt, DMA_FROM_DEVICE); - stk_urb->sgt = NULL; + free_urb: usb_free_urb(stk_urb->urb); stk_urb->urb = NULL; @@ -494,12 +477,13 @@ int stk1160_alloc_isoc(struct stk1160 *dev) urb->transfer_buffer = dev->isoc_ctl.urb_ctl[i].transfer_buffer; urb->transfer_buffer_length = sb_size; urb->complete = stk1160_isoc_irq; - urb->context = &dev->isoc_ctl.urb_ctl[i]; + urb->context = dev; urb->interval = 1; urb->start_frame = 0; urb->number_of_packets = max_packets; urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; urb->transfer_dma = dev->isoc_ctl.urb_ctl[i].dma; + urb->sgt = dev->isoc_ctl.urb_ctl[i].sgt; k = 0; for (j = 0; j < max_packets; j++) { diff --git a/drivers/media/usb/stk1160/stk1160.h b/drivers/media/usb/stk1160/stk1160.h index 7b498d14ed7a..4cbcb0a03bab 100644 --- a/drivers/media/usb/stk1160/stk1160.h +++ b/drivers/media/usb/stk1160/stk1160.h @@ -16,8 +16,6 @@ #include <media/videobuf2-v4l2.h> #include <media/v4l2-device.h> #include <media/v4l2-ctrls.h> -#include <linux/usb.h> -#include <linux/usb/hcd.h> #define STK1160_VERSION "0.9.5" #define STK1160_VERSION_NUM 0x000905 @@ -195,8 +193,3 @@ void stk1160_select_input(struct stk1160 *dev); /* Provided by stk1160-ac97.c */ void stk1160_ac97_setup(struct stk1160 *dev); - -static inline struct device *stk1160_get_dmadev(struct stk1160 *dev) -{ - return bus_to_hcd(dev->udev->bus)->self.sysdev; -} diff --git a/drivers/media/usb/usbtv/usbtv-video.c b/drivers/media/usb/usbtv/usbtv-video.c index be22a9697197..de0328100a60 100644 --- a/drivers/media/usb/usbtv/usbtv-video.c +++ b/drivers/media/usb/usbtv/usbtv-video.c @@ -73,6 +73,10 @@ static int usbtv_configure_for_norm(struct usbtv *usbtv, v4l2_std_id norm) } if (params) { + if (vb2_is_busy(&usbtv->vb2q) && + (usbtv->width != params->cap_width || + usbtv->height != params->cap_height)) + return -EBUSY; usbtv->width = params->cap_width; usbtv->height = params->cap_height; usbtv->n_chunks = usbtv->width * usbtv->height diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c index 4fe26e82e3d1..2905505c240c 100644 --- a/drivers/media/usb/uvc/uvc_ctrl.c +++ b/drivers/media/usb/uvc/uvc_ctrl.c @@ -358,6 +358,33 @@ static const struct uvc_control_info uvc_ctrls[] = { .flags = UVC_CTRL_FLAG_GET_CUR | UVC_CTRL_FLAG_AUTO_UPDATE, }, + /* + * UVC_CTRL_FLAG_AUTO_UPDATE is needed because the RoI may get updated + * by sensors. + * "This RoI should be the same as specified in most recent SET_CUR + * except in the case where the ‘Auto Detect and Track’ and/or + * ‘Image Stabilization’ bit have been set." + * 4.2.2.1.20 Digital Region of Interest (ROI) Control + */ + { + .entity = UVC_GUID_UVC_CAMERA, + .selector = UVC_CT_REGION_OF_INTEREST_CONTROL, + .index = 21, + .size = 10, + .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR + | UVC_CTRL_FLAG_GET_MIN | UVC_CTRL_FLAG_GET_MAX + | UVC_CTRL_FLAG_GET_DEF + | UVC_CTRL_FLAG_AUTO_UPDATE, + }, + { + .entity = UVC_GUID_CHROMEOS_XU, + .selector = UVC_CROSXU_CONTROL_IQ_PROFILE, + .index = 3, + .size = 1, + .flags = UVC_CTRL_FLAG_SET_CUR + | UVC_CTRL_FLAG_GET_RANGE + | UVC_CTRL_FLAG_RESTORE, + }, }; static const u32 uvc_control_classes[] = { @@ -366,6 +393,40 @@ static const u32 uvc_control_classes[] = { }; static const int exposure_auto_mapping[] = { 2, 1, 4, 8 }; +static const int cros_colorfx_mapping[] = { + 1, /* V4L2_COLORFX_NONE */ + -1, /* V4L2_COLORFX_BW */ + -1, /* V4L2_COLORFX_SEPIA */ + -1, /* V4L2_COLORFX_NEGATIVE */ + -1, /* V4L2_COLORFX_EMBOSS */ + -1, /* V4L2_COLORFX_SKETCH */ + -1, /* V4L2_COLORFX_SKY_BLUE */ + -1, /* V4L2_COLORFX_GRASS_GREEN */ + -1, /* V4L2_COLORFX_SKIN_WHITEN */ + 0, /* V4L2_COLORFX_VIVID */ +}; + + +static 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 @@ -405,58 +466,93 @@ 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; - data[first] = value == 0 ? 0 : (value > 0) ? 1 : 0xff; - data[first+1] = min_t(int, abs(value), 0xff); + if (WARN_ON(v4l2_size != sizeof(s32))) + return -EINVAL; + + value = *(u32 *)v4l2_in; + out[first] = value == 0 ? 0 : (value > 0) ? 1 : 0xff; + out[first + 1] = min_t(int, abs(value), 0xff); + + return 0; } static const struct uvc_control_mapping uvc_ctrl_power_line_mapping_limited = { @@ -547,6 +643,44 @@ end: 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[] = { { .id = V4L2_CID_BRIGHTNESS, @@ -841,6 +975,40 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = { .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", + }, + { + .id = V4L2_CID_COLORFX, + .entity = UVC_GUID_CHROMEOS_XU, + .selector = UVC_CROSXU_CONTROL_IQ_PROFILE, + .size = 8, + .offset = 0, + .v4l2_type = V4L2_CTRL_TYPE_MENU, + .data_type = UVC_CTRL_DATA_TYPE_ENUM, + .menu_mapping = cros_colorfx_mapping, + .menu_mask = BIT(V4L2_COLORFX_VIVID) | + BIT(V4L2_COLORFX_NONE), + }, }; /* ------------------------------------------------------------------------ @@ -862,20 +1030,45 @@ static inline void uvc_clear_bit(u8 *data, int bit) data[bit >> 3] &= ~(1 << (bit & 7)); } +static s32 uvc_menu_to_v4l2_menu(struct uvc_control_mapping *mapping, s32 val) +{ + unsigned int i; + + for (i = 0; BIT(i) <= mapping->menu_mask; ++i) { + u32 menu_value; + + if (!test_bit(i, &mapping->menu_mask)) + continue; + + menu_value = uvc_mapping_get_menu_value(mapping, i); + + if (menu_value == val) + return i; + } + + return val; +} + /* * Extract the bit string specified by mapping->offset and mapping->size * from the little-endian data stored at 'data' and return the result as * a signed 32bit integer. Sign extension will be performed if the mapping * references a signed data type. */ -static s32 uvc_get_le_value(struct uvc_control_mapping *mapping, - u8 query, const u8 *data) +static int uvc_get_le_value(struct uvc_control_mapping *mapping, + u8 query, const void *uvc_in, size_t v4l2_size, + void *v4l2_out) { - int bits = mapping->size; int offset = mapping->offset; + int bits = mapping->size; + const u8 *data = uvc_in; + s32 *out = v4l2_out; s32 value = 0; u8 mask; + if (WARN_ON(v4l2_size != sizeof(s32))) + return -EINVAL; + data += offset / 8; offset &= 7; mask = ((1LL << bits) - 1) << offset; @@ -896,28 +1089,58 @@ static s32 uvc_get_le_value(struct uvc_control_mapping *mapping, if (mapping->data_type == UVC_CTRL_DATA_TYPE_SIGNED) value |= -(value & (1 << (mapping->size - 1))); - return value; + /* If it is a menu, convert from uvc to v4l2. */ + if (mapping->v4l2_type != V4L2_CTRL_TYPE_MENU) { + *out = value; + return 0; + } + + switch (query) { + case UVC_GET_CUR: + case UVC_GET_DEF: + *out = uvc_menu_to_v4l2_menu(mapping, value); + return 0; + } + + *out = value; + return 0; } /* * Set the bit string specified by mapping->offset and mapping->size * in the little-endian data stored at 'data' to the value 'value'. */ -static void uvc_set_le_value(struct uvc_control_mapping *mapping, - s32 value, u8 *data) +static int uvc_set_le_value(struct uvc_control_mapping *mapping, + size_t v4l2_size, const void *v4l2_in, + void *uvc_out) { - int bits = mapping->size; int offset = mapping->offset; + int bits = mapping->size; + u8 *data = uvc_out; + s32 value; u8 mask; - /* - * According to the v4l2 spec, writing any value to a button control - * should result in the action belonging to the button control being - * triggered. UVC devices however want to see a 1 written -> override - * value. - */ - if (mapping->v4l2_type == V4L2_CTRL_TYPE_BUTTON) + if (WARN_ON(v4l2_size != sizeof(s32))) + return -EINVAL; + + value = *(s32 *)v4l2_in; + + switch (mapping->v4l2_type) { + case V4L2_CTRL_TYPE_MENU: + value = uvc_mapping_get_menu_value(mapping, value); + break; + case V4L2_CTRL_TYPE_BUTTON: + /* + * According to the v4l2 spec, writing any value to a button + * control should result in the action belonging to the button + * control being triggered. UVC devices however want to see a 1 + * written -> override value. + */ value = -1; + break; + default: + break; + } data += offset / 8; offset &= 7; @@ -929,6 +1152,8 @@ static void uvc_set_le_value(struct uvc_control_mapping *mapping, bits -= 8 - offset; offset = 0; } + + return 0; } /* ------------------------------------------------------------------------ @@ -947,7 +1172,7 @@ static int uvc_entity_match_guid(const struct uvc_entity *entity, static void __uvc_find_control(struct uvc_entity *entity, u32 v4l2_id, struct uvc_control_mapping **mapping, struct uvc_control **control, - int next) + int next, int next_compound) { struct uvc_control *ctrl; struct uvc_control_mapping *map; @@ -962,14 +1187,16 @@ static void __uvc_find_control(struct uvc_entity *entity, u32 v4l2_id, continue; list_for_each_entry(map, &ctrl->info.mappings, list) { - if ((map->id == v4l2_id) && !next) { + if (map->id == v4l2_id && !next && !next_compound) { *control = ctrl; *mapping = map; return; } if ((*mapping == NULL || (*mapping)->id > map->id) && - (map->id > v4l2_id) && next) { + (map->id > v4l2_id) && + (uvc_ctrl_mapping_is_compound(map) ? + next_compound : next)) { *control = ctrl; *mapping = map; } @@ -983,6 +1210,7 @@ static struct uvc_control *uvc_find_control(struct uvc_video_chain *chain, struct uvc_control *ctrl = NULL; struct uvc_entity *entity; int next = v4l2_id & V4L2_CTRL_FLAG_NEXT_CTRL; + int next_compound = v4l2_id & V4L2_CTRL_FLAG_NEXT_COMPOUND; *mapping = NULL; @@ -991,12 +1219,13 @@ static struct uvc_control *uvc_find_control(struct uvc_video_chain *chain, /* Find the control. */ list_for_each_entry(entity, &chain->entities, chain) { - __uvc_find_control(entity, v4l2_id, mapping, &ctrl, next); - if (ctrl && !next) + __uvc_find_control(entity, v4l2_id, mapping, &ctrl, next, + next_compound); + if (ctrl && !next && !next_compound) return ctrl; } - if (ctrl == NULL && !next) + if (!ctrl && !next && !next_compound) uvc_dbg(chain->dev, CONTROL, "Control 0x%08x not found\n", v4l2_id); @@ -1060,32 +1289,6 @@ static int uvc_ctrl_populate_cache(struct uvc_video_chain *chain, return 0; } -static s32 __uvc_ctrl_get_value(struct uvc_control_mapping *mapping, - const u8 *data) -{ - s32 value = mapping->get(mapping, UVC_GET_CUR, data); - - if (mapping->v4l2_type == V4L2_CTRL_TYPE_MENU) { - 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) { @@ -1136,8 +1339,8 @@ static int __uvc_ctrl_get(struct uvc_video_chain *chain, if (ret < 0) return ret; - *value = __uvc_ctrl_get_value(mapping, - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT)); + *value = uvc_mapping_get_s32(mapping, UVC_GET_CUR, + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT)); return 0; } @@ -1145,7 +1348,8 @@ static int __uvc_ctrl_get(struct uvc_video_chain *chain, static int __uvc_query_v4l2_class(struct uvc_video_chain *chain, u32 req_id, u32 found_id) { - bool find_next = req_id & V4L2_CTRL_FLAG_NEXT_CTRL; + bool find_next = req_id & + (V4L2_CTRL_FLAG_NEXT_CTRL | V4L2_CTRL_FLAG_NEXT_COMPOUND); unsigned int i; req_id &= V4L2_CTRL_ID_MASK; @@ -1167,7 +1371,8 @@ static int __uvc_query_v4l2_class(struct uvc_video_chain *chain, u32 req_id, } static int uvc_query_v4l2_class(struct uvc_video_chain *chain, u32 req_id, - u32 found_id, struct v4l2_queryctrl *v4l2_ctrl) + u32 found_id, + struct v4l2_query_ext_ctrl *v4l2_ctrl) { int idx; @@ -1185,6 +1390,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). @@ -1203,7 +1439,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; @@ -1215,10 +1450,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) @@ -1235,10 +1470,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) @@ -1270,59 +1507,44 @@ 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) -{ - 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; +/* + * Maximum retry count to avoid spurious errors with controls. Increasing this + * value does no seem to produce better results in the tested hardware. + */ +#define MAX_QUERY_RETRIES 2 - 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; +static int __uvc_queryctrl_boundaries(struct uvc_video_chain *chain, + struct uvc_control *ctrl, + struct uvc_control_mapping *mapping, + struct v4l2_query_ext_ctrl *v4l2_ctrl) +{ + if (!ctrl->cached) { + unsigned int retries; + int ret; - if (val != mapping->master_manual) - v4l2_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; - } + for (retries = 0; retries < MAX_QUERY_RETRIES; retries++) { + ret = uvc_ctrl_populate_cache(chain, ctrl); + if (ret != -EIO) + break; + } - if (!ctrl->cached) { - int ret = uvc_ctrl_populate_cache(chain, ctrl); - if (ret < 0) + if (ret) return ret; } if (ctrl->info.flags & UVC_CTRL_FLAG_GET_DEF) { - v4l2_ctrl->default_value = mapping->get(mapping, UVC_GET_DEF, - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF)); + v4l2_ctrl->default_value = uvc_mapping_get_s32(mapping, + UVC_GET_DEF, uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF)); } switch (mapping->v4l2_type) { @@ -1330,21 +1552,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: @@ -1370,22 +1577,120 @@ 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; + int ret; + + memset(v4l2_ctrl, 0, sizeof(*v4l2_ctrl)); + v4l2_ctrl->id = mapping->id; + v4l2_ctrl->type = mapping->v4l2_type; + strscpy(v4l2_ctrl->name, uvc_map_get_name(mapping), + sizeof(v4l2_ctrl->name)); + v4l2_ctrl->flags = 0; + + if (!(ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR)) + v4l2_ctrl->flags |= V4L2_CTRL_FLAG_WRITE_ONLY; + if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR)) + v4l2_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + if ((ctrl->info.flags & UVC_CTRL_FLAG_GET_MAX) && + (ctrl->info.flags & UVC_CTRL_FLAG_GET_MIN)) + v4l2_ctrl->flags |= V4L2_CTRL_FLAG_HAS_WHICH_MIN_MAX; + + if (mapping->master_id) + __uvc_find_control(ctrl->entity, mapping->master_id, + &master_map, &master_ctrl, 0, 0); + if (master_ctrl && (master_ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR)) { + unsigned int retries; + s32 val; + int ret; + + if (WARN_ON(uvc_ctrl_mapping_is_compound(master_map))) + return -EIO; + + for (retries = 0; retries < MAX_QUERY_RETRIES; retries++) { + ret = __uvc_ctrl_get(chain, master_ctrl, master_map, + &val); + if (!ret) + break; + if (ret < 0 && ret != -EIO) + return ret; + } + + if (ret == -EIO) { + dev_warn_ratelimited(&chain->dev->intf->dev, + "UVC non compliance: Error %d querying master control %x (%s)\n", + ret, master_map->id, + uvc_map_get_name(master_map)); + } else { + if (val != mapping->master_manual) + v4l2_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + } + } + + v4l2_ctrl->elem_size = uvc_mapping_v4l2_size(mapping); + v4l2_ctrl->elems = 1; + + if (v4l2_ctrl->type >= V4L2_CTRL_COMPOUND_TYPES) { + v4l2_ctrl->flags |= V4L2_CTRL_FLAG_HAS_PAYLOAD; + v4l2_ctrl->default_value = 0; + v4l2_ctrl->minimum = 0; + v4l2_ctrl->maximum = 0; + v4l2_ctrl->step = 0; + return 0; + } + + ret = __uvc_queryctrl_boundaries(chain, ctrl, mapping, v4l2_ctrl); + if (ret && !mapping->disabled) { + dev_warn(&chain->dev->intf->dev, + "UVC non compliance: permanently disabling control %x (%s), due to error %d\n", + mapping->id, uvc_map_get_name(mapping), ret); + mapping->disabled = true; + } + + if (mapping->disabled) + v4l2_ctrl->flags |= V4L2_CTRL_FLAG_DISABLED; return 0; } int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, - struct v4l2_queryctrl *v4l2_ctrl) + struct v4l2_query_ext_ctrl *v4l2_ctrl) { struct uvc_control *ctrl; struct uvc_control_mapping *mapping; @@ -1511,7 +1816,7 @@ static void uvc_ctrl_fill_event(struct uvc_video_chain *chain, struct uvc_control_mapping *mapping, s32 value, u32 changes) { - struct v4l2_queryctrl v4l2_ctrl; + struct v4l2_query_ext_ctrl v4l2_ctrl; __uvc_query_v4l2_ctrl(chain, ctrl, mapping, &v4l2_ctrl); @@ -1569,16 +1874,62 @@ static void uvc_ctrl_send_slave_event(struct uvc_video_chain *chain, u32 changes = V4L2_EVENT_CTRL_CH_FLAGS; s32 val = 0; - __uvc_find_control(master->entity, slave_id, &mapping, &ctrl, 0); + __uvc_find_control(master->entity, slave_id, &mapping, &ctrl, 0, 0); if (ctrl == NULL) return; - if (__uvc_ctrl_get(chain, ctrl, mapping, &val) == 0) + if (uvc_ctrl_mapping_is_compound(mapping) || + __uvc_ctrl_get(chain, ctrl, mapping, &val) == 0) changes |= V4L2_EVENT_CTRL_CH_VALUE; uvc_ctrl_send_event(chain, handle, ctrl, mapping, val, changes); } +static int uvc_ctrl_set_handle(struct uvc_control *ctrl, struct uvc_fh *handle) +{ + int ret; + + lockdep_assert_held(&handle->chain->ctrl_mutex); + + if (ctrl->handle) { + dev_warn_ratelimited(&handle->stream->dev->intf->dev, + "UVC non compliance: Setting an async control with a pending operation."); + + if (ctrl->handle == handle) + return 0; + + WARN_ON(!ctrl->handle->pending_async_ctrls); + if (ctrl->handle->pending_async_ctrls) + ctrl->handle->pending_async_ctrls--; + ctrl->handle = handle; + ctrl->handle->pending_async_ctrls++; + return 0; + } + + ret = uvc_pm_get(handle->chain->dev); + if (ret) + return ret; + + ctrl->handle = handle; + ctrl->handle->pending_async_ctrls++; + return 0; +} + +static int uvc_ctrl_clear_handle(struct uvc_control *ctrl) +{ + lockdep_assert_held(&ctrl->handle->chain->ctrl_mutex); + + if (WARN_ON(!ctrl->handle->pending_async_ctrls)) { + ctrl->handle = NULL; + return -EINVAL; + } + + ctrl->handle->pending_async_ctrls--; + uvc_pm_put(ctrl->handle->chain->dev); + ctrl->handle = NULL; + return 0; +} + void uvc_ctrl_status_event(struct uvc_video_chain *chain, struct uvc_control *ctrl, const u8 *data) { @@ -1588,11 +1939,20 @@ void uvc_ctrl_status_event(struct uvc_video_chain *chain, mutex_lock(&chain->ctrl_mutex); + /* Flush the control cache, the data might have changed. */ + ctrl->loaded = 0; + handle = ctrl->handle; - ctrl->handle = NULL; + if (handle) + uvc_ctrl_clear_handle(ctrl); list_for_each_entry(mapping, &ctrl->info.mappings, list) { - s32 value = __uvc_ctrl_get_value(mapping, data); + s32 value; + + if (uvc_ctrl_mapping_is_compound(mapping)) + value = 0; + else + value = uvc_mapping_get_s32(mapping, UVC_GET_CUR, data); /* * handle may be NULL here if the device sends auto-update @@ -1630,7 +1990,7 @@ static void uvc_ctrl_status_event_work(struct work_struct *work) w->urb->interval = dev->int_ep->desc.bInterval; ret = usb_submit_urb(w->urb, GFP_KERNEL); if (ret < 0) - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "Failed to resubmit status URB (%d).\n", ret); } @@ -1640,10 +2000,8 @@ bool uvc_ctrl_status_event_async(struct urb *urb, struct uvc_video_chain *chain, struct uvc_device *dev = chain->dev; struct uvc_ctrl_work *w = &dev->async_ctrl; - if (list_empty(&ctrl->info.mappings)) { - ctrl->handle = NULL; + if (list_empty(&ctrl->info.mappings)) return false; - } w->data = data; w->urb = urb; @@ -1669,16 +2027,22 @@ static bool uvc_ctrl_xctrls_has_control(const struct v4l2_ext_control *xctrls, } static void uvc_ctrl_send_events(struct uvc_fh *handle, - const struct v4l2_ext_control *xctrls, unsigned int xctrls_count) + struct uvc_entity *entity, + const struct v4l2_ext_control *xctrls, + unsigned int xctrls_count) { struct uvc_control_mapping *mapping; struct uvc_control *ctrl; - u32 changes = V4L2_EVENT_CTRL_CH_VALUE; unsigned int i; unsigned int j; for (i = 0; i < xctrls_count; ++i) { + u32 changes = V4L2_EVENT_CTRL_CH_VALUE; + s32 value; + ctrl = uvc_find_control(handle->chain, xctrls[i].id, &mapping); + if (ctrl->entity != entity) + continue; if (ctrl->info.flags & UVC_CTRL_FLAG_ASYNCHRONOUS) /* Notification will be sent from an Interrupt event. */ @@ -1702,6 +2066,10 @@ static void uvc_ctrl_send_events(struct uvc_fh *handle, slave_id); } + if (uvc_ctrl_mapping_is_compound(mapping)) + value = 0; + else + value = xctrls[i].value; /* * If the master is being modified in the same transaction * flags may change too. @@ -1712,7 +2080,7 @@ static void uvc_ctrl_send_events(struct uvc_fh *handle, changes |= V4L2_EVENT_CTRL_CH_FLAGS; uvc_ctrl_send_event(handle->chain, handle, ctrl, mapping, - xctrls[i].value, changes); + value, changes); } } @@ -1738,17 +2106,24 @@ static int uvc_ctrl_add_event(struct v4l2_subscribed_event *sev, unsigned elems) goto done; } - list_add_tail(&sev->node, &mapping->ev_subs); if (sev->flags & V4L2_EVENT_SUB_FL_SEND_INITIAL) { struct v4l2_event ev; u32 changes = V4L2_EVENT_CTRL_CH_FLAGS; s32 val = 0; - if (__uvc_ctrl_get(handle->chain, ctrl, mapping, &val) == 0) + ret = uvc_pm_get(handle->chain->dev); + if (ret) + goto done; + + if (uvc_ctrl_mapping_is_compound(mapping) || + __uvc_ctrl_get(handle->chain, ctrl, mapping, &val) == 0) changes |= V4L2_EVENT_CTRL_CH_VALUE; uvc_ctrl_fill_event(handle->chain, &ev, ctrl, mapping, val, changes); + + uvc_pm_put(handle->chain->dev); + /* * Mark the queue as active, allowing this initial event to be * accepted. @@ -1757,6 +2132,8 @@ static int uvc_ctrl_add_event(struct v4l2_subscribed_event *sev, unsigned elems) v4l2_event_queue_fh(sev->fh, &ev); } + list_add_tail(&sev->node, &mapping->ev_subs); + done: mutex_unlock(&handle->chain->ctrl_mutex); return ret; @@ -1810,12 +2187,20 @@ int uvc_ctrl_begin(struct uvc_video_chain *chain) return mutex_lock_interruptible(&chain->ctrl_mutex) ? -ERESTARTSYS : 0; } +/* + * Returns the number of uvc controls that have been correctly set, or a + * negative number if there has been an error. + */ static int uvc_ctrl_commit_entity(struct uvc_device *dev, - struct uvc_entity *entity, int rollback, struct uvc_control **err_ctrl) + struct uvc_fh *handle, + struct uvc_entity *entity, + int rollback, + struct uvc_control **err_ctrl) { + unsigned int processed_ctrls = 0; struct uvc_control *ctrl; unsigned int i; - int ret; + int ret = 0; if (entity == NULL) return 0; @@ -1844,8 +2229,9 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev, dev->intfnum, ctrl->info.selector, uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), ctrl->info.size); - else - ret = 0; + + if (!ret) + processed_ctrls++; if (rollback || ret < 0) memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), @@ -1854,14 +2240,25 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev, ctrl->dirty = 0; - if (ret < 0) { + if (!rollback && handle && !ret && + ctrl->info.flags & UVC_CTRL_FLAG_ASYNCHRONOUS) + ret = uvc_ctrl_set_handle(ctrl, handle); + + if (ret < 0 && !rollback) { if (err_ctrl) *err_ctrl = ctrl; - return ret; + /* + * If we fail to set a control, we need to rollback + * the next ones. + */ + rollback = 1; } } - return 0; + if (ret) + return ret; + + return processed_ctrls; } static int uvc_ctrl_find_ctrl_idx(struct uvc_entity *entity, @@ -1877,7 +2274,7 @@ static int uvc_ctrl_find_ctrl_idx(struct uvc_entity *entity, for (i = 0; i < ctrls->count; i++) { __uvc_find_control(entity, ctrls->controls[i].id, &mapping, - &ctrl_found, 0); + &ctrl_found, 0, 0); if (uvc_control == ctrl_found) return i; } @@ -1891,30 +2288,151 @@ int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback, struct uvc_video_chain *chain = handle->chain; struct uvc_control *err_ctrl; struct uvc_entity *entity; - int ret = 0; + int ret_out = 0; + int ret; /* Find the control. */ list_for_each_entry(entity, &chain->entities, chain) { - ret = uvc_ctrl_commit_entity(chain->dev, entity, rollback, - &err_ctrl); + 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); - goto done; + /* + * 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: 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; +} + +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, - struct v4l2_ext_control *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; @@ -1923,34 +2441,23 @@ int uvc_ctrl_get(struct uvc_video_chain *chain, return -EACCES; ctrl = uvc_find_control(chain, xctrl->id, &mapping); - if (ctrl == NULL) + if (!ctrl) return -EINVAL; - return __uvc_ctrl_get(chain, ctrl, mapping, &xctrl->value); + return uvc_mapping_get_xctrl(chain, ctrl, mapping, which, xctrl); } -int uvc_ctrl_set(struct uvc_fh *handle, - struct v4l2_ext_control *xctrl) +static int uvc_ctrl_clamp(struct uvc_video_chain *chain, + struct uvc_control *ctrl, + struct uvc_control_mapping *mapping, + s32 *value_in_out) { - struct uvc_video_chain *chain = handle->chain; - struct uvc_control *ctrl; - struct uvc_control_mapping *mapping; - s32 value; + s32 value = *value_in_out; u32 step; s32 min; s32 max; int ret; - if (__uvc_query_v4l2_class(chain, xctrl->id, 0) >= 0) - return -EACCES; - - ctrl = uvc_find_control(chain, xctrl->id, &mapping); - if (ctrl == NULL) - return -EINVAL; - if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR)) - return -EACCES; - - /* Clamp out of range values. */ switch (mapping->v4l2_type) { case V4L2_CTRL_TYPE_INTEGER: if (!ctrl->cached) { @@ -1959,23 +2466,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) { @@ -1984,47 +2490,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 @@ -2043,11 +2604,9 @@ int uvc_ctrl_set(struct uvc_fh *handle, ctrl->info.size); } - mapping->set(mapping, value, - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT)); - - if (ctrl->info.flags & UVC_CTRL_FLAG_ASYNCHRONOUS) - ctrl->handle = handle; + ret = uvc_mapping_set_xctrl(ctrl, mapping, xctrl); + if (ret) + return ret; ctrl->dirty = 1; ctrl->modified = 1; @@ -2370,14 +2929,14 @@ int uvc_ctrl_restore_values(struct uvc_device *dev) if (!ctrl->initialized || !ctrl->modified || (ctrl->info.flags & UVC_CTRL_FLAG_RESTORE) == 0) continue; - dev_dbg(&dev->udev->dev, + dev_dbg(&dev->intf->dev, "restoring control %pUl/%u/%u\n", ctrl->info.entity, ctrl->info.index, ctrl->info.selector); ctrl->dirty = 1; } - ret = uvc_ctrl_commit_entity(dev, entity, 0, NULL); + ret = uvc_ctrl_commit_entity(dev, NULL, entity, 0, NULL); if (ret < 0) return ret; } @@ -2422,6 +2981,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. @@ -2462,6 +3022,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) @@ -2483,11 +3049,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, @@ -2647,15 +3215,6 @@ static void uvc_ctrl_init_ctrl(struct uvc_video_chain *chain, { unsigned int i; - /* - * XU controls initialization requires querying the device for control - * information. As some buggy UVC devices will crash when queried - * repeatedly in a tight loop, delay XU controls initialization until - * first use. - */ - if (UVC_ENTITY_TYPE(ctrl->entity) == UVC_VC_EXTENSION_UNIT) - return; - for (i = 0; i < ARRAY_SIZE(uvc_ctrls); ++i) { const struct uvc_control_info *info = &uvc_ctrls[i]; @@ -2770,6 +3329,30 @@ int uvc_ctrl_init_device(struct uvc_device *dev) return 0; } +void uvc_ctrl_cleanup_fh(struct uvc_fh *handle) +{ + struct uvc_entity *entity; + + guard(mutex)(&handle->chain->ctrl_mutex); + + if (!handle->pending_async_ctrls) + return; + + list_for_each_entry(entity, &handle->chain->dev->entities, list) { + for (unsigned int i = 0; i < entity->ncontrols; ++i) { + if (entity->controls[i].handle != handle) + continue; + uvc_ctrl_clear_handle(&entity->controls[i]); + } + } + + if (!WARN_ON(handle->pending_async_ctrls)) + return; + + for (unsigned int i = 0; i < handle->pending_async_ctrls; i++) + uvc_pm_put(handle->stream->dev); +} + /* * Cleanup device controls. */ diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index b3c8411dc05c..ee4f54d68349 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -32,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 */ @@ -135,6 +137,9 @@ struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id) { struct uvc_entity *entity; + if (id == UVC_INVALID_ENTITY_ID) + return NULL; + list_for_each_entry(entity, &dev->entities, list) { if (entity->id == id) return entity; @@ -162,13 +167,26 @@ static struct uvc_entity *uvc_entity_by_reference(struct uvc_device *dev, static struct uvc_streaming *uvc_stream_by_id(struct uvc_device *dev, int id) { - struct uvc_streaming *stream; + struct uvc_streaming *stream, *last_stream; + unsigned int count = 0; list_for_each_entry(stream, &dev->streams, list) { + count += 1; + last_stream = stream; if (stream->header.bTerminalLink == id) return stream; } + /* + * If the streaming entity is referenced by an invalid ID, notify the + * user and use heuristics to guess the correct entity. + */ + if (count == 1 && id == UVC_INVALID_ENTITY_ID) { + dev_warn(&dev->intf->dev, + "UVC non compliance: Invalid USB header. The streaming entity has an invalid ID, guessing the correct one."); + return last_stream; + } + return NULL; } @@ -181,8 +199,6 @@ static void uvc_stream_delete(struct uvc_streaming *stream) if (stream->async_wq) destroy_workqueue(stream->async_wq); - mutex_destroy(&stream->mutex); - usb_put_intf(stream->intf); kfree(stream->formats); @@ -199,8 +215,6 @@ static struct uvc_streaming *uvc_stream_new(struct uvc_device *dev, if (stream == NULL) return NULL; - mutex_init(&stream->mutex); - stream->dev = dev; stream->intf = usb_get_intf(intf); stream->intfnum = intf->cur_altsetting->desc.bInterfaceNumber; @@ -220,20 +234,130 @@ 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; + + if (buflen < 4) + return -EINVAL; format->type = buffer[2]; format->index = buffer[3]; @@ -371,111 +495,19 @@ static int uvc_parse_format(struct uvc_device *dev, * Parse the frame descriptors. Only uncompressed, MJPEG and frame * based formats have frame descriptors. */ - while (ftype && 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 && @@ -519,7 +551,7 @@ static int uvc_parse_streaming(struct uvc_device *dev, unsigned int nformats = 0, nframes = 0, nintervals = 0; unsigned int size, i, n, p; u32 *interval; - u16 psize; + u32 psize; int ret = -EINVAL; if (intf->cur_altsetting->desc.bInterfaceSubClass @@ -531,7 +563,7 @@ static int uvc_parse_streaming(struct uvc_device *dev, return -EINVAL; } - if (usb_driver_claim_interface(&uvc_driver.driver, intf, dev)) { + if (usb_driver_claim_interface(&uvc_driver, intf, dev)) { uvc_dbg(dev, DESCR, "device %d interface %d is already claimed\n", dev->udev->devnum, @@ -541,7 +573,7 @@ static int uvc_parse_streaming(struct uvc_device *dev, streaming = uvc_stream_new(dev, intf); if (streaming == NULL) { - usb_driver_release_interface(&uvc_driver.driver, intf); + usb_driver_release_interface(&uvc_driver, intf); return -ENOMEM; } @@ -755,7 +787,7 @@ static int uvc_parse_streaming(struct uvc_device *dev, streaming->header.bEndpointAddress); if (ep == NULL) continue; - psize = uvc_endpoint_max_bpi(dev->udev, ep); + psize = usb_endpoint_max_periodic_payload(dev->udev, ep); if (psize > streaming->maxpsize) streaming->maxpsize = psize; } @@ -764,7 +796,7 @@ static int uvc_parse_streaming(struct uvc_device *dev, return 0; error: - usb_driver_release_interface(&uvc_driver.driver, intf); + usb_driver_release_interface(&uvc_driver, intf); uvc_stream_delete(streaming); return ret; } @@ -786,14 +818,14 @@ static struct uvc_entity *uvc_alloc_new_entity(struct uvc_device *dev, u16 type, /* Per UVC 1.1+ spec 3.7.2, the ID should be non-zero. */ if (id == 0) { - dev_err(&dev->udev->dev, "Found Unit with invalid ID 0.\n"); - return ERR_PTR(-EINVAL); + dev_err(&dev->intf->dev, "Found Unit with invalid ID 0\n"); + id = UVC_INVALID_ENTITY_ID; } /* Per UVC 1.1+ spec 3.7.2, the ID is unique. */ if (uvc_entity_by_id(dev, id)) { - dev_err(&dev->udev->dev, "Found multiple Units with ID %u\n", id); - return ERR_PTR(-EINVAL); + dev_err(&dev->intf->dev, "Found multiple Units with ID %u\n", id); + id = UVC_INVALID_ENTITY_ID; } extra_size = roundup(extra_size, sizeof(*entity->pads)); @@ -875,7 +907,7 @@ static int uvc_parse_vendor_control(struct uvc_device *dev, unsigned int n, p; int handled = 0; - switch (le16_to_cpu(dev->udev->descriptor.idVendor)) { + switch (le16_to_cpu(udev->descriptor.idVendor)) { case 0x046d: /* Logitech */ if (buffer[1] != 0x41 || buffer[2] != 0x01) break; @@ -1295,14 +1327,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_new_entity(dev, UVC_EXT_GPIO_UNIT, @@ -1329,15 +1366,27 @@ static int uvc_gpio_parse(struct uvc_device *dev) static int uvc_gpio_init_irq(struct uvc_device *dev) { struct uvc_entity *unit = dev->gpio_unit; + int ret; if (!unit || unit->gpio.irq < 0) return 0; - return devm_request_threaded_irq(&dev->udev->dev, unit->gpio.irq, NULL, - uvc_gpio_irq, - IRQF_ONESHOT | IRQF_TRIGGER_FALLING | - IRQF_TRIGGER_RISING, - "uvc_privacy_gpio", dev); + ret = request_threaded_irq(unit->gpio.irq, NULL, uvc_gpio_irq, + IRQF_ONESHOT | IRQF_TRIGGER_FALLING | + IRQF_TRIGGER_RISING, + "uvc_privacy_gpio", dev); + + unit->gpio.initialized = !ret; + + return ret; +} + +static void uvc_gpio_deinit(struct uvc_device *dev) +{ + if (!dev->gpio_unit || !dev->gpio_unit->gpio.initialized) + return; + + free_irq(dev->gpio_unit->gpio.irq, dev); } /* ------------------------------------------------------------------------ @@ -1847,8 +1896,8 @@ static int uvc_scan_device(struct uvc_device *dev) uvc_scan_fallback(dev); if (list_empty(&dev->chains)) { - dev_info(&dev->udev->dev, "No valid video chain found.\n"); - return -1; + dev_info(&dev->intf->dev, "No valid video chain found.\n"); + return -ENODEV; } /* Add GPIO entity to the first chain. */ @@ -1911,8 +1960,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); } @@ -1934,37 +1982,15 @@ 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)) + if (!video_is_registered(&stream->queue.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); - - /* 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); + vb2_video_unregister_device(&stream->queue.vdev); + vb2_video_unregister_device(&stream->meta.queue.vdev); /* * Now both vdevs are not streaming and all the ioctls will @@ -1986,16 +2012,16 @@ static void uvc_unregister_video(struct uvc_device *dev) int uvc_register_video_device(struct uvc_device *dev, struct uvc_streaming *stream, - struct video_device *vdev, struct uvc_video_queue *queue, enum v4l2_buf_type type, const struct v4l2_file_operations *fops, const struct v4l2_ioctl_ops *ioctl_ops) { + struct video_device *vdev = &queue->vdev; int ret; /* Initialize the video buffers queue. */ - ret = uvc_queue_init(queue, type, !uvc_no_drop_param); + ret = uvc_queue_init(queue, type); if (ret) return ret; @@ -2011,6 +2037,8 @@ int uvc_register_video_device(struct uvc_device *dev, vdev->ioctl_ops = ioctl_ops; vdev->release = uvc_release; vdev->prio = &stream->chain->prio; + vdev->queue = &queue->queue; + vdev->lock = &queue->mutex; if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT) vdev->vfl_dir = VFL_DIR_TX; else @@ -2071,9 +2099,9 @@ static int uvc_register_video(struct uvc_device *dev, uvc_debugfs_init_stream(stream); /* Register the device with V4L. */ - return uvc_register_video_device(dev, stream, &stream->vdev, - &stream->queue, stream->type, - &uvc_fops, &uvc_ioctl_ops); + return uvc_register_video_device(dev, stream, &stream->queue, + stream->type, &uvc_fops, + &uvc_ioctl_ops); } /* @@ -2092,7 +2120,7 @@ static int uvc_register_terms(struct uvc_device *dev, stream = uvc_stream_by_id(dev, term->id); if (stream == NULL) { - dev_info(&dev->udev->dev, + dev_info(&dev->intf->dev, "No streaming interface found for terminal %u.", term->id); continue; @@ -2109,7 +2137,7 @@ static int uvc_register_terms(struct uvc_device *dev, */ uvc_meta_register(stream); - term->vdev = &stream->vdev; + term->vdev = &stream->queue.vdev; } return 0; @@ -2128,7 +2156,7 @@ static int uvc_register_chains(struct uvc_device *dev) #ifdef CONFIG_MEDIA_CONTROLLER ret = uvc_mc_register_entities(chain); if (ret < 0) - dev_info(&dev->udev->dev, + dev_info(&dev->intf->dev, "Failed to register entities (%d).\n", ret); #endif } @@ -2218,56 +2246,61 @@ static int uvc_probe(struct usb_interface *intf, #endif /* Parse the Video Class control descriptor. */ - if (uvc_parse_control(dev) < 0) { + ret = uvc_parse_control(dev); + if (ret < 0) { uvc_dbg(dev, PROBE, "Unable to parse UVC descriptors\n"); goto error; } /* Parse the associated GPIOs. */ - if (uvc_gpio_parse(dev) < 0) { - uvc_dbg(dev, PROBE, "Unable to parse UVC GPIOs\n"); + ret = uvc_gpio_parse(dev); + if (ret < 0) goto error; - } - dev_info(&dev->udev->dev, "Found UVC %u.%02x device %s (%04x:%04x)\n", + dev_info(&dev->intf->dev, "Found UVC %u.%02x device %s (%04x:%04x)\n", dev->uvc_version >> 8, dev->uvc_version & 0xff, udev->product ? udev->product : "<unnamed>", le16_to_cpu(udev->descriptor.idVendor), le16_to_cpu(udev->descriptor.idProduct)); if (dev->quirks != dev->info->quirks) { - dev_info(&dev->udev->dev, + dev_info(&dev->intf->dev, "Forcing device quirks to 0x%x by module parameter for testing purpose.\n", dev->quirks); - dev_info(&dev->udev->dev, + dev_info(&dev->intf->dev, "Please report required quirks to the linux-media mailing list.\n"); } if (dev->info->uvc_version) { dev->uvc_version = dev->info->uvc_version; - dev_info(&dev->udev->dev, "Forcing UVC version to %u.%02x\n", + dev_info(&dev->intf->dev, "Forcing UVC version to %u.%02x\n", dev->uvc_version >> 8, dev->uvc_version & 0xff); } /* Register the V4L2 device. */ - if (v4l2_device_register(&intf->dev, &dev->vdev) < 0) + ret = v4l2_device_register(&intf->dev, &dev->vdev); + if (ret < 0) goto error; /* Scan the device for video chains. */ - if (uvc_scan_device(dev) < 0) + ret = uvc_scan_device(dev); + if (ret < 0) goto error; /* Initialize controls. */ - if (uvc_ctrl_init_device(dev) < 0) + ret = uvc_ctrl_init_device(dev); + if (ret < 0) goto error; /* Register video device nodes. */ - if (uvc_register_chains(dev) < 0) + ret = uvc_register_chains(dev); + if (ret < 0) goto error; #ifdef CONFIG_MEDIA_CONTROLLER /* Register the media device node */ - if (media_device_register(&dev->mdev) < 0) + ret = media_device_register(&dev->mdev); + if (ret < 0) goto error; #endif /* Save our data pointer in the interface data. */ @@ -2276,18 +2309,25 @@ static int uvc_probe(struct usb_interface *intf, /* Initialize the interrupt URB. */ ret = uvc_status_init(dev); if (ret < 0) { - dev_info(&dev->udev->dev, + dev_info(&dev->intf->dev, "Unable to initialize the status endpoint (%d), status interrupt will not be supported.\n", ret); } ret = uvc_gpio_init_irq(dev); if (ret < 0) { - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "Unable to request privacy GPIO IRQ (%d)\n", ret); goto error; } + ret = uvc_meta_init(dev); + if (ret < 0) { + dev_err(&dev->intf->dev, + "Error initializing the metadata formats (%d)\n", ret); + goto error; + } + if (dev->quirks & UVC_QUIRK_NO_RESET_RESUME) udev->quirks &= ~USB_QUIRK_RESET_RESUME; @@ -2301,7 +2341,7 @@ static int uvc_probe(struct usb_interface *intf, error: uvc_unregister_video(dev); kref_put(&dev->ref, uvc_delete); - return -ENODEV; + return ret; } static void uvc_disconnect(struct usb_interface *intf) @@ -2370,9 +2410,12 @@ static int __uvc_resume(struct usb_interface *intf, int reset) list_for_each_entry(stream, &dev->streams, list) { if (stream->intf == intf) { ret = uvc_video_resume(stream, reset); - if (ret < 0) - uvc_queue_streamoff(&stream->queue, - stream->queue.queue.type); + if (ret < 0) { + mutex_lock(&stream->queue.mutex); + vb2_streamoff(&stream->queue.queue, + stream->queue.queue.type); + mutex_unlock(&stream->queue.mutex); + } return ret; } } @@ -2424,8 +2467,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); @@ -2469,6 +2529,15 @@ static const struct uvc_device_info uvc_quirk_force_y8 = { * Sort these by vendor/product ID. */ static const struct usb_device_id uvc_ids[] = { + /* HP Webcam HD 2300 */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x03f0, + .idProduct = 0xe207, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = (kernel_ulong_t)&uvc_quirk_stream_no_fid }, /* Quanta ACER HD User Facing */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, @@ -2802,6 +2871,15 @@ static const struct usb_device_id uvc_ids[] = { .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, .driver_info = (kernel_ulong_t)&uvc_quirk_probe_minmax }, + /* Sonix Technology Co. Ltd. - 292A IPC AR0330 */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x0c45, + .idProduct = 0x6366, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_MJPEG_NO_EOF) }, /* MT6227 */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, @@ -2830,6 +2908,15 @@ static const struct usb_device_id uvc_ids[] = { .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, .driver_info = (kernel_ulong_t)&uvc_quirk_probe_minmax }, + /* Kurokesu C1 PRO */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x16d0, + .idProduct = 0x0ed1, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_MJPEG_NO_EOF) }, /* Syntek (HP Spartan) */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, @@ -3014,6 +3101,15 @@ 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, @@ -3148,17 +3244,15 @@ static const struct usb_device_id uvc_ids[] = { MODULE_DEVICE_TABLE(usb, uvc_ids); -struct uvc_driver uvc_driver = { - .driver = { - .name = "uvcvideo", - .probe = uvc_probe, - .disconnect = uvc_disconnect, - .suspend = uvc_suspend, - .resume = uvc_resume, - .reset_resume = uvc_reset_resume, - .id_table = uvc_ids, - .supports_autosuspend = 1, - }, +static struct usb_driver uvc_driver = { + .name = "uvcvideo", + .probe = uvc_probe, + .disconnect = uvc_disconnect, + .suspend = uvc_suspend, + .resume = uvc_resume, + .reset_resume = uvc_reset_resume, + .id_table = uvc_ids, + .supports_autosuspend = 1, }; static int __init uvc_init(void) @@ -3167,7 +3261,7 @@ static int __init uvc_init(void) uvc_debugfs_init(); - ret = usb_register(&uvc_driver.driver); + ret = usb_register(&uvc_driver); if (ret < 0) { uvc_debugfs_cleanup(); return ret; @@ -3178,7 +3272,7 @@ static int __init uvc_init(void) static void __exit uvc_cleanup(void) { - usb_deregister(&uvc_driver.driver); + usb_deregister(&uvc_driver); uvc_debugfs_cleanup(); } diff --git a/drivers/media/usb/uvc/uvc_entity.c b/drivers/media/usb/uvc/uvc_entity.c index cc68dd24eb42..3823ac9c8045 100644 --- a/drivers/media/usb/uvc/uvc_entity.c +++ b/drivers/media/usb/uvc/uvc_entity.c @@ -140,7 +140,7 @@ int uvc_mc_register_entities(struct uvc_video_chain *chain) list_for_each_entry(entity, &chain->entities, chain) { ret = uvc_mc_init_entity(chain, entity); if (ret < 0) { - dev_info(&chain->dev->udev->dev, + dev_info(&chain->dev->intf->dev, "Failed to initialize entity for entity %u\n", entity->id); return ret; @@ -150,7 +150,7 @@ int uvc_mc_register_entities(struct uvc_video_chain *chain) list_for_each_entry(entity, &chain->entities, chain) { ret = uvc_mc_create_links(chain, entity); if (ret < 0) { - dev_info(&chain->dev->udev->dev, + dev_info(&chain->dev->intf->dev, "Failed to create links for entity %u\n", entity->id); return ret; diff --git a/drivers/media/usb/uvc/uvc_metadata.c b/drivers/media/usb/uvc/uvc_metadata.c index 82de7781f5b6..c23b174965c3 100644 --- a/drivers/media/usb/uvc/uvc_metadata.c +++ b/drivers/media/usb/uvc/uvc_metadata.c @@ -10,6 +10,7 @@ #include <linux/list.h> #include <linux/module.h> #include <linux/usb.h> +#include <linux/usb/uvc.h> #include <linux/videodev2.h> #include <media/v4l2-ioctl.h> @@ -22,10 +23,10 @@ * V4L2 ioctls */ -static int uvc_meta_v4l2_querycap(struct file *file, void *fh, +static int uvc_meta_v4l2_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct uvc_streaming *stream = video_get_drvdata(vfh->vdev); struct uvc_video_chain *chain = stream->chain; @@ -38,54 +39,58 @@ static int uvc_meta_v4l2_querycap(struct file *file, void *fh, return 0; } -static int uvc_meta_v4l2_get_format(struct file *file, void *fh, +static int uvc_meta_v4l2_get_format(struct file *file, void *priv, struct v4l2_format *format) { - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct uvc_streaming *stream = video_get_drvdata(vfh->vdev); struct v4l2_meta_format *fmt = &format->fmt.meta; if (format->type != vfh->vdev->queue->type) return -EINVAL; - memset(fmt, 0, sizeof(*fmt)); - fmt->dataformat = stream->meta.format; fmt->buffersize = UVC_METADATA_BUF_SIZE; return 0; } -static int uvc_meta_v4l2_try_format(struct file *file, void *fh, +static int uvc_meta_v4l2_try_format(struct file *file, void *priv, struct v4l2_format *format) { - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct uvc_streaming *stream = video_get_drvdata(vfh->vdev); struct uvc_device *dev = stream->dev; struct v4l2_meta_format *fmt = &format->fmt.meta; - u32 fmeta = fmt->dataformat; + u32 fmeta = V4L2_META_FMT_UVC; if (format->type != vfh->vdev->queue->type) return -EINVAL; + for (unsigned int i = 0; i < dev->nmeta_formats; i++) { + if (dev->meta_formats[i] == fmt->dataformat) { + fmeta = fmt->dataformat; + break; + } + } + memset(fmt, 0, sizeof(*fmt)); - fmt->dataformat = fmeta == dev->info->meta_format - ? fmeta : V4L2_META_FMT_UVC; + fmt->dataformat = fmeta; fmt->buffersize = UVC_METADATA_BUF_SIZE; return 0; } -static int uvc_meta_v4l2_set_format(struct file *file, void *fh, +static int uvc_meta_v4l2_set_format(struct file *file, void *priv, struct v4l2_format *format) { - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct uvc_streaming *stream = video_get_drvdata(vfh->vdev); struct v4l2_meta_format *fmt = &format->fmt.meta; int ret; - ret = uvc_meta_v4l2_try_format(file, fh, format); + ret = uvc_meta_v4l2_try_format(file, priv, format); if (ret < 0) return ret; @@ -94,35 +99,28 @@ static int uvc_meta_v4l2_set_format(struct file *file, void *fh, * Metadata buffers would still be perfectly parseable, but it's more * consistent and cleaner to disallow that. */ - mutex_lock(&stream->mutex); + if (vb2_is_busy(&stream->meta.queue.queue)) + return -EBUSY; - if (uvc_queue_allocated(&stream->queue)) - ret = -EBUSY; - else - stream->meta.format = fmt->dataformat; + stream->meta.format = fmt->dataformat; - mutex_unlock(&stream->mutex); - - return ret; + return 0; } -static int uvc_meta_v4l2_enum_formats(struct file *file, void *fh, +static int uvc_meta_v4l2_enum_formats(struct file *file, void *priv, struct v4l2_fmtdesc *fdesc) { - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct uvc_streaming *stream = video_get_drvdata(vfh->vdev); struct uvc_device *dev = stream->dev; - u32 index = fdesc->index; - if (fdesc->type != vfh->vdev->queue->type || - index > 1U || (index && !dev->info->meta_format)) + if (fdesc->type != vfh->vdev->queue->type) return -EINVAL; - memset(fdesc, 0, sizeof(*fdesc)); + if (fdesc->index >= dev->nmeta_formats) + return -EINVAL; - fdesc->type = vfh->vdev->queue->type; - fdesc->index = index; - fdesc->pixelformat = index ? dev->info->meta_format : V4L2_META_FMT_UVC; + fdesc->pixelformat = dev->meta_formats[fdesc->index]; return 0; } @@ -156,21 +154,108 @@ static const struct v4l2_file_operations uvc_meta_fops = { .mmap = vb2_fop_mmap, }; +static struct uvc_entity *uvc_meta_find_msxu(struct uvc_device *dev) +{ + static const u8 uvc_msxu_guid[16] = UVC_GUID_MSXU_1_5; + struct uvc_entity *entity; + + list_for_each_entry(entity, &dev->entities, list) { + if (!memcmp(entity->guid, uvc_msxu_guid, sizeof(entity->guid))) + return entity; + } + + return NULL; +} + +static int uvc_meta_detect_msxu(struct uvc_device *dev) +{ + u32 *data __free(kfree) = NULL; + struct uvc_entity *entity; + int ret; + + entity = uvc_meta_find_msxu(dev); + if (!entity) + return 0; + + /* + * USB requires buffers aligned in a special way, simplest way is to + * make sure that query_ctrl will work is to kmalloc() them. + */ + data = kmalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + /* + * Check if the metadata is already enabled, or if the device always + * returns metadata. + */ + ret = uvc_query_ctrl(dev, UVC_GET_CUR, entity->id, dev->intfnum, + UVC_MSXU_CONTROL_METADATA, data, sizeof(*data)); + if (ret) + return 0; + + if (*data) { + dev->quirks |= UVC_QUIRK_MSXU_META; + return 0; + } + + /* + * Set the value of UVC_MSXU_CONTROL_METADATA to the value reported by + * GET_MAX to enable production of MSXU metadata. The GET_MAX request + * reports the maximum size of the metadata, if its value is 0 then MSXU + * metadata is not supported. For more information, see + * https://learn.microsoft.com/en-us/windows-hardware/drivers/stream/uvc-extensions-1-5#2229-metadata-control + */ + ret = uvc_query_ctrl(dev, UVC_GET_MAX, entity->id, dev->intfnum, + UVC_MSXU_CONTROL_METADATA, data, sizeof(*data)); + if (ret || !*data) + return 0; + + /* + * If we can set UVC_MSXU_CONTROL_METADATA, the device will report + * metadata. + */ + ret = uvc_query_ctrl(dev, UVC_SET_CUR, entity->id, dev->intfnum, + UVC_MSXU_CONTROL_METADATA, data, sizeof(*data)); + if (!ret) + dev->quirks |= UVC_QUIRK_MSXU_META; + + return 0; +} + int uvc_meta_register(struct uvc_streaming *stream) { struct uvc_device *dev = stream->dev; - struct video_device *vdev = &stream->meta.vdev; struct uvc_video_queue *queue = &stream->meta.queue; stream->meta.format = V4L2_META_FMT_UVC; - /* - * The video interface queue uses manual locking and thus does not set - * the queue pointer. Set it manually here. - */ - vdev->queue = &queue->queue; - - return uvc_register_video_device(dev, stream, vdev, queue, + return uvc_register_video_device(dev, stream, queue, V4L2_BUF_TYPE_META_CAPTURE, &uvc_meta_fops, &uvc_meta_ioctl_ops); } + +int uvc_meta_init(struct uvc_device *dev) +{ + unsigned int i = 0; + int ret; + + ret = uvc_meta_detect_msxu(dev); + if (ret) + return ret; + + dev->meta_formats[i++] = V4L2_META_FMT_UVC; + + if (dev->info->meta_format && + !WARN_ON(dev->info->meta_format == V4L2_META_FMT_UVC)) + dev->meta_formats[i++] = dev->info->meta_format; + + if (dev->quirks & UVC_QUIRK_MSXU_META && + !WARN_ON(dev->info->meta_format == V4L2_META_FMT_UVC_MSXU_1_5)) + dev->meta_formats[i++] = V4L2_META_FMT_UVC_MSXU_1_5; + + /* IMPORTANT: for new meta-formats update UVC_MAX_META_DATA_FORMATS. */ + dev->nmeta_formats = i; + + return 0; +} diff --git a/drivers/media/usb/uvc/uvc_queue.c b/drivers/media/usb/uvc/uvc_queue.c index 26ee85657fc8..790184c9843d 100644 --- a/drivers/media/usb/uvc/uvc_queue.c +++ b/drivers/media/usb/uvc/uvc_queue.c @@ -42,13 +42,15 @@ static inline struct uvc_buffer *uvc_vbuf_to_buffer(struct vb2_v4l2_buffer *buf) * * This function must be called with the queue spinlock held. */ -static void uvc_queue_return_buffers(struct uvc_video_queue *queue, - enum uvc_buffer_state state) +static void __uvc_queue_return_buffers(struct uvc_video_queue *queue, + enum uvc_buffer_state state) { enum vb2_buffer_state vb2_state = state == UVC_BUF_STATE_ERROR ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_QUEUED; + lockdep_assert_held(&queue->irqlock); + while (!list_empty(&queue->irqqueue)) { struct uvc_buffer *buf = list_first_entry(&queue->irqqueue, struct uvc_buffer, @@ -59,6 +61,14 @@ static void uvc_queue_return_buffers(struct uvc_video_queue *queue, } } +static void uvc_queue_return_buffers(struct uvc_video_queue *queue, + enum uvc_buffer_state state) +{ + spin_lock_irq(&queue->irqlock); + __uvc_queue_return_buffers(queue, state); + spin_unlock_irq(&queue->irqlock); +} + /* ----------------------------------------------------------------------------- * videobuf2 queue operations */ @@ -157,7 +167,7 @@ static void uvc_buffer_finish(struct vb2_buffer *vb) uvc_video_clock_update(stream, vbuf, buf); } -static int uvc_start_streaming(struct vb2_queue *vq, unsigned int count) +static int uvc_start_streaming_video(struct vb2_queue *vq, unsigned int count) { struct uvc_video_queue *queue = vb2_get_drv_priv(vq); struct uvc_streaming *stream = uvc_queue_to_stream(queue); @@ -165,31 +175,44 @@ static int uvc_start_streaming(struct vb2_queue *vq, unsigned int count) lockdep_assert_irqs_enabled(); + ret = uvc_pm_get(stream->dev); + if (ret) + return ret; + queue->buf_used = 0; ret = uvc_video_start_streaming(stream); if (ret == 0) return 0; - spin_lock_irq(&queue->irqlock); + uvc_pm_put(stream->dev); + uvc_queue_return_buffers(queue, UVC_BUF_STATE_QUEUED); - spin_unlock_irq(&queue->irqlock); return ret; } -static void uvc_stop_streaming(struct vb2_queue *vq) +static void uvc_stop_streaming_video(struct vb2_queue *vq) { struct uvc_video_queue *queue = vb2_get_drv_priv(vq); + struct uvc_streaming *stream = uvc_queue_to_stream(queue); lockdep_assert_irqs_enabled(); - if (vq->type != V4L2_BUF_TYPE_META_CAPTURE) - uvc_video_stop_streaming(uvc_queue_to_stream(queue)); + uvc_video_stop_streaming(uvc_queue_to_stream(queue)); + + uvc_pm_put(stream->dev); + + uvc_queue_return_buffers(queue, UVC_BUF_STATE_ERROR); +} + +static void uvc_stop_streaming_meta(struct vb2_queue *vq) +{ + struct uvc_video_queue *queue = vb2_get_drv_priv(vq); + + lockdep_assert_irqs_enabled(); - spin_lock_irq(&queue->irqlock); uvc_queue_return_buffers(queue, UVC_BUF_STATE_ERROR); - spin_unlock_irq(&queue->irqlock); } static const struct vb2_ops uvc_queue_qops = { @@ -197,19 +220,23 @@ static const struct vb2_ops uvc_queue_qops = { .buf_prepare = uvc_buffer_prepare, .buf_queue = uvc_buffer_queue, .buf_finish = uvc_buffer_finish, - .start_streaming = uvc_start_streaming, - .stop_streaming = uvc_stop_streaming, + .start_streaming = uvc_start_streaming_video, + .stop_streaming = uvc_stop_streaming_video, }; static const struct vb2_ops uvc_meta_queue_qops = { .queue_setup = uvc_queue_setup, .buf_prepare = uvc_buffer_prepare, .buf_queue = uvc_buffer_queue, - .stop_streaming = uvc_stop_streaming, + /* + * .start_streaming is not provided here. Metadata relies on video + * streaming being active. If video isn't streaming, then no metadata + * will arrive either. + */ + .stop_streaming = uvc_stop_streaming_meta, }; -int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type, - int drop_corrupted) +int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type) { int ret; @@ -239,159 +266,15 @@ int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type, mutex_init(&queue->mutex); spin_lock_init(&queue->irqlock); INIT_LIST_HEAD(&queue->irqqueue); - queue->flags = drop_corrupted ? UVC_QUEUE_DROP_CORRUPTED : 0; return 0; } -void uvc_queue_release(struct uvc_video_queue *queue) -{ - mutex_lock(&queue->mutex); - vb2_queue_release(&queue->queue); - mutex_unlock(&queue->mutex); -} - -/* ----------------------------------------------------------------------------- - * V4L2 queue operations - */ - -int uvc_request_buffers(struct uvc_video_queue *queue, - struct v4l2_requestbuffers *rb) -{ - int ret; - - mutex_lock(&queue->mutex); - ret = vb2_reqbufs(&queue->queue, rb); - mutex_unlock(&queue->mutex); - - return ret ? ret : rb->count; -} - -int uvc_query_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf) -{ - int ret; - - mutex_lock(&queue->mutex); - ret = vb2_querybuf(&queue->queue, buf); - mutex_unlock(&queue->mutex); - - return ret; -} - -int uvc_create_buffers(struct uvc_video_queue *queue, - struct v4l2_create_buffers *cb) -{ - int ret; - - mutex_lock(&queue->mutex); - ret = vb2_create_bufs(&queue->queue, cb); - mutex_unlock(&queue->mutex); - - return ret; -} - -int uvc_queue_buffer(struct uvc_video_queue *queue, - struct media_device *mdev, struct v4l2_buffer *buf) -{ - int ret; - - mutex_lock(&queue->mutex); - ret = vb2_qbuf(&queue->queue, mdev, buf); - mutex_unlock(&queue->mutex); - - return ret; -} - -int uvc_export_buffer(struct uvc_video_queue *queue, - struct v4l2_exportbuffer *exp) -{ - int ret; - - mutex_lock(&queue->mutex); - ret = vb2_expbuf(&queue->queue, exp); - mutex_unlock(&queue->mutex); - - return ret; -} - -int uvc_dequeue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf, - int nonblocking) -{ - int ret; - - mutex_lock(&queue->mutex); - ret = vb2_dqbuf(&queue->queue, buf, nonblocking); - mutex_unlock(&queue->mutex); - - return ret; -} - -int uvc_queue_streamon(struct uvc_video_queue *queue, enum v4l2_buf_type type) -{ - int ret; - - mutex_lock(&queue->mutex); - ret = vb2_streamon(&queue->queue, type); - mutex_unlock(&queue->mutex); - - return ret; -} - -int uvc_queue_streamoff(struct uvc_video_queue *queue, enum v4l2_buf_type type) -{ - int ret; - - mutex_lock(&queue->mutex); - ret = vb2_streamoff(&queue->queue, type); - mutex_unlock(&queue->mutex); - - return ret; -} - -int uvc_queue_mmap(struct uvc_video_queue *queue, struct vm_area_struct *vma) -{ - return vb2_mmap(&queue->queue, vma); -} - -#ifndef CONFIG_MMU -unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue, - unsigned long pgoff) -{ - return vb2_get_unmapped_area(&queue->queue, 0, 0, pgoff, 0); -} -#endif - -__poll_t uvc_queue_poll(struct uvc_video_queue *queue, struct file *file, - poll_table *wait) -{ - __poll_t ret; - - mutex_lock(&queue->mutex); - ret = vb2_poll(&queue->queue, file, wait); - mutex_unlock(&queue->mutex); - - return ret; -} - /* ----------------------------------------------------------------------------- * */ /* - * Check if buffers have been allocated. - */ -int uvc_queue_allocated(struct uvc_video_queue *queue) -{ - int allocated; - - mutex_lock(&queue->mutex); - allocated = vb2_is_busy(&queue->queue); - mutex_unlock(&queue->mutex); - - return allocated; -} - -/* * Cancel the video buffers queue. * * Cancelling the queue marks all buffers on the irq queue as erroneous, @@ -408,7 +291,7 @@ void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect) unsigned long flags; spin_lock_irqsave(&queue->irqlock, flags); - uvc_queue_return_buffers(queue, UVC_BUF_STATE_ERROR); + __uvc_queue_return_buffers(queue, UVC_BUF_STATE_ERROR); /* * This must be protected by the irqlock spinlock to avoid race * conditions between uvc_buffer_queue and the disconnection event that @@ -472,14 +355,15 @@ static void uvc_queue_buffer_complete(struct kref *ref) struct vb2_buffer *vb = &buf->buf.vb2_buf; struct uvc_video_queue *queue = vb2_get_drv_priv(vb->vb2_queue); - if ((queue->flags & UVC_QUEUE_DROP_CORRUPTED) && buf->error) { + if (buf->error && !uvc_no_drop_param) { uvc_queue_buffer_requeue(queue, buf); return; } buf->state = buf->error ? UVC_BUF_STATE_ERROR : UVC_BUF_STATE_DONE; vb2_set_plane_payload(&buf->buf.vb2_buf, 0, buf->bytesused); - vb2_buffer_done(&buf->buf.vb2_buf, VB2_BUF_STATE_DONE); + vb2_buffer_done(&buf->buf.vb2_buf, buf->error ? VB2_BUF_STATE_ERROR : + VB2_BUF_STATE_DONE); } /* diff --git a/drivers/media/usb/uvc/uvc_status.c b/drivers/media/usb/uvc/uvc_status.c index 06c867510c8f..231cfee8e7c2 100644 --- a/drivers/media/usb/uvc/uvc_status.c +++ b/drivers/media/usb/uvc/uvc_status.c @@ -62,7 +62,8 @@ static int uvc_input_init(struct uvc_device *dev) __set_bit(EV_KEY, input->evbit); __set_bit(KEY_CAMERA, input->keybit); - if ((ret = input_register_device(input)) < 0) + ret = input_register_device(input); + if (ret < 0) goto error; dev->input = input; @@ -215,7 +216,7 @@ static void uvc_status_complete(struct urb *urb) return; default: - dev_warn(&dev->udev->dev, + dev_warn(&dev->intf->dev, "Non-zero status (%d) in status completion handler.\n", urb->status); return; @@ -247,7 +248,7 @@ static void uvc_status_complete(struct urb *urb) urb->interval = dev->int_ep->desc.bInterval; ret = usb_submit_urb(urb, GFP_ATOMIC); if (ret < 0) - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "Failed to resubmit status URB (%d).\n", ret); } @@ -262,8 +263,6 @@ int uvc_status_init(struct uvc_device *dev) if (ep == NULL) return 0; - uvc_input_init(dev); - dev->status = kzalloc(sizeof(*dev->status), GFP_KERNEL); if (!dev->status) return -ENOMEM; @@ -271,6 +270,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; } @@ -289,11 +289,16 @@ 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) { + if (!dev->status) + return; + uvc_status_suspend(dev); uvc_input_unregister(dev); } diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c index 97c5407f6603..9e4a251eca88 100644 --- a/drivers/media/usb/uvc/uvc_v4l2.c +++ b/drivers/media/usb/uvc/uvc_v4l2.c @@ -26,6 +26,27 @@ #include "uvcvideo.h" +int uvc_pm_get(struct uvc_device *dev) +{ + int ret; + + ret = usb_autopm_get_interface(dev->intf); + if (ret) + return ret; + + ret = uvc_status_get(dev); + if (ret) + usb_autopm_put_interface(dev->intf); + + return ret; +} + +void uvc_pm_put(struct uvc_device *dev) +{ + uvc_status_put(dev); + usb_autopm_put_interface(dev->intf); +} + static int uvc_control_add_xu_mapping(struct uvc_video_chain *chain, struct uvc_control_mapping *map, const struct uvc_xu_control_mapping *xmap) @@ -106,6 +127,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; @@ -302,14 +329,12 @@ static int uvc_v4l2_try_format(struct uvc_streaming *stream, * developers test their webcams with the Linux driver as well as with * the Windows driver). */ - mutex_lock(&stream->mutex); if (stream->dev->quirks & UVC_QUIRK_PROBE_EXTRAFIELDS) probe->dwMaxVideoFrameSize = stream->ctrl.dwMaxVideoFrameSize; /* Probe the device. */ ret = uvc_probe_video(stream, probe); - mutex_unlock(&stream->mutex); if (ret < 0) return ret; @@ -361,24 +386,22 @@ static int uvc_v4l2_try_format(struct uvc_streaming *stream, return ret; } -static int uvc_v4l2_get_format(struct uvc_streaming *stream, - struct v4l2_format *fmt) +static int uvc_ioctl_g_fmt(struct file *file, void *priv, + struct v4l2_format *fmt) { + struct uvc_fh *handle = to_uvc_fh(file); + struct uvc_streaming *stream = handle->stream; const struct uvc_format *format; const struct uvc_frame *frame; - int ret = 0; if (fmt->type != stream->type) return -EINVAL; - mutex_lock(&stream->mutex); format = stream->cur_format; frame = stream->cur_frame; - if (format == NULL || frame == NULL) { - ret = -EINVAL; - goto done; - } + if (!format || !frame) + return -EINVAL; fmt->fmt.pix.pixelformat = format->fcc; fmt->fmt.pix.width = frame->wWidth; @@ -390,14 +413,14 @@ static int uvc_v4l2_get_format(struct uvc_streaming *stream, fmt->fmt.pix.xfer_func = format->xfer_func; fmt->fmt.pix.ycbcr_enc = format->ycbcr_enc; -done: - mutex_unlock(&stream->mutex); - return ret; + return 0; } -static int uvc_v4l2_set_format(struct uvc_streaming *stream, - struct v4l2_format *fmt) +static int uvc_ioctl_s_fmt(struct file *file, void *priv, + struct v4l2_format *fmt) { + struct uvc_fh *handle = to_uvc_fh(file); + struct uvc_streaming *stream = handle->stream; struct uvc_streaming_control probe; const struct uvc_format *format; const struct uvc_frame *frame; @@ -410,34 +433,27 @@ static int uvc_v4l2_set_format(struct uvc_streaming *stream, if (ret < 0) return ret; - mutex_lock(&stream->mutex); - - if (uvc_queue_allocated(&stream->queue)) { - ret = -EBUSY; - goto done; - } + if (vb2_is_busy(&stream->queue.queue)) + return -EBUSY; stream->ctrl = probe; stream->cur_format = format; stream->cur_frame = frame; -done: - mutex_unlock(&stream->mutex); - return ret; + return 0; } -static int uvc_v4l2_get_streamparm(struct uvc_streaming *stream, - struct v4l2_streamparm *parm) +static int uvc_ioctl_g_parm(struct file *file, void *priv, + struct v4l2_streamparm *parm) { u32 numerator, denominator; + struct uvc_fh *handle = to_uvc_fh(file); + struct uvc_streaming *stream = handle->stream; if (parm->type != stream->type) return -EINVAL; - mutex_lock(&stream->mutex); numerator = stream->ctrl.dwFrameInterval; - mutex_unlock(&stream->mutex); - denominator = 10000000; v4l2_simplify_fraction(&numerator, &denominator, 8, 333); @@ -461,9 +477,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 *priv, + struct v4l2_streamparm *parm) { + struct uvc_fh *handle = to_uvc_fh(file); + struct uvc_streaming *stream = handle->stream; struct uvc_streaming_control probe; struct v4l2_fract timeperframe; const struct uvc_format *format; @@ -485,12 +503,8 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream, uvc_dbg(stream->dev, FORMAT, "Setting frame interval to %u/%u (%u)\n", timeperframe.numerator, timeperframe.denominator, interval); - mutex_lock(&stream->mutex); - - if (uvc_queue_streaming(&stream->queue)) { - mutex_unlock(&stream->mutex); + if (uvc_queue_streaming(&stream->queue)) return -EBUSY; - } format = stream->cur_format; frame = stream->cur_frame; @@ -522,14 +536,11 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream, /* Probe the device with the new settings. */ ret = uvc_probe_video(stream, &probe); - if (ret < 0) { - mutex_unlock(&stream->mutex); + if (ret < 0) return ret; - } stream->ctrl = probe; stream->cur_frame = frame; - mutex_unlock(&stream->mutex); /* Return the actual frame period. */ timeperframe.numerator = probe.dwFrameInterval; @@ -549,62 +560,6 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream, } /* ------------------------------------------------------------------------ - * Privilege management - */ - -/* - * Privilege management is the multiple-open implementation basis. The current - * implementation is completely transparent for the end-user and doesn't - * require explicit use of the VIDIOC_G_PRIORITY and VIDIOC_S_PRIORITY ioctls. - * Those ioctls enable finer control on the device (by making possible for a - * user to request exclusive access to a device), but are not mature yet. - * Switching to the V4L2 priority mechanism might be considered in the future - * if this situation changes. - * - * Each open instance of a UVC device can either be in a privileged or - * unprivileged state. Only a single instance can be in a privileged state at - * a given time. Trying to perform an operation that requires privileges will - * automatically acquire the required privileges if possible, or return -EBUSY - * otherwise. Privileges are dismissed when closing the instance or when - * freeing the video buffers using VIDIOC_REQBUFS. - * - * Operations that require privileges are: - * - * - VIDIOC_S_INPUT - * - VIDIOC_S_PARM - * - VIDIOC_S_FMT - * - VIDIOC_REQBUFS - */ -static int uvc_acquire_privileges(struct uvc_fh *handle) -{ - /* Always succeed if the handle is already privileged. */ - if (handle->state == UVC_HANDLE_ACTIVE) - return 0; - - /* Check if the device already has a privileged handle. */ - if (atomic_inc_return(&handle->stream->active) != 1) { - atomic_dec(&handle->stream->active); - return -EBUSY; - } - - handle->state = UVC_HANDLE_ACTIVE; - return 0; -} - -static void uvc_dismiss_privileges(struct uvc_fh *handle) -{ - if (handle->state == UVC_HANDLE_ACTIVE) - atomic_dec(&handle->stream->active); - - handle->state = UVC_HANDLE_PASSIVE; -} - -static int uvc_has_privileges(struct uvc_fh *handle) -{ - return handle->state == UVC_HANDLE_ACTIVE; -} - -/* ------------------------------------------------------------------------ * V4L2 file operations */ @@ -612,67 +567,42 @@ static int uvc_v4l2_open(struct file *file) { struct uvc_streaming *stream; struct uvc_fh *handle; - int ret = 0; stream = video_drvdata(file); uvc_dbg(stream->dev, CALLS, "%s\n", __func__); - ret = usb_autopm_get_interface(stream->dev->intf); - if (ret < 0) - return ret; - /* Create the device handle. */ handle = kzalloc(sizeof(*handle), GFP_KERNEL); - if (handle == NULL) { - usb_autopm_put_interface(stream->dev->intf); + if (!handle) return -ENOMEM; - } - ret = uvc_status_get(stream->dev); - if (ret) { - usb_autopm_put_interface(stream->dev->intf); - kfree(handle); - return ret; - } - - v4l2_fh_init(&handle->vfh, &stream->vdev); - v4l2_fh_add(&handle->vfh); + v4l2_fh_init(&handle->vfh, &stream->queue.vdev); + v4l2_fh_add(&handle->vfh, file); handle->chain = stream->chain; handle->stream = stream; - handle->state = UVC_HANDLE_PASSIVE; - file->private_data = handle; return 0; } static int uvc_v4l2_release(struct file *file) { - struct uvc_fh *handle = file->private_data; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_streaming *stream = handle->stream; uvc_dbg(stream->dev, CALLS, "%s\n", __func__); - /* Only free resources if this is a privileged handle. */ - if (uvc_has_privileges(handle)) - uvc_queue_release(&stream->queue); + uvc_ctrl_cleanup_fh(handle); /* Release the file handle. */ - uvc_dismiss_privileges(handle); - v4l2_fh_del(&handle->vfh); - v4l2_fh_exit(&handle->vfh); - kfree(handle); - file->private_data = NULL; - - uvc_status_put(stream->dev); + vb2_fop_release(file); - usb_autopm_put_interface(stream->dev->intf); return 0; } -static int uvc_ioctl_querycap(struct file *file, void *fh, +static int uvc_ioctl_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct uvc_fh *handle = file->private_data; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_video_chain *chain = handle->chain; struct uvc_streaming *stream = handle->stream; @@ -685,11 +615,13 @@ static int uvc_ioctl_querycap(struct file *file, void *fh, return 0; } -static int uvc_ioctl_enum_fmt(struct uvc_streaming *stream, +static int uvc_ioctl_enum_fmt(struct file *file, void *priv, struct v4l2_fmtdesc *fmt) { - const struct uvc_format *format; + struct uvc_fh *handle = to_uvc_fh(file); + struct uvc_streaming *stream = handle->stream; enum v4l2_buf_type type = fmt->type; + const struct uvc_format *format; u32 index = fmt->index; if (fmt->type != stream->type || fmt->index >= stream->nformats) @@ -707,212 +639,20 @@ 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) +static int uvc_ioctl_try_fmt(struct file *file, void *priv, + struct v4l2_format *fmt) { - struct uvc_fh *handle = fh; - struct uvc_streaming *stream = handle->stream; - - return uvc_ioctl_enum_fmt(stream, fmt); -} - -static int uvc_ioctl_g_fmt_vid_cap(struct file *file, void *fh, - struct v4l2_format *fmt) -{ - struct uvc_fh *handle = fh; - struct uvc_streaming *stream = handle->stream; - - return uvc_v4l2_get_format(stream, fmt); -} - -static int uvc_ioctl_g_fmt_vid_out(struct file *file, void *fh, - struct v4l2_format *fmt) -{ - struct uvc_fh *handle = fh; - struct uvc_streaming *stream = handle->stream; - - return uvc_v4l2_get_format(stream, fmt); -} - -static int uvc_ioctl_s_fmt_vid_cap(struct file *file, void *fh, - struct v4l2_format *fmt) -{ - struct uvc_fh *handle = fh; - struct uvc_streaming *stream = handle->stream; - int ret; - - ret = uvc_acquire_privileges(handle); - if (ret < 0) - return ret; - - return uvc_v4l2_set_format(stream, fmt); -} - -static int uvc_ioctl_s_fmt_vid_out(struct file *file, void *fh, - struct v4l2_format *fmt) -{ - struct uvc_fh *handle = fh; - struct uvc_streaming *stream = handle->stream; - int ret; - - ret = uvc_acquire_privileges(handle); - if (ret < 0) - return ret; - - return uvc_v4l2_set_format(stream, fmt); -} - -static int uvc_ioctl_try_fmt_vid_cap(struct file *file, void *fh, - struct v4l2_format *fmt) -{ - struct uvc_fh *handle = fh; - struct uvc_streaming *stream = handle->stream; - struct uvc_streaming_control probe; - - return uvc_v4l2_try_format(stream, fmt, &probe, NULL, NULL); -} - -static int uvc_ioctl_try_fmt_vid_out(struct file *file, void *fh, - struct v4l2_format *fmt) -{ - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_streaming *stream = handle->stream; struct uvc_streaming_control probe; return uvc_v4l2_try_format(stream, fmt, &probe, NULL, NULL); } -static int uvc_ioctl_reqbufs(struct file *file, void *fh, - struct v4l2_requestbuffers *rb) -{ - struct uvc_fh *handle = fh; - struct uvc_streaming *stream = handle->stream; - int ret; - - ret = uvc_acquire_privileges(handle); - if (ret < 0) - return ret; - - mutex_lock(&stream->mutex); - ret = uvc_request_buffers(&stream->queue, rb); - mutex_unlock(&stream->mutex); - if (ret < 0) - return ret; - - if (ret == 0) - uvc_dismiss_privileges(handle); - - return 0; -} - -static int uvc_ioctl_querybuf(struct file *file, void *fh, - struct v4l2_buffer *buf) -{ - struct uvc_fh *handle = fh; - struct uvc_streaming *stream = handle->stream; - - if (!uvc_has_privileges(handle)) - return -EBUSY; - - return uvc_query_buffer(&stream->queue, buf); -} - -static int uvc_ioctl_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf) -{ - struct uvc_fh *handle = fh; - struct uvc_streaming *stream = handle->stream; - - if (!uvc_has_privileges(handle)) - return -EBUSY; - - return uvc_queue_buffer(&stream->queue, - stream->vdev.v4l2_dev->mdev, buf); -} - -static int uvc_ioctl_expbuf(struct file *file, void *fh, - struct v4l2_exportbuffer *exp) -{ - struct uvc_fh *handle = fh; - struct uvc_streaming *stream = handle->stream; - - if (!uvc_has_privileges(handle)) - return -EBUSY; - - return uvc_export_buffer(&stream->queue, exp); -} - -static int uvc_ioctl_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf) -{ - struct uvc_fh *handle = fh; - struct uvc_streaming *stream = handle->stream; - - if (!uvc_has_privileges(handle)) - return -EBUSY; - - return uvc_dequeue_buffer(&stream->queue, buf, - file->f_flags & O_NONBLOCK); -} - -static int uvc_ioctl_create_bufs(struct file *file, void *fh, - struct v4l2_create_buffers *cb) -{ - struct uvc_fh *handle = fh; - struct uvc_streaming *stream = handle->stream; - int ret; - - ret = uvc_acquire_privileges(handle); - if (ret < 0) - return ret; - - return uvc_create_buffers(&stream->queue, cb); -} - -static int uvc_ioctl_streamon(struct file *file, void *fh, - enum v4l2_buf_type type) -{ - struct uvc_fh *handle = fh; - struct uvc_streaming *stream = handle->stream; - int ret; - - if (!uvc_has_privileges(handle)) - return -EBUSY; - - mutex_lock(&stream->mutex); - ret = uvc_queue_streamon(&stream->queue, type); - mutex_unlock(&stream->mutex); - - return ret; -} - -static int uvc_ioctl_streamoff(struct file *file, void *fh, - enum v4l2_buf_type type) -{ - struct uvc_fh *handle = fh; - struct uvc_streaming *stream = handle->stream; - - if (!uvc_has_privileges(handle)) - return -EBUSY; - - mutex_lock(&stream->mutex); - uvc_queue_streamoff(&stream->queue, type); - mutex_unlock(&stream->mutex); - - return 0; -} - -static int uvc_ioctl_enum_input(struct file *file, void *fh, +static int uvc_ioctl_enum_input(struct file *file, void *priv, struct v4l2_input *input) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_video_chain *chain = handle->chain; const struct uvc_entity *selector = chain->selector; struct uvc_entity *iterm = NULL; @@ -952,9 +692,9 @@ static int uvc_ioctl_enum_input(struct file *file, void *fh, return 0; } -static int uvc_ioctl_g_input(struct file *file, void *fh, unsigned int *input) +static int uvc_ioctl_g_input(struct file *file, void *priv, unsigned int *input) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_video_chain *chain = handle->chain; u8 *buf; int ret; @@ -980,16 +720,16 @@ static int uvc_ioctl_g_input(struct file *file, void *fh, unsigned int *input) return ret; } -static int uvc_ioctl_s_input(struct file *file, void *fh, unsigned int input) +static int uvc_ioctl_s_input(struct file *file, void *priv, unsigned int input) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); + struct uvc_streaming *stream = handle->stream; struct uvc_video_chain *chain = handle->chain; u8 *buf; int ret; - ret = uvc_acquire_privileges(handle); - if (ret < 0) - return ret; + if (vb2_is_busy(&stream->queue.queue)) + return -EBUSY; if (chain->selector == NULL || (chain->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) { @@ -1014,42 +754,13 @@ static int uvc_ioctl_s_input(struct file *file, void *fh, unsigned int input) return ret; } -static int uvc_ioctl_queryctrl(struct file *file, void *fh, - struct v4l2_queryctrl *qc) -{ - struct uvc_fh *handle = fh; - struct uvc_video_chain *chain = handle->chain; - - return uvc_query_v4l2_ctrl(chain, qc); -} - -static int uvc_ioctl_query_ext_ctrl(struct file *file, void *fh, +static int uvc_ioctl_query_ext_ctrl(struct file *file, void *priv, struct v4l2_query_ext_ctrl *qec) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_video_chain *chain = handle->chain; - struct v4l2_queryctrl qc = { qec->id }; - int ret; - - ret = uvc_query_v4l2_ctrl(chain, &qc); - if (ret) - return ret; - qec->id = qc.id; - qec->type = qc.type; - strscpy(qec->name, qc.name, sizeof(qec->name)); - qec->minimum = qc.minimum; - qec->maximum = qc.maximum; - qec->step = qc.step; - qec->default_value = qc.default_value; - qec->flags = qc.flags; - qec->elem_size = 4; - qec->elems = 1; - qec->nr_of_dims = 0; - memset(qec->dims, 0, sizeof(qec->dims)); - memset(qec->reserved, 0, sizeof(qec->reserved)); - - return 0; + return uvc_query_v4l2_ctrl(chain, qec); } static int uvc_ctrl_check_access(struct uvc_video_chain *chain, @@ -1071,41 +782,40 @@ static int uvc_ctrl_check_access(struct uvc_video_chain *chain, return ret; } -static int uvc_ioctl_g_ext_ctrls(struct file *file, void *fh, +static int uvc_ioctl_g_ext_ctrls(struct file *file, void *priv, struct v4l2_ext_controls *ctrls) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_video_chain *chain = handle->chain; struct v4l2_ext_control *ctrl = ctrls->controls; unsigned int i; + u32 which; int ret; + if (!ctrls->count) + return 0; + + switch (ctrls->which) { + case V4L2_CTRL_WHICH_DEF_VAL: + case V4L2_CTRL_WHICH_CUR_VAL: + case V4L2_CTRL_WHICH_MAX_VAL: + case V4L2_CTRL_WHICH_MIN_VAL: + which = ctrls->which; + break; + default: + which = V4L2_CTRL_WHICH_CUR_VAL; + } + ret = uvc_ctrl_check_access(chain, ctrls, VIDIOC_G_EXT_CTRLS); if (ret < 0) return ret; - if (ctrls->which == V4L2_CTRL_WHICH_DEF_VAL) { - for (i = 0; i < ctrls->count; ++ctrl, ++i) { - struct v4l2_queryctrl qc = { .id = ctrl->id }; - - ret = uvc_query_v4l2_ctrl(chain, &qc); - if (ret < 0) { - ctrls->error_idx = i; - return ret; - } - - ctrl->value = qc.default_value; - } - - return 0; - } - ret = uvc_ctrl_begin(chain); if (ret < 0) return ret; for (i = 0; i < ctrls->count; ++ctrl, ++i) { - ret = uvc_ctrl_get(chain, ctrl); + ret = uvc_ctrl_get(chain, which, ctrl); if (ret < 0) { uvc_ctrl_rollback(handle); ctrls->error_idx = i; @@ -1127,6 +837,9 @@ static int uvc_ioctl_s_try_ext_ctrls(struct uvc_fh *handle, unsigned int i; int ret; + if (!ctrls->count) + return 0; + ret = uvc_ctrl_check_access(chain, ctrls, ioctl); if (ret < 0) return ret; @@ -1153,35 +866,35 @@ static int uvc_ioctl_s_try_ext_ctrls(struct uvc_fh *handle, return uvc_ctrl_rollback(handle); } -static int uvc_ioctl_s_ext_ctrls(struct file *file, void *fh, +static int uvc_ioctl_s_ext_ctrls(struct file *file, void *priv, struct v4l2_ext_controls *ctrls) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); return uvc_ioctl_s_try_ext_ctrls(handle, ctrls, VIDIOC_S_EXT_CTRLS); } -static int uvc_ioctl_try_ext_ctrls(struct file *file, void *fh, +static int uvc_ioctl_try_ext_ctrls(struct file *file, void *priv, struct v4l2_ext_controls *ctrls) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); return uvc_ioctl_s_try_ext_ctrls(handle, ctrls, VIDIOC_TRY_EXT_CTRLS); } -static int uvc_ioctl_querymenu(struct file *file, void *fh, +static int uvc_ioctl_querymenu(struct file *file, void *priv, struct v4l2_querymenu *qm) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_video_chain *chain = handle->chain; return uvc_query_v4l2_menu(chain, qm); } -static int uvc_ioctl_g_selection(struct file *file, void *fh, +static int uvc_ioctl_g_selection(struct file *file, void *priv, struct v4l2_selection *sel) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_streaming *stream = handle->stream; if (sel->type != stream->type) @@ -1204,41 +917,16 @@ static int uvc_ioctl_g_selection(struct file *file, void *fh, sel->r.left = 0; sel->r.top = 0; - mutex_lock(&stream->mutex); sel->r.width = stream->cur_frame->wWidth; sel->r.height = stream->cur_frame->wHeight; - mutex_unlock(&stream->mutex); return 0; } -static int uvc_ioctl_g_parm(struct file *file, void *fh, - struct v4l2_streamparm *parm) -{ - struct uvc_fh *handle = fh; - struct uvc_streaming *stream = handle->stream; - - return uvc_v4l2_get_streamparm(stream, parm); -} - -static int uvc_ioctl_s_parm(struct file *file, void *fh, - struct v4l2_streamparm *parm) -{ - struct uvc_fh *handle = fh; - struct uvc_streaming *stream = handle->stream; - int ret; - - ret = uvc_acquire_privileges(handle); - if (ret < 0) - return ret; - - return uvc_v4l2_set_streamparm(stream, parm); -} - -static int uvc_ioctl_enum_framesizes(struct file *file, void *fh, +static int uvc_ioctl_enum_framesizes(struct file *file, void *priv, struct v4l2_frmsizeenum *fsize) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_streaming *stream = handle->stream; const struct uvc_format *format = NULL; const struct uvc_frame *frame = NULL; @@ -1275,10 +963,10 @@ static int uvc_ioctl_enum_framesizes(struct file *file, void *fh, return 0; } -static int uvc_ioctl_enum_frameintervals(struct file *file, void *fh, +static int uvc_ioctl_enum_frameintervals(struct file *file, void *priv, struct v4l2_frmivalenum *fival) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_streaming *stream = handle->stream; const struct uvc_format *format = NULL; const struct uvc_frame *frame = NULL; @@ -1347,10 +1035,10 @@ static int uvc_ioctl_subscribe_event(struct v4l2_fh *fh, } } -static long uvc_ioctl_default(struct file *file, void *fh, bool valid_prio, +static long uvc_ioctl_default(struct file *file, void *priv, bool valid_prio, unsigned int cmd, void *arg) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_video_chain *chain = handle->chain; switch (cmd) { @@ -1456,7 +1144,7 @@ static int uvc_v4l2_put_xu_query(const struct uvc_xu_control_query *kp, static long uvc_v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) { - struct uvc_fh *handle = file->private_data; + struct uvc_fh *handle = to_uvc_fh(file); union { struct uvc_xu_control_mapping xmap; struct uvc_xu_control_query xqry; @@ -1464,114 +1152,112 @@ static long uvc_v4l2_compat_ioctl32(struct file *file, void __user *up = compat_ptr(arg); long ret; + ret = uvc_pm_get(handle->stream->dev); + if (ret) + return ret; + switch (cmd) { case UVCIOC_CTRL_MAP32: ret = uvc_v4l2_get_xu_mapping(&karg.xmap, up); if (ret) - return ret; + break; ret = uvc_ioctl_xu_ctrl_map(handle->chain, &karg.xmap); if (ret) - return ret; + break; ret = uvc_v4l2_put_xu_mapping(&karg.xmap, up); if (ret) - return ret; - + break; break; case UVCIOC_CTRL_QUERY32: ret = uvc_v4l2_get_xu_query(&karg.xqry, up); if (ret) - return ret; + break; ret = uvc_xu_ctrl_query(handle->chain, &karg.xqry); if (ret) - return ret; + break; ret = uvc_v4l2_put_xu_query(&karg.xqry, up); if (ret) - return ret; + break; break; default: - return -ENOIOCTLCMD; + ret = -ENOIOCTLCMD; + break; } + uvc_pm_put(handle->stream->dev); + return ret; } #endif -static ssize_t uvc_v4l2_read(struct file *file, char __user *data, - size_t count, loff_t *ppos) -{ - struct uvc_fh *handle = file->private_data; - struct uvc_streaming *stream = handle->stream; - - uvc_dbg(stream->dev, CALLS, "%s: not implemented\n", __func__); - return -EINVAL; -} - -static int uvc_v4l2_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct uvc_fh *handle = file->private_data; - struct uvc_streaming *stream = handle->stream; - - uvc_dbg(stream->dev, CALLS, "%s\n", __func__); - - return uvc_queue_mmap(&stream->queue, vma); -} - -static __poll_t uvc_v4l2_poll(struct file *file, poll_table *wait) -{ - struct uvc_fh *handle = file->private_data; - struct uvc_streaming *stream = handle->stream; - - uvc_dbg(stream->dev, CALLS, "%s\n", __func__); - - return uvc_queue_poll(&stream->queue, file, wait); -} - -#ifndef CONFIG_MMU -static unsigned long uvc_v4l2_get_unmapped_area(struct file *file, - unsigned long addr, unsigned long len, unsigned long pgoff, - unsigned long flags) +static long uvc_v4l2_unlocked_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) { - struct uvc_fh *handle = file->private_data; - struct uvc_streaming *stream = handle->stream; + struct uvc_fh *handle = to_uvc_fh(file); + unsigned int converted_cmd = v4l2_translate_cmd(cmd); + int ret; - uvc_dbg(stream->dev, CALLS, "%s\n", __func__); + /* The following IOCTLs need to turn on the camera. */ + switch (converted_cmd) { + case UVCIOC_CTRL_MAP: + case UVCIOC_CTRL_QUERY: + case VIDIOC_G_CTRL: + case VIDIOC_G_EXT_CTRLS: + case VIDIOC_G_INPUT: + case VIDIOC_QUERYCTRL: + case VIDIOC_QUERYMENU: + case VIDIOC_QUERY_EXT_CTRL: + case VIDIOC_S_CTRL: + case VIDIOC_S_EXT_CTRLS: + case VIDIOC_S_FMT: + case VIDIOC_S_INPUT: + case VIDIOC_S_PARM: + case VIDIOC_TRY_EXT_CTRLS: + case VIDIOC_TRY_FMT: + ret = uvc_pm_get(handle->stream->dev); + if (ret) + return ret; + ret = video_ioctl2(file, cmd, arg); + uvc_pm_put(handle->stream->dev); + return ret; + } - return uvc_queue_get_unmapped_area(&stream->queue, pgoff); + /* The other IOCTLs can run with the camera off. */ + return video_ioctl2(file, cmd, arg); } -#endif const struct v4l2_ioctl_ops uvc_ioctl_ops = { + .vidioc_g_fmt_vid_cap = uvc_ioctl_g_fmt, + .vidioc_g_fmt_vid_out = uvc_ioctl_g_fmt, + .vidioc_s_fmt_vid_cap = uvc_ioctl_s_fmt, + .vidioc_s_fmt_vid_out = uvc_ioctl_s_fmt, + .vidioc_g_parm = uvc_ioctl_g_parm, + .vidioc_s_parm = uvc_ioctl_s_parm, .vidioc_querycap = uvc_ioctl_querycap, - .vidioc_enum_fmt_vid_cap = uvc_ioctl_enum_fmt_vid_cap, - .vidioc_enum_fmt_vid_out = uvc_ioctl_enum_fmt_vid_out, - .vidioc_g_fmt_vid_cap = uvc_ioctl_g_fmt_vid_cap, - .vidioc_g_fmt_vid_out = uvc_ioctl_g_fmt_vid_out, - .vidioc_s_fmt_vid_cap = uvc_ioctl_s_fmt_vid_cap, - .vidioc_s_fmt_vid_out = uvc_ioctl_s_fmt_vid_out, - .vidioc_try_fmt_vid_cap = uvc_ioctl_try_fmt_vid_cap, - .vidioc_try_fmt_vid_out = uvc_ioctl_try_fmt_vid_out, - .vidioc_reqbufs = uvc_ioctl_reqbufs, - .vidioc_querybuf = uvc_ioctl_querybuf, - .vidioc_qbuf = uvc_ioctl_qbuf, - .vidioc_expbuf = uvc_ioctl_expbuf, - .vidioc_dqbuf = uvc_ioctl_dqbuf, - .vidioc_create_bufs = uvc_ioctl_create_bufs, - .vidioc_streamon = uvc_ioctl_streamon, - .vidioc_streamoff = uvc_ioctl_streamoff, + .vidioc_enum_fmt_vid_cap = uvc_ioctl_enum_fmt, + .vidioc_enum_fmt_vid_out = uvc_ioctl_enum_fmt, + .vidioc_try_fmt_vid_cap = uvc_ioctl_try_fmt, + .vidioc_try_fmt_vid_out = uvc_ioctl_try_fmt, + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, .vidioc_enum_input = uvc_ioctl_enum_input, .vidioc_g_input = uvc_ioctl_g_input, .vidioc_s_input = uvc_ioctl_s_input, - .vidioc_queryctrl = uvc_ioctl_queryctrl, .vidioc_query_ext_ctrl = uvc_ioctl_query_ext_ctrl, .vidioc_g_ext_ctrls = uvc_ioctl_g_ext_ctrls, .vidioc_s_ext_ctrls = uvc_ioctl_s_ext_ctrls, .vidioc_try_ext_ctrls = uvc_ioctl_try_ext_ctrls, .vidioc_querymenu = uvc_ioctl_querymenu, .vidioc_g_selection = uvc_ioctl_g_selection, - .vidioc_g_parm = uvc_ioctl_g_parm, - .vidioc_s_parm = uvc_ioctl_s_parm, .vidioc_enum_framesizes = uvc_ioctl_enum_framesizes, .vidioc_enum_frameintervals = uvc_ioctl_enum_frameintervals, .vidioc_subscribe_event = uvc_ioctl_subscribe_event, @@ -1583,15 +1269,14 @@ const struct v4l2_file_operations uvc_fops = { .owner = THIS_MODULE, .open = uvc_v4l2_open, .release = uvc_v4l2_release, - .unlocked_ioctl = video_ioctl2, + .unlocked_ioctl = uvc_v4l2_unlocked_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl32 = uvc_v4l2_compat_ioctl32, #endif - .read = uvc_v4l2_read, - .mmap = uvc_v4l2_mmap, - .poll = uvc_v4l2_poll, + .mmap = vb2_fop_mmap, + .poll = vb2_fop_poll, #ifndef CONFIG_MMU - .get_unmapped_area = uvc_v4l2_get_unmapped_area, + .get_unmapped_area = vb2_fop_get_unmapped_area, #endif }; diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c index e00f38dd07d9..2094e059d7d3 100644 --- a/drivers/media/usb/uvc/uvc_video.c +++ b/drivers/media/usb/uvc/uvc_video.c @@ -20,6 +20,7 @@ #include <linux/atomic.h> #include <linux/unaligned.h> +#include <media/jpeg.h> #include <media/v4l2-common.h> #include "uvcvideo.h" @@ -79,8 +80,29 @@ 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->intf->dev, + "UVC non compliance: %s control %u on unit %u returned %d bytes when we expected %u.\n", + uvc_query_name(query), cs, unit, ret, size); + return 0; + } + if (ret != -EPIPE) { - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "Failed to query (%s) UVC control %u on unit %u: %d (exp. %u).\n", uvc_query_name(query), cs, unit, ret, size); return ret < 0 ? ret : -EPIPE; @@ -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->intf->dev, + "Failed to query (%s) UVC error code control %u on unit %u: %d (exp. 1).\n", + uvc_query_name(query), cs, unit, ret); return ret < 0 ? ret : -EPIPE; + } uvc_dbg(dev, CONTROL, "Control error %u\n", error); @@ -236,6 +262,15 @@ static void uvc_fixup_video_ctrl(struct uvc_streaming *stream, ctrl->dwMaxPayloadTransferSize = bandwidth; } + + if (stream->intf->num_altsetting > 1 && + ctrl->dwMaxPayloadTransferSize > stream->maxpsize) { + dev_warn_ratelimited(&stream->intf->dev, + "UVC non compliance: Reducing max payload transfer size (%u) to fit endpoint limit (%u).\n", + ctrl->dwMaxPayloadTransferSize, + stream->maxpsize); + ctrl->dwMaxPayloadTransferSize = stream->maxpsize; + } } static size_t uvc_video_ctrl_size(struct uvc_streaming *stream) @@ -297,8 +332,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; } @@ -1116,6 +1152,7 @@ static void uvc_video_stats_stop(struct uvc_streaming *stream) static int uvc_video_decode_start(struct uvc_streaming *stream, struct uvc_buffer *buf, const u8 *data, int len) { + u8 header_len; u8 fid; /* @@ -1129,6 +1166,7 @@ static int uvc_video_decode_start(struct uvc_streaming *stream, return -EINVAL; } + header_len = data[0]; fid = data[1] & UVC_STREAM_FID; /* @@ -1210,9 +1248,31 @@ static int uvc_video_decode_start(struct uvc_streaming *stream, return -EAGAIN; } + /* + * Some cameras, when running two parallel streams (one MJPEG alongside + * another non-MJPEG stream), are known to lose the EOF packet for a frame. + * We can detect the end of a frame by checking for a new SOI marker, as + * the SOI always lies on the packet boundary between two frames for + * these devices. + */ + if (stream->dev->quirks & UVC_QUIRK_MJPEG_NO_EOF && + (stream->cur_format->fcc == V4L2_PIX_FMT_MJPEG || + stream->cur_format->fcc == V4L2_PIX_FMT_JPEG)) { + const u8 *packet = data + header_len; + + if (len >= header_len + 2 && + packet[0] == 0xff && packet[1] == JPEG_MARKER_SOI && + buf->bytesused != 0) { + buf->state = UVC_BUF_STATE_READY; + buf->error = 1; + stream->last_fid ^= UVC_STREAM_FID; + return -EAGAIN; + } + } + stream->last_fid = fid; - return data[0]; + return header_len; } static inline enum dma_data_direction uvc_stream_dir( @@ -1224,20 +1284,6 @@ static inline enum dma_data_direction uvc_stream_dir( return DMA_TO_DEVICE; } -static inline struct device *uvc_stream_to_dmadev(struct uvc_streaming *stream) -{ - return bus_to_hcd(stream->dev->udev->bus)->self.sysdev; -} - -static int uvc_submit_urb(struct uvc_urb *uvc_urb, gfp_t mem_flags) -{ - /* Sync DMA. */ - dma_sync_sgtable_for_device(uvc_stream_to_dmadev(uvc_urb->stream), - uvc_urb->sgt, - uvc_stream_dir(uvc_urb->stream)); - return usb_submit_urb(uvc_urb->urb, mem_flags); -} - /* * uvc_video_decode_data_work: Asynchronous memcpy processing * @@ -1259,7 +1305,7 @@ static void uvc_video_copy_data_work(struct work_struct *work) uvc_queue_buffer_release(op->buf); } - ret = uvc_submit_urb(uvc_urb, GFP_KERNEL); + ret = usb_submit_urb(uvc_urb->urb, GFP_KERNEL); if (ret < 0) dev_err(&uvc_urb->stream->intf->dev, "Failed to resubmit video URB (%d).\n", ret); @@ -1382,12 +1428,6 @@ static void uvc_video_decode_meta(struct uvc_streaming *stream, if (!meta_buf || length == 2) return; - if (meta_buf->length - meta_buf->bytesused < - length + sizeof(meta->ns) + sizeof(meta->sof)) { - meta_buf->error = 1; - return; - } - has_pts = mem[1] & UVC_STREAM_PTS; has_scr = mem[1] & UVC_STREAM_SCR; @@ -1408,6 +1448,12 @@ static void uvc_video_decode_meta(struct uvc_streaming *stream, !memcmp(scr, stream->clock.last_scr, 6))) return; + if (meta_buf->length - meta_buf->bytesused < + length + sizeof(meta->ns) + sizeof(meta->sof)) { + meta_buf->error = 1; + return; + } + meta = (struct uvc_meta_buf *)((u8 *)meta_buf->mem + meta_buf->bytesused); local_irq_save(flags); time = uvc_video_get_time(); @@ -1645,7 +1691,7 @@ static void uvc_video_complete(struct urb *urb) struct uvc_streaming *stream = uvc_urb->stream; struct uvc_video_queue *queue = &stream->queue; struct uvc_video_queue *qmeta = &stream->meta.queue; - struct vb2_queue *vb2_qmeta = stream->meta.vdev.queue; + struct vb2_queue *vb2_qmeta = stream->meta.queue.vdev.queue; struct uvc_buffer *buf = NULL; struct uvc_buffer *buf_meta = NULL; unsigned long flags; @@ -1685,12 +1731,6 @@ static void uvc_video_complete(struct urb *urb) /* Re-initialise the URB async work. */ uvc_urb->async_operations = 0; - /* Sync DMA and invalidate vmap range. */ - dma_sync_sgtable_for_cpu(uvc_stream_to_dmadev(uvc_urb->stream), - uvc_urb->sgt, uvc_stream_dir(stream)); - invalidate_kernel_vmap_range(uvc_urb->buffer, - uvc_urb->stream->urb_size); - /* * Process the URB headers, and optionally queue expensive memcpy tasks * to be deferred to a work queue. @@ -1699,7 +1739,7 @@ static void uvc_video_complete(struct urb *urb) /* If no async work is needed, resubmit the URB immediately. */ if (!uvc_urb->async_operations) { - ret = uvc_submit_urb(uvc_urb, GFP_ATOMIC); + ret = usb_submit_urb(uvc_urb->urb, GFP_ATOMIC); if (ret < 0) dev_err(&stream->intf->dev, "Failed to resubmit video URB (%d).\n", ret); @@ -1714,17 +1754,15 @@ static void uvc_video_complete(struct urb *urb) */ static void uvc_free_urb_buffers(struct uvc_streaming *stream) { - struct device *dma_dev = uvc_stream_to_dmadev(stream); + struct usb_device *udev = stream->dev->udev; struct uvc_urb *uvc_urb; for_each_uvc_urb(uvc_urb, stream) { if (!uvc_urb->buffer) continue; - dma_vunmap_noncontiguous(dma_dev, uvc_urb->buffer); - dma_free_noncontiguous(dma_dev, stream->urb_size, uvc_urb->sgt, - uvc_stream_dir(stream)); - + usb_free_noncoherent(udev, stream->urb_size, uvc_urb->buffer, + uvc_stream_dir(stream), uvc_urb->sgt); uvc_urb->buffer = NULL; uvc_urb->sgt = NULL; } @@ -1735,26 +1773,13 @@ static void uvc_free_urb_buffers(struct uvc_streaming *stream) static bool uvc_alloc_urb_buffer(struct uvc_streaming *stream, struct uvc_urb *uvc_urb, gfp_t gfp_flags) { - struct device *dma_dev = uvc_stream_to_dmadev(stream); - - uvc_urb->sgt = dma_alloc_noncontiguous(dma_dev, stream->urb_size, - uvc_stream_dir(stream), - gfp_flags, 0); - if (!uvc_urb->sgt) - return false; - uvc_urb->dma = uvc_urb->sgt->sgl->dma_address; - - uvc_urb->buffer = dma_vmap_noncontiguous(dma_dev, stream->urb_size, - uvc_urb->sgt); - if (!uvc_urb->buffer) { - dma_free_noncontiguous(dma_dev, stream->urb_size, - uvc_urb->sgt, - uvc_stream_dir(stream)); - uvc_urb->sgt = NULL; - return false; - } + struct usb_device *udev = stream->dev->udev; - return true; + uvc_urb->buffer = usb_alloc_noncoherent(udev, stream->urb_size, + gfp_flags, &uvc_urb->dma, + uvc_stream_dir(stream), + &uvc_urb->sgt); + return !!uvc_urb->buffer; } /* @@ -1845,24 +1870,6 @@ static void uvc_video_stop_transfer(struct uvc_streaming *stream, } /* - * Compute the maximum number of bytes per interval for an endpoint. - */ -u16 uvc_endpoint_max_bpi(struct usb_device *dev, struct usb_host_endpoint *ep) -{ - u16 psize; - - switch (dev->speed) { - case USB_SPEED_SUPER: - case USB_SPEED_SUPER_PLUS: - return le16_to_cpu(ep->ss_ep_comp.wBytesPerInterval); - default: - psize = usb_endpoint_maxp(&ep->desc); - psize *= usb_endpoint_maxp_mult(&ep->desc); - return psize; - } -} - -/* * Initialize isochronous URBs and allocate transfer buffers. The packet size * is given by the endpoint. */ @@ -1872,10 +1879,10 @@ static int uvc_init_video_isoc(struct uvc_streaming *stream, struct urb *urb; struct uvc_urb *uvc_urb; unsigned int npackets, i; - u16 psize; + u32 psize; u32 size; - psize = uvc_endpoint_max_bpi(stream->dev->udev, ep); + psize = usb_endpoint_max_periodic_payload(stream->dev->udev, ep); size = stream->ctrl.dwMaxVideoFrameSize; npackets = uvc_alloc_urb_buffers(stream, size, psize, gfp_flags); @@ -1902,6 +1909,7 @@ static int uvc_init_video_isoc(struct uvc_streaming *stream, urb->complete = uvc_video_complete; urb->number_of_packets = npackets; urb->transfer_buffer_length = size; + urb->sgt = uvc_urb->sgt; for (i = 0; i < npackets; ++i) { urb->iso_frame_desc[i].offset = i * psize; @@ -1958,6 +1966,7 @@ static int uvc_init_video_bulk(struct uvc_streaming *stream, size, uvc_video_complete, uvc_urb); urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; urb->transfer_dma = uvc_urb->dma; + urb->sgt = uvc_urb->sgt; uvc_urb->urb = urb; } @@ -2016,7 +2025,7 @@ static int uvc_video_start_transfer(struct uvc_streaming *stream, continue; /* Check if the bandwidth is high enough. */ - psize = uvc_endpoint_max_bpi(stream->dev->udev, ep); + psize = usb_endpoint_max_periodic_payload(stream->dev->udev, ep); if (psize >= bandwidth && psize < best_psize) { altsetting = alts->desc.bAlternateSetting; best_psize = psize; @@ -2069,7 +2078,7 @@ static int uvc_video_start_transfer(struct uvc_streaming *stream, /* Submit the URBs. */ for_each_uvc_urb(uvc_urb, stream) { - ret = uvc_submit_urb(uvc_urb, gfp_flags); + ret = usb_submit_urb(uvc_urb->urb, gfp_flags); if (ret < 0) { dev_err(&stream->intf->dev, "Failed to submit URB %u (%d).\n", diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index 07f9921d83f2..ed7bad31f75c 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -41,6 +41,8 @@ #define UVC_EXT_GPIO_UNIT 0x7ffe #define UVC_EXT_GPIO_UNIT_ID 0x100 +#define UVC_INVALID_ENTITY_ID 0xffff + /* ------------------------------------------------------------------------ * Driver specific constants. */ @@ -76,6 +78,8 @@ #define UVC_QUIRK_NO_RESET_RESUME 0x00004000 #define UVC_QUIRK_DISABLE_AUTOSUSPEND 0x00008000 #define UVC_QUIRK_INVALID_DEVICE_SOF 0x00010000 +#define UVC_QUIRK_MJPEG_NO_EOF 0x00020000 +#define UVC_QUIRK_MSXU_META 0x00040000 /* Format flags */ #define UVC_FMT_FLAG_COMPRESSED 0x00000001 @@ -115,7 +119,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; @@ -128,13 +137,15 @@ struct uvc_control_mapping { s32 master_manual; u32 slave_ids[2]; + bool disabled; + const struct uvc_control_mapping *(*filter_mapping) (struct uvc_video_chain *chain, struct uvc_control *ctrl); - s32 (*get)(struct uvc_control_mapping *mapping, u8 query, - const u8 *data); - void (*set)(struct uvc_control_mapping *mapping, s32 value, - u8 *data); + 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 { @@ -234,6 +245,7 @@ struct uvc_entity { u8 *bmControls; struct gpio_desc *gpio_privacy; int irq; + bool initialized; } gpio; }; @@ -316,11 +328,14 @@ struct uvc_buffer { }; #define UVC_QUEUE_DISCONNECTED (1 << 0) -#define UVC_QUEUE_DROP_CORRUPTED (1 << 1) struct uvc_video_queue { + struct video_device vdev; struct vb2_queue queue; - struct mutex mutex; /* Protects queue */ + struct mutex mutex; /* + * Serializes vb2_queue and + * fops + */ unsigned int flags; unsigned int buf_used; @@ -337,7 +352,11 @@ struct uvc_video_chain { struct uvc_entity *processing; /* Processing unit */ struct uvc_entity *selector; /* Selector unit */ - struct mutex ctrl_mutex; /* Protects ctrl.info */ + struct mutex ctrl_mutex; /* + * Protects ctrl.info, + * ctrl.handle and + * uvc_fh.pending_async_ctrls + */ struct v4l2_prio_state prio; /* V4L2 priority state */ u32 caps; /* V4L2 chain-wide caps */ @@ -434,13 +453,12 @@ struct uvc_urb { struct uvc_streaming { struct list_head list; struct uvc_device *dev; - struct video_device vdev; struct uvc_video_chain *chain; atomic_t active; struct usb_interface *intf; int intfnum; - u16 maxpsize; + u32 maxpsize; struct uvc_streaming_header header; enum v4l2_buf_type type; @@ -453,12 +471,6 @@ struct uvc_streaming { const struct uvc_format *cur_format; const struct uvc_frame *cur_frame; - /* - * Protect access to ctrl, cur_format, cur_frame and hardware video - * probe control. - */ - struct mutex mutex; - /* Buffers queue. */ unsigned int frozen : 1; struct uvc_video_queue queue; @@ -467,7 +479,6 @@ struct uvc_streaming { struct uvc_buffer *meta_buf); struct { - struct video_device vdev; struct uvc_video_queue queue; u32 format; } meta; @@ -533,6 +544,13 @@ struct uvc_device_info { u16 uvc_version; }; +struct uvc_rect { + u16 top; + u16 left; + u16 bottom; + u16 right; +} __packed; + struct uvc_status_streaming { u8 button; } __packed; @@ -553,6 +571,8 @@ struct uvc_status { }; } __packed; +#define UVC_MAX_META_DATA_FORMATS 3 + struct uvc_device { struct usb_device *udev; struct usb_interface *intf; @@ -563,6 +583,9 @@ struct uvc_device { const struct uvc_device_info *info; + u32 meta_formats[UVC_MAX_META_DATA_FORMATS]; + unsigned int nmeta_formats; + atomic_t nmappings; /* Video control interface */ @@ -602,21 +625,17 @@ struct uvc_device { struct uvc_entity *gpio_unit; }; -enum uvc_handle_state { - UVC_HANDLE_PASSIVE = 0, - UVC_HANDLE_ACTIVE = 1, -}; - struct uvc_fh { struct v4l2_fh vfh; struct uvc_video_chain *chain; struct uvc_streaming *stream; - enum uvc_handle_state state; + unsigned int pending_async_ctrls; }; -struct uvc_driver { - struct usb_driver driver; -}; +static inline struct uvc_fh *to_uvc_fh(struct file *filp) +{ + return container_of(file_to_v4l2_fh(filp), struct uvc_fh, vfh); +} /* ------------------------------------------------------------------------ * Debugging, printing and logging @@ -648,7 +667,7 @@ extern unsigned int uvc_hw_timestamps_param; #define uvc_dbg(_dev, flag, fmt, ...) \ do { \ if (uvc_dbg_param & UVC_DBG_##flag) \ - dev_printk(KERN_DEBUG, &(_dev)->udev->dev, fmt, \ + dev_printk(KERN_DEBUG, &(_dev)->intf->dev, fmt, \ ##__VA_ARGS__); \ } while (0) @@ -661,51 +680,22 @@ do { \ #define uvc_warn_once(_dev, warn, fmt, ...) \ do { \ if (!test_and_set_bit(warn, &(_dev)->warnings)) \ - dev_info(&(_dev)->udev->dev, fmt, ##__VA_ARGS__); \ + dev_info(&(_dev)->intf->dev, fmt, ##__VA_ARGS__); \ } while (0) /* -------------------------------------------------------------------------- * Internal functions. */ -/* Core driver */ -extern struct uvc_driver uvc_driver; - struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id); /* Video buffers queue management. */ -int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type, - int drop_corrupted); -void uvc_queue_release(struct uvc_video_queue *queue); -int uvc_request_buffers(struct uvc_video_queue *queue, - struct v4l2_requestbuffers *rb); -int uvc_query_buffer(struct uvc_video_queue *queue, - struct v4l2_buffer *v4l2_buf); -int uvc_create_buffers(struct uvc_video_queue *queue, - struct v4l2_create_buffers *v4l2_cb); -int uvc_queue_buffer(struct uvc_video_queue *queue, - struct media_device *mdev, - struct v4l2_buffer *v4l2_buf); -int uvc_export_buffer(struct uvc_video_queue *queue, - struct v4l2_exportbuffer *exp); -int uvc_dequeue_buffer(struct uvc_video_queue *queue, - struct v4l2_buffer *v4l2_buf, int nonblocking); -int uvc_queue_streamon(struct uvc_video_queue *queue, enum v4l2_buf_type type); -int uvc_queue_streamoff(struct uvc_video_queue *queue, enum v4l2_buf_type type); +int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type); void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect); struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue, struct uvc_buffer *buf); struct uvc_buffer *uvc_queue_get_current_buffer(struct uvc_video_queue *queue); void uvc_queue_buffer_release(struct uvc_buffer *buf); -int uvc_queue_mmap(struct uvc_video_queue *queue, - struct vm_area_struct *vma); -__poll_t uvc_queue_poll(struct uvc_video_queue *queue, struct file *file, - poll_table *wait); -#ifndef CONFIG_MMU -unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue, - unsigned long pgoff); -#endif -int uvc_queue_allocated(struct uvc_video_queue *queue); static inline int uvc_queue_streaming(struct uvc_video_queue *queue) { return vb2_is_streaming(&queue->queue); @@ -738,11 +728,11 @@ int uvc_query_ctrl(struct uvc_device *dev, u8 query, u8 unit, void uvc_video_clock_update(struct uvc_streaming *stream, struct vb2_v4l2_buffer *vbuf, struct uvc_buffer *buf); +int uvc_meta_init(struct uvc_device *dev); int uvc_meta_register(struct uvc_streaming *stream); int uvc_register_video_device(struct uvc_device *dev, struct uvc_streaming *stream, - struct video_device *vdev, struct uvc_video_queue *queue, enum v4l2_buf_type type, const struct v4l2_file_operations *fops, @@ -757,11 +747,15 @@ void uvc_status_suspend(struct uvc_device *dev); int uvc_status_get(struct uvc_device *dev); void uvc_status_put(struct uvc_device *dev); +/* PM */ +int uvc_pm_get(struct uvc_device *dev); +void uvc_pm_put(struct uvc_device *dev); + /* Controls */ extern const struct v4l2_subscribed_event_ops uvc_ctrl_sub_ev_ops; int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, - struct v4l2_queryctrl *v4l2_ctrl); + struct v4l2_query_ext_ctrl *v4l2_ctrl); int uvc_query_v4l2_menu(struct uvc_video_chain *chain, struct v4l2_querymenu *query_menu); @@ -788,7 +782,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, @@ -797,11 +792,11 @@ 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); -u16 uvc_endpoint_max_bpi(struct usb_device *dev, struct usb_host_endpoint *ep); - /* Quirks support */ void uvc_video_decode_isight(struct uvc_urb *uvc_urb, struct uvc_buffer *buf, |
