summaryrefslogtreecommitdiff
path: root/drivers/media/usb
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/usb')
-rw-r--r--drivers/media/usb/airspy/airspy.c4
-rw-r--r--drivers/media/usb/as102/as102_usb_drv.c2
-rw-r--r--drivers/media/usb/au0828/au0828-vbi.c2
-rw-r--r--drivers/media/usb/au0828/au0828-video.c7
-rw-r--r--drivers/media/usb/b2c2/flexcop-usb.c24
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-417.c6
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-avcore.c60
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-cards.c6
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-i2c.c5
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-vbi.c2
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-video.c4
-rw-r--r--drivers/media/usb/cx231xx/cx231xx.h5
-rw-r--r--drivers/media/usb/dvb-usb-v2/af9035.c28
-rw-r--r--drivers/media/usb/dvb-usb-v2/anysee.c21
-rw-r--r--drivers/media/usb/dvb-usb-v2/lmedm04.c12
-rw-r--r--drivers/media/usb/dvb-usb/cxusb-analog.c2
-rw-r--r--drivers/media/usb/dvb-usb/dib0700_devices.c18
-rw-r--r--drivers/media/usb/dvb-usb/dibusb-common.c1
-rw-r--r--drivers/media/usb/dvb-usb/dibusb-mc-common.c1
-rw-r--r--drivers/media/usb/dvb-usb/dvb-usb.h2
-rw-r--r--drivers/media/usb/dvb-usb/dw2102.c462
-rw-r--r--drivers/media/usb/dvb-usb/m920x.c2
-rw-r--r--drivers/media/usb/dvb-usb/opera1.c4
-rw-r--r--drivers/media/usb/em28xx/em28xx-cards.c56
-rw-r--r--drivers/media/usb/em28xx/em28xx-core.c3
-rw-r--r--drivers/media/usb/em28xx/em28xx-vbi.c2
-rw-r--r--drivers/media/usb/em28xx/em28xx-video.c2
-rw-r--r--drivers/media/usb/em28xx/em28xx.h1
-rw-r--r--drivers/media/usb/go7007/go7007-driver.c9
-rw-r--r--drivers/media/usb/go7007/go7007-fw.c4
-rw-r--r--drivers/media/usb/go7007/go7007-i2c.c30
-rw-r--r--drivers/media/usb/go7007/go7007-usb.c5
-rw-r--r--drivers/media/usb/go7007/go7007-v4l2.c2
-rw-r--r--drivers/media/usb/go7007/s2250-board.c2
-rw-r--r--drivers/media/usb/gspca/cpia1.c6
-rw-r--r--drivers/media/usb/gspca/gspca.c2
-rw-r--r--drivers/media/usb/gspca/ov534.c2
-rw-r--r--drivers/media/usb/hackrf/hackrf.c6
-rw-r--r--drivers/media/usb/msi2500/msi2500.c44
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-context.c10
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-debugifc.c5
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-dvb.c12
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-io.c4
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-v4l2.c11
-rw-r--r--drivers/media/usb/pwc/pwc-if.c4
-rw-r--r--drivers/media/usb/s2255/s2255drv.c29
-rw-r--r--drivers/media/usb/siano/smsusb.c22
-rw-r--r--drivers/media/usb/stk1160/stk1160-v4l.c2
-rw-r--r--drivers/media/usb/stk1160/stk1160-video.c30
-rw-r--r--drivers/media/usb/ttusb-dec/ttusb_dec.c21
-rw-r--r--drivers/media/usb/usbtv/usbtv-video.c9
-rw-r--r--drivers/media/usb/uvc/uvc_ctrl.c313
-rw-r--r--drivers/media/usb/uvc/uvc_debugfs.c1
-rw-r--r--drivers/media/usb/uvc/uvc_driver.c520
-rw-r--r--drivers/media/usb/uvc/uvc_queue.c13
-rw-r--r--drivers/media/usb/uvc/uvc_status.c71
-rw-r--r--drivers/media/usb/uvc/uvc_v4l2.c186
-rw-r--r--drivers/media/usb/uvc/uvc_video.c230
-rw-r--r--drivers/media/usb/uvc/uvcvideo.h37
59 files changed, 1328 insertions, 1058 deletions
diff --git a/drivers/media/usb/airspy/airspy.c b/drivers/media/usb/airspy/airspy.c
index e24e655fb1db..08f0920cf6ca 100644
--- a/drivers/media/usb/airspy/airspy.c
+++ b/drivers/media/usb/airspy/airspy.c
@@ -603,8 +603,6 @@ static const struct vb2_ops airspy_vb2_ops = {
.buf_queue = airspy_buf_queue,
.start_streaming = airspy_start_streaming,
.stop_streaming = airspy_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static int airspy_querycap(struct file *file, void *fh,
@@ -1017,6 +1015,7 @@ static int airspy_probe(struct usb_interface *intf,
s->vb_queue.ops = &airspy_vb2_ops;
s->vb_queue.mem_ops = &vb2_vmalloc_memops;
s->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ s->vb_queue.lock = &s->vb_queue_lock;
ret = vb2_queue_init(&s->vb_queue);
if (ret) {
dev_err(s->dev, "Could not initialize vb2 queue\n");
@@ -1026,7 +1025,6 @@ static int airspy_probe(struct usb_interface *intf,
/* Init video_device structure */
s->vdev = airspy_template;
s->vdev.queue = &s->vb_queue;
- s->vdev.queue->lock = &s->vb_queue_lock;
video_set_drvdata(&s->vdev, s);
/* Register the v4l2_device structure */
diff --git a/drivers/media/usb/as102/as102_usb_drv.c b/drivers/media/usb/as102/as102_usb_drv.c
index 6b380144d6c2..e0ef66a522e2 100644
--- a/drivers/media/usb/as102/as102_usb_drv.c
+++ b/drivers/media/usb/as102/as102_usb_drv.c
@@ -259,7 +259,7 @@ static int as102_alloc_usb_stream_buffer(struct as102_dev_t *dev)
for (i = 0; i < MAX_STREAM_URB; i++) {
struct urb *urb;
- urb = usb_alloc_urb(0, GFP_ATOMIC);
+ urb = usb_alloc_urb(0, GFP_KERNEL);
if (urb == NULL) {
as102_free_usb_stream_buffer(dev);
return -ENOMEM;
diff --git a/drivers/media/usb/au0828/au0828-vbi.c b/drivers/media/usb/au0828/au0828-vbi.c
index b0333637b747..11203adf47ea 100644
--- a/drivers/media/usb/au0828/au0828-vbi.c
+++ b/drivers/media/usb/au0828/au0828-vbi.c
@@ -74,6 +74,4 @@ const struct vb2_ops au0828_vbi_qops = {
.prepare_streaming = v4l_vb2q_enable_media_source,
.start_streaming = au0828_start_analog_streaming,
.stop_streaming = au0828_stop_vbi_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c
index fd9fc43d47e0..e9cd2a335f7f 100644
--- a/drivers/media/usb/au0828/au0828-video.c
+++ b/drivers/media/usb/au0828/au0828-video.c
@@ -602,10 +602,7 @@ static inline int au0828_isoc_copy(struct au0828_dev *dev, struct urb *urb)
vbi_field_size = dev->vbi_width * dev->vbi_height * 2;
if (dev->vbi_read < vbi_field_size) {
remain = vbi_field_size - dev->vbi_read;
- if (len < remain)
- lencopy = len;
- else
- lencopy = remain;
+ lencopy = umin(len, remain);
if (vbi_buf != NULL)
au0828_copy_vbi(dev, vbi_dma_q, vbi_buf, p,
@@ -918,8 +915,6 @@ static const struct vb2_ops au0828_video_qops = {
.prepare_streaming = v4l_vb2q_enable_media_source,
.start_streaming = au0828_start_analog_streaming,
.stop_streaming = au0828_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
/* ------------------------------------------------------------------
diff --git a/drivers/media/usb/b2c2/flexcop-usb.c b/drivers/media/usb/b2c2/flexcop-usb.c
index 790787f0eba8..8033622543f2 100644
--- a/drivers/media/usb/b2c2/flexcop-usb.c
+++ b/drivers/media/usb/b2c2/flexcop-usb.c
@@ -179,7 +179,7 @@ static int flexcop_usb_memory_req(struct flexcop_usb *fc_usb,
flexcop_usb_request_t req, flexcop_usb_mem_page_t page_start,
u32 addr, int extended, u8 *buf, u32 len)
{
- int i, ret = 0;
+ int ret = 0;
u16 wMax;
u32 pagechunk = 0;
@@ -196,11 +196,8 @@ static int flexcop_usb_memory_req(struct flexcop_usb *fc_usb,
default:
return -EINVAL;
}
- for (i = 0; i < len;) {
- pagechunk =
- wMax < bytes_left_to_read_on_page(addr, len) ?
- wMax :
- bytes_left_to_read_on_page(addr, len);
+ while (len) {
+ pagechunk = min(wMax, bytes_left_to_read_on_page(addr, len));
deb_info("%x\n",
(addr & V8_MEMORY_PAGE_MASK) |
(V8_MEMORY_EXTENDED*extended));
@@ -209,11 +206,12 @@ static int flexcop_usb_memory_req(struct flexcop_usb *fc_usb,
page_start + (addr / V8_MEMORY_PAGE_SIZE),
(addr & V8_MEMORY_PAGE_MASK) |
(V8_MEMORY_EXTENDED*extended),
- &buf[i], pagechunk);
+ buf, pagechunk);
if (ret < 0)
return ret;
addr += pagechunk;
+ buf += pagechunk;
len -= pagechunk;
}
return 0;
@@ -448,7 +446,7 @@ static int flexcop_usb_transfer_init(struct flexcop_usb *fc_usb)
/* creating iso urbs */
for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++) {
fc_usb->iso_urb[i] = usb_alloc_urb(B2C2_USB_FRAMES_PER_ISO,
- GFP_ATOMIC);
+ GFP_KERNEL);
if (fc_usb->iso_urb[i] == NULL) {
ret = -ENOMEM;
goto urb_error;
@@ -481,7 +479,7 @@ static int flexcop_usb_transfer_init(struct flexcop_usb *fc_usb)
frame_offset += frame_size;
}
- if ((ret = usb_submit_urb(fc_usb->iso_urb[i],GFP_ATOMIC))) {
+ if ((ret = usb_submit_urb(fc_usb->iso_urb[i],GFP_KERNEL))) {
err("submitting urb %d failed with %d.", i, ret);
goto urb_error;
}
@@ -515,7 +513,7 @@ static int flexcop_usb_init(struct flexcop_usb *fc_usb)
alt = fc_usb->uintf->cur_altsetting;
- if (alt->desc.bNumEndpoints < 1)
+ if (alt->desc.bNumEndpoints < 2)
return -ENODEV;
if (!usb_endpoint_is_isoc_in(&alt->endpoint[0].desc))
return -ENODEV;
@@ -531,6 +529,12 @@ static int flexcop_usb_init(struct flexcop_usb *fc_usb)
case USB_SPEED_HIGH:
info("running at HIGH speed.");
break;
+ case USB_SPEED_SUPER:
+ info("running at SUPER speed.");
+ break;
+ case USB_SPEED_SUPER_PLUS:
+ info("running at SUPER+ speed.");
+ break;
case USB_SPEED_UNKNOWN:
default:
err("cannot handle USB speed because it is unknown.");
diff --git a/drivers/media/usb/cx231xx/cx231xx-417.c b/drivers/media/usb/cx231xx/cx231xx-417.c
index 3b75d062e602..a4a9781328c5 100644
--- a/drivers/media/usb/cx231xx/cx231xx-417.c
+++ b/drivers/media/usb/cx231xx/cx231xx-417.c
@@ -1453,13 +1453,11 @@ static void stop_streaming(struct vb2_queue *vq)
return_all_buffers(dev, VB2_BUF_STATE_ERROR);
}
-static struct vb2_ops cx231xx_video_qops = {
+static const struct vb2_ops cx231xx_video_qops = {
.queue_setup = queue_setup,
.buf_queue = buffer_queue,
.start_streaming = start_streaming,
.stop_streaming = stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
/* ------------------------------------------------------------------ */
@@ -1759,7 +1757,7 @@ int cx231xx_417_register(struct cx231xx *dev)
dev->mpeg_ctrl_handler.ops = &cx231xx_ops;
if (dev->sd_cx25840)
v4l2_ctrl_add_handler(&dev->mpeg_ctrl_handler.hdl,
- dev->sd_cx25840->ctrl_handler, NULL, false);
+ dev->sd_cx25840->ctrl_handler, NULL, true);
if (dev->mpeg_ctrl_handler.hdl.error) {
err = dev->mpeg_ctrl_handler.hdl.error;
dprintk(3, "%s: can't add cx25840 controls\n", dev->name);
diff --git a/drivers/media/usb/cx231xx/cx231xx-avcore.c b/drivers/media/usb/cx231xx/cx231xx-avcore.c
index 3d3c881c8e58..1cfec76b72f3 100644
--- a/drivers/media/usb/cx231xx/cx231xx-avcore.c
+++ b/drivers/media/usb/cx231xx/cx231xx-avcore.c
@@ -623,7 +623,7 @@ int cx231xx_set_video_input_mux(struct cx231xx *dev, u8 input)
}
int cx231xx_set_decoder_video_input(struct cx231xx *dev,
- u8 pin_type, u8 input)
+ u8 pin_type, u32 input)
{
int status = 0;
u32 value = 0;
@@ -1338,39 +1338,6 @@ void update_HH_register_after_set_DIF(struct cx231xx *dev)
*/
}
-void cx231xx_dump_HH_reg(struct cx231xx *dev)
-{
- u32 value = 0;
- u16 i = 0;
-
- value = 0x45005390;
- vid_blk_write_word(dev, 0x104, value);
-
- for (i = 0x100; i < 0x140; i++) {
- vid_blk_read_word(dev, i, &value);
- dev_dbg(dev->dev, "reg0x%x=0x%x\n", i, value);
- i = i+3;
- }
-
- for (i = 0x300; i < 0x400; i++) {
- vid_blk_read_word(dev, i, &value);
- dev_dbg(dev->dev, "reg0x%x=0x%x\n", i, value);
- i = i+3;
- }
-
- for (i = 0x400; i < 0x440; i++) {
- vid_blk_read_word(dev, i, &value);
- dev_dbg(dev->dev, "reg0x%x=0x%x\n", i, value);
- i = i+3;
- }
-
- vid_blk_read_word(dev, AFE_CTRL_C2HH_SRC_CTRL, &value);
- dev_dbg(dev->dev, "AFE_CTRL_C2HH_SRC_CTRL=0x%x\n", value);
- vid_blk_write_word(dev, AFE_CTRL_C2HH_SRC_CTRL, 0x4485D390);
- vid_blk_read_word(dev, AFE_CTRL_C2HH_SRC_CTRL, &value);
- dev_dbg(dev->dev, "AFE_CTRL_C2HH_SRC_CTRL=0x%x\n", value);
-}
-
#if 0
static void cx231xx_dump_SC_reg(struct cx231xx *dev)
{
@@ -2460,30 +2427,6 @@ int cx231xx_set_power_mode(struct cx231xx *dev, enum AV_MODE mode)
return status;
}
-int cx231xx_power_suspend(struct cx231xx *dev)
-{
- u8 value[4] = { 0, 0, 0, 0 };
- u32 tmp = 0;
- int status = 0;
-
- status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, PWR_CTL_EN,
- value, 4);
- if (status > 0)
- return status;
-
- tmp = le32_to_cpu(*((__le32 *) value));
- tmp &= (~PWR_MODE_MASK);
-
- value[0] = (u8) tmp;
- value[1] = (u8) (tmp >> 8);
- value[2] = (u8) (tmp >> 16);
- value[3] = (u8) (tmp >> 24);
- status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, PWR_CTL_EN,
- value, 4);
-
- return status;
-}
-
/******************************************************************************
* S T R E A M C O N T R O L functions *
******************************************************************************/
@@ -2761,7 +2704,6 @@ int cx231xx_set_gpio_value(struct cx231xx *dev, int pin_number, int pin_value)
dev->gpio_dir = value;
status = cx231xx_set_gpio_bit(dev, dev->gpio_dir,
dev->gpio_val);
- value = 0;
}
if (pin_value == 0)
diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c
index 92efe6c1f47b..691f073892b3 100644
--- a/drivers/media/usb/cx231xx/cx231xx-cards.c
+++ b/drivers/media/usb/cx231xx/cx231xx-cards.c
@@ -679,8 +679,7 @@ struct cx231xx_board cx231xx_boards[] = {
}, {
.type = CX231XX_VMUX_SVIDEO,
.vmux = CX231XX_VIN_1_1 |
- (CX231XX_VIN_1_2 << 8) |
- CX25840_SVIDEO_ON,
+ (CX231XX_VIN_3_2 << 8),
.amux = CX231XX_AMUX_LINE_IN,
.gpio = NULL,
}
@@ -990,10 +989,11 @@ struct cx231xx_board cx231xx_boards[] = {
} },
},
};
-const unsigned int cx231xx_bcount = ARRAY_SIZE(cx231xx_boards);
/* table of devices that work with this driver */
struct usb_device_id cx231xx_id_table[] = {
+ {USB_DEVICE(0x1D19, 0x6108),
+ .driver_info = CX231XX_BOARD_PV_XCAPTURE_USB},
{USB_DEVICE(0x1D19, 0x6109),
.driver_info = CX231XX_BOARD_PV_XCAPTURE_USB},
{USB_DEVICE(0x0572, 0x5A3C),
diff --git a/drivers/media/usb/cx231xx/cx231xx-i2c.c b/drivers/media/usb/cx231xx/cx231xx-i2c.c
index c6659253c6fb..6da8e7943d94 100644
--- a/drivers/media/usb/cx231xx/cx231xx-i2c.c
+++ b/drivers/media/usb/cx231xx/cx231xx-i2c.c
@@ -567,10 +567,7 @@ int cx231xx_i2c_mux_create(struct cx231xx *dev)
int cx231xx_i2c_mux_register(struct cx231xx *dev, int mux_no)
{
- return i2c_mux_add_adapter(dev->muxc,
- 0,
- mux_no /* chan_id */,
- 0 /* class */);
+ return i2c_mux_add_adapter(dev->muxc, 0, mux_no);
}
void cx231xx_i2c_mux_unregister(struct cx231xx *dev)
diff --git a/drivers/media/usb/cx231xx/cx231xx-vbi.c b/drivers/media/usb/cx231xx/cx231xx-vbi.c
index 33431d9f54c2..338e10148465 100644
--- a/drivers/media/usb/cx231xx/cx231xx-vbi.c
+++ b/drivers/media/usb/cx231xx/cx231xx-vbi.c
@@ -243,8 +243,6 @@ struct vb2_ops cx231xx_vbi_qops = {
.buf_queue = vbi_buf_queue,
.start_streaming = vbi_start_streaming,
.stop_streaming = vbi_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
/* ------------------------------------------------------------------
diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c
index 8f347bbeeb32..2cd4e333bc4b 100644
--- a/drivers/media/usb/cx231xx/cx231xx-video.c
+++ b/drivers/media/usb/cx231xx/cx231xx-video.c
@@ -795,13 +795,11 @@ static void stop_streaming(struct vb2_queue *vq)
return_all_buffers(dev, VB2_BUF_STATE_ERROR);
}
-static struct vb2_ops cx231xx_video_qops = {
+static const struct vb2_ops cx231xx_video_qops = {
.queue_setup = queue_setup,
.buf_queue = buffer_queue,
.start_streaming = start_streaming,
.stop_streaming = stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
/********************* v4l2 interface **************************************/
diff --git a/drivers/media/usb/cx231xx/cx231xx.h b/drivers/media/usb/cx231xx/cx231xx.h
index 74339a6a2f71..19f5036a78d7 100644
--- a/drivers/media/usb/cx231xx/cx231xx.h
+++ b/drivers/media/usb/cx231xx/cx231xx.h
@@ -790,7 +790,6 @@ void cx231xx_set_DIF_bandpass(struct cx231xx *dev, u32 if_freq,
u8 spectral_invert, u32 mode);
void cx231xx_Setup_AFE_for_LowIF(struct cx231xx *dev);
void reset_s5h1432_demod(struct cx231xx *dev);
-void cx231xx_dump_HH_reg(struct cx231xx *dev);
void update_HH_register_after_set_DIF(struct cx231xx *dev);
@@ -905,7 +904,6 @@ int cx231xx_initialize_stream_xfer(struct cx231xx *dev, u32 media_type);
/* Power control functions */
int cx231xx_set_power_mode(struct cx231xx *dev, enum AV_MODE mode);
-int cx231xx_power_suspend(struct cx231xx *dev);
/* chip specific control functions */
int cx231xx_init_ctrl_pin_status(struct cx231xx *dev);
@@ -916,7 +914,7 @@ int cx231xx_enable_i2c_port_3(struct cx231xx *dev, bool is_port_3);
/* video audio decoder related functions */
void video_mux(struct cx231xx *dev, int index);
int cx231xx_set_video_input_mux(struct cx231xx *dev, u8 input);
-int cx231xx_set_decoder_video_input(struct cx231xx *dev, u8 pin_type, u8 input);
+int cx231xx_set_decoder_video_input(struct cx231xx *dev, u8 pin_type, u32 input);
int cx231xx_do_mode_ctrl_overrides(struct cx231xx *dev);
int cx231xx_set_audio_input(struct cx231xx *dev, u8 input);
@@ -949,7 +947,6 @@ extern void cx231xx_pre_card_setup(struct cx231xx *dev);
extern void cx231xx_card_setup(struct cx231xx *dev);
extern struct cx231xx_board cx231xx_boards[];
extern struct usb_device_id cx231xx_id_table[];
-extern const unsigned int cx231xx_bcount;
int cx231xx_tuner_callback(void *ptr, int component, int command, int arg);
/* cx23885-417.c */
diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c
index 4eb7dd4599b7..218f712f56b1 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;
@@ -868,6 +874,9 @@ static int af9035_read_config(struct dvb_usb_device *d)
if ((le16_to_cpu(d->udev->descriptor.idVendor) == USB_VID_AVERMEDIA) &&
(le16_to_cpu(d->udev->descriptor.idProduct) == USB_PID_AVERMEDIA_TD310)) {
state->it930x_addresses = 1;
+ /* TD310 RC works with NEC defaults */
+ state->ir_mode = 0x05;
+ state->ir_type = 0x00;
}
return 0;
}
@@ -2066,6 +2075,11 @@ static const struct dvb_usb_device_properties it930x_props = {
.tuner_attach = it930x_tuner_attach,
.tuner_detach = it930x_tuner_detach,
.init = it930x_init,
+ /*
+ * dvb_usbv2_remote_init() calls rc_config() only for those devices
+ * which have non-empty rc_map, so it's safe to enable it for every IT930x
+ */
+ .get_rc_config = af9035_get_rc_config,
.get_stream_config = af9035_get_stream_config,
.get_adapter_count = af9035_get_adapter_count,
@@ -2157,7 +2171,7 @@ static const struct usb_device_id af9035_id_table[] = {
{ DVB_USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9303,
&it930x_props, "ITE 9303 Generic", NULL) },
{ DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_TD310,
- &it930x_props, "AVerMedia TD310 DVB-T2", NULL) },
+ &it930x_props, "AVerMedia TD310 DVB-T2", RC_MAP_AVERMEDIA_RM_KS) },
{ DVB_USB_DEVICE(USB_VID_DEXATEK, 0x0100,
&it930x_props, "Logilink VG0022A", NULL) },
{ DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_TC2_STICK,
diff --git a/drivers/media/usb/dvb-usb-v2/anysee.c b/drivers/media/usb/dvb-usb-v2/anysee.c
index a1235d0cce92..bea12cdc85e8 100644
--- a/drivers/media/usb/dvb-usb-v2/anysee.c
+++ b/drivers/media/usb/dvb-usb-v2/anysee.c
@@ -46,24 +46,15 @@ static int anysee_ctrl_msg(struct dvb_usb_device *d,
dev_dbg(&d->udev->dev, "%s: >>> %*ph\n", __func__, slen, state->buf);
- /* We need receive one message more after dvb_usb_generic_rw due
- to weird transaction flow, which is 1 x send + 2 x receive. */
+ /*
+ * We need receive one message more after dvb_usbv2_generic_rw_locked()
+ * due to weird transaction flow, which is 1 x send + 2 x receive.
+ */
ret = dvb_usbv2_generic_rw_locked(d, state->buf, sizeof(state->buf),
state->buf, sizeof(state->buf));
if (ret)
goto error_unlock;
- /* TODO FIXME: dvb_usb_generic_rw() fails rarely with error code -32
- * (EPIPE, Broken pipe). Function supports currently msleep() as a
- * parameter but I would not like to use it, since according to
- * Documentation/timers/timers-howto.rst it should not be used such
- * short, under < 20ms, sleeps. Repeating failed message would be
- * better choice as not to add unwanted delays...
- * Fixing that correctly is one of those or both;
- * 1) use repeat if possible
- * 2) add suitable delay
- */
-
/* get answer, retry few times if error returned */
for (i = 0; i < 3; i++) {
/* receive 2nd answer */
@@ -202,14 +193,14 @@ static int anysee_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
while (i < num) {
if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) {
- if (msg[i].len != 2 || msg[i + 1].len > 60) {
+ if (msg[i].len < 1 || msg[i].len > 2 || msg[i + 1].len > 60) {
ret = -EOPNOTSUPP;
break;
}
buf[0] = CMD_I2C_READ;
buf[1] = (msg[i].addr << 1) | 0x01;
buf[2] = msg[i].buf[0];
- buf[3] = msg[i].buf[1];
+ buf[3] = (msg[i].len < 2) ? 0 : msg[i].buf[1];
buf[4] = msg[i].len-1;
buf[5] = msg[i+1].len;
ret = anysee_ctrl_msg(d, buf, 6, msg[i+1].buf,
diff --git a/drivers/media/usb/dvb-usb-v2/lmedm04.c b/drivers/media/usb/dvb-usb-v2/lmedm04.c
index 8a34e6c0d6a6..f0537b741d13 100644
--- a/drivers/media/usb/dvb-usb-v2/lmedm04.c
+++ b/drivers/media/usb/dvb-usb-v2/lmedm04.c
@@ -373,6 +373,7 @@ static int lme2510_int_read(struct dvb_usb_adapter *adap)
struct dvb_usb_device *d = adap_to_d(adap);
struct lme2510_state *lme_int = adap_to_priv(adap);
struct usb_host_endpoint *ep;
+ int ret;
lme_int->lme_urb = usb_alloc_urb(0, GFP_KERNEL);
@@ -390,11 +391,20 @@ static int lme2510_int_read(struct dvb_usb_adapter *adap)
/* Quirk of pipe reporting PIPE_BULK but behaves as interrupt */
ep = usb_pipe_endpoint(d->udev, lme_int->lme_urb->pipe);
+ if (!ep) {
+ usb_free_urb(lme_int->lme_urb);
+ return -ENODEV;
+ }
if (usb_endpoint_type(&ep->desc) == USB_ENDPOINT_XFER_BULK)
lme_int->lme_urb->pipe = usb_rcvbulkpipe(d->udev, 0xa);
- usb_submit_urb(lme_int->lme_urb, GFP_KERNEL);
+ ret = usb_submit_urb(lme_int->lme_urb, GFP_KERNEL);
+ if (ret) {
+ usb_free_urb(lme_int->lme_urb);
+ return ret;
+ }
+
info("INT Interrupt Service Started");
return 0;
diff --git a/drivers/media/usb/dvb-usb/cxusb-analog.c b/drivers/media/usb/dvb-usb/cxusb-analog.c
index b5d8c6b75ae1..8253046cd6e6 100644
--- a/drivers/media/usb/dvb-usb/cxusb-analog.c
+++ b/drivers/media/usb/dvb-usb/cxusb-analog.c
@@ -956,8 +956,6 @@ static const struct vb2_ops cxdev_video_qops = {
.start_streaming = cxusb_medion_v_start_streaming,
.stop_streaming = cxusb_medion_v_stop_streaming,
.buf_queue = cxusub_medion_v_buf_queue,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish
};
static const __u32 videocaps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER |
diff --git a/drivers/media/usb/dvb-usb/dib0700_devices.c b/drivers/media/usb/dvb-usb/dib0700_devices.c
index 3af594134a6d..6ddc20513393 100644
--- a/drivers/media/usb/dvb-usb/dib0700_devices.c
+++ b/drivers/media/usb/dvb-usb/dib0700_devices.c
@@ -2412,7 +2412,12 @@ static int stk9090m_frontend_attach(struct dvb_usb_adapter *adap)
adap->fe_adap[0].fe = dvb_attach(dib9000_attach, &adap->dev->i2c_adap, 0x80, &stk9090m_config);
- return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
+ if (!adap->fe_adap[0].fe) {
+ release_firmware(state->frontend_firmware);
+ return -ENODEV;
+ }
+
+ return 0;
}
static int dib9090_tuner_attach(struct dvb_usb_adapter *adap)
@@ -2485,8 +2490,10 @@ static int nim9090md_frontend_attach(struct dvb_usb_adapter *adap)
dib9000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x20, 0x80);
adap->fe_adap[0].fe = dvb_attach(dib9000_attach, &adap->dev->i2c_adap, 0x80, &nim9090md_config[0]);
- if (adap->fe_adap[0].fe == NULL)
+ if (!adap->fe_adap[0].fe) {
+ release_firmware(state->frontend_firmware);
return -ENODEV;
+ }
i2c = dib9000_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_GPIO_3_4, 0);
dib9000_i2c_enumeration(i2c, 1, 0x12, 0x82);
@@ -2494,7 +2501,12 @@ static int nim9090md_frontend_attach(struct dvb_usb_adapter *adap)
fe_slave = dvb_attach(dib9000_attach, i2c, 0x82, &nim9090md_config[1]);
dib9000_set_slave_frontend(adap->fe_adap[0].fe, fe_slave);
- return fe_slave == NULL ? -ENODEV : 0;
+ if (!fe_slave) {
+ release_firmware(state->frontend_firmware);
+ return -ENODEV;
+ }
+
+ return 0;
}
static int nim9090md_tuner_attach(struct dvb_usb_adapter *adap)
diff --git a/drivers/media/usb/dvb-usb/dibusb-common.c b/drivers/media/usb/dvb-usb/dibusb-common.c
index aff60c10cb0b..20f1ef3393a5 100644
--- a/drivers/media/usb/dvb-usb/dibusb-common.c
+++ b/drivers/media/usb/dvb-usb/dibusb-common.c
@@ -14,6 +14,7 @@
static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "set debugging level (1=info (|-able))." DVB_USB_DEBUG_STATUS);
+MODULE_DESCRIPTION("Common methods for dibusb-based receivers");
MODULE_LICENSE("GPL");
#define deb_info(args...) dprintk(debug,0x01,args)
diff --git a/drivers/media/usb/dvb-usb/dibusb-mc-common.c b/drivers/media/usb/dvb-usb/dibusb-mc-common.c
index b8cde4cded33..36bc7762acf4 100644
--- a/drivers/media/usb/dvb-usb/dibusb-mc-common.c
+++ b/drivers/media/usb/dvb-usb/dibusb-mc-common.c
@@ -8,6 +8,7 @@
#include "dibusb.h"
+MODULE_DESCRIPTION("Common methods for DIB3000MC");
MODULE_LICENSE("GPL");
/* 3000MC/P stuff */
diff --git a/drivers/media/usb/dvb-usb/dvb-usb.h b/drivers/media/usb/dvb-usb/dvb-usb.h
index 0990aa4a17bb..cbb0541d4dc1 100644
--- a/drivers/media/usb/dvb-usb/dvb-usb.h
+++ b/drivers/media/usb/dvb-usb/dvb-usb.h
@@ -126,8 +126,6 @@ struct usb_data_stream_properties {
* @caps: capabilities of the DVB USB device.
* @pid_filter_count: number of PID filter position in the optional hardware
* PID-filter.
- * @num_frontends: number of frontends of the DVB USB adapter.
- * @frontend_ctrl: called to power on/off active frontend.
* @streaming_ctrl: called to start and stop the MPEG2-TS streaming of the
* device (not URB submitting/killing).
* This callback will be called without data URBs being active - data URBs
diff --git a/drivers/media/usb/dvb-usb/dw2102.c b/drivers/media/usb/dvb-usb/dw2102.c
index b3bb1805829a..79e2ccf974c9 100644
--- a/drivers/media/usb/dvb-usb/dw2102.c
+++ b/drivers/media/usb/dvb-usb/dw2102.c
@@ -36,7 +36,6 @@
/* Max transfer size done by I2C transfer functions */
#define MAX_XFER_SIZE 64
-
#define DW210X_READ_MSG 0
#define DW210X_WRITE_MSG 1
@@ -53,10 +52,10 @@
#define DW2102_FIRMWARE "dvb-usb-dw2102.fw"
#define DW2104_FIRMWARE "dvb-usb-dw2104.fw"
#define DW3101_FIRMWARE "dvb-usb-dw3101.fw"
-#define S630_FIRMWARE "dvb-usb-s630.fw"
-#define S660_FIRMWARE "dvb-usb-s660.fw"
-#define P1100_FIRMWARE "dvb-usb-p1100.fw"
-#define P7500_FIRMWARE "dvb-usb-p7500.fw"
+#define S630_FIRMWARE "dvb-usb-s630.fw"
+#define S660_FIRMWARE "dvb-usb-s660.fw"
+#define P1100_FIRMWARE "dvb-usb-p1100.fw"
+#define P7500_FIRMWARE "dvb-usb-p7500.fw"
#define err_str "did not find the firmware file '%s'. You can use <kernel_dir>/scripts/get_dvb_firmware to get the firmware"
@@ -87,7 +86,7 @@ MODULE_PARM_DESC(demod, "demod to probe (1=cx24116 2=stv0903+stv6110 4=stv0903+s
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
static int dw210x_op_rw(struct usb_device *dev, u8 request, u16 value,
- u16 index, u8 * data, u16 len, int flags)
+ u16 index, u8 *data, u16 len, int flags)
{
int ret;
u8 *u8buf;
@@ -99,11 +98,10 @@ static int dw210x_op_rw(struct usb_device *dev, u8 request, u16 value,
if (!u8buf)
return -ENOMEM;
-
if (flags == DW210X_WRITE_MSG)
memcpy(u8buf, data, len);
ret = usb_control_msg(dev, pipe, request, request_type | USB_TYPE_VENDOR,
- value, index , u8buf, len, 2000);
+ value, index, u8buf, len, 2000);
if (flags == DW210X_READ_MSG)
memcpy(data, u8buf, len);
@@ -114,7 +112,7 @@ static int dw210x_op_rw(struct usb_device *dev, u8 request, u16 value,
/* I2C */
static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
- int num)
+ int num)
{
struct dvb_usb_device *d = i2c_get_adapdata(adap);
int i = 0;
@@ -136,7 +134,7 @@ static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
value = msg[0].buf[0];/* register */
for (i = 0; i < msg[1].len; i++) {
dw210x_op_rw(d->udev, 0xb5, value + i, 0,
- buf6, 2, DW210X_READ_MSG);
+ buf6, 2, DW210X_READ_MSG);
msg[1].buf[i] = buf6[0];
}
break;
@@ -152,7 +150,7 @@ static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
buf6[1] = msg[0].buf[0];
buf6[2] = msg[0].buf[1];
dw210x_op_rw(d->udev, 0xb2, 0, 0,
- buf6, 3, DW210X_WRITE_MSG);
+ buf6, 3, DW210X_WRITE_MSG);
break;
case 0x60:
if (msg[0].flags == 0) {
@@ -169,7 +167,7 @@ static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
buf6[5] = msg[0].buf[2];
buf6[6] = msg[0].buf[3];
dw210x_op_rw(d->udev, 0xb2, 0, 0,
- buf6, 7, DW210X_WRITE_MSG);
+ buf6, 7, DW210X_WRITE_MSG);
} else {
if (msg[0].len < 1) {
num = -EOPNOTSUPP;
@@ -177,7 +175,7 @@ static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
}
/* read from tuner */
dw210x_op_rw(d->udev, 0xb5, 0, 0,
- buf6, 1, DW210X_READ_MSG);
+ buf6, 1, DW210X_READ_MSG);
msg[0].buf[0] = buf6[0];
}
break;
@@ -187,7 +185,7 @@ static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
break;
}
dw210x_op_rw(d->udev, 0xb8, 0, 0,
- buf6, 2, DW210X_READ_MSG);
+ buf6, 2, DW210X_READ_MSG);
msg[0].buf[0] = buf6[0];
msg[0].buf[1] = buf6[1];
break;
@@ -199,7 +197,7 @@ static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
buf6[0] = 0x30;
buf6[1] = msg[0].buf[0];
dw210x_op_rw(d->udev, 0xb2, 0, 0,
- buf6, 2, DW210X_WRITE_MSG);
+ buf6, 2, DW210X_WRITE_MSG);
break;
}
@@ -211,7 +209,7 @@ static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
}
static int dw2102_serit_i2c_transfer(struct i2c_adapter *adap,
- struct i2c_msg msg[], int num)
+ struct i2c_msg msg[], int num)
{
struct dvb_usb_device *d = i2c_get_adapdata(adap);
u8 buf6[] = {0, 0, 0, 0, 0, 0, 0};
@@ -242,10 +240,10 @@ static int dw2102_serit_i2c_transfer(struct i2c_adapter *adap,
buf6[1] = msg[0].len;
buf6[2] = msg[0].buf[0];
dw210x_op_rw(d->udev, 0xc2, 0, 0,
- buf6, msg[0].len + 2, DW210X_WRITE_MSG);
+ buf6, msg[0].len + 2, DW210X_WRITE_MSG);
/* read si2109 register */
dw210x_op_rw(d->udev, 0xc3, 0xd0, 0,
- buf6, msg[1].len + 2, DW210X_READ_MSG);
+ buf6, msg[1].len + 2, DW210X_READ_MSG);
memcpy(msg[1].buf, buf6 + 2, msg[1].len);
break;
@@ -264,11 +262,11 @@ static int dw2102_serit_i2c_transfer(struct i2c_adapter *adap,
buf6[1] = msg[0].len;
memcpy(buf6 + 2, msg[0].buf, msg[0].len);
dw210x_op_rw(d->udev, 0xc2, 0, 0, buf6,
- msg[0].len + 2, DW210X_WRITE_MSG);
+ msg[0].len + 2, DW210X_WRITE_MSG);
break;
case(DW2102_RC_QUERY):
dw210x_op_rw(d->udev, 0xb8, 0, 0,
- buf6, 2, DW210X_READ_MSG);
+ buf6, 2, DW210X_READ_MSG);
msg[0].buf[0] = buf6[0];
msg[0].buf[1] = buf6[1];
break;
@@ -276,7 +274,7 @@ static int dw2102_serit_i2c_transfer(struct i2c_adapter *adap,
buf6[0] = 0x30;
buf6[1] = msg[0].buf[0];
dw210x_op_rw(d->udev, 0xb2, 0, 0,
- buf6, 2, DW210X_WRITE_MSG);
+ buf6, 2, DW210X_WRITE_MSG);
break;
}
break;
@@ -320,10 +318,10 @@ static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg ms
obuf[1] = msg[0].len;
obuf[2] = msg[0].buf[0];
dw210x_op_rw(d->udev, 0xc2, 0, 0,
- obuf, msg[0].len + 2, DW210X_WRITE_MSG);
+ obuf, msg[0].len + 2, DW210X_WRITE_MSG);
/* second read registers */
- dw210x_op_rw(d->udev, 0xc3, 0xd1 , 0,
- ibuf, msg[1].len + 2, DW210X_READ_MSG);
+ dw210x_op_rw(d->udev, 0xc3, 0xd1, 0,
+ ibuf, msg[1].len + 2, DW210X_READ_MSG);
memcpy(msg[1].buf, ibuf + 2, msg[1].len);
break;
@@ -345,7 +343,7 @@ static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg ms
obuf[1] = msg[0].len;
memcpy(obuf + 2, msg[0].buf, msg[0].len);
dw210x_op_rw(d->udev, 0xc2, 0, 0,
- obuf, msg[0].len + 2, DW210X_WRITE_MSG);
+ obuf, msg[0].len + 2, DW210X_WRITE_MSG);
break;
}
case 0x61: {
@@ -363,22 +361,24 @@ static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg ms
obuf[1] = msg[0].len;
memcpy(obuf + 2, msg[0].buf, msg[0].len);
dw210x_op_rw(d->udev, 0xc2, 0, 0,
- obuf, msg[0].len + 2, DW210X_WRITE_MSG);
+ obuf, msg[0].len + 2, DW210X_WRITE_MSG);
break;
}
case(DW2102_RC_QUERY): {
u8 ibuf[2];
+
dw210x_op_rw(d->udev, 0xb8, 0, 0,
- ibuf, 2, DW210X_READ_MSG);
- memcpy(msg[0].buf, ibuf , 2);
+ ibuf, 2, DW210X_READ_MSG);
+ memcpy(msg[0].buf, ibuf, 2);
break;
}
case(DW2102_VOLTAGE_CTRL): {
u8 obuf[2];
+
obuf[0] = 0x30;
obuf[1] = msg[0].buf[0];
dw210x_op_rw(d->udev, 0xb2, 0, 0,
- obuf, 2, DW210X_WRITE_MSG);
+ obuf, 2, DW210X_WRITE_MSG);
break;
}
}
@@ -406,23 +406,26 @@ static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], i
switch (msg[j].addr) {
case(DW2102_RC_QUERY): {
u8 ibuf[2];
+
dw210x_op_rw(d->udev, 0xb8, 0, 0,
- ibuf, 2, DW210X_READ_MSG);
- memcpy(msg[j].buf, ibuf , 2);
+ ibuf, 2, DW210X_READ_MSG);
+ memcpy(msg[j].buf, ibuf, 2);
break;
}
case(DW2102_VOLTAGE_CTRL): {
u8 obuf[2];
+
obuf[0] = 0x30;
obuf[1] = msg[j].buf[0];
dw210x_op_rw(d->udev, 0xb2, 0, 0,
- obuf, 2, DW210X_WRITE_MSG);
+ obuf, 2, DW210X_WRITE_MSG);
break;
}
- /*case 0x55: cx24116
- case 0x6a: stv0903
- case 0x68: ds3000, stv0903
- case 0x60: ts2020, stv6110, stb6100 */
+ /* case 0x55: cx24116
+ * case 0x6a: stv0903
+ * case 0x68: ds3000, stv0903
+ * case 0x60: ts2020, stv6110, stb6100
+ */
default: {
if (msg[j].flags == I2C_M_RD) {
/* read registers */
@@ -436,17 +439,16 @@ static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], i
}
dw210x_op_rw(d->udev, 0xc3,
- (msg[j].addr << 1) + 1, 0,
- ibuf, msg[j].len + 2,
- DW210X_READ_MSG);
+ (msg[j].addr << 1) + 1, 0,
+ ibuf, msg[j].len + 2,
+ DW210X_READ_MSG);
memcpy(msg[j].buf, ibuf + 2, msg[j].len);
mdelay(10);
- } else if (((msg[j].buf[0] == 0xb0) &&
- (msg[j].addr == 0x68)) ||
- ((msg[j].buf[0] == 0xf7) &&
- (msg[j].addr == 0x55))) {
+ } else if (((msg[j].buf[0] == 0xb0) && (msg[j].addr == 0x68)) ||
+ ((msg[j].buf[0] == 0xf7) && (msg[j].addr == 0x55))) {
/* write firmware */
u8 obuf[19];
+
obuf[0] = msg[j].addr << 1;
obuf[1] = (msg[j].len > 15 ? 17 : msg[j].len);
obuf[2] = msg[j].buf[0];
@@ -454,10 +456,10 @@ static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], i
i = 1;
do {
memcpy(obuf + 3, msg[j].buf + i,
- (len > 16 ? 16 : len));
+ (len > 16 ? 16 : len));
dw210x_op_rw(d->udev, 0xc2, 0, 0,
- obuf, (len > 16 ? 16 : len) + 3,
- DW210X_WRITE_MSG);
+ obuf, (len > 16 ? 16 : len) + 3,
+ DW210X_WRITE_MSG);
i += 16;
len -= 16;
} while (len > 0);
@@ -476,13 +478,12 @@ static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], i
obuf[1] = msg[j].len;
memcpy(obuf + 2, msg[j].buf, msg[j].len);
dw210x_op_rw(d->udev, 0xc2, 0, 0,
- obuf, msg[j].len + 2,
- DW210X_WRITE_MSG);
+ obuf, msg[j].len + 2,
+ DW210X_WRITE_MSG);
}
break;
}
}
-
}
ret = num;
@@ -492,7 +493,7 @@ unlock:
}
static int dw3101_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
- int num)
+ int num)
{
struct dvb_usb_device *d = i2c_get_adapdata(adap);
int ret;
@@ -525,10 +526,10 @@ static int dw3101_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
obuf[1] = msg[0].len;
obuf[2] = msg[0].buf[0];
dw210x_op_rw(d->udev, 0xc2, 0, 0,
- obuf, msg[0].len + 2, DW210X_WRITE_MSG);
+ obuf, msg[0].len + 2, DW210X_WRITE_MSG);
/* second read registers */
- dw210x_op_rw(d->udev, 0xc3, 0x19 , 0,
- ibuf, msg[1].len + 2, DW210X_READ_MSG);
+ dw210x_op_rw(d->udev, 0xc3, 0x19, 0,
+ ibuf, msg[1].len + 2, DW210X_READ_MSG);
memcpy(msg[1].buf, ibuf + 2, msg[1].len);
break;
@@ -550,14 +551,15 @@ static int dw3101_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
obuf[1] = msg[0].len;
memcpy(obuf + 2, msg[0].buf, msg[0].len);
dw210x_op_rw(d->udev, 0xc2, 0, 0,
- obuf, msg[0].len + 2, DW210X_WRITE_MSG);
+ obuf, msg[0].len + 2, DW210X_WRITE_MSG);
break;
}
case(DW2102_RC_QUERY): {
u8 ibuf[2];
+
dw210x_op_rw(d->udev, 0xb8, 0, 0,
- ibuf, 2, DW210X_READ_MSG);
- memcpy(msg[0].buf, ibuf , 2);
+ ibuf, 2, DW210X_READ_MSG);
+ memcpy(msg[0].buf, ibuf, 2);
break;
}
}
@@ -567,7 +569,7 @@ static int dw3101_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
for (i = 0; i < num; i++) {
deb_xfer("%02x:%02x: %s ", i, msg[i].addr,
- msg[i].flags == 0 ? ">>>" : "<<<");
+ msg[i].flags == 0 ? ">>>" : "<<<");
debug_dump(msg[i].buf, msg[i].len, deb_xfer);
}
ret = num;
@@ -578,7 +580,7 @@ unlock:
}
static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
- int num)
+ int num)
{
struct dvb_usb_device *d = i2c_get_adapdata(adap);
struct usb_device *udev;
@@ -594,8 +596,9 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
switch (msg[j].addr) {
case (DW2102_RC_QUERY): {
u8 ibuf[5];
+
dw210x_op_rw(d->udev, 0xb8, 0, 0,
- ibuf, 5, DW210X_READ_MSG);
+ ibuf, 5, DW210X_READ_MSG);
memcpy(msg[j].buf, ibuf + 3, 2);
break;
}
@@ -605,11 +608,11 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
obuf[0] = 1;
obuf[1] = msg[j].buf[1];/* off-on */
dw210x_op_rw(d->udev, 0x8a, 0, 0,
- obuf, 2, DW210X_WRITE_MSG);
+ obuf, 2, DW210X_WRITE_MSG);
obuf[0] = 3;
obuf[1] = msg[j].buf[0];/* 13v-18v */
dw210x_op_rw(d->udev, 0x8a, 0, 0,
- obuf, 2, DW210X_WRITE_MSG);
+ obuf, 2, DW210X_WRITE_MSG);
break;
}
case (DW2102_LED_CTRL): {
@@ -618,14 +621,15 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
obuf[0] = 5;
obuf[1] = msg[j].buf[0];
dw210x_op_rw(d->udev, 0x8a, 0, 0,
- obuf, 2, DW210X_WRITE_MSG);
+ obuf, 2, DW210X_WRITE_MSG);
break;
}
- /*case 0x55: cx24116
- case 0x6a: stv0903
- case 0x68: ds3000, stv0903, rs2000
- case 0x60: ts2020, stv6110, stb6100
- case 0xa0: eeprom */
+ /* case 0x55: cx24116
+ * case 0x6a: stv0903
+ * case 0x68: ds3000, stv0903, rs2000
+ * case 0x60: ts2020, stv6110, stb6100
+ * case 0xa0: eeprom
+ */
default: {
if (msg[j].flags == I2C_M_RD) {
/* read registers */
@@ -639,14 +643,14 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
}
dw210x_op_rw(d->udev, 0x91, 0, 0,
- ibuf, msg[j].len,
+ ibuf, msg[j].len,
DW210X_READ_MSG);
memcpy(msg[j].buf, ibuf, msg[j].len);
break;
- } else if ((msg[j].buf[0] == 0xb0) &&
- (msg[j].addr == 0x68)) {
+ } else if ((msg[j].buf[0] == 0xb0) && (msg[j].addr == 0x68)) {
/* write firmware */
u8 obuf[19];
+
obuf[0] = (msg[j].len > 16 ?
18 : msg[j].len + 1);
obuf[1] = msg[j].addr << 1;
@@ -655,10 +659,10 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
i = 1;
do {
memcpy(obuf + 3, msg[j].buf + i,
- (len > 16 ? 16 : len));
+ (len > 16 ? 16 : len));
dw210x_op_rw(d->udev, 0x80, 0, 0,
- obuf, (len > 16 ? 16 : len) + 3,
- DW210X_WRITE_MSG);
+ obuf, (len > 16 ? 16 : len) + 3,
+ DW210X_WRITE_MSG);
i += 16;
len -= 16;
} while (len > 0);
@@ -677,10 +681,9 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
obuf[1] = (msg[j].addr << 1);
memcpy(obuf + 2, msg[j].buf, msg[j].len);
dw210x_op_rw(d->udev,
- le16_to_cpu(udev->descriptor.idProduct) ==
- 0x7500 ? 0x92 : 0x90, 0, 0,
- obuf, msg[j].len + 2,
- DW210X_WRITE_MSG);
+ le16_to_cpu(udev->descriptor.idProduct) == 0x7500 ? 0x92 : 0x90,
+ 0, 0, obuf, msg[j].len + 2,
+ DW210X_WRITE_MSG);
break;
} else {
/* write registers */
@@ -696,8 +699,8 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
obuf[1] = (msg[j].addr << 1);
memcpy(obuf + 2, msg[j].buf, msg[j].len);
dw210x_op_rw(d->udev, 0x80, 0, 0,
- obuf, msg[j].len + 2,
- DW210X_WRITE_MSG);
+ obuf, msg[j].len + 2,
+ DW210X_WRITE_MSG);
break;
}
break;
@@ -712,10 +715,11 @@ unlock:
}
static int su3000_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
- int num)
+ int num)
{
struct dvb_usb_device *d = i2c_get_adapdata(adap);
struct dw2102_state *state;
+ int j;
if (!d)
return -ENODEV;
@@ -729,77 +733,102 @@ static int su3000_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
return -EAGAIN;
}
- switch (num) {
- case 1:
- switch (msg[0].addr) {
+ j = 0;
+ while (j < num) {
+ switch (msg[j].addr) {
case SU3000_STREAM_CTRL:
- state->data[0] = msg[0].buf[0] + 0x36;
+ state->data[0] = msg[j].buf[0] + 0x36;
state->data[1] = 3;
state->data[2] = 0;
if (dvb_usb_generic_rw(d, state->data, 3,
- state->data, 0, 0) < 0)
+ state->data, 0, 0) < 0)
err("i2c transfer failed.");
break;
case DW2102_RC_QUERY:
state->data[0] = 0x10;
if (dvb_usb_generic_rw(d, state->data, 1,
- state->data, 2, 0) < 0)
+ state->data, 2, 0) < 0)
err("i2c transfer failed.");
- msg[0].buf[1] = state->data[0];
- msg[0].buf[0] = state->data[1];
+ msg[j].buf[1] = state->data[0];
+ msg[j].buf[0] = state->data[1];
break;
default:
- if (3 + msg[0].len > sizeof(state->data)) {
- warn("i2c wr: len=%d is too big!\n",
- msg[0].len);
- num = -EOPNOTSUPP;
+ /* if the current write msg is followed by a another
+ * read msg to/from the same address
+ */
+ if ((j + 1 < num) && (msg[j + 1].flags & I2C_M_RD) &&
+ (msg[j].addr == msg[j + 1].addr)) {
+ /* join both i2c msgs to one usb read command */
+ if (4 + msg[j].len > sizeof(state->data)) {
+ warn("i2c combined wr/rd: write len=%d is too big!\n",
+ msg[j].len);
+ num = -EOPNOTSUPP;
+ break;
+ }
+ if (1 + msg[j + 1].len > sizeof(state->data)) {
+ warn("i2c combined wr/rd: read len=%d is too big!\n",
+ msg[j + 1].len);
+ num = -EOPNOTSUPP;
+ break;
+ }
+
+ state->data[0] = 0x09;
+ state->data[1] = msg[j].len;
+ state->data[2] = msg[j + 1].len;
+ state->data[3] = msg[j].addr;
+ memcpy(&state->data[4], msg[j].buf, msg[j].len);
+
+ if (dvb_usb_generic_rw(d, state->data, msg[j].len + 4,
+ state->data, msg[j + 1].len + 1, 0) < 0)
+ err("i2c transfer failed.");
+
+ memcpy(msg[j + 1].buf, &state->data[1], msg[j + 1].len);
+ j++;
break;
}
- /* always i2c write*/
- state->data[0] = 0x08;
- state->data[1] = msg[0].addr;
- state->data[2] = msg[0].len;
+ if (msg[j].flags & I2C_M_RD) {
+ /* single read */
+ if (4 + msg[j].len > sizeof(state->data)) {
+ warn("i2c rd: len=%d is too big!\n", msg[j].len);
+ num = -EOPNOTSUPP;
+ break;
+ }
- memcpy(&state->data[3], msg[0].buf, msg[0].len);
+ state->data[0] = 0x09;
+ state->data[1] = 0;
+ state->data[2] = msg[j].len;
+ state->data[3] = msg[j].addr;
+ memcpy(&state->data[4], msg[j].buf, msg[j].len);
- if (dvb_usb_generic_rw(d, state->data, msg[0].len + 3,
- state->data, 1, 0) < 0)
- err("i2c transfer failed.");
+ if (dvb_usb_generic_rw(d, state->data, 4,
+ state->data, msg[j].len + 1, 0) < 0)
+ err("i2c transfer failed.");
- }
- break;
- case 2:
- /* always i2c read */
- if (4 + msg[0].len > sizeof(state->data)) {
- warn("i2c rd: len=%d is too big!\n",
- msg[0].len);
- num = -EOPNOTSUPP;
- break;
- }
- if (1 + msg[1].len > sizeof(state->data)) {
- warn("i2c rd: len=%d is too big!\n",
- msg[1].len);
- num = -EOPNOTSUPP;
- break;
- }
+ memcpy(msg[j].buf, &state->data[1], msg[j].len);
+ break;
+ }
- state->data[0] = 0x09;
- state->data[1] = msg[0].len;
- state->data[2] = msg[1].len;
- state->data[3] = msg[0].addr;
- memcpy(&state->data[4], msg[0].buf, msg[0].len);
+ /* single write */
+ if (3 + msg[j].len > sizeof(state->data)) {
+ warn("i2c wr: len=%d is too big!\n", msg[j].len);
+ num = -EOPNOTSUPP;
+ break;
+ }
- if (dvb_usb_generic_rw(d, state->data, msg[0].len + 4,
- state->data, msg[1].len + 1, 0) < 0)
- err("i2c transfer failed.");
+ state->data[0] = 0x08;
+ state->data[1] = msg[j].addr;
+ state->data[2] = msg[j].len;
- memcpy(msg[1].buf, &state->data[1], msg[1].len);
- break;
- default:
- warn("more than 2 i2c messages at a time is not handled yet.");
- break;
- }
+ memcpy(&state->data[3], msg[j].buf, msg[j].len);
+
+ if (dvb_usb_generic_rw(d, state->data, msg[j].len + 3,
+ state->data, 1, 0) < 0)
+ err("i2c transfer failed.");
+ } // switch
+ j++;
+
+ } // while
mutex_unlock(&d->data_mutex);
mutex_unlock(&d->i2c_mutex);
return num;
@@ -852,11 +881,11 @@ static int dw210x_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
u8 eeprom[256], eepromline[16];
for (i = 0; i < 256; i++) {
- if (dw210x_op_rw(d->udev, 0xb6, 0xa0 , i, ibuf, 2, DW210X_READ_MSG) < 0) {
+ if (dw210x_op_rw(d->udev, 0xb6, 0xa0, i, ibuf, 2, DW210X_READ_MSG) < 0) {
err("read eeprom failed.");
return -EIO;
} else {
- eepromline[i%16] = ibuf[0];
+ eepromline[i % 16] = ibuf[0];
eeprom[i] = ibuf[0];
}
if ((i % 16) == 15) {
@@ -963,7 +992,6 @@ static int su3000_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
.flags = I2C_M_RD,
.buf = ibuf,
.len = 1,
-
}
};
@@ -983,8 +1011,6 @@ static int su3000_identify_state(struct usb_device *udev,
const struct dvb_usb_device_description **desc,
int *cold)
{
- info("%s", __func__);
-
*cold = 0;
return 0;
}
@@ -1003,6 +1029,7 @@ static int dw210x_set_voltage(struct dvb_frontend *fe,
};
struct dvb_usb_adapter *udev_adap = fe->dvb->priv;
+
if (voltage == SEC_VOLTAGE_18)
msg.buf = command_18v;
else if (voltage == SEC_VOLTAGE_13)
@@ -1206,11 +1233,11 @@ static int dw2104_frontend_attach(struct dvb_usb_adapter *d)
if (demod_probe & 4) {
d->fe_adap[0].fe = dvb_attach(stv0900_attach, &dw2104a_stv0900_config,
- &d->dev->i2c_adap, 0);
- if (d->fe_adap[0].fe != NULL) {
+ &d->dev->i2c_adap, 0);
+ if (d->fe_adap[0].fe) {
if (dvb_attach(stb6100_attach, d->fe_adap[0].fe,
- &dw2104a_stb6100_config,
- &d->dev->i2c_adap)) {
+ &dw2104a_stb6100_config,
+ &d->dev->i2c_adap)) {
tuner_ops = &d->fe_adap[0].fe->ops.tuner_ops;
tuner_ops->set_frequency = stb6100_set_freq;
tuner_ops->get_frequency = stb6100_get_freq;
@@ -1225,11 +1252,11 @@ static int dw2104_frontend_attach(struct dvb_usb_adapter *d)
if (demod_probe & 2) {
d->fe_adap[0].fe = dvb_attach(stv0900_attach, &dw2104_stv0900_config,
- &d->dev->i2c_adap, 0);
- if (d->fe_adap[0].fe != NULL) {
+ &d->dev->i2c_adap, 0);
+ if (d->fe_adap[0].fe) {
if (dvb_attach(stv6110_attach, d->fe_adap[0].fe,
- &dw2104_stv6110_config,
- &d->dev->i2c_adap)) {
+ &dw2104_stv6110_config,
+ &d->dev->i2c_adap)) {
d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
info("Attached STV0900+STV6110A!");
return 0;
@@ -1239,8 +1266,8 @@ static int dw2104_frontend_attach(struct dvb_usb_adapter *d)
if (demod_probe & 1) {
d->fe_adap[0].fe = dvb_attach(cx24116_attach, &dw2104_config,
- &d->dev->i2c_adap);
- if (d->fe_adap[0].fe != NULL) {
+ &d->dev->i2c_adap);
+ if (d->fe_adap[0].fe) {
d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
info("Attached cx24116!");
return 0;
@@ -1248,10 +1275,10 @@ static int dw2104_frontend_attach(struct dvb_usb_adapter *d)
}
d->fe_adap[0].fe = dvb_attach(ds3000_attach, &dw2104_ds3000_config,
- &d->dev->i2c_adap);
- if (d->fe_adap[0].fe != NULL) {
+ &d->dev->i2c_adap);
+ if (d->fe_adap[0].fe) {
dvb_attach(ts2020_attach, d->fe_adap[0].fe,
- &dw2104_ts2020_config, &d->dev->i2c_adap);
+ &dw2104_ts2020_config, &d->dev->i2c_adap);
d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
info("Attached DS3000!");
return 0;
@@ -1269,8 +1296,8 @@ static int dw2102_frontend_attach(struct dvb_usb_adapter *d)
if (dw2102_properties.i2c_algo == &dw2102_serit_i2c_algo) {
/*dw2102_properties.adapter->tuner_attach = NULL;*/
d->fe_adap[0].fe = dvb_attach(si21xx_attach, &serit_sp1511lhb_config,
- &d->dev->i2c_adap);
- if (d->fe_adap[0].fe != NULL) {
+ &d->dev->i2c_adap);
+ if (d->fe_adap[0].fe) {
d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
info("Attached si21xx!");
return 0;
@@ -1279,10 +1306,10 @@ static int dw2102_frontend_attach(struct dvb_usb_adapter *d)
if (dw2102_properties.i2c_algo == &dw2102_earda_i2c_algo) {
d->fe_adap[0].fe = dvb_attach(stv0288_attach, &earda_config,
- &d->dev->i2c_adap);
- if (d->fe_adap[0].fe != NULL) {
+ &d->dev->i2c_adap);
+ if (d->fe_adap[0].fe) {
if (dvb_attach(stb6000_attach, d->fe_adap[0].fe, 0x61,
- &d->dev->i2c_adap)) {
+ &d->dev->i2c_adap)) {
d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
info("Attached stv0288!");
return 0;
@@ -1293,8 +1320,8 @@ static int dw2102_frontend_attach(struct dvb_usb_adapter *d)
if (dw2102_properties.i2c_algo == &dw2102_i2c_algo) {
/*dw2102_properties.adapter->tuner_attach = dw2102_tuner_attach;*/
d->fe_adap[0].fe = dvb_attach(stv0299_attach, &sharp_z0194a_config,
- &d->dev->i2c_adap);
- if (d->fe_adap[0].fe != NULL) {
+ &d->dev->i2c_adap);
+ if (d->fe_adap[0].fe) {
d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
info("Attached stv0299!");
return 0;
@@ -1306,8 +1333,8 @@ static int dw2102_frontend_attach(struct dvb_usb_adapter *d)
static int dw3101_frontend_attach(struct dvb_usb_adapter *d)
{
d->fe_adap[0].fe = dvb_attach(tda10023_attach, &dw3101_tda10023_config,
- &d->dev->i2c_adap, 0x48);
- if (d->fe_adap[0].fe != NULL) {
+ &d->dev->i2c_adap, 0x48);
+ if (d->fe_adap[0].fe) {
info("Attached tda10023!");
return 0;
}
@@ -1317,10 +1344,10 @@ static int dw3101_frontend_attach(struct dvb_usb_adapter *d)
static int zl100313_frontend_attach(struct dvb_usb_adapter *d)
{
d->fe_adap[0].fe = dvb_attach(mt312_attach, &zl313_config,
- &d->dev->i2c_adap);
- if (d->fe_adap[0].fe != NULL) {
+ &d->dev->i2c_adap);
+ if (d->fe_adap[0].fe) {
if (dvb_attach(zl10039_attach, d->fe_adap[0].fe, 0x60,
- &d->dev->i2c_adap)) {
+ &d->dev->i2c_adap)) {
d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
info("Attached zl100313+zl10039!");
return 0;
@@ -1335,12 +1362,12 @@ static int stv0288_frontend_attach(struct dvb_usb_adapter *d)
u8 obuf[] = {7, 1};
d->fe_adap[0].fe = dvb_attach(stv0288_attach, &earda_config,
- &d->dev->i2c_adap);
+ &d->dev->i2c_adap);
- if (d->fe_adap[0].fe == NULL)
+ if (!d->fe_adap[0].fe)
return -EIO;
- if (NULL == dvb_attach(stb6000_attach, d->fe_adap[0].fe, 0x61, &d->dev->i2c_adap))
+ if (dvb_attach(stb6000_attach, d->fe_adap[0].fe, 0x61, &d->dev->i2c_adap) == NULL)
return -EIO;
d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
@@ -1350,7 +1377,6 @@ static int stv0288_frontend_attach(struct dvb_usb_adapter *d)
info("Attached stv0288+stb6000!");
return 0;
-
}
static int ds3000_frontend_attach(struct dvb_usb_adapter *d)
@@ -1359,13 +1385,13 @@ static int ds3000_frontend_attach(struct dvb_usb_adapter *d)
u8 obuf[] = {7, 1};
d->fe_adap[0].fe = dvb_attach(ds3000_attach, &s660_ds3000_config,
- &d->dev->i2c_adap);
+ &d->dev->i2c_adap);
- if (d->fe_adap[0].fe == NULL)
+ if (!d->fe_adap[0].fe)
return -EIO;
dvb_attach(ts2020_attach, d->fe_adap[0].fe, &s660_ts2020_config,
- &d->dev->i2c_adap);
+ &d->dev->i2c_adap);
st->old_set_voltage = d->fe_adap[0].fe->ops.set_voltage;
d->fe_adap[0].fe->ops.set_voltage = s660_set_voltage;
@@ -1382,8 +1408,8 @@ static int prof_7500_frontend_attach(struct dvb_usb_adapter *d)
u8 obuf[] = {7, 1};
d->fe_adap[0].fe = dvb_attach(stv0900_attach, &prof_7500_stv0900_config,
- &d->dev->i2c_adap, 0);
- if (d->fe_adap[0].fe == NULL)
+ &d->dev->i2c_adap, 0);
+ if (!d->fe_adap[0].fe)
return -EIO;
d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
@@ -1439,12 +1465,12 @@ static int su3000_frontend_attach(struct dvb_usb_adapter *adap)
mutex_unlock(&d->data_mutex);
adap->fe_adap[0].fe = dvb_attach(ds3000_attach, &su3000_ds3000_config,
- &d->i2c_adap);
- if (adap->fe_adap[0].fe == NULL)
+ &d->i2c_adap);
+ if (!adap->fe_adap[0].fe)
return -EIO;
if (dvb_attach(ts2020_attach, adap->fe_adap[0].fe,
- &dw2104_ts2020_config,
+ &dw2104_ts2020_config,
&d->i2c_adap)) {
info("Attached DS3000/TS2020!");
return 0;
@@ -1499,10 +1525,10 @@ static int t220_frontend_attach(struct dvb_usb_adapter *adap)
mutex_unlock(&d->data_mutex);
adap->fe_adap[0].fe = dvb_attach(cxd2820r_attach, &cxd2820r_config,
- &d->i2c_adap, NULL);
- if (adap->fe_adap[0].fe != NULL) {
+ &d->i2c_adap, NULL);
+ if (adap->fe_adap[0].fe) {
if (dvb_attach(tda18271_attach, adap->fe_adap[0].fe, 0x60,
- &d->i2c_adap, &tda18271_config)) {
+ &d->i2c_adap, &tda18271_config)) {
info("Attached TDA18271HD/CXD2820R!");
return 0;
}
@@ -1527,14 +1553,14 @@ static int m88rs2000_frontend_attach(struct dvb_usb_adapter *adap)
mutex_unlock(&d->data_mutex);
adap->fe_adap[0].fe = dvb_attach(m88rs2000_attach,
- &s421_m88rs2000_config,
- &d->i2c_adap);
+ &s421_m88rs2000_config,
+ &d->i2c_adap);
- if (adap->fe_adap[0].fe == NULL)
+ if (!adap->fe_adap[0].fe)
return -EIO;
if (dvb_attach(ts2020_attach, adap->fe_adap[0].fe,
- &dw2104_ts2020_config,
+ &dw2104_ts2020_config,
&d->i2c_adap)) {
info("Attached RS2000/TS2020!");
return 0;
@@ -1701,14 +1727,14 @@ static int tt_s2_4600_frontend_attach(struct dvb_usb_adapter *adap)
static int dw2102_tuner_attach(struct dvb_usb_adapter *adap)
{
dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60,
- &adap->dev->i2c_adap, DVB_PLL_OPERA1);
+ &adap->dev->i2c_adap, DVB_PLL_OPERA1);
return 0;
}
static int dw3101_tuner_attach(struct dvb_usb_adapter *adap)
{
dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60,
- &adap->dev->i2c_adap, DVB_PLL_TUA6034);
+ &adap->dev->i2c_adap, DVB_PLL_TUA6034);
return 0;
}
@@ -1726,7 +1752,7 @@ static int dw2102_rc_query(struct dvb_usb_device *d)
if (d->props.i2c_algo->master_xfer(&d->i2c_adap, &msg, 1) == 1) {
if (msg.buf[0] != 0xff) {
deb_rc("%s: rc code: %x, %x\n",
- __func__, key[0], key[1]);
+ __func__, key[0], key[1]);
rc_keydown(d->rc_dev, RC_PROTO_UNKNOWN, key[0], 0);
}
}
@@ -1747,7 +1773,7 @@ static int prof_rc_query(struct dvb_usb_device *d)
if (d->props.i2c_algo->master_xfer(&d->i2c_adap, &msg, 1) == 1) {
if (msg.buf[0] != 0xff) {
deb_rc("%s: rc code: %x, %x\n",
- __func__, key[0], key[1]);
+ __func__, key[0], key[1]);
rc_keydown(d->rc_dev, RC_PROTO_UNKNOWN, key[0] ^ 0xff,
0);
}
@@ -1769,7 +1795,7 @@ static int su3000_rc_query(struct dvb_usb_device *d)
if (d->props.i2c_algo->master_xfer(&d->i2c_adap, &msg, 1) == 1) {
if (msg.buf[0] != 0xff) {
deb_rc("%s: rc code: %x, %x\n",
- __func__, key[0], key[1]);
+ __func__, key[0], key[1]);
rc_keydown(d->rc_dev, RC_PROTO_RC5,
RC_SCANCODE_RC5(key[1], key[0]), 0);
}
@@ -1807,7 +1833,6 @@ enum dw2102_table_entry {
TECHNOTREND_CONNECT_S2_4600,
TEVII_S482_1,
TEVII_S482_2,
- TERRATEC_CINERGY_S2_BOX,
TEVII_S662
};
@@ -1840,7 +1865,6 @@ static struct usb_device_id dw2102_table[] = {
DVB_USB_DEV(TECHNOTREND, TECHNOTREND_CONNECT_S2_4600),
DVB_USB_DEV(TEVII, TEVII_S482_1),
DVB_USB_DEV(TEVII, TEVII_S482_2),
- DVB_USB_DEV(TERRATEC, TERRATEC_CINERGY_S2_BOX),
DVB_USB_DEV(TEVII, TEVII_S662),
{ }
};
@@ -1848,7 +1872,7 @@ static struct usb_device_id dw2102_table[] = {
MODULE_DEVICE_TABLE(usb, dw2102_table);
static int dw2102_load_firmware(struct usb_device *dev,
- const struct firmware *frmwr)
+ const struct firmware *frmwr)
{
u8 *b, *p;
int ret = 0, i;
@@ -1875,12 +1899,12 @@ static int dw2102_load_firmware(struct usb_device *dev,
dw210x_op_rw(dev, 0xa0, 0x7f92, 0, &reset, 1, DW210X_WRITE_MSG);
dw210x_op_rw(dev, 0xa0, 0xe600, 0, &reset, 1, DW210X_WRITE_MSG);
- if (p != NULL) {
+ if (p) {
memcpy(p, fw->data, fw->size);
for (i = 0; i < fw->size; i += 0x40) {
- b = (u8 *) p + i;
- if (dw210x_op_rw(dev, 0xa0, i, 0, b , 0x40,
- DW210X_WRITE_MSG) != 0x40) {
+ b = (u8 *)p + i;
+ if (dw210x_op_rw(dev, 0xa0, i, 0, b, 0x40,
+ DW210X_WRITE_MSG) != 0x40) {
err("error while transferring firmware");
ret = -EINVAL;
break;
@@ -1906,50 +1930,49 @@ static int dw2102_load_firmware(struct usb_device *dev,
case USB_PID_CYPRESS_DW2104:
reset = 1;
dw210x_op_rw(dev, 0xc4, 0x0000, 0, &reset, 1,
- DW210X_WRITE_MSG);
+ DW210X_WRITE_MSG);
fallthrough;
case USB_PID_CYPRESS_DW3101:
reset = 0;
dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0,
- DW210X_WRITE_MSG);
+ DW210X_WRITE_MSG);
break;
case USB_PID_TERRATEC_CINERGY_S:
case USB_PID_CYPRESS_DW2102:
dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0,
- DW210X_WRITE_MSG);
+ DW210X_WRITE_MSG);
dw210x_op_rw(dev, 0xb9, 0x0000, 0, &reset16[0], 2,
- DW210X_READ_MSG);
+ DW210X_READ_MSG);
/* check STV0299 frontend */
dw210x_op_rw(dev, 0xb5, 0, 0, &reset16[0], 2,
- DW210X_READ_MSG);
+ DW210X_READ_MSG);
if ((reset16[0] == 0xa1) || (reset16[0] == 0x80)) {
dw2102_properties.i2c_algo = &dw2102_i2c_algo;
dw2102_properties.adapter->fe[0].tuner_attach = &dw2102_tuner_attach;
break;
- } else {
- /* check STV0288 frontend */
- reset16[0] = 0xd0;
- reset16[1] = 1;
- reset16[2] = 0;
- dw210x_op_rw(dev, 0xc2, 0, 0, &reset16[0], 3,
- DW210X_WRITE_MSG);
- dw210x_op_rw(dev, 0xc3, 0xd1, 0, &reset16[0], 3,
- DW210X_READ_MSG);
- if (reset16[2] == 0x11) {
- dw2102_properties.i2c_algo = &dw2102_earda_i2c_algo;
- break;
- }
+ }
+ /* check STV0288 frontend */
+ reset16[0] = 0xd0;
+ reset16[1] = 1;
+ reset16[2] = 0;
+ dw210x_op_rw(dev, 0xc2, 0, 0, &reset16[0], 3,
+ DW210X_WRITE_MSG);
+ dw210x_op_rw(dev, 0xc3, 0xd1, 0, &reset16[0], 3,
+ DW210X_READ_MSG);
+ if (reset16[2] == 0x11) {
+ dw2102_properties.i2c_algo = &dw2102_earda_i2c_algo;
+ break;
}
fallthrough;
case 0x2101:
dw210x_op_rw(dev, 0xbc, 0x0030, 0, &reset16[0], 2,
- DW210X_READ_MSG);
+ DW210X_READ_MSG);
dw210x_op_rw(dev, 0xba, 0x0000, 0, &reset16[0], 7,
- DW210X_READ_MSG);
+ DW210X_READ_MSG);
dw210x_op_rw(dev, 0xba, 0x0000, 0, &reset16[0], 7,
- DW210X_READ_MSG);
+ DW210X_READ_MSG);
dw210x_op_rw(dev, 0xb9, 0x0000, 0, &reset16[0], 2,
- DW210X_READ_MSG);
+ DW210X_READ_MSG);
break;
}
@@ -2551,7 +2574,7 @@ static struct dvb_usb_device_properties tt_s2_4600_properties = {
{ NULL },
},
{ "Terratec Cinergy S2 USB BOX",
- { &dw2102_table[TERRATEC_CINERGY_S2_BOX], NULL },
+ { &dw2102_table[TERRATEC_CINERGY_S2_R4], NULL },
{ NULL },
},
{ "TeVii S662",
@@ -2562,18 +2585,18 @@ static struct dvb_usb_device_properties tt_s2_4600_properties = {
};
static int dw2102_probe(struct usb_interface *intf,
- const struct usb_device_id *id)
+ const struct usb_device_id *id)
{
if (!(dvb_usb_device_init(intf, &dw2102_properties,
- THIS_MODULE, NULL, adapter_nr) &&
+ THIS_MODULE, NULL, adapter_nr) &&
dvb_usb_device_init(intf, &dw2104_properties,
THIS_MODULE, NULL, adapter_nr) &&
dvb_usb_device_init(intf, &dw3101_properties,
- THIS_MODULE, NULL, adapter_nr) &&
+ THIS_MODULE, NULL, adapter_nr) &&
dvb_usb_device_init(intf, &s6x0_properties,
- THIS_MODULE, NULL, adapter_nr) &&
+ THIS_MODULE, NULL, adapter_nr) &&
dvb_usb_device_init(intf, &p1100_properties,
- THIS_MODULE, NULL, adapter_nr) &&
+ THIS_MODULE, NULL, adapter_nr) &&
dvb_usb_device_init(intf, &s660_properties,
THIS_MODULE, NULL, adapter_nr) &&
dvb_usb_device_init(intf, &p7500_properties,
@@ -2586,7 +2609,6 @@ static int dw2102_probe(struct usb_interface *intf,
THIS_MODULE, NULL, adapter_nr) &&
dvb_usb_device_init(intf, &tt_s2_4600_properties,
THIS_MODULE, NULL, adapter_nr))) {
-
return 0;
}
diff --git a/drivers/media/usb/dvb-usb/m920x.c b/drivers/media/usb/dvb-usb/m920x.c
index c88a202daf5f..a2054b1b100f 100644
--- a/drivers/media/usb/dvb-usb/m920x.c
+++ b/drivers/media/usb/dvb-usb/m920x.c
@@ -17,7 +17,7 @@
#include <media/tuner.h>
#include "tuner-simple.h"
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
/* debug */
static int dvb_usb_m920x_debug;
diff --git a/drivers/media/usb/dvb-usb/opera1.c b/drivers/media/usb/dvb-usb/opera1.c
index d269f8bb2dee..268f05fc8691 100644
--- a/drivers/media/usb/dvb-usb/opera1.c
+++ b/drivers/media/usb/dvb-usb/opera1.c
@@ -32,10 +32,6 @@
struct opera1_state {
u32 last_key_pressed;
};
-struct rc_map_opera_table {
- u32 keycode;
- u32 event;
-};
static int dvb_usb_opera1_debug;
module_param_named(debug, dvb_usb_opera1_debug, int, 0644);
diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
index 4d037c92af7c..a51cbcf429e1 100644
--- a/drivers/media/usb/em28xx/em28xx-cards.c
+++ b/drivers/media/usb/em28xx/em28xx-cards.c
@@ -555,6 +555,30 @@ static struct em28xx_reg_seq hauppauge_usb_quadhd_atsc_reg_seq[] = {
};
/*
+ * MyGica USB TV Box
+ * GPIO_1,0: 00=Composite audio
+ * 01=Tuner audio
+ * 10=Mute audio
+ * 11=FM radio? (if equipped)
+ * GPIO_2-6: Unused
+ * GPIO_7: ??
+ */
+static const struct em28xx_reg_seq mygica_utv3_composite_audio_gpio[] = {
+ {EM2820_R08_GPIO_CTRL, 0xfc, 0xff, 0},
+ { -1, -1, -1, -1},
+};
+
+static const struct em28xx_reg_seq mygica_utv3_tuner_audio_gpio[] = {
+ {EM2820_R08_GPIO_CTRL, 0xfd, 0xff, 0},
+ { -1, -1, -1, -1},
+};
+
+static const struct em28xx_reg_seq mygica_utv3_suspend_gpio[] = {
+ {EM2820_R08_GPIO_CTRL, 0xfe, 0xff, 0},
+ { -1, -1, -1, -1},
+};
+
+/*
* Button definitions
*/
static const struct em28xx_button std_snapshot_button[] = {
@@ -2578,6 +2602,32 @@ const struct em28xx_board em28xx_boards[] = {
.tuner_gpio = hauppauge_usb_quadhd_atsc_reg_seq,
.leds = hauppauge_usb_quadhd_leds,
},
+ /*
+ * eb1a:2860 MyGica UTV3 Analog USB2.0 TV Box
+ * Empia EM2860, Philips SAA7113, NXP TDA9801T demod,
+ * Tena TNF931D-DFDR1 tuner (contains NXP TDA6509A),
+ * ST HCF4052 demux (switches audio to line out),
+ * no audio over USB
+ */
+ [EM2860_BOARD_MYGICA_UTV3] = {
+ .name = "MyGica UTV3 Analog USB2.0 TV Box",
+ .xclk = EM28XX_XCLK_IR_RC5_MODE | EM28XX_XCLK_FREQUENCY_12MHZ,
+ .tuner_type = TUNER_TENA_TNF_931D_DFDR1,
+ .ir_codes = RC_MAP_MYGICA_UTV3,
+ .decoder = EM28XX_SAA711X,
+ .suspend_gpio = mygica_utv3_suspend_gpio,
+ .input = { {
+ .type = EM28XX_VMUX_COMPOSITE,
+ .vmux = SAA7115_COMPOSITE0,
+ .amux = EM28XX_AMUX_VIDEO,
+ .gpio = mygica_utv3_composite_audio_gpio,
+ }, {
+ .type = EM28XX_VMUX_TELEVISION,
+ .vmux = SAA7115_COMPOSITE2,
+ .amux = EM28XX_AMUX_VIDEO,
+ .gpio = mygica_utv3_tuner_audio_gpio,
+ } },
+ },
};
EXPORT_SYMBOL_GPL(em28xx_boards);
@@ -2819,6 +2869,7 @@ static const struct em28xx_hash_table em28xx_eeprom_hash[] = {
{0x63f653bd, EM2870_BOARD_REDDO_DVB_C_USB_BOX, TUNER_ABSENT},
{0x4e913442, EM2882_BOARD_DIKOM_DK300, TUNER_XC2028},
{0x85dd871e, EM2882_BOARD_ZOLID_HYBRID_TV_STICK, TUNER_XC2028},
+ {0x8f597549, EM2860_BOARD_MYGICA_UTV3, TUNER_TENA_TNF_931D_DFDR1},
};
/* I2C devicelist hash table for devices with generic USB IDs */
@@ -2831,6 +2882,7 @@ static const struct em28xx_hash_table em28xx_i2c_hash[] = {
{0x4ba50080, EM2861_BOARD_GADMEI_UTV330PLUS, TUNER_TNF_5335MF},
{0x6b800080, EM2874_BOARD_LEADERSHIP_ISDBT, TUNER_ABSENT},
{0x27e10080, EM2882_BOARD_ZOLID_HYBRID_TV_STICK, TUNER_XC2028},
+ {0x840d0484, EM2860_BOARD_MYGICA_UTV3, TUNER_TENA_TNF_931D_DFDR1},
};
/* NOTE: introduce a separate hash table for devices with 16 bit eeproms */
@@ -4094,6 +4146,10 @@ static int em28xx_usb_probe(struct usb_interface *intf,
* topology will likely change after the load of the em28xx subdrivers.
*/
#ifdef CONFIG_MEDIA_CONTROLLER
+ /*
+ * No need to check the return value, the device will still be
+ * usable without media controller API.
+ */
retval = media_device_register(dev->media_dev);
#endif
diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c
index 61d7bf701d57..29a7f3f19b56 100644
--- a/drivers/media/usb/em28xx/em28xx-core.c
+++ b/drivers/media/usb/em28xx/em28xx-core.c
@@ -416,8 +416,9 @@ int em28xx_audio_analog_set(struct em28xx *dev)
int ret, i;
u8 xclk;
+ /* Set GPIOs here for boards without audio */
if (dev->int_audio_type == EM28XX_INT_AUDIO_NONE)
- return 0;
+ return em28xx_gpio_set(dev, INPUT(dev->ctl_input)->gpio);
/*
* It is assumed that all devices use master volume for output.
diff --git a/drivers/media/usb/em28xx/em28xx-vbi.c b/drivers/media/usb/em28xx/em28xx-vbi.c
index b253c44c9724..8c5d95181223 100644
--- a/drivers/media/usb/em28xx/em28xx-vbi.c
+++ b/drivers/media/usb/em28xx/em28xx-vbi.c
@@ -84,6 +84,4 @@ const struct vb2_ops em28xx_vbi_qops = {
.buf_queue = vbi_buffer_queue,
.start_streaming = em28xx_start_analog_streaming,
.stop_streaming = em28xx_stop_vbi_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
index 4aef584e21da..66c09bc6d59e 100644
--- a/drivers/media/usb/em28xx/em28xx-video.c
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -1229,8 +1229,6 @@ static const struct vb2_ops em28xx_video_qops = {
.buf_queue = buffer_queue,
.start_streaming = em28xx_start_analog_streaming,
.stop_streaming = em28xx_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static int em28xx_vb2_setup(struct em28xx *dev)
diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
index db18dd814a67..f3449c240d21 100644
--- a/drivers/media/usb/em28xx/em28xx.h
+++ b/drivers/media/usb/em28xx/em28xx.h
@@ -143,6 +143,7 @@
#define EM28178_BOARD_PCTV_461E_V2 104
#define EM2860_BOARD_MYGICA_IGRABBER 105
#define EM2874_BOARD_HAUPPAUGE_USB_QUADHD 106
+#define EM2860_BOARD_MYGICA_UTV3 107
/* Limits minimum and default number of buffers */
#define EM28XX_MIN_BUF 4
diff --git a/drivers/media/usb/go7007/go7007-driver.c b/drivers/media/usb/go7007/go7007-driver.c
index 0c24e2984304..468406302cd5 100644
--- a/drivers/media/usb/go7007/go7007-driver.c
+++ b/drivers/media/usb/go7007/go7007-driver.c
@@ -80,7 +80,7 @@ static int go7007_load_encoder(struct go7007 *go)
const struct firmware *fw_entry;
char fw_name[] = "go7007/go7007fw.bin";
void *bounce;
- int fw_len, rv = 0;
+ int fw_len;
u16 intr_val, intr_data;
if (go->boot_fw == NULL) {
@@ -109,9 +109,11 @@ static int go7007_load_encoder(struct go7007 *go)
go7007_read_interrupt(go, &intr_val, &intr_data) < 0 ||
(intr_val & ~0x1) != 0x5a5a) {
v4l2_err(go, "error transferring firmware\n");
- rv = -1;
+ kfree(go->boot_fw);
+ go->boot_fw = NULL;
+ return -1;
}
- return rv;
+ return 0;
}
MODULE_FIRMWARE("go7007/go7007fw.bin");
@@ -734,4 +736,5 @@ void go7007_update_board(struct go7007 *go)
}
EXPORT_SYMBOL(go7007_update_board);
+MODULE_DESCRIPTION("WIS GO7007 MPEG encoder support");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/usb/go7007/go7007-fw.c b/drivers/media/usb/go7007/go7007-fw.c
index 018019ba47d4..86ce593e0c54 100644
--- a/drivers/media/usb/go7007/go7007-fw.c
+++ b/drivers/media/usb/go7007/go7007-fw.c
@@ -1289,8 +1289,8 @@ static int avsync_to_package(struct go7007 *go, __le16 *code, int space)
0xbf99, (u16)((-adjratio) >> 16),
0xbf92, 0,
0xbf93, 0,
- 0xbff4, f1 > f2 ? f1 : f2,
- 0xbff5, f1 < f2 ? f1 : f2,
+ 0xbff4, max(f1, f2),
+ 0xbff5, min(f1, f2),
0xbff6, f1 < f2 ? ratio : ratio + 1,
0xbff7, f1 > f2 ? ratio : ratio + 1,
0xbff8, 0,
diff --git a/drivers/media/usb/go7007/go7007-i2c.c b/drivers/media/usb/go7007/go7007-i2c.c
index 2880370e45c8..f6ce28a4a768 100644
--- a/drivers/media/usb/go7007/go7007-i2c.c
+++ b/drivers/media/usb/go7007/go7007-i2c.c
@@ -33,7 +33,21 @@
/* There is only one I2C port on the TW2804 that feeds all four GO7007 VIPs
* on the Adlink PCI-MPG24, so access is shared between all of them. */
-static DEFINE_MUTEX(adlink_mpg24_i2c_lock);
+static DEFINE_MUTEX(adlink_mpg24_i2c_mutex);
+
+static inline void adlink_mpg24_i2c_lock(struct go7007 *go)
+{
+ /* Bridge the I2C port on this GO7007 to the shared bus */
+ mutex_lock(&adlink_mpg24_i2c_mutex);
+ go7007_write_addr(go, 0x3c82, 0x0020);
+}
+
+static inline void adlink_mpg24_i2c_unlock(struct go7007 *go)
+{
+ /* Isolate the I2C port on this GO7007 from the shared bus */
+ go7007_write_addr(go, 0x3c82, 0x0000);
+ mutex_unlock(&adlink_mpg24_i2c_mutex);
+}
static int go7007_i2c_xfer(struct go7007 *go, u16 addr, int read,
u16 command, int flags, u8 *data)
@@ -56,11 +70,8 @@ static int go7007_i2c_xfer(struct go7007 *go, u16 addr, int read,
mutex_lock(&go->hw_lock);
- if (go->board_id == GO7007_BOARDID_ADLINK_MPG24) {
- /* Bridge the I2C port on this GO7007 to the shared bus */
- mutex_lock(&adlink_mpg24_i2c_lock);
- go7007_write_addr(go, 0x3c82, 0x0020);
- }
+ if (go->board_id == GO7007_BOARDID_ADLINK_MPG24)
+ adlink_mpg24_i2c_lock(go);
/* Wait for I2C adapter to be ready */
for (i = 0; i < 10; ++i) {
@@ -116,11 +127,8 @@ static int go7007_i2c_xfer(struct go7007 *go, u16 addr, int read,
ret = 0;
i2c_done:
- if (go->board_id == GO7007_BOARDID_ADLINK_MPG24) {
- /* Isolate the I2C port on this GO7007 from the shared bus */
- go7007_write_addr(go, 0x3c82, 0x0000);
- mutex_unlock(&adlink_mpg24_i2c_lock);
- }
+ if (go->board_id == GO7007_BOARDID_ADLINK_MPG24)
+ adlink_mpg24_i2c_unlock(go);
mutex_unlock(&go->hw_lock);
return ret;
}
diff --git a/drivers/media/usb/go7007/go7007-usb.c b/drivers/media/usb/go7007/go7007-usb.c
index eeb85981e02b..334cdde81a5c 100644
--- a/drivers/media/usb/go7007/go7007-usb.c
+++ b/drivers/media/usb/go7007/go7007-usb.c
@@ -1201,7 +1201,9 @@ static int go7007_usb_probe(struct usb_interface *intf,
u16 channel;
/* read channel number from GPIO[1:0] */
- go7007_read_addr(go, 0x3c81, &channel);
+ if (go7007_read_addr(go, 0x3c81, &channel))
+ goto allocfail;
+
channel &= 0x3;
go->board_id = GO7007_BOARDID_ADLINK_MPG24;
usb->board = board = &board_adlink_mpg24;
@@ -1350,4 +1352,5 @@ static struct usb_driver go7007_usb_driver = {
};
module_usb_driver(go7007_usb_driver);
+MODULE_DESCRIPTION("WIS GO7007 USB support");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/usb/go7007/go7007-v4l2.c b/drivers/media/usb/go7007/go7007-v4l2.c
index 13256565b034..2087ffcb85a5 100644
--- a/drivers/media/usb/go7007/go7007-v4l2.c
+++ b/drivers/media/usb/go7007/go7007-v4l2.c
@@ -452,8 +452,6 @@ static const struct vb2_ops go7007_video_qops = {
.buf_finish = go7007_buf_finish,
.start_streaming = go7007_start_streaming,
.stop_streaming = go7007_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static int vidioc_g_parm(struct file *filp, void *priv,
diff --git a/drivers/media/usb/go7007/s2250-board.c b/drivers/media/usb/go7007/s2250-board.c
index db1fab96d529..a155b987282f 100644
--- a/drivers/media/usb/go7007/s2250-board.c
+++ b/drivers/media/usb/go7007/s2250-board.c
@@ -611,7 +611,7 @@ static void s2250_remove(struct i2c_client *client)
}
static const struct i2c_device_id s2250_id[] = {
- { "s2250", 0 },
+ { "s2250" },
{ }
};
MODULE_DEVICE_TABLE(i2c, s2250_id);
diff --git a/drivers/media/usb/gspca/cpia1.c b/drivers/media/usb/gspca/cpia1.c
index 5f5fa851ca64..14aaf36cde6e 100644
--- a/drivers/media/usb/gspca/cpia1.c
+++ b/drivers/media/usb/gspca/cpia1.c
@@ -604,10 +604,8 @@ static int find_over_exposure(int brightness)
MaxAllowableOverExposure = FLICKER_MAX_EXPOSURE - brightness -
FLICKER_BRIGHTNESS_CONSTANT;
- if (MaxAllowableOverExposure < FLICKER_ALLOWABLE_OVER_EXPOSURE)
- OverExposure = MaxAllowableOverExposure;
- else
- OverExposure = FLICKER_ALLOWABLE_OVER_EXPOSURE;
+ OverExposure = min(MaxAllowableOverExposure,
+ FLICKER_ALLOWABLE_OVER_EXPOSURE);
return OverExposure;
}
diff --git a/drivers/media/usb/gspca/gspca.c b/drivers/media/usb/gspca/gspca.c
index e8c8bdb9c40b..25edd2189654 100644
--- a/drivers/media/usb/gspca/gspca.c
+++ b/drivers/media/usb/gspca/gspca.c
@@ -1380,8 +1380,6 @@ static const struct vb2_ops gspca_qops = {
.buf_queue = gspca_buffer_queue,
.start_streaming = gspca_start_streaming,
.stop_streaming = gspca_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static const struct v4l2_file_operations dev_fops = {
diff --git a/drivers/media/usb/gspca/ov534.c b/drivers/media/usb/gspca/ov534.c
index 8b6a57f170d0..bdff64a29a33 100644
--- a/drivers/media/usb/gspca/ov534.c
+++ b/drivers/media/usb/gspca/ov534.c
@@ -847,7 +847,7 @@ static void set_frame_rate(struct gspca_dev *gspca_dev)
r = rate_1;
i = ARRAY_SIZE(rate_1);
}
- while (--i > 0) {
+ while (--i >= 0) {
if (sd->frame_rate >= r->fps)
break;
r++;
diff --git a/drivers/media/usb/hackrf/hackrf.c b/drivers/media/usb/hackrf/hackrf.c
index 9c0ecd5f056c..0b50de8775a3 100644
--- a/drivers/media/usb/hackrf/hackrf.c
+++ b/drivers/media/usb/hackrf/hackrf.c
@@ -888,8 +888,6 @@ static const struct vb2_ops hackrf_vb2_ops = {
.buf_queue = hackrf_buf_queue,
.start_streaming = hackrf_start_streaming,
.stop_streaming = hackrf_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static int hackrf_querycap(struct file *file, void *fh,
@@ -1398,6 +1396,7 @@ static int hackrf_probe(struct usb_interface *intf,
dev->rx_vb2_queue.drv_priv = dev;
dev->rx_vb2_queue.buf_struct_size = sizeof(struct hackrf_buffer);
dev->rx_vb2_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ dev->rx_vb2_queue.lock = &dev->vb_queue_lock;
ret = vb2_queue_init(&dev->rx_vb2_queue);
if (ret) {
dev_err(dev->dev, "Could not initialize rx vb2 queue\n");
@@ -1413,6 +1412,7 @@ static int hackrf_probe(struct usb_interface *intf,
dev->tx_vb2_queue.drv_priv = dev;
dev->tx_vb2_queue.buf_struct_size = sizeof(struct hackrf_buffer);
dev->tx_vb2_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ dev->tx_vb2_queue.lock = &dev->vb_queue_lock;
ret = vb2_queue_init(&dev->tx_vb2_queue);
if (ret) {
dev_err(dev->dev, "Could not initialize tx vb2 queue\n");
@@ -1474,7 +1474,6 @@ static int hackrf_probe(struct usb_interface *intf,
/* Init video_device structure for receiver */
dev->rx_vdev = hackrf_template;
dev->rx_vdev.queue = &dev->rx_vb2_queue;
- dev->rx_vdev.queue->lock = &dev->vb_queue_lock;
dev->rx_vdev.v4l2_dev = &dev->v4l2_dev;
dev->rx_vdev.ctrl_handler = &dev->rx_ctrl_handler;
dev->rx_vdev.lock = &dev->v4l2_lock;
@@ -1494,7 +1493,6 @@ static int hackrf_probe(struct usb_interface *intf,
/* Init video_device structure for transmitter */
dev->tx_vdev = hackrf_template;
dev->tx_vdev.queue = &dev->tx_vb2_queue;
- dev->tx_vdev.queue->lock = &dev->vb_queue_lock;
dev->tx_vdev.v4l2_dev = &dev->v4l2_dev;
dev->tx_vdev.ctrl_handler = &dev->tx_ctrl_handler;
dev->tx_vdev.lock = &dev->v4l2_lock;
diff --git a/drivers/media/usb/msi2500/msi2500.c b/drivers/media/usb/msi2500/msi2500.c
index 9759996ee6a4..33099f39146a 100644
--- a/drivers/media/usb/msi2500/msi2500.c
+++ b/drivers/media/usb/msi2500/msi2500.c
@@ -107,7 +107,7 @@ struct msi2500_dev {
struct video_device vdev;
struct v4l2_device v4l2_dev;
struct v4l2_subdev *v4l2_subdev;
- struct spi_master *master;
+ struct spi_controller *ctlr;
/* videobuf2 queue and queued buffers list */
struct vb2_queue vb_queue;
@@ -574,7 +574,7 @@ static void msi2500_disconnect(struct usb_interface *intf)
dev->udev = NULL;
v4l2_device_disconnect(&dev->v4l2_dev);
video_unregister_device(&dev->vdev);
- spi_unregister_master(dev->master);
+ spi_unregister_controller(dev->ctlr);
mutex_unlock(&dev->v4l2_lock);
mutex_unlock(&dev->vb_queue_lock);
@@ -883,8 +883,6 @@ static const struct vb2_ops msi2500_vb2_ops = {
.buf_queue = msi2500_buf_queue,
.start_streaming = msi2500_start_streaming,
.stop_streaming = msi2500_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static int msi2500_enum_fmt_sdr_cap(struct file *file, void *priv,
@@ -1136,10 +1134,10 @@ static void msi2500_video_release(struct v4l2_device *v)
kfree(dev);
}
-static int msi2500_transfer_one_message(struct spi_master *master,
+static int msi2500_transfer_one_message(struct spi_controller *ctlr,
struct spi_message *m)
{
- struct msi2500_dev *dev = spi_master_get_devdata(master);
+ struct msi2500_dev *dev = spi_controller_get_devdata(ctlr);
struct spi_transfer *t;
int ret = 0;
u32 data;
@@ -1154,7 +1152,7 @@ static int msi2500_transfer_one_message(struct spi_master *master,
}
m->status = ret;
- spi_finalize_current_message(master);
+ spi_finalize_current_message(ctlr);
return ret;
}
@@ -1163,7 +1161,7 @@ static int msi2500_probe(struct usb_interface *intf,
{
struct msi2500_dev *dev;
struct v4l2_subdev *sd;
- struct spi_master *master;
+ struct spi_controller *ctlr;
int ret;
static struct spi_board_info board_info = {
.modalias = "msi001",
@@ -1199,6 +1197,7 @@ static int msi2500_probe(struct usb_interface *intf,
dev->vb_queue.ops = &msi2500_vb2_ops;
dev->vb_queue.mem_ops = &vb2_vmalloc_memops;
dev->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ dev->vb_queue.lock = &dev->vb_queue_lock;
ret = vb2_queue_init(&dev->vb_queue);
if (ret) {
dev_err(dev->dev, "Could not initialize vb2 queue\n");
@@ -1208,7 +1207,6 @@ static int msi2500_probe(struct usb_interface *intf,
/* Init video_device structure */
dev->vdev = msi2500_template;
dev->vdev.queue = &dev->vb_queue;
- dev->vdev.queue->lock = &dev->vb_queue_lock;
video_set_drvdata(&dev->vdev, dev);
/* Register the v4l2_device structure */
@@ -1219,31 +1217,31 @@ static int msi2500_probe(struct usb_interface *intf,
goto err_free_mem;
}
- /* SPI master adapter */
- master = spi_alloc_master(dev->dev, 0);
- if (master == NULL) {
+ /* SPI host adapter */
+ ctlr = spi_alloc_host(dev->dev, 0);
+ if (ctlr == NULL) {
ret = -ENOMEM;
goto err_unregister_v4l2_dev;
}
- dev->master = master;
- master->bus_num = -1;
- master->num_chipselect = 1;
- master->transfer_one_message = msi2500_transfer_one_message;
- spi_master_set_devdata(master, dev);
- ret = spi_register_master(master);
+ dev->ctlr = ctlr;
+ ctlr->bus_num = -1;
+ ctlr->num_chipselect = 1;
+ ctlr->transfer_one_message = msi2500_transfer_one_message;
+ spi_controller_set_devdata(ctlr, dev);
+ ret = spi_register_controller(ctlr);
if (ret) {
- spi_master_put(master);
+ spi_controller_put(ctlr);
goto err_unregister_v4l2_dev;
}
/* load v4l2 subdevice */
- sd = v4l2_spi_new_subdev(&dev->v4l2_dev, master, &board_info);
+ sd = v4l2_spi_new_subdev(&dev->v4l2_dev, ctlr, &board_info);
dev->v4l2_subdev = sd;
if (sd == NULL) {
dev_err(dev->dev, "cannot get v4l2 subdevice\n");
ret = -ENODEV;
- goto err_unregister_master;
+ goto err_unregister_controller;
}
/* Register controls */
@@ -1276,8 +1274,8 @@ static int msi2500_probe(struct usb_interface *intf,
return 0;
err_free_controls:
v4l2_ctrl_handler_free(&dev->hdl);
-err_unregister_master:
- spi_unregister_master(dev->master);
+err_unregister_controller:
+ spi_unregister_controller(dev->ctlr);
err_unregister_v4l2_dev:
v4l2_device_unregister(&dev->v4l2_dev);
err_free_mem:
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-context.c b/drivers/media/usb/pvrusb2/pvrusb2-context.c
index 1764674de98b..73c95ba2328a 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-context.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-context.c
@@ -90,8 +90,10 @@ static void pvr2_context_destroy(struct pvr2_context *mp)
}
-static void pvr2_context_notify(struct pvr2_context *mp)
+static void pvr2_context_notify(void *ptr)
{
+ struct pvr2_context *mp = ptr;
+
pvr2_context_set_notify(mp,!0);
}
@@ -106,9 +108,7 @@ static void pvr2_context_check(struct pvr2_context *mp)
pvr2_trace(PVR2_TRACE_CTXT,
"pvr2_context %p (initialize)", mp);
/* Finish hardware initialization */
- if (pvr2_hdw_initialize(mp->hdw,
- (void (*)(void *))pvr2_context_notify,
- mp)) {
+ if (pvr2_hdw_initialize(mp->hdw, pvr2_context_notify, mp)) {
mp->video_stream.stream =
pvr2_hdw_get_video_stream(mp->hdw);
/* Trigger interface initialization. By doing this
@@ -267,9 +267,9 @@ static void pvr2_context_exit(struct pvr2_context *mp)
void pvr2_context_disconnect(struct pvr2_context *mp)
{
pvr2_hdw_disconnect(mp->hdw);
- mp->disconnect_flag = !0;
if (!pvr2_context_shutok())
pvr2_context_notify(mp);
+ mp->disconnect_flag = !0;
}
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-debugifc.c b/drivers/media/usb/pvrusb2/pvrusb2-debugifc.c
index 84cfb5ce8b8d..81d711269ab5 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-debugifc.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-debugifc.c
@@ -9,11 +9,6 @@
#include "pvrusb2-hdw.h"
#include "pvrusb2-debug.h"
-struct debugifc_mask_item {
- const char *name;
- unsigned long msk;
-};
-
static unsigned int debugifc_count_whitespace(const char *buf,
unsigned int count)
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-dvb.c b/drivers/media/usb/pvrusb2/pvrusb2-dvb.c
index 26811efe0fb5..3610139fb9ad 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-dvb.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-dvb.c
@@ -33,9 +33,6 @@ static int pvr2_dvb_feed_func(struct pvr2_dvb_adapter *adap)
for (;;) {
if (kthread_should_stop()) break;
- /* Not sure about this... */
- try_to_freeze();
-
bp = pvr2_stream_get_ready_buffer(stream);
if (bp != NULL) {
count = pvr2_buffer_get_count(bp);
@@ -62,8 +59,7 @@ static int pvr2_dvb_feed_func(struct pvr2_dvb_adapter *adap)
/* Wait until more buffers become available or we're
told not to wait any longer. */
- ret = wait_event_interruptible(
- adap->buffer_wait_data,
+ ret = wait_event_freezable(adap->buffer_wait_data,
(pvr2_stream_get_ready_count(stream) > 0) ||
kthread_should_stop());
if (ret < 0) break;
@@ -88,8 +84,10 @@ static int pvr2_dvb_feed_thread(void *data)
return stat;
}
-static void pvr2_dvb_notify(struct pvr2_dvb_adapter *adap)
+static void pvr2_dvb_notify(void *ptr)
{
+ struct pvr2_dvb_adapter *adap = ptr;
+
wake_up(&adap->buffer_wait_data);
}
@@ -149,7 +147,7 @@ static int pvr2_dvb_stream_do_start(struct pvr2_dvb_adapter *adap)
}
pvr2_stream_set_callback(pvr->video_stream.stream,
- (pvr2_stream_callback) pvr2_dvb_notify, adap);
+ pvr2_dvb_notify, adap);
ret = pvr2_stream_set_buffer_count(stream, PVR2_DVB_BUFFER_COUNT);
if (ret < 0) return ret;
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-io.c b/drivers/media/usb/pvrusb2/pvrusb2-io.c
index 675dc7153e2b..28ffe7981f8c 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-io.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-io.c
@@ -335,8 +335,8 @@ static int pvr2_stream_buffer_count(struct pvr2_stream *sp, unsigned int cnt)
if (scnt < sp->buffer_slot_count) {
struct pvr2_buffer **nb = NULL;
if (scnt) {
- nb = kmemdup(sp->buffers, scnt * sizeof(*nb),
- GFP_KERNEL);
+ nb = kmemdup_array(sp->buffers, scnt, sizeof(*nb),
+ GFP_KERNEL);
if (!nb) return -ENOMEM;
}
kfree(sp->buffers);
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c
index c04ab7258d64..d608b793fa84 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c
@@ -1033,8 +1033,10 @@ static int pvr2_v4l2_open(struct file *file)
}
-static void pvr2_v4l2_notify(struct pvr2_v4l2_fh *fhp)
+static void pvr2_v4l2_notify(void *ptr)
{
+ struct pvr2_v4l2_fh *fhp = ptr;
+
wake_up(&fhp->wait_data);
}
@@ -1067,7 +1069,7 @@ static int pvr2_v4l2_iosetup(struct pvr2_v4l2_fh *fh)
hdw = fh->channel.mc_head->hdw;
sp = fh->pdi->stream->stream;
- pvr2_stream_set_callback(sp,(pvr2_stream_callback)pvr2_v4l2_notify,fh);
+ pvr2_stream_set_callback(sp, pvr2_v4l2_notify, fh);
pvr2_hdw_set_stream_type(hdw,fh->pdi->config);
if ((ret = pvr2_hdw_set_streaming(hdw,!0)) < 0) return ret;
return pvr2_ioread_set_enabled(fh->rhp,!0);
@@ -1198,11 +1200,6 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,
dip->minor_type = pvr2_v4l_type_video;
nr_ptr = video_nr;
caps |= V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_AUDIO;
- if (!dip->stream) {
- pr_err(KBUILD_MODNAME
- ": Failed to set up pvrusb2 v4l video dev due to missing stream instance\n");
- return;
- }
break;
case VFL_TYPE_VBI:
dip->config = pvr2_config_vbi;
diff --git a/drivers/media/usb/pwc/pwc-if.c b/drivers/media/usb/pwc/pwc-if.c
index e342199711d3..3ec9eb5956ed 100644
--- a/drivers/media/usb/pwc/pwc-if.c
+++ b/drivers/media/usb/pwc/pwc-if.c
@@ -760,8 +760,6 @@ static const struct vb2_ops pwc_vb_queue_ops = {
.buf_queue = buffer_queue,
.start_streaming = start_streaming,
.stop_streaming = stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
/***************************************************************************/
@@ -1054,6 +1052,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
pdev->vb_queue.ops = &pwc_vb_queue_ops;
pdev->vb_queue.mem_ops = &vb2_vmalloc_memops;
pdev->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ pdev->vb_queue.lock = &pdev->vb_queue_lock;
rc = vb2_queue_init(&pdev->vb_queue);
if (rc < 0) {
PWC_ERROR("Oops, could not initialize vb2 queue.\n");
@@ -1064,7 +1063,6 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
pdev->vdev = pwc_template;
strscpy(pdev->vdev.name, name, sizeof(pdev->vdev.name));
pdev->vdev.queue = &pdev->vb_queue;
- pdev->vdev.queue->lock = &pdev->vb_queue_lock;
video_set_drvdata(&pdev->vdev, pdev);
pdev->release = le16_to_cpu(udev->descriptor.bcdDevice);
diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c
index 3c2627712fe9..899a7a67e2ba 100644
--- a/drivers/media/usb/s2255/s2255drv.c
+++ b/drivers/media/usb/s2255/s2255drv.c
@@ -247,7 +247,7 @@ struct s2255_vc {
struct s2255_dev {
struct s2255_vc vc[MAX_CHANNELS];
struct v4l2_device v4l2_dev;
- atomic_t num_channels;
+ refcount_t num_channels;
int frames;
struct mutex lock; /* channels[].vdev.lock */
struct mutex cmdlock; /* protects cmdbuf */
@@ -704,8 +704,6 @@ static const struct vb2_ops s2255_video_qops = {
.buf_queue = buffer_queue,
.start_streaming = start_streaming,
.stop_streaming = stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static int vidioc_querycap(struct file *file, void *priv,
@@ -1550,11 +1548,11 @@ static void s2255_video_device_release(struct video_device *vdev)
container_of(vdev, struct s2255_vc, vdev);
dprintk(dev, 4, "%s, chnls: %d\n", __func__,
- atomic_read(&dev->num_channels));
+ refcount_read(&dev->num_channels));
v4l2_ctrl_handler_free(&vc->hdl);
- if (atomic_dec_and_test(&dev->num_channels))
+ if (refcount_dec_and_test(&dev->num_channels))
s2255_destroy(dev);
return;
}
@@ -1659,7 +1657,7 @@ static int s2255_probe_v4l(struct s2255_dev *dev)
"failed to register video device!\n");
break;
}
- atomic_inc(&dev->num_channels);
+ refcount_inc(&dev->num_channels);
v4l2_info(&dev->v4l2_dev, "V4L2 device registered as %s\n",
video_device_node_name(&vc->vdev));
@@ -1667,11 +1665,11 @@ static int s2255_probe_v4l(struct s2255_dev *dev)
pr_info("Sensoray 2255 V4L driver Revision: %s\n",
S2255_VERSION);
/* if no channels registered, return error and probe will fail*/
- if (atomic_read(&dev->num_channels) == 0) {
+ if (refcount_read(&dev->num_channels) == 0) {
v4l2_device_unregister(&dev->v4l2_dev);
return ret;
}
- if (atomic_read(&dev->num_channels) != MAX_CHANNELS)
+ if (refcount_read(&dev->num_channels) != MAX_CHANNELS)
pr_warn("s2255: Not all channels available.\n");
return 0;
}
@@ -1906,9 +1904,10 @@ static int s2255_get_fx2fw(struct s2255_dev *dev)
{
int fw;
int ret;
- unsigned char transBuffer[64];
- ret = s2255_vendor_req(dev, S2255_VR_FW, 0, 0, transBuffer, 2,
- S2255_VR_IN);
+ u8 transBuffer[2] = {};
+
+ ret = s2255_vendor_req(dev, S2255_VR_FW, 0, 0, transBuffer,
+ sizeof(transBuffer), S2255_VR_IN);
if (ret < 0)
dprintk(dev, 2, "get fw error: %x\n", ret);
fw = transBuffer[0] + (transBuffer[1] << 8);
@@ -2220,7 +2219,7 @@ static int s2255_probe(struct usb_interface *interface,
goto errorFWDATA1;
}
- atomic_set(&dev->num_channels, 0);
+ refcount_set(&dev->num_channels, 0);
dev->pid = id->idProduct;
dev->fw_data = kzalloc(sizeof(struct s2255_fw), GFP_KERNEL);
if (!dev->fw_data)
@@ -2340,12 +2339,12 @@ static void s2255_disconnect(struct usb_interface *interface)
{
struct s2255_dev *dev = to_s2255_dev(usb_get_intfdata(interface));
int i;
- int channels = atomic_read(&dev->num_channels);
+ int channels = refcount_read(&dev->num_channels);
mutex_lock(&dev->lock);
v4l2_device_disconnect(&dev->v4l2_dev);
mutex_unlock(&dev->lock);
/*see comments in the uvc_driver.c usb disconnect function */
- atomic_inc(&dev->num_channels);
+ refcount_inc(&dev->num_channels);
/* unregister each video device. */
for (i = 0; i < channels; i++)
video_unregister_device(&dev->vc[i].vdev);
@@ -2358,7 +2357,7 @@ static void s2255_disconnect(struct usb_interface *interface)
dev->vc[i].vidstatus_ready = 1;
wake_up(&dev->vc[i].wait_vidstatus);
}
- if (atomic_dec_and_test(&dev->num_channels))
+ if (refcount_dec_and_test(&dev->num_channels))
s2255_destroy(dev);
dev_info(&interface->dev, "%s\n", __func__);
}
diff --git a/drivers/media/usb/siano/smsusb.c b/drivers/media/usb/siano/smsusb.c
index 9d9e14c858e6..2c8179a84991 100644
--- a/drivers/media/usb/siano/smsusb.c
+++ b/drivers/media/usb/siano/smsusb.c
@@ -40,7 +40,7 @@ struct smsusb_urb_t {
struct smscore_buffer_t *cb;
struct smsusb_device_t *dev;
- struct urb urb;
+ struct urb *urb;
/* For the bottom half */
struct work_struct wq;
@@ -160,7 +160,7 @@ static int smsusb_submit_urb(struct smsusb_device_t *dev,
}
usb_fill_bulk_urb(
- &surb->urb,
+ surb->urb,
dev->udev,
usb_rcvbulkpipe(dev->udev, dev->in_ep),
surb->cb->p,
@@ -168,9 +168,9 @@ static int smsusb_submit_urb(struct smsusb_device_t *dev,
smsusb_onresponse,
surb
);
- surb->urb.transfer_flags |= URB_FREE_BUFFER;
+ surb->urb->transfer_flags |= URB_FREE_BUFFER;
- return usb_submit_urb(&surb->urb, GFP_ATOMIC);
+ return usb_submit_urb(surb->urb, GFP_ATOMIC);
}
static void smsusb_stop_streaming(struct smsusb_device_t *dev)
@@ -178,7 +178,7 @@ static void smsusb_stop_streaming(struct smsusb_device_t *dev)
int i;
for (i = 0; i < MAX_URBS; i++) {
- usb_kill_urb(&dev->surbs[i].urb);
+ usb_kill_urb(dev->surbs[i].urb);
if (dev->surbs[i].wq.func)
cancel_work_sync(&dev->surbs[i].wq);
@@ -338,6 +338,8 @@ static void smsusb_term_device(struct usb_interface *intf)
struct smsusb_device_t *dev = usb_get_intfdata(intf);
if (dev) {
+ int i;
+
dev->state = SMSUSB_DISCONNECTED;
smsusb_stop_streaming(dev);
@@ -346,6 +348,9 @@ static void smsusb_term_device(struct usb_interface *intf)
if (dev->coredev)
smscore_unregister_device(dev->coredev);
+ for (i = 0; i < MAX_URBS; i++)
+ usb_free_urb(dev->surbs[i].urb);
+
pr_debug("device 0x%p destroyed\n", dev);
kfree(dev);
}
@@ -463,7 +468,9 @@ static int smsusb_init_device(struct usb_interface *intf, int board_id)
/* initialize urbs */
for (i = 0; i < MAX_URBS; i++) {
dev->surbs[i].dev = dev;
- usb_init_urb(&dev->surbs[i].urb);
+ dev->surbs[i].urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!dev->surbs[i].urb)
+ goto err_unregister_device;
}
pr_debug("smsusb_start_streaming(...).\n");
@@ -486,6 +493,7 @@ static int smsusb_init_device(struct usb_interface *intf, int board_id)
return rc;
err_unregister_device:
+ /* smsusb_term_device() frees any allocated urb. */
smsusb_term_device(intf);
#ifdef CONFIG_MEDIA_CONTROLLER_DVB
media_device_unregister(mdev);
@@ -724,5 +732,5 @@ static struct usb_driver smsusb_driver = {
module_usb_driver(smsusb_driver);
MODULE_DESCRIPTION("Driver for the Siano SMS1xxx USB dongle");
-MODULE_AUTHOR("Siano Mobile Silicon, INC. (uris@siano-ms.com)");
+MODULE_AUTHOR("Siano Mobile Silicon, Inc. <uris@siano-ms.com>");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/stk1160/stk1160-v4l.c b/drivers/media/usb/stk1160/stk1160-v4l.c
index a1f785a5ffd8..5ba3d9c4b3fb 100644
--- a/drivers/media/usb/stk1160/stk1160-v4l.c
+++ b/drivers/media/usb/stk1160/stk1160-v4l.c
@@ -734,8 +734,6 @@ static const struct vb2_ops stk1160_video_qops = {
.buf_queue = buffer_queue,
.start_streaming = start_streaming,
.stop_streaming = stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static const struct video_device v4l_template = {
diff --git a/drivers/media/usb/stk1160/stk1160-video.c b/drivers/media/usb/stk1160/stk1160-video.c
index 366f0e4a5dc0..9cbd957ecc90 100644
--- a/drivers/media/usb/stk1160/stk1160-video.c
+++ b/drivers/media/usb/stk1160/stk1160-video.c
@@ -99,7 +99,7 @@ void stk1160_buffer_done(struct stk1160 *dev)
static inline
void stk1160_copy_video(struct stk1160 *dev, u8 *src, int len)
{
- int linesdone, lineoff, lencopy;
+ int linesdone, lineoff, lencopy, offset;
int bytesperline = dev->width * 2;
struct stk1160_buffer *buf = dev->isoc_ctl.buf;
u8 *dst = buf->mem;
@@ -130,17 +130,19 @@ void stk1160_copy_video(struct stk1160 *dev, u8 *src, int len)
dst += linesdone * bytesperline * 2 + lineoff;
/* Copy the remaining of current line */
- if (remain < (bytesperline - lineoff))
- lencopy = remain;
- else
- lencopy = bytesperline - lineoff;
+ lencopy = min(remain, bytesperline - lineoff);
/*
* Check if we have enough space left in the buffer.
* In that case, we force loop exit after copy.
*/
- if (lencopy > buf->bytesused - buf->length) {
- lencopy = buf->bytesused - buf->length;
+ offset = dst - (u8 *)buf->mem;
+ if (offset > buf->length) {
+ dev_warn_ratelimited(dev->dev, "out of bounds offset\n");
+ return;
+ }
+ if (lencopy > buf->length - offset) {
+ lencopy = buf->length - offset;
remain = lencopy;
}
@@ -173,17 +175,19 @@ void stk1160_copy_video(struct stk1160 *dev, u8 *src, int len)
src += lencopy;
/* Copy one line at a time */
- if (remain < bytesperline)
- lencopy = remain;
- else
- lencopy = bytesperline;
+ lencopy = min(remain, bytesperline);
/*
* Check if we have enough space left in the buffer.
* In that case, we force loop exit after copy.
*/
- if (lencopy > buf->bytesused - buf->length) {
- lencopy = buf->bytesused - buf->length;
+ offset = dst - (u8 *)buf->mem;
+ if (offset > buf->length) {
+ dev_warn_ratelimited(dev->dev, "offset out of bounds\n");
+ return;
+ }
+ if (lencopy > buf->length - offset) {
+ lencopy = buf->length - offset;
remain = lencopy;
}
diff --git a/drivers/media/usb/ttusb-dec/ttusb_dec.c b/drivers/media/usb/ttusb-dec/ttusb_dec.c
index 79faa2560613..b4575fe89c95 100644
--- a/drivers/media/usb/ttusb-dec/ttusb_dec.c
+++ b/drivers/media/usb/ttusb-dec/ttusb_dec.c
@@ -19,6 +19,7 @@
#include <linux/input.h>
#include <linux/mutex.h>
+#include <linux/workqueue.h>
#include <media/dmxdev.h>
#include <media/dvb_demux.h>
@@ -139,7 +140,7 @@ struct ttusb_dec {
int v_pes_postbytes;
struct list_head urb_frame_list;
- struct tasklet_struct urb_tasklet;
+ struct work_struct urb_bh_work;
spinlock_t urb_frame_list_lock;
struct dvb_demux_filter *audio_filter;
@@ -766,9 +767,9 @@ static void ttusb_dec_process_urb_frame(struct ttusb_dec *dec, u8 *b,
}
}
-static void ttusb_dec_process_urb_frame_list(struct tasklet_struct *t)
+static void ttusb_dec_process_urb_frame_list(struct work_struct *t)
{
- struct ttusb_dec *dec = from_tasklet(dec, t, urb_tasklet);
+ struct ttusb_dec *dec = from_work(dec, t, urb_bh_work);
struct list_head *item;
struct urb_frame *frame;
unsigned long flags;
@@ -822,7 +823,7 @@ static void ttusb_dec_process_urb(struct urb *urb)
spin_unlock_irqrestore(&dec->urb_frame_list_lock,
flags);
- tasklet_schedule(&dec->urb_tasklet);
+ queue_work(system_bh_wq, &dec->urb_bh_work);
}
}
} else {
@@ -1198,11 +1199,11 @@ static int ttusb_dec_alloc_iso_urbs(struct ttusb_dec *dec)
return 0;
}
-static void ttusb_dec_init_tasklet(struct ttusb_dec *dec)
+static void ttusb_dec_init_bh_work(struct ttusb_dec *dec)
{
spin_lock_init(&dec->urb_frame_list_lock);
INIT_LIST_HEAD(&dec->urb_frame_list);
- tasklet_setup(&dec->urb_tasklet, ttusb_dec_process_urb_frame_list);
+ INIT_WORK(&dec->urb_bh_work, ttusb_dec_process_urb_frame_list);
}
static int ttusb_init_rc( struct ttusb_dec *dec)
@@ -1588,12 +1589,12 @@ static void ttusb_dec_exit_usb(struct ttusb_dec *dec)
ttusb_dec_free_iso_urbs(dec);
}
-static void ttusb_dec_exit_tasklet(struct ttusb_dec *dec)
+static void ttusb_dec_exit_bh_work(struct ttusb_dec *dec)
{
struct list_head *item;
struct urb_frame *frame;
- tasklet_kill(&dec->urb_tasklet);
+ cancel_work_sync(&dec->urb_bh_work);
while ((item = dec->urb_frame_list.next) != &dec->urb_frame_list) {
frame = list_entry(item, struct urb_frame, urb_frame_list);
@@ -1703,7 +1704,7 @@ static int ttusb_dec_probe(struct usb_interface *intf,
ttusb_dec_init_v_pes(dec);
ttusb_dec_init_filters(dec);
- ttusb_dec_init_tasklet(dec);
+ ttusb_dec_init_bh_work(dec);
dec->active = 1;
@@ -1729,7 +1730,7 @@ static void ttusb_dec_disconnect(struct usb_interface *intf)
dprintk("%s\n", __func__);
if (dec->active) {
- ttusb_dec_exit_tasklet(dec);
+ ttusb_dec_exit_bh_work(dec);
ttusb_dec_exit_filters(dec);
if(enable_rc)
ttusb_dec_exit_rc(dec);
diff --git a/drivers/media/usb/usbtv/usbtv-video.c b/drivers/media/usb/usbtv/usbtv-video.c
index 62a583040cd4..be22a9697197 100644
--- a/drivers/media/usb/usbtv/usbtv-video.c
+++ b/drivers/media/usb/usbtv/usbtv-video.c
@@ -780,8 +780,6 @@ static const struct vb2_ops usbtv_vb2_ops = {
.buf_queue = usbtv_buf_queue,
.start_streaming = usbtv_start_streaming,
.stop_streaming = usbtv_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static int usbtv_s_ctrl(struct v4l2_ctrl *ctrl)
@@ -963,15 +961,8 @@ ctrl_fail:
void usbtv_video_free(struct usbtv *usbtv)
{
- mutex_lock(&usbtv->vb2q_lock);
- mutex_lock(&usbtv->v4l2_lock);
-
- usbtv_stop(usbtv);
vb2_video_unregister_device(&usbtv->vdev);
v4l2_device_disconnect(&usbtv->v4l2_dev);
- mutex_unlock(&usbtv->v4l2_lock);
- mutex_unlock(&usbtv->vb2q_lock);
-
v4l2_device_put(&usbtv->v4l2_dev);
}
diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index e59a463c2761..4e58476d305e 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -459,6 +459,94 @@ static void uvc_ctrl_set_rel_speed(struct uvc_control_mapping *mapping,
data[first+1] = min_t(int, abs(value), 0xff);
}
+static const struct uvc_control_mapping uvc_ctrl_power_line_mapping_limited = {
+ .id = V4L2_CID_POWER_LINE_FREQUENCY,
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = UVC_PU_POWER_LINE_FREQUENCY_CONTROL,
+ .size = 2,
+ .offset = 0,
+ .v4l2_type = V4L2_CTRL_TYPE_MENU,
+ .data_type = UVC_CTRL_DATA_TYPE_ENUM,
+ .menu_mask = GENMASK(V4L2_CID_POWER_LINE_FREQUENCY_60HZ,
+ V4L2_CID_POWER_LINE_FREQUENCY_50HZ),
+};
+
+static const struct uvc_control_mapping uvc_ctrl_power_line_mapping_uvc11 = {
+ .id = V4L2_CID_POWER_LINE_FREQUENCY,
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = UVC_PU_POWER_LINE_FREQUENCY_CONTROL,
+ .size = 2,
+ .offset = 0,
+ .v4l2_type = V4L2_CTRL_TYPE_MENU,
+ .data_type = UVC_CTRL_DATA_TYPE_ENUM,
+ .menu_mask = GENMASK(V4L2_CID_POWER_LINE_FREQUENCY_60HZ,
+ V4L2_CID_POWER_LINE_FREQUENCY_DISABLED),
+};
+
+static const struct uvc_control_mapping uvc_ctrl_power_line_mapping_uvc15 = {
+ .id = V4L2_CID_POWER_LINE_FREQUENCY,
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = UVC_PU_POWER_LINE_FREQUENCY_CONTROL,
+ .size = 2,
+ .offset = 0,
+ .v4l2_type = V4L2_CTRL_TYPE_MENU,
+ .data_type = UVC_CTRL_DATA_TYPE_ENUM,
+ .menu_mask = GENMASK(V4L2_CID_POWER_LINE_FREQUENCY_AUTO,
+ V4L2_CID_POWER_LINE_FREQUENCY_DISABLED),
+};
+
+static const struct uvc_control_mapping *uvc_ctrl_filter_plf_mapping(
+ struct uvc_video_chain *chain, struct uvc_control *ctrl)
+{
+ const struct uvc_control_mapping *out_mapping =
+ &uvc_ctrl_power_line_mapping_uvc11;
+ u8 *buf __free(kfree) = NULL;
+ u8 init_val;
+ int ret;
+
+ buf = kmalloc(sizeof(*buf), GFP_KERNEL);
+ if (!buf)
+ return NULL;
+
+ /* Save the current PLF value, so we can restore it. */
+ ret = uvc_query_ctrl(chain->dev, UVC_GET_CUR, ctrl->entity->id,
+ chain->dev->intfnum, ctrl->info.selector,
+ buf, sizeof(*buf));
+ /* If we cannot read the control skip it. */
+ if (ret)
+ return NULL;
+ init_val = *buf;
+
+ /* If PLF value cannot be set to off, it is limited. */
+ *buf = V4L2_CID_POWER_LINE_FREQUENCY_DISABLED;
+ ret = uvc_query_ctrl(chain->dev, UVC_SET_CUR, ctrl->entity->id,
+ chain->dev->intfnum, ctrl->info.selector,
+ buf, sizeof(*buf));
+ if (ret)
+ return &uvc_ctrl_power_line_mapping_limited;
+
+ /* UVC 1.1 does not define auto, we can exit. */
+ if (chain->dev->uvc_version < 0x150)
+ goto end;
+
+ /* Check if the device supports auto. */
+ *buf = V4L2_CID_POWER_LINE_FREQUENCY_AUTO;
+ ret = uvc_query_ctrl(chain->dev, UVC_SET_CUR, ctrl->entity->id,
+ chain->dev->intfnum, ctrl->info.selector,
+ buf, sizeof(*buf));
+ if (!ret)
+ out_mapping = &uvc_ctrl_power_line_mapping_uvc15;
+
+end:
+ /* Restore initial value and add mapping. */
+ *buf = init_val;
+ uvc_query_ctrl(chain->dev, UVC_SET_CUR, ctrl->entity->id,
+ chain->dev->intfnum, ctrl->info.selector,
+ buf, sizeof(*buf));
+
+ return out_mapping;
+}
+
static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
{
.id = V4L2_CID_BRIGHTNESS,
@@ -748,52 +836,11 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
.v4l2_type = V4L2_CTRL_TYPE_BOOLEAN,
.data_type = UVC_CTRL_DATA_TYPE_BOOLEAN,
},
-};
-
-const struct uvc_control_mapping uvc_ctrl_power_line_mapping_limited = {
- .id = V4L2_CID_POWER_LINE_FREQUENCY,
- .entity = UVC_GUID_UVC_PROCESSING,
- .selector = UVC_PU_POWER_LINE_FREQUENCY_CONTROL,
- .size = 2,
- .offset = 0,
- .v4l2_type = V4L2_CTRL_TYPE_MENU,
- .data_type = UVC_CTRL_DATA_TYPE_ENUM,
- .menu_mask = GENMASK(V4L2_CID_POWER_LINE_FREQUENCY_60HZ,
- V4L2_CID_POWER_LINE_FREQUENCY_50HZ),
-};
-
-const struct uvc_control_mapping uvc_ctrl_power_line_mapping_uvc11 = {
- .id = V4L2_CID_POWER_LINE_FREQUENCY,
- .entity = UVC_GUID_UVC_PROCESSING,
- .selector = UVC_PU_POWER_LINE_FREQUENCY_CONTROL,
- .size = 2,
- .offset = 0,
- .v4l2_type = V4L2_CTRL_TYPE_MENU,
- .data_type = UVC_CTRL_DATA_TYPE_ENUM,
- .menu_mask = GENMASK(V4L2_CID_POWER_LINE_FREQUENCY_60HZ,
- V4L2_CID_POWER_LINE_FREQUENCY_DISABLED),
-};
-
-static const struct uvc_control_mapping *uvc_ctrl_mappings_uvc11[] = {
- &uvc_ctrl_power_line_mapping_uvc11,
- NULL, /* Sentinel */
-};
-
-static const struct uvc_control_mapping uvc_ctrl_power_line_mapping_uvc15 = {
- .id = V4L2_CID_POWER_LINE_FREQUENCY,
- .entity = UVC_GUID_UVC_PROCESSING,
- .selector = UVC_PU_POWER_LINE_FREQUENCY_CONTROL,
- .size = 2,
- .offset = 0,
- .v4l2_type = V4L2_CTRL_TYPE_MENU,
- .data_type = UVC_CTRL_DATA_TYPE_ENUM,
- .menu_mask = GENMASK(V4L2_CID_POWER_LINE_FREQUENCY_AUTO,
- V4L2_CID_POWER_LINE_FREQUENCY_DISABLED),
-};
-
-static const struct uvc_control_mapping *uvc_ctrl_mappings_uvc15[] = {
- &uvc_ctrl_power_line_mapping_uvc15,
- NULL, /* Sentinel */
+ {
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = UVC_PU_POWER_LINE_FREQUENCY_CONTROL,
+ .filter_mapping = uvc_ctrl_filter_plf_mapping,
+ },
};
/* ------------------------------------------------------------------------
@@ -836,7 +883,7 @@ static s32 uvc_get_le_value(struct uvc_control_mapping *mapping,
while (1) {
u8 byte = *data & mask;
value |= offset > 0 ? (byte >> offset) : (byte << (-offset));
- bits -= 8 - (offset > 0 ? offset : 0);
+ bits -= 8 - max(offset, 0);
if (bits <= 0)
break;
@@ -1532,6 +1579,40 @@ static void uvc_ctrl_send_slave_event(struct uvc_video_chain *chain,
uvc_ctrl_send_event(chain, handle, ctrl, mapping, val, changes);
}
+static void uvc_ctrl_set_handle(struct uvc_fh *handle, struct uvc_control *ctrl,
+ struct uvc_fh *new_handle)
+{
+ lockdep_assert_held(&handle->chain->ctrl_mutex);
+
+ if (new_handle) {
+ if (ctrl->handle)
+ dev_warn_ratelimited(&handle->stream->dev->udev->dev,
+ "UVC non compliance: Setting an async control with a pending operation.");
+
+ if (new_handle == ctrl->handle)
+ return;
+
+ if (ctrl->handle) {
+ WARN_ON(!ctrl->handle->pending_async_ctrls);
+ if (ctrl->handle->pending_async_ctrls)
+ ctrl->handle->pending_async_ctrls--;
+ }
+
+ ctrl->handle = new_handle;
+ handle->pending_async_ctrls++;
+ return;
+ }
+
+ /* Cannot clear the handle for a control not owned by us.*/
+ if (WARN_ON(ctrl->handle != handle))
+ return;
+
+ ctrl->handle = NULL;
+ if (WARN_ON(!handle->pending_async_ctrls))
+ return;
+ handle->pending_async_ctrls--;
+}
+
void uvc_ctrl_status_event(struct uvc_video_chain *chain,
struct uvc_control *ctrl, const u8 *data)
{
@@ -1541,8 +1622,12 @@ void uvc_ctrl_status_event(struct uvc_video_chain *chain,
mutex_lock(&chain->ctrl_mutex);
+ /* Flush the control cache, the data might have changed. */
+ ctrl->loaded = 0;
+
handle = ctrl->handle;
- ctrl->handle = NULL;
+ if (handle)
+ uvc_ctrl_set_handle(handle, ctrl, NULL);
list_for_each_entry(mapping, &ctrl->info.mappings, list) {
s32 value = __uvc_ctrl_get_value(mapping, data);
@@ -1593,10 +1678,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;
@@ -1626,13 +1709,13 @@ static void uvc_ctrl_send_events(struct uvc_fh *handle,
{
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) {
- ctrl = uvc_find_control(handle->chain, xctrls[i].id, &mapping);
+ u32 changes = V4L2_EVENT_CTRL_CH_VALUE;
+ ctrl = uvc_find_control(handle->chain, xctrls[i].id, &mapping);
if (ctrl->info.flags & UVC_CTRL_FLAG_ASYNCHRONOUS)
/* Notification will be sent from an Interrupt event. */
continue;
@@ -1764,7 +1847,10 @@ int uvc_ctrl_begin(struct uvc_video_chain *chain)
}
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)
{
struct uvc_control *ctrl;
unsigned int i;
@@ -1812,6 +1898,10 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev,
*err_ctrl = ctrl;
return ret;
}
+
+ if (!rollback && handle &&
+ ctrl->info.flags & UVC_CTRL_FLAG_ASYNCHRONOUS)
+ uvc_ctrl_set_handle(handle, ctrl, handle);
}
return 0;
@@ -1848,18 +1938,20 @@ int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback,
/* Find the control. */
list_for_each_entry(entity, &chain->entities, chain) {
- ret = uvc_ctrl_commit_entity(chain->dev, entity, rollback,
- &err_ctrl);
- if (ret < 0)
+ 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;
+ }
}
if (!rollback)
uvc_ctrl_send_events(handle, ctrls->controls, ctrls->count);
done:
- if (ret < 0 && ctrls)
- ctrls->error_idx = uvc_ctrl_find_ctrl_idx(entity, ctrls,
- err_ctrl);
mutex_unlock(&chain->ctrl_mutex);
return ret;
}
@@ -1892,6 +1984,8 @@ int uvc_ctrl_set(struct uvc_fh *handle,
s32 max;
int ret;
+ lockdep_assert_held(&chain->ctrl_mutex);
+
if (__uvc_query_v4l2_class(chain, xctrl->id, 0) >= 0)
return -EACCES;
@@ -1997,9 +2091,6 @@ int uvc_ctrl_set(struct uvc_fh *handle,
mapping->set(mapping, value,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT));
- if (ctrl->info.flags & UVC_CTRL_FLAG_ASYNCHRONOUS)
- ctrl->handle = handle;
-
ctrl->dirty = 1;
ctrl->modified = 1;
return 0;
@@ -2029,7 +2120,13 @@ static int uvc_ctrl_get_flags(struct uvc_device *dev,
else
ret = uvc_query_ctrl(dev, UVC_GET_INFO, ctrl->entity->id,
dev->intfnum, info->selector, data, 1);
- if (!ret)
+
+ if (!ret) {
+ info->flags &= ~(UVC_CTRL_FLAG_GET_CUR |
+ UVC_CTRL_FLAG_SET_CUR |
+ UVC_CTRL_FLAG_AUTO_UPDATE |
+ UVC_CTRL_FLAG_ASYNCHRONOUS);
+
info->flags |= (data[0] & UVC_CONTROL_CAP_GET ?
UVC_CTRL_FLAG_GET_CUR : 0)
| (data[0] & UVC_CONTROL_CAP_SET ?
@@ -2038,6 +2135,7 @@ static int uvc_ctrl_get_flags(struct uvc_device *dev,
UVC_CTRL_FLAG_AUTO_UPDATE : 0)
| (data[0] & UVC_CONTROL_CAP_ASYNCHRONOUS ?
UVC_CTRL_FLAG_ASYNCHRONOUS : 0);
+ }
kfree(data);
return ret;
@@ -2165,7 +2263,7 @@ static int uvc_ctrl_init_xu_ctrl(struct uvc_device *dev,
int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
struct uvc_xu_control_query *xqry)
{
- struct uvc_entity *entity;
+ struct uvc_entity *entity, *iter;
struct uvc_control *ctrl;
unsigned int i;
bool found;
@@ -2175,16 +2273,16 @@ int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
int ret;
/* Find the extension unit. */
- found = false;
- list_for_each_entry(entity, &chain->entities, chain) {
- if (UVC_ENTITY_TYPE(entity) == UVC_VC_EXTENSION_UNIT &&
- entity->id == xqry->unit) {
- found = true;
+ entity = NULL;
+ list_for_each_entry(iter, &chain->entities, chain) {
+ if (UVC_ENTITY_TYPE(iter) == UVC_VC_EXTENSION_UNIT &&
+ iter->id == xqry->unit) {
+ entity = iter;
break;
}
}
- if (!found) {
+ if (!entity) {
uvc_dbg(chain->dev, CONTROL, "Extension unit %u not found\n",
xqry->unit);
return -ENOENT;
@@ -2321,7 +2419,7 @@ int uvc_ctrl_restore_values(struct uvc_device *dev)
ctrl->dirty = 1;
}
- ret = uvc_ctrl_commit_entity(dev, entity, 0, NULL);
+ ret = uvc_ctrl_commit_entity(dev, NULL, entity, 0, NULL);
if (ret < 0)
return ret;
}
@@ -2589,7 +2687,6 @@ static void uvc_ctrl_prune_entity(struct uvc_device *dev,
static void uvc_ctrl_init_ctrl(struct uvc_video_chain *chain,
struct uvc_control *ctrl)
{
- const struct uvc_control_mapping **mappings;
unsigned int i;
/*
@@ -2621,50 +2718,22 @@ static void uvc_ctrl_init_ctrl(struct uvc_video_chain *chain,
if (!ctrl->initialized)
return;
- /*
- * First check if the device provides a custom mapping for this control,
- * used to override standard mappings for non-conformant devices. Don't
- * process standard mappings if a custom mapping is found. This
- * mechanism doesn't support combining standard and custom mappings for
- * a single control.
- */
- if (chain->dev->info->mappings) {
- bool custom = false;
-
- for (i = 0; chain->dev->info->mappings[i]; ++i) {
- const struct uvc_control_mapping *mapping =
- chain->dev->info->mappings[i];
-
- if (uvc_entity_match_guid(ctrl->entity, mapping->entity) &&
- ctrl->info.selector == mapping->selector) {
- __uvc_ctrl_add_mapping(chain, ctrl, mapping);
- custom = true;
- }
- }
-
- if (custom)
- return;
- }
-
- /* Process common mappings next. */
+ /* Process common mappings. */
for (i = 0; i < ARRAY_SIZE(uvc_ctrl_mappings); ++i) {
const struct uvc_control_mapping *mapping = &uvc_ctrl_mappings[i];
- if (uvc_entity_match_guid(ctrl->entity, mapping->entity) &&
- ctrl->info.selector == mapping->selector)
- __uvc_ctrl_add_mapping(chain, ctrl, mapping);
- }
-
- /* Finally process version-specific mappings. */
- mappings = chain->dev->uvc_version < 0x0150
- ? uvc_ctrl_mappings_uvc11 : uvc_ctrl_mappings_uvc15;
+ if (!uvc_entity_match_guid(ctrl->entity, mapping->entity) ||
+ ctrl->info.selector != mapping->selector)
+ continue;
- for (i = 0; mappings[i]; ++i) {
- const struct uvc_control_mapping *mapping = mappings[i];
+ /* Let the device provide a custom mapping. */
+ if (mapping->filter_mapping) {
+ mapping = mapping->filter_mapping(chain, ctrl);
+ if (!mapping)
+ continue;
+ }
- if (uvc_entity_match_guid(ctrl->entity, mapping->entity) &&
- ctrl->info.selector == mapping->selector)
- __uvc_ctrl_add_mapping(chain, ctrl, mapping);
+ __uvc_ctrl_add_mapping(chain, ctrl, mapping);
}
}
@@ -2743,6 +2812,26 @@ 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_set_handle(handle, &entity->controls[i], NULL);
+ }
+ }
+
+ WARN_ON(handle->pending_async_ctrls);
+}
+
/*
* Cleanup device controls.
*/
diff --git a/drivers/media/usb/uvc/uvc_debugfs.c b/drivers/media/usb/uvc/uvc_debugfs.c
index 1a1258d4ffca..14fa41cb8148 100644
--- a/drivers/media/usb/uvc/uvc_debugfs.c
+++ b/drivers/media/usb/uvc/uvc_debugfs.c
@@ -59,7 +59,6 @@ static int uvc_debugfs_stats_release(struct inode *inode, struct file *file)
static const struct file_operations uvc_debugfs_stats_fops = {
.owner = THIS_MODULE,
.open = uvc_debugfs_stats_open,
- .llseek = no_llseek,
.read = uvc_debugfs_stats_read,
.release = uvc_debugfs_stats_release,
};
diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
index bbd90123a4e7..deadbcea5e22 100644
--- a/drivers/media/usb/uvc/uvc_driver.c
+++ b/drivers/media/usb/uvc/uvc_driver.c
@@ -14,11 +14,12 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/usb.h>
+#include <linux/usb/quirks.h>
#include <linux/usb/uvc.h>
#include <linux/videodev2.h>
#include <linux/vmalloc.h>
#include <linux/wait.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
@@ -31,7 +32,7 @@
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;
@@ -219,20 +220,127 @@ static struct uvc_streaming *uvc_stream_new(struct uvc_device *dev,
* Descriptors parsing
*/
+static int uvc_parse_frame(struct uvc_device *dev,
+ struct uvc_streaming *streaming,
+ struct uvc_format *format, struct uvc_frame *frame,
+ u32 **intervals, u8 ftype, int width_multiplier,
+ const unsigned char *buffer, int buflen)
+{
+ struct usb_host_interface *alts = streaming->intf->cur_altsetting;
+ unsigned int maxIntervalIndex;
+ unsigned int interval;
+ unsigned int i, n;
+
+ if (ftype != UVC_VS_FRAME_FRAME_BASED)
+ n = buflen > 25 ? buffer[25] : 0;
+ else
+ n = buflen > 21 ? buffer[21] : 0;
+
+ n = n ? n : 3;
+
+ if (buflen < 26 + 4 * n) {
+ uvc_dbg(dev, DESCR,
+ "device %d videostreaming interface %d FRAME error\n",
+ dev->udev->devnum, alts->desc.bInterfaceNumber);
+ return -EINVAL;
+ }
+
+ frame->bFrameIndex = buffer[3];
+ frame->bmCapabilities = buffer[4];
+ frame->wWidth = get_unaligned_le16(&buffer[5]) * width_multiplier;
+ frame->wHeight = get_unaligned_le16(&buffer[7]);
+ frame->dwMinBitRate = get_unaligned_le32(&buffer[9]);
+ frame->dwMaxBitRate = get_unaligned_le32(&buffer[13]);
+ if (ftype != UVC_VS_FRAME_FRAME_BASED) {
+ frame->dwMaxVideoFrameBufferSize =
+ get_unaligned_le32(&buffer[17]);
+ frame->dwDefaultFrameInterval =
+ get_unaligned_le32(&buffer[21]);
+ frame->bFrameIntervalType = buffer[25];
+ } else {
+ frame->dwMaxVideoFrameBufferSize = 0;
+ frame->dwDefaultFrameInterval =
+ get_unaligned_le32(&buffer[17]);
+ frame->bFrameIntervalType = buffer[21];
+ }
+
+ /*
+ * Copy the frame intervals.
+ *
+ * Some bogus devices report dwMinFrameInterval equal to
+ * dwMaxFrameInterval and have dwFrameIntervalStep set to zero. Setting
+ * all null intervals to 1 fixes the problem and some other divisions
+ * by zero that could happen.
+ */
+ frame->dwFrameInterval = *intervals;
+
+ for (i = 0; i < n; ++i) {
+ interval = get_unaligned_le32(&buffer[26 + 4 * i]);
+ (*intervals)[i] = interval ? interval : 1;
+ }
+
+ /*
+ * Apply more fixes, quirks and workarounds to handle incorrect or
+ * broken descriptors.
+ */
+
+ /*
+ * Several UVC chipsets screw up dwMaxVideoFrameBufferSize completely.
+ * Observed behaviours range from setting the value to 1.1x the actual
+ * frame size to hardwiring the 16 low bits to 0. This results in a
+ * higher than necessary memory usage as well as a wrong image size
+ * information. For uncompressed formats this can be fixed by computing
+ * the value from the frame size.
+ */
+ if (!(format->flags & UVC_FMT_FLAG_COMPRESSED))
+ frame->dwMaxVideoFrameBufferSize = format->bpp * frame->wWidth
+ * frame->wHeight / 8;
+
+ /*
+ * Clamp the default frame interval to the boundaries. A zero
+ * bFrameIntervalType value indicates a continuous frame interval
+ * range, with dwFrameInterval[0] storing the minimum value and
+ * dwFrameInterval[1] storing the maximum value.
+ */
+ maxIntervalIndex = frame->bFrameIntervalType ? n - 1 : 1;
+ frame->dwDefaultFrameInterval =
+ clamp(frame->dwDefaultFrameInterval,
+ frame->dwFrameInterval[0],
+ frame->dwFrameInterval[maxIntervalIndex]);
+
+ /*
+ * Some devices report frame intervals that are not functional. If the
+ * corresponding quirk is set, restrict operation to the first interval
+ * only.
+ */
+ if (dev->quirks & UVC_QUIRK_RESTRICT_FRAME_RATE) {
+ frame->bFrameIntervalType = 1;
+ (*intervals)[0] = frame->dwDefaultFrameInterval;
+ }
+
+ uvc_dbg(dev, DESCR, "- %ux%u (%u.%u fps)\n",
+ frame->wWidth, frame->wHeight,
+ 10000000 / frame->dwDefaultFrameInterval,
+ (100000000 / frame->dwDefaultFrameInterval) % 10);
+
+ *intervals += n;
+
+ return buffer[0];
+}
+
static int uvc_parse_format(struct uvc_device *dev,
struct uvc_streaming *streaming, struct uvc_format *format,
struct uvc_frame *frames, u32 **intervals, const unsigned char *buffer,
int buflen)
{
- struct usb_interface *intf = streaming->intf;
- struct usb_host_interface *alts = intf->cur_altsetting;
+ struct usb_host_interface *alts = streaming->intf->cur_altsetting;
const struct uvc_format_desc *fmtdesc;
struct uvc_frame *frame;
const unsigned char *start = buffer;
unsigned int width_multiplier = 1;
- unsigned int interval;
unsigned int i, n;
u8 ftype;
+ int ret;
format->type = buffer[2];
format->index = buffer[3];
@@ -370,111 +478,19 @@ static int uvc_parse_format(struct uvc_device *dev,
* Parse the frame descriptors. Only uncompressed, MJPEG and frame
* based formats have frame descriptors.
*/
- while (buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE &&
- buffer[2] == ftype) {
- unsigned int maxIntervalIndex;
-
- frame = &frames[format->nframes];
- if (ftype != UVC_VS_FRAME_FRAME_BASED)
- n = buflen > 25 ? buffer[25] : 0;
- else
- n = buflen > 21 ? buffer[21] : 0;
-
- n = n ? n : 3;
-
- if (buflen < 26 + 4*n) {
- uvc_dbg(dev, DESCR,
- "device %d videostreaming interface %d FRAME error\n",
- dev->udev->devnum,
- alts->desc.bInterfaceNumber);
- return -EINVAL;
- }
-
- frame->bFrameIndex = buffer[3];
- frame->bmCapabilities = buffer[4];
- frame->wWidth = get_unaligned_le16(&buffer[5])
- * width_multiplier;
- frame->wHeight = get_unaligned_le16(&buffer[7]);
- frame->dwMinBitRate = get_unaligned_le32(&buffer[9]);
- frame->dwMaxBitRate = get_unaligned_le32(&buffer[13]);
- if (ftype != UVC_VS_FRAME_FRAME_BASED) {
- frame->dwMaxVideoFrameBufferSize =
- get_unaligned_le32(&buffer[17]);
- frame->dwDefaultFrameInterval =
- get_unaligned_le32(&buffer[21]);
- frame->bFrameIntervalType = buffer[25];
- } else {
- frame->dwMaxVideoFrameBufferSize = 0;
- frame->dwDefaultFrameInterval =
- get_unaligned_le32(&buffer[17]);
- frame->bFrameIntervalType = buffer[21];
- }
-
- /*
- * Copy the frame intervals.
- *
- * Some bogus devices report dwMinFrameInterval equal to
- * dwMaxFrameInterval and have dwFrameIntervalStep set to
- * zero. Setting all null intervals to 1 fixes the problem and
- * some other divisions by zero that could happen.
- */
- frame->dwFrameInterval = *intervals;
-
- for (i = 0; i < n; ++i) {
- interval = get_unaligned_le32(&buffer[26+4*i]);
- (*intervals)[i] = interval ? interval : 1;
- }
-
- /*
- * Apply more fixes, quirks and workarounds to handle incorrect
- * or broken descriptors.
- */
-
- /*
- * Several UVC chipsets screw up dwMaxVideoFrameBufferSize
- * completely. Observed behaviours range from setting the
- * value to 1.1x the actual frame size to hardwiring the
- * 16 low bits to 0. This results in a higher than necessary
- * memory usage as well as a wrong image size information. For
- * uncompressed formats this can be fixed by computing the
- * value from the frame size.
- */
- if (!(format->flags & UVC_FMT_FLAG_COMPRESSED))
- frame->dwMaxVideoFrameBufferSize = format->bpp
- * frame->wWidth * frame->wHeight / 8;
-
- /*
- * Clamp the default frame interval to the boundaries. A zero
- * bFrameIntervalType value indicates a continuous frame
- * interval range, with dwFrameInterval[0] storing the minimum
- * value and dwFrameInterval[1] storing the maximum value.
- */
- maxIntervalIndex = frame->bFrameIntervalType ? n - 1 : 1;
- frame->dwDefaultFrameInterval =
- clamp(frame->dwDefaultFrameInterval,
- frame->dwFrameInterval[0],
- frame->dwFrameInterval[maxIntervalIndex]);
-
- /*
- * Some devices report frame intervals that are not functional.
- * If the corresponding quirk is set, restrict operation to the
- * first interval only.
- */
- if (dev->quirks & UVC_QUIRK_RESTRICT_FRAME_RATE) {
- frame->bFrameIntervalType = 1;
- (*intervals)[0] = frame->dwDefaultFrameInterval;
+ if (ftype) {
+ while (buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE &&
+ buffer[2] == ftype) {
+ frame = &frames[format->nframes];
+ ret = uvc_parse_frame(dev, streaming, format, frame,
+ intervals, ftype, width_multiplier,
+ buffer, buflen);
+ if (ret < 0)
+ return ret;
+ format->nframes++;
+ buflen -= ret;
+ buffer += ret;
}
-
- uvc_dbg(dev, DESCR, "- %ux%u (%u.%u fps)\n",
- frame->wWidth, frame->wHeight,
- 10000000 / frame->dwDefaultFrameInterval,
- (100000000 / frame->dwDefaultFrameInterval) % 10);
-
- format->nframes++;
- *intervals += n;
-
- buflen -= buffer[0];
- buffer += buffer[0];
}
if (buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE &&
@@ -686,16 +702,26 @@ static int uvc_parse_streaming(struct uvc_device *dev,
goto error;
}
- size = nformats * sizeof(*format) + nframes * sizeof(*frame)
+ /*
+ * Allocate memory for the formats, the frames and the intervals,
+ * plus any required padding to guarantee that everything has the
+ * correct alignment.
+ */
+ size = nformats * sizeof(*format);
+ size = ALIGN(size, __alignof__(*frame)) + nframes * sizeof(*frame);
+ size = ALIGN(size, __alignof__(*interval))
+ nintervals * sizeof(*interval);
+
format = kzalloc(size, GFP_KERNEL);
- if (format == NULL) {
+ if (!format) {
ret = -ENOMEM;
goto error;
}
- frame = (struct uvc_frame *)&format[nformats];
- interval = (u32 *)&frame[nframes];
+ frame = (void *)format + nformats * sizeof(*format);
+ frame = PTR_ALIGN(frame, __alignof__(*frame));
+ interval = (void *)frame + nframes * sizeof(*frame);
+ interval = PTR_ALIGN(interval, __alignof__(*interval));
streaming->formats = format;
streaming->nformats = 0;
@@ -1269,14 +1295,14 @@ 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);
irq = gpiod_to_irq(gpio_privacy);
if (irq < 0)
- return dev_err_probe(&dev->udev->dev, irq,
+ return dev_err_probe(&dev->intf->dev, irq,
"No IRQ for privacy GPIO\n");
unit = uvc_alloc_entity(UVC_EXT_GPIO_UNIT, UVC_EXT_GPIO_UNIT_ID, 0, 1);
@@ -1302,15 +1328,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);
}
/* ------------------------------------------------------------------------
@@ -1907,12 +1945,44 @@ static void uvc_unregister_video(struct uvc_device *dev)
{
struct uvc_streaming *stream;
+ uvc_gpio_deinit(dev);
+
list_for_each_entry(stream, &dev->streams, list) {
+ /* Nothing to do here, continue. */
if (!video_is_registered(&stream->vdev))
continue;
+ /*
+ * For stream->vdev we follow the same logic as:
+ * vb2_video_unregister_device().
+ */
+
+ /* 1. Take a reference to vdev */
+ get_device(&stream->vdev.dev);
+
+ /* 2. Ensure that no new ioctls can be called. */
video_unregister_device(&stream->vdev);
- video_unregister_device(&stream->meta.vdev);
+
+ /* 3. Wait for old ioctls to finish. */
+ mutex_lock(&stream->mutex);
+
+ /* 4. Stop streaming. */
+ uvc_queue_release(&stream->queue);
+
+ mutex_unlock(&stream->mutex);
+
+ put_device(&stream->vdev.dev);
+
+ /*
+ * For stream->meta.vdev we can directly call:
+ * vb2_video_unregister_device().
+ */
+ vb2_video_unregister_device(&stream->meta.vdev);
+
+ /*
+ * Now both vdevs are not streaming and all the ioctls will
+ * return -ENODEV.
+ */
uvc_debugfs_cleanup_stream(stream);
}
@@ -1938,7 +2008,7 @@ int uvc_register_video_device(struct uvc_device *dev,
int ret;
/* Initialize the video buffers queue. */
- ret = uvc_queue_init(queue, type, !uvc_no_drop_param);
+ ret = uvc_queue_init(queue, type);
if (ret)
return ret;
@@ -2105,7 +2175,6 @@ static int uvc_probe(struct usb_interface *intf,
INIT_LIST_HEAD(&dev->streams);
kref_init(&dev->ref);
atomic_set(&dev->nmappings, 0);
- mutex_init(&dev->lock);
dev->udev = usb_get_dev(udev);
dev->intf = usb_get_intf(intf);
@@ -2232,8 +2301,14 @@ static int uvc_probe(struct usb_interface *intf,
goto error;
}
+ if (dev->quirks & UVC_QUIRK_NO_RESET_RESUME)
+ udev->quirks &= ~USB_QUIRK_RESET_RESUME;
+
+ if (!(dev->quirks & UVC_QUIRK_DISABLE_AUTOSUSPEND))
+ usb_enable_autosuspend(udev);
+
uvc_dbg(dev, PROBE, "UVC device initialized\n");
- usb_enable_autosuspend(udev);
+
return 0;
error:
@@ -2271,10 +2346,7 @@ static int uvc_suspend(struct usb_interface *intf, pm_message_t message)
/* Controls are cached on the fly so they don't need to be saved. */
if (intf->cur_altsetting->desc.bInterfaceSubClass ==
UVC_SC_VIDEOCONTROL) {
- mutex_lock(&dev->lock);
- if (dev->users)
- uvc_status_stop(dev);
- mutex_unlock(&dev->lock);
+ uvc_status_suspend(dev);
return 0;
}
@@ -2305,12 +2377,7 @@ static int __uvc_resume(struct usb_interface *intf, int reset)
return ret;
}
- mutex_lock(&dev->lock);
- if (dev->users)
- ret = uvc_status_start(dev, GFP_NOIO);
- mutex_unlock(&dev->lock);
-
- return ret;
+ return uvc_status_resume(dev);
}
list_for_each_entry(stream, &dev->streams, list) {
@@ -2370,8 +2437,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, &param_ops_nodrop, &uvc_no_drop_param, 0644);
+__MODULE_PARM_TYPE(nodrop, "uint");
MODULE_PARM_DESC(nodrop, "Don't drop incomplete frames");
+
module_param_named(quirks, uvc_quirks_param, uint, 0644);
MODULE_PARM_DESC(quirks, "Forced device quirks");
module_param_named(trace, uvc_dbg_param, uint, 0644);
@@ -2383,20 +2467,6 @@ MODULE_PARM_DESC(timeout, "Streaming control requests timeout");
* Driver initialization and cleanup
*/
-static const struct uvc_device_info uvc_ctrl_power_line_limited = {
- .mappings = (const struct uvc_control_mapping *[]) {
- &uvc_ctrl_power_line_mapping_limited,
- NULL, /* Sentinel */
- },
-};
-
-static const struct uvc_device_info uvc_ctrl_power_line_uvc11 = {
- .mappings = (const struct uvc_control_mapping *[]) {
- &uvc_ctrl_power_line_mapping_uvc11,
- NULL, /* Sentinel */
- },
-};
-
static const struct uvc_device_info uvc_quirk_probe_minmax = {
.quirks = UVC_QUIRK_PROBE_MINMAX,
};
@@ -2425,35 +2495,32 @@ static const struct uvc_device_info uvc_quirk_force_y8 = {
* The Logitech cameras listed below have their interface class set to
* VENDOR_SPEC because they don't announce themselves as UVC devices, even
* though they are compliant.
+ *
+ * Sort these by vendor/product ID.
*/
static const struct usb_device_id uvc_ids[] = {
- /* Quanta USB2.0 HD UVC Webcam */
+ /* Quanta ACER HD User Facing */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
.idVendor = 0x0408,
- .idProduct = 0x3090,
+ .idProduct = 0x4033,
.bInterfaceClass = USB_CLASS_VIDEO,
.bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_limited },
- /* Quanta USB2.0 HD UVC Webcam */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x0408,
- .idProduct = 0x4030,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_limited },
- /* Quanta USB2.0 HD UVC Webcam */
+ .bInterfaceProtocol = UVC_PC_PROTOCOL_15,
+ .driver_info = (kernel_ulong_t)&(const struct uvc_device_info){
+ .uvc_version = 0x010a,
+ } },
+ /* Quanta ACER HD User Facing */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
.idVendor = 0x0408,
- .idProduct = 0x4034,
+ .idProduct = 0x4035,
.bInterfaceClass = USB_CLASS_VIDEO,
.bInterfaceSubClass = 1,
.bInterfaceProtocol = UVC_PC_PROTOCOL_15,
- .driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_limited },
+ .driver_info = (kernel_ulong_t)&(const struct uvc_device_info){
+ .uvc_version = 0x010a,
+ } },
/* LogiLink Wireless Webcam */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
@@ -2573,52 +2640,53 @@ static const struct usb_device_id uvc_ids[] = {
.bInterfaceClass = USB_CLASS_VIDEO,
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
- .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_RESTORE_CTRLS_ON_INIT) },
- /* Chicony CNF7129 (Asus EEE 100HE) */
+ .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_RESTORE_CTRLS_ON_INIT
+ | UVC_QUIRK_INVALID_DEVICE_SOF) },
+ /* Logitech HD Pro Webcam C922 */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x04f2,
- .idProduct = 0xb071,
+ .idVendor = 0x046d,
+ .idProduct = 0x085c,
.bInterfaceClass = USB_CLASS_VIDEO,
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
- .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_RESTRICT_FRAME_RATE) },
- /* Chicony EasyCamera */
+ .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_INVALID_DEVICE_SOF) },
+ /* Logitech Rally Bar Huddle */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x04f2,
- .idProduct = 0xb5eb,
+ .idVendor = 0x046d,
+ .idProduct = 0x087c,
.bInterfaceClass = USB_CLASS_VIDEO,
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
- .driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_limited },
- /* Chicony Electronics Co., Ltd Integrated Camera */
+ .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_NO_RESET_RESUME) },
+ /* Logitech Rally Bar */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x04f2,
- .idProduct = 0xb67c,
+ .idVendor = 0x046d,
+ .idProduct = 0x089b,
.bInterfaceClass = USB_CLASS_VIDEO,
.bInterfaceSubClass = 1,
- .bInterfaceProtocol = UVC_PC_PROTOCOL_15,
- .driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_uvc11 },
- /* Chicony EasyCamera */
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_NO_RESET_RESUME) },
+ /* Logitech Rally Bar Mini */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x04f2,
- .idProduct = 0xb6ba,
+ .idVendor = 0x046d,
+ .idProduct = 0x08d3,
.bInterfaceClass = USB_CLASS_VIDEO,
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
- .driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_limited },
- /* Chicony EasyCamera */
+ .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_NO_RESET_RESUME) },
+ /* Chicony CNF7129 (Asus EEE 100HE) */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
.idVendor = 0x04f2,
- .idProduct = 0xb746,
+ .idProduct = 0xb071,
.bInterfaceClass = USB_CLASS_VIDEO,
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
- .driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_limited },
+ .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_RESTRICT_FRAME_RATE) },
/* Alcor Micro AU3820 (Future Boy PC USB Webcam) */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
@@ -2764,6 +2832,15 @@ static const struct usb_device_id uvc_ids[] = {
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
.driver_info = (kernel_ulong_t)&uvc_quirk_probe_minmax },
+ /* Sonix Technology Co. Ltd. - 292A IPC AR0330 */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x0c45,
+ .idProduct = 0x6366,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_MJPEG_NO_EOF) },
/* MT6227 */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
@@ -2792,6 +2869,15 @@ static const struct usb_device_id uvc_ids[] = {
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
.driver_info = (kernel_ulong_t)&uvc_quirk_probe_minmax },
+ /* Kurokesu C1 PRO */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x16d0,
+ .idProduct = 0x0ed1,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_MJPEG_NO_EOF) },
/* Syntek (HP Spartan) */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
@@ -2976,6 +3062,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) },
+ /* NXP Semiconductors IR VIDEO */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x1fc9,
+ .idProduct = 0x009b,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = (kernel_ulong_t)&uvc_quirk_probe_minmax },
/* Oculus VR Positional Tracker DK2 */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
@@ -3003,51 +3098,15 @@ static const struct usb_device_id uvc_ids[] = {
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
.driver_info = UVC_INFO_QUIRK(UVC_QUIRK_FORCE_BPP) },
- /* SunplusIT Inc HD Camera */
+ /* Insta360 Link */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x2b7e,
- .idProduct = 0xb752,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = UVC_PC_PROTOCOL_15,
- .driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_uvc11 },
- /* Lenovo Integrated Camera */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x30c9,
- .idProduct = 0x0093,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = UVC_PC_PROTOCOL_15,
- .driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_uvc11 },
- /* Sonix Technology USB 2.0 Camera */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x3277,
- .idProduct = 0x0072,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_limited },
- /* Acer EasyCamera */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x5986,
- .idProduct = 0x1172,
+ .idVendor = 0x2e1a,
+ .idProduct = 0x4c01,
.bInterfaceClass = USB_CLASS_VIDEO,
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
- .driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_limited },
- /* Acer EasyCamera */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x5986,
- .idProduct = 0x1180,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_limited },
+ .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_DISABLE_AUTOSUSPEND) },
/* Intel D410/ASR depth camera */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
@@ -3120,6 +3179,15 @@ static const struct usb_device_id uvc_ids[] = {
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
.driver_info = UVC_INFO_META(V4L2_META_FMT_D4XX) },
+ /* Intel D421 Depth Module */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x8086,
+ .idProduct = 0x1155,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_INFO_META(V4L2_META_FMT_D4XX) },
/* Generic USB Video Class */
{ USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, UVC_PC_PROTOCOL_UNDEFINED) },
{ USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, UVC_PC_PROTOCOL_15) },
diff --git a/drivers/media/usb/uvc/uvc_queue.c b/drivers/media/usb/uvc/uvc_queue.c
index 16fa17bbd15e..2ee142621042 100644
--- a/drivers/media/usb/uvc/uvc_queue.c
+++ b/drivers/media/usb/uvc/uvc_queue.c
@@ -197,8 +197,6 @@ static const struct vb2_ops uvc_queue_qops = {
.buf_prepare = uvc_buffer_prepare,
.buf_queue = uvc_buffer_queue,
.buf_finish = uvc_buffer_finish,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.start_streaming = uvc_start_streaming,
.stop_streaming = uvc_stop_streaming,
};
@@ -207,13 +205,10 @@ static const struct vb2_ops uvc_meta_queue_qops = {
.queue_setup = uvc_queue_setup,
.buf_prepare = uvc_buffer_prepare,
.buf_queue = uvc_buffer_queue,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.stop_streaming = uvc_stop_streaming,
};
-int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type,
- int drop_corrupted)
+int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type)
{
int ret;
@@ -243,7 +238,6 @@ int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type,
mutex_init(&queue->mutex);
spin_lock_init(&queue->irqlock);
INIT_LIST_HEAD(&queue->irqqueue);
- queue->flags = drop_corrupted ? UVC_QUEUE_DROP_CORRUPTED : 0;
return 0;
}
@@ -476,14 +470,15 @@ static void uvc_queue_buffer_complete(struct kref *ref)
struct vb2_buffer *vb = &buf->buf.vb2_buf;
struct uvc_video_queue *queue = vb2_get_drv_priv(vb->vb2_queue);
- if ((queue->flags & UVC_QUEUE_DROP_CORRUPTED) && buf->error) {
+ if (buf->error && !uvc_no_drop_param) {
uvc_queue_buffer_requeue(queue, buf);
return;
}
buf->state = buf->error ? UVC_BUF_STATE_ERROR : UVC_BUF_STATE_DONE;
vb2_set_plane_payload(&buf->buf.vb2_buf, 0, buf->bytesused);
- vb2_buffer_done(&buf->buf.vb2_buf, VB2_BUF_STATE_DONE);
+ vb2_buffer_done(&buf->buf.vb2_buf, buf->error ? VB2_BUF_STATE_ERROR :
+ VB2_BUF_STATE_DONE);
}
/*
diff --git a/drivers/media/usb/uvc/uvc_status.c b/drivers/media/usb/uvc/uvc_status.c
index a78a88c710e2..ee01dce4b783 100644
--- a/drivers/media/usb/uvc/uvc_status.c
+++ b/drivers/media/usb/uvc/uvc_status.c
@@ -257,11 +257,11 @@ int uvc_status_init(struct uvc_device *dev)
unsigned int pipe;
int interval;
+ mutex_init(&dev->status_lock);
+
if (ep == NULL)
return 0;
- uvc_input_init(dev);
-
dev->status = kzalloc(sizeof(*dev->status), GFP_KERNEL);
if (!dev->status)
return -ENOMEM;
@@ -269,6 +269,7 @@ int uvc_status_init(struct uvc_device *dev)
dev->int_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!dev->int_urb) {
kfree(dev->status);
+ dev->status = NULL;
return -ENOMEM;
}
@@ -287,12 +288,17 @@ int uvc_status_init(struct uvc_device *dev)
dev->status, sizeof(*dev->status), uvc_status_complete,
dev, interval);
+ uvc_input_init(dev);
+
return 0;
}
void uvc_status_unregister(struct uvc_device *dev)
{
- usb_kill_urb(dev->int_urb);
+ if (!dev->status)
+ return;
+
+ uvc_status_suspend(dev);
uvc_input_unregister(dev);
}
@@ -302,18 +308,25 @@ void uvc_status_cleanup(struct uvc_device *dev)
kfree(dev->status);
}
-int uvc_status_start(struct uvc_device *dev, gfp_t flags)
+static int uvc_status_start(struct uvc_device *dev, gfp_t flags)
{
- if (dev->int_urb == NULL)
+ lockdep_assert_held(&dev->status_lock);
+
+ if (!dev->int_urb)
return 0;
return usb_submit_urb(dev->int_urb, flags);
}
-void uvc_status_stop(struct uvc_device *dev)
+static void uvc_status_stop(struct uvc_device *dev)
{
struct uvc_ctrl_work *w = &dev->async_ctrl;
+ lockdep_assert_held(&dev->status_lock);
+
+ if (!dev->int_urb)
+ return;
+
/*
* Prevent the asynchronous control handler from requeing the URB. The
* barrier is needed so the flush_status change is visible to other
@@ -350,3 +363,49 @@ void uvc_status_stop(struct uvc_device *dev)
*/
smp_store_release(&dev->flush_status, false);
}
+
+int uvc_status_resume(struct uvc_device *dev)
+{
+ guard(mutex)(&dev->status_lock);
+
+ if (dev->status_users)
+ return uvc_status_start(dev, GFP_NOIO);
+
+ return 0;
+}
+
+void uvc_status_suspend(struct uvc_device *dev)
+{
+ guard(mutex)(&dev->status_lock);
+
+ if (dev->status_users)
+ uvc_status_stop(dev);
+}
+
+int uvc_status_get(struct uvc_device *dev)
+{
+ int ret;
+
+ guard(mutex)(&dev->status_lock);
+
+ if (!dev->status_users) {
+ ret = uvc_status_start(dev, GFP_KERNEL);
+ if (ret)
+ return ret;
+ }
+
+ dev->status_users++;
+
+ return 0;
+}
+
+void uvc_status_put(struct uvc_device *dev)
+{
+ guard(mutex)(&dev->status_lock);
+
+ if (dev->status_users == 1)
+ uvc_status_stop(dev);
+ WARN_ON(!dev->status_users);
+ if (dev->status_users)
+ dev->status_users--;
+}
diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
index f4988f03640a..93c6cdb23881 100644
--- a/drivers/media/usb/uvc/uvc_v4l2.c
+++ b/drivers/media/usb/uvc/uvc_v4l2.c
@@ -26,6 +26,8 @@
#include "uvcvideo.h"
+static int uvc_acquire_privileges(struct uvc_fh *handle);
+
static int uvc_control_add_xu_mapping(struct uvc_video_chain *chain,
struct uvc_control_mapping *map,
const struct uvc_xu_control_mapping *xmap)
@@ -361,9 +363,11 @@ static int uvc_v4l2_try_format(struct uvc_streaming *stream,
return ret;
}
-static int uvc_v4l2_get_format(struct uvc_streaming *stream,
- struct v4l2_format *fmt)
+static int uvc_ioctl_g_fmt(struct file *file, void *fh,
+ struct v4l2_format *fmt)
{
+ struct uvc_fh *handle = fh;
+ struct uvc_streaming *stream = handle->stream;
const struct uvc_format *format;
const struct uvc_frame *frame;
int ret = 0;
@@ -395,14 +399,20 @@ done:
return ret;
}
-static int uvc_v4l2_set_format(struct uvc_streaming *stream,
- struct v4l2_format *fmt)
+static int uvc_ioctl_s_fmt(struct file *file, void *fh,
+ struct v4l2_format *fmt)
{
+ struct uvc_fh *handle = fh;
+ struct uvc_streaming *stream = handle->stream;
struct uvc_streaming_control probe;
const struct uvc_format *format;
const struct uvc_frame *frame;
int ret;
+ ret = uvc_acquire_privileges(handle);
+ if (ret < 0)
+ return ret;
+
if (fmt->type != stream->type)
return -EINVAL;
@@ -426,10 +436,12 @@ done:
return ret;
}
-static int uvc_v4l2_get_streamparm(struct uvc_streaming *stream,
- struct v4l2_streamparm *parm)
+static int uvc_ioctl_g_parm(struct file *file, void *fh,
+ struct v4l2_streamparm *parm)
{
u32 numerator, denominator;
+ struct uvc_fh *handle = fh;
+ struct uvc_streaming *stream = handle->stream;
if (parm->type != stream->type)
return -EINVAL;
@@ -461,9 +473,11 @@ static int uvc_v4l2_get_streamparm(struct uvc_streaming *stream,
return 0;
}
-static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream,
- struct v4l2_streamparm *parm)
+static int uvc_ioctl_s_parm(struct file *file, void *fh,
+ struct v4l2_streamparm *parm)
{
+ struct uvc_fh *handle = fh;
+ struct uvc_streaming *stream = handle->stream;
struct uvc_streaming_control probe;
struct v4l2_fract timeperframe;
const struct uvc_format *format;
@@ -472,6 +486,10 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream,
unsigned int i;
int ret;
+ ret = uvc_acquire_privileges(handle);
+ if (ret < 0)
+ return ret;
+
if (parm->type != stream->type)
return -EINVAL;
@@ -573,6 +591,7 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream,
* - VIDIOC_S_INPUT
* - VIDIOC_S_PARM
* - VIDIOC_S_FMT
+ * - VIDIOC_CREATE_BUFS
* - VIDIOC_REQBUFS
*/
static int uvc_acquire_privileges(struct uvc_fh *handle)
@@ -628,20 +647,13 @@ static int uvc_v4l2_open(struct file *file)
return -ENOMEM;
}
- mutex_lock(&stream->dev->lock);
- if (stream->dev->users == 0) {
- ret = uvc_status_start(stream->dev, GFP_KERNEL);
- if (ret < 0) {
- mutex_unlock(&stream->dev->lock);
- usb_autopm_put_interface(stream->dev->intf);
- kfree(handle);
- return ret;
- }
+ ret = uvc_status_get(stream->dev);
+ if (ret) {
+ usb_autopm_put_interface(stream->dev->intf);
+ kfree(handle);
+ return ret;
}
- stream->dev->users++;
- mutex_unlock(&stream->dev->lock);
-
v4l2_fh_init(&handle->vfh, &stream->vdev);
v4l2_fh_add(&handle->vfh);
handle->chain = stream->chain;
@@ -659,6 +671,8 @@ static int uvc_v4l2_release(struct file *file)
uvc_dbg(stream->dev, CALLS, "%s\n", __func__);
+ uvc_ctrl_cleanup_fh(handle);
+
/* Only free resources if this is a privileged handle. */
if (uvc_has_privileges(handle))
uvc_queue_release(&stream->queue);
@@ -670,10 +684,7 @@ static int uvc_v4l2_release(struct file *file)
kfree(handle);
file->private_data = NULL;
- mutex_lock(&stream->dev->lock);
- if (--stream->dev->users == 0)
- uvc_status_stop(stream->dev);
- mutex_unlock(&stream->dev->lock);
+ uvc_status_put(stream->dev);
usb_autopm_put_interface(stream->dev->intf);
return 0;
@@ -695,11 +706,13 @@ static int uvc_ioctl_querycap(struct file *file, void *fh,
return 0;
}
-static int uvc_ioctl_enum_fmt(struct uvc_streaming *stream,
+static int uvc_ioctl_enum_fmt(struct file *file, void *fh,
struct v4l2_fmtdesc *fmt)
{
- const struct uvc_format *format;
+ struct uvc_fh *handle = fh;
+ struct uvc_streaming *stream = handle->stream;
enum v4l2_buf_type type = fmt->type;
+ const struct uvc_format *format;
u32 index = fmt->index;
if (fmt->type != stream->type || fmt->index >= stream->nformats)
@@ -717,82 +730,8 @@ static int uvc_ioctl_enum_fmt(struct uvc_streaming *stream,
return 0;
}
-static int uvc_ioctl_enum_fmt_vid_cap(struct file *file, void *fh,
- struct v4l2_fmtdesc *fmt)
-{
- struct uvc_fh *handle = fh;
- struct uvc_streaming *stream = handle->stream;
-
- return uvc_ioctl_enum_fmt(stream, fmt);
-}
-
-static int uvc_ioctl_enum_fmt_vid_out(struct file *file, void *fh,
- struct v4l2_fmtdesc *fmt)
-{
- struct uvc_fh *handle = fh;
- struct uvc_streaming *stream = handle->stream;
-
- return uvc_ioctl_enum_fmt(stream, fmt);
-}
-
-static int uvc_ioctl_g_fmt_vid_cap(struct file *file, void *fh,
- struct v4l2_format *fmt)
-{
- struct uvc_fh *handle = fh;
- struct uvc_streaming *stream = handle->stream;
-
- return uvc_v4l2_get_format(stream, fmt);
-}
-
-static int uvc_ioctl_g_fmt_vid_out(struct file *file, void *fh,
- struct v4l2_format *fmt)
-{
- struct uvc_fh *handle = fh;
- struct uvc_streaming *stream = handle->stream;
-
- return uvc_v4l2_get_format(stream, fmt);
-}
-
-static int uvc_ioctl_s_fmt_vid_cap(struct file *file, void *fh,
- struct v4l2_format *fmt)
-{
- struct uvc_fh *handle = fh;
- struct uvc_streaming *stream = handle->stream;
- int ret;
-
- ret = uvc_acquire_privileges(handle);
- if (ret < 0)
- return ret;
-
- return uvc_v4l2_set_format(stream, fmt);
-}
-
-static int uvc_ioctl_s_fmt_vid_out(struct file *file, void *fh,
- struct v4l2_format *fmt)
-{
- struct uvc_fh *handle = fh;
- struct uvc_streaming *stream = handle->stream;
- int ret;
-
- ret = uvc_acquire_privileges(handle);
- if (ret < 0)
- return ret;
-
- return uvc_v4l2_set_format(stream, fmt);
-}
-
-static int uvc_ioctl_try_fmt_vid_cap(struct file *file, void *fh,
- struct v4l2_format *fmt)
-{
- struct uvc_fh *handle = fh;
- struct uvc_streaming *stream = handle->stream;
- struct uvc_streaming_control probe;
-
- return uvc_v4l2_try_format(stream, fmt, &probe, NULL, NULL);
-}
-
-static int uvc_ioctl_try_fmt_vid_out(struct file *file, void *fh,
- struct v4l2_format *fmt)
+static int uvc_ioctl_try_fmt(struct file *file, void *fh,
+ struct v4l2_format *fmt)
{
struct uvc_fh *handle = fh;
struct uvc_streaming *stream = handle->stream;
@@ -1222,29 +1161,6 @@ static int uvc_ioctl_g_selection(struct file *file, void *fh,
return 0;
}
-static int uvc_ioctl_g_parm(struct file *file, void *fh,
- struct v4l2_streamparm *parm)
-{
- struct uvc_fh *handle = fh;
- struct uvc_streaming *stream = handle->stream;
-
- return uvc_v4l2_get_streamparm(stream, parm);
-}
-
-static int uvc_ioctl_s_parm(struct file *file, void *fh,
- struct v4l2_streamparm *parm)
-{
- struct uvc_fh *handle = fh;
- struct uvc_streaming *stream = handle->stream;
- int ret;
-
- ret = uvc_acquire_privileges(handle);
- if (ret < 0)
- return ret;
-
- return uvc_v4l2_set_streamparm(stream, parm);
-}
-
static int uvc_ioctl_enum_framesizes(struct file *file, void *fh,
struct v4l2_frmsizeenum *fsize)
{
@@ -1553,15 +1469,17 @@ static unsigned long uvc_v4l2_get_unmapped_area(struct file *file,
#endif
const struct v4l2_ioctl_ops uvc_ioctl_ops = {
+ .vidioc_g_fmt_vid_cap = uvc_ioctl_g_fmt,
+ .vidioc_g_fmt_vid_out = uvc_ioctl_g_fmt,
+ .vidioc_s_fmt_vid_cap = uvc_ioctl_s_fmt,
+ .vidioc_s_fmt_vid_out = uvc_ioctl_s_fmt,
+ .vidioc_g_parm = uvc_ioctl_g_parm,
+ .vidioc_s_parm = uvc_ioctl_s_parm,
.vidioc_querycap = uvc_ioctl_querycap,
- .vidioc_enum_fmt_vid_cap = uvc_ioctl_enum_fmt_vid_cap,
- .vidioc_enum_fmt_vid_out = uvc_ioctl_enum_fmt_vid_out,
- .vidioc_g_fmt_vid_cap = uvc_ioctl_g_fmt_vid_cap,
- .vidioc_g_fmt_vid_out = uvc_ioctl_g_fmt_vid_out,
- .vidioc_s_fmt_vid_cap = uvc_ioctl_s_fmt_vid_cap,
- .vidioc_s_fmt_vid_out = uvc_ioctl_s_fmt_vid_out,
- .vidioc_try_fmt_vid_cap = uvc_ioctl_try_fmt_vid_cap,
- .vidioc_try_fmt_vid_out = uvc_ioctl_try_fmt_vid_out,
+ .vidioc_enum_fmt_vid_cap = uvc_ioctl_enum_fmt,
+ .vidioc_enum_fmt_vid_out = uvc_ioctl_enum_fmt,
+ .vidioc_try_fmt_vid_cap = uvc_ioctl_try_fmt,
+ .vidioc_try_fmt_vid_out = uvc_ioctl_try_fmt,
.vidioc_reqbufs = uvc_ioctl_reqbufs,
.vidioc_querybuf = uvc_ioctl_querybuf,
.vidioc_qbuf = uvc_ioctl_qbuf,
@@ -1580,8 +1498,6 @@ const struct v4l2_ioctl_ops uvc_ioctl_ops = {
.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,
diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c
index 7cbf4692bd87..e3567aeb0007 100644
--- a/drivers/media/usb/uvc/uvc_video.c
+++ b/drivers/media/usb/uvc/uvc_video.c
@@ -18,8 +18,9 @@
#include <linux/vmalloc.h>
#include <linux/wait.h>
#include <linux/atomic.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
+#include <media/jpeg.h>
#include <media/v4l2-common.h>
#include "uvcvideo.h"
@@ -79,6 +80,27 @@ int uvc_query_ctrl(struct uvc_device *dev, u8 query, u8 unit,
if (likely(ret == size))
return 0;
+ /*
+ * Some devices return shorter USB control packets than expected if the
+ * returned value can fit in less bytes. Zero all the bytes that the
+ * device has not written.
+ *
+ * This quirk is applied to all controls, regardless of their data type.
+ * Most controls are little-endian integers, in which case the missing
+ * bytes become 0 MSBs. For other data types, a different heuristic
+ * could be implemented if a device is found needing it.
+ *
+ * We exclude UVC_GET_INFO from the quirk. UVC_GET_LEN does not need
+ * to be excluded because its size is always 1.
+ */
+ if (ret > 0 && query != UVC_GET_INFO) {
+ memset(data + ret, 0, size - ret);
+ dev_warn_once(&dev->udev->dev,
+ "UVC non compliance: %s control %u on unit %u returned %d bytes when we expected %u.\n",
+ uvc_query_name(query), cs, unit, ret, size);
+ return 0;
+ }
+
if (ret != -EPIPE) {
dev_err(&dev->udev->dev,
"Failed to query (%s) UVC control %u on unit %u: %d (exp. %u).\n",
@@ -96,8 +118,12 @@ int uvc_query_ctrl(struct uvc_device *dev, u8 query, u8 unit,
error = *(u8 *)data;
*(u8 *)data = tmp;
- if (ret != 1)
+ if (ret != 1) {
+ dev_err_ratelimited(&dev->udev->dev,
+ "Failed to query (%s) UVC error code control %u on unit %u: %d (exp. 1).\n",
+ uvc_query_name(query), cs, unit, ret);
return ret < 0 ? ret : -EPIPE;
+ }
uvc_dbg(dev, CONTROL, "Control error %u\n", error);
@@ -214,13 +240,13 @@ static void uvc_fixup_video_ctrl(struct uvc_streaming *stream,
* Compute a bandwidth estimation by multiplying the frame
* size by the number of video frames per second, divide the
* result by the number of USB frames (or micro-frames for
- * high-speed devices) per second and add the UVC header size
- * (assumed to be 12 bytes long).
+ * high- and super-speed devices) per second and add the UVC
+ * header size (assumed to be 12 bytes long).
*/
bandwidth = frame->wWidth * frame->wHeight / 8 * format->bpp;
bandwidth *= 10000000 / interval + 1;
bandwidth /= 1000;
- if (stream->dev->udev->speed == USB_SPEED_HIGH)
+ if (stream->dev->udev->speed >= USB_SPEED_HIGH)
bandwidth /= 8;
bandwidth += 12;
@@ -297,8 +323,9 @@ static int uvc_get_video_ctrl(struct uvc_streaming *stream,
goto out;
} else if (ret != size) {
dev_err(&stream->intf->dev,
- "Failed to query (%u) UVC %s control : %d (exp. %u).\n",
- query, probe ? "probe" : "commit", ret, size);
+ "Failed to query (%s) UVC %s control : %d (exp. %u).\n",
+ uvc_query_name(query), probe ? "probe" : "commit",
+ ret, size);
ret = (ret == -EPROTO) ? -EPROTO : -EIO;
goto out;
}
@@ -466,18 +493,49 @@ static inline ktime_t uvc_video_get_time(void)
return ktime_get_real();
}
+static void uvc_video_clock_add_sample(struct uvc_clock *clock,
+ const struct uvc_clock_sample *sample)
+{
+ unsigned long flags;
+
+ /*
+ * If we write new data on the position where we had the last
+ * overflow, remove the overflow pointer. There is no SOF overflow
+ * in the whole circular buffer.
+ */
+ if (clock->head == clock->last_sof_overflow)
+ clock->last_sof_overflow = -1;
+
+ spin_lock_irqsave(&clock->lock, flags);
+
+ if (clock->count > 0 && clock->last_sof > sample->dev_sof) {
+ /*
+ * Remove data from the circular buffer that is older than the
+ * last SOF overflow. We only support one SOF overflow per
+ * circular buffer.
+ */
+ if (clock->last_sof_overflow != -1)
+ clock->count = (clock->head - clock->last_sof_overflow
+ + clock->size) % clock->size;
+ clock->last_sof_overflow = clock->head;
+ }
+
+ /* Add sample. */
+ clock->samples[clock->head] = *sample;
+ clock->head = (clock->head + 1) % clock->size;
+ clock->count = min(clock->count + 1, clock->size);
+
+ spin_unlock_irqrestore(&clock->lock, flags);
+}
+
static void
uvc_video_clock_decode(struct uvc_streaming *stream, struct uvc_buffer *buf,
const u8 *data, int len)
{
- struct uvc_clock_sample *sample;
+ struct uvc_clock_sample sample;
unsigned int header_size;
bool has_pts = false;
bool has_scr = false;
- unsigned long flags;
- ktime_t time;
- u16 host_sof;
- u16 dev_sof;
switch (data[1] & (UVC_STREAM_PTS | UVC_STREAM_SCR)) {
case UVC_STREAM_PTS | UVC_STREAM_SCR:
@@ -522,14 +580,51 @@ uvc_video_clock_decode(struct uvc_streaming *stream, struct uvc_buffer *buf,
* all the data packets of the same frame contains the same SOF. In that
* case only the first one will match the host_sof.
*/
- dev_sof = get_unaligned_le16(&data[header_size - 2]);
- if (dev_sof == stream->clock.last_sof)
+ sample.dev_sof = get_unaligned_le16(&data[header_size - 2]);
+ if (sample.dev_sof == stream->clock.last_sof)
return;
- stream->clock.last_sof = dev_sof;
+ sample.dev_stc = get_unaligned_le32(&data[header_size - 6]);
- host_sof = usb_get_current_frame_number(stream->dev->udev);
- time = uvc_video_get_time();
+ /*
+ * STC (Source Time Clock) is the clock used by the camera. The UVC 1.5
+ * standard states that it "must be captured when the first video data
+ * of a video frame is put on the USB bus". This is generally understood
+ * as requiring devices to clear the payload header's SCR bit before
+ * the first packet containing video data.
+ *
+ * Most vendors follow that interpretation, but some (namely SunplusIT
+ * on some devices) always set the `UVC_STREAM_SCR` bit, fill the SCR
+ * field with 0's,and expect that the driver only processes the SCR if
+ * there is data in the packet.
+ *
+ * Ignore all the hardware timestamp information if we haven't received
+ * any data for this frame yet, the packet contains no data, and both
+ * STC and SOF are zero. This heuristics should be safe on compliant
+ * devices. This should be safe with compliant devices, as in the very
+ * unlikely case where a UVC 1.1 device would send timing information
+ * only before the first packet containing data, and both STC and SOF
+ * happen to be zero for a particular frame, we would only miss one
+ * clock sample from many and the clock recovery algorithm wouldn't
+ * suffer from this condition.
+ */
+ if (buf && buf->bytesused == 0 && len == header_size &&
+ sample.dev_stc == 0 && sample.dev_sof == 0)
+ return;
+
+ sample.host_sof = usb_get_current_frame_number(stream->dev->udev);
+
+ /*
+ * On some devices, like the Logitech C922, the device SOF does not run
+ * at a stable rate of 1kHz. For those devices use the host SOF instead.
+ * In the tests performed so far, this improves the timestamp precision.
+ * This is probably explained by a small packet handling jitter from the
+ * host, but the exact reason hasn't been fully determined.
+ */
+ if (stream->dev->quirks & UVC_QUIRK_INVALID_DEVICE_SOF)
+ sample.dev_sof = sample.host_sof;
+
+ sample.host_time = uvc_video_get_time();
/*
* The UVC specification allows device implementations that can't obtain
@@ -552,46 +647,29 @@ uvc_video_clock_decode(struct uvc_streaming *stream, struct uvc_buffer *buf,
* the 8 LSBs of the delta are kept.
*/
if (stream->clock.sof_offset == (u16)-1) {
- u16 delta_sof = (host_sof - dev_sof) & 255;
+ u16 delta_sof = (sample.host_sof - sample.dev_sof) & 255;
if (delta_sof >= 10)
stream->clock.sof_offset = delta_sof;
else
stream->clock.sof_offset = 0;
}
- dev_sof = (dev_sof + stream->clock.sof_offset) & 2047;
-
- spin_lock_irqsave(&stream->clock.lock, flags);
-
- sample = &stream->clock.samples[stream->clock.head];
- sample->dev_stc = get_unaligned_le32(&data[header_size - 6]);
- sample->dev_sof = dev_sof;
- sample->host_sof = host_sof;
- sample->host_time = time;
-
- /* Update the sliding window head and count. */
- stream->clock.head = (stream->clock.head + 1) % stream->clock.size;
-
- if (stream->clock.count < stream->clock.size)
- stream->clock.count++;
-
- spin_unlock_irqrestore(&stream->clock.lock, flags);
+ sample.dev_sof = (sample.dev_sof + stream->clock.sof_offset) & 2047;
+ uvc_video_clock_add_sample(&stream->clock, &sample);
+ stream->clock.last_sof = sample.dev_sof;
}
-static void uvc_video_clock_reset(struct uvc_streaming *stream)
+static void uvc_video_clock_reset(struct uvc_clock *clock)
{
- struct uvc_clock *clock = &stream->clock;
-
clock->head = 0;
clock->count = 0;
clock->last_sof = -1;
+ clock->last_sof_overflow = -1;
clock->sof_offset = -1;
}
-static int uvc_video_clock_init(struct uvc_streaming *stream)
+static int uvc_video_clock_init(struct uvc_clock *clock)
{
- struct uvc_clock *clock = &stream->clock;
-
spin_lock_init(&clock->lock);
clock->size = 32;
@@ -600,15 +678,15 @@ static int uvc_video_clock_init(struct uvc_streaming *stream)
if (clock->samples == NULL)
return -ENOMEM;
- uvc_video_clock_reset(stream);
+ uvc_video_clock_reset(clock);
return 0;
}
-static void uvc_video_clock_cleanup(struct uvc_streaming *stream)
+static void uvc_video_clock_cleanup(struct uvc_clock *clock)
{
- kfree(stream->clock.samples);
- stream->clock.samples = NULL;
+ kfree(clock->samples);
+ clock->samples = NULL;
}
/*
@@ -709,11 +787,11 @@ void uvc_video_clock_update(struct uvc_streaming *stream,
unsigned long flags;
u64 timestamp;
u32 delta_stc;
- u32 y1, y2;
+ u32 y1;
u32 x1, x2;
u32 mean;
u32 sof;
- u64 y;
+ u64 y, y2;
if (!uvc_hw_timestamps_param)
return;
@@ -728,11 +806,11 @@ void uvc_video_clock_update(struct uvc_streaming *stream,
spin_lock_irqsave(&clock->lock, flags);
- if (clock->count < clock->size)
+ if (clock->count < 2)
goto done;
- first = &clock->samples[clock->head];
- last = &clock->samples[(clock->head - 1) % clock->size];
+ first = &clock->samples[(clock->head - clock->count + clock->size) % clock->size];
+ last = &clock->samples[(clock->head - 1 + clock->size) % clock->size];
/* First step, PTS to SOF conversion. */
delta_stc = buf->pts - (1UL << 31);
@@ -746,6 +824,18 @@ void uvc_video_clock_update(struct uvc_streaming *stream,
if (y2 < y1)
y2 += 2048 << 16;
+ /*
+ * Have at least 1/4 of a second of timestamps before we
+ * try to do any calculation. Otherwise we do not have enough
+ * precision. This value was determined by running Android CTS
+ * on different devices.
+ *
+ * dev_sof runs at 1KHz, and we have a fixed point precision of
+ * 16 bits.
+ */
+ if ((y2 - y1) < ((1000 / 4) << 16))
+ goto done;
+
y = (u64)(y2 - y1) * (1ULL << 31) + (u64)y1 * (u64)x2
- (u64)y2 * (u64)x1;
y = div_u64(y, x2 - x1);
@@ -753,7 +843,7 @@ void uvc_video_clock_update(struct uvc_streaming *stream,
sof = y;
uvc_dbg(stream->dev, CLOCK,
- "%s: PTS %u y %llu.%06llu SOF %u.%06llu (x1 %u x2 %u y1 %u y2 %u SOF offset %u)\n",
+ "%s: PTS %u y %llu.%06llu SOF %u.%06llu (x1 %u x2 %u y1 %u y2 %llu SOF offset %u)\n",
stream->dev->name, buf->pts,
y >> 16, div_u64((y & 0xffff) * 1000000, 65536),
sof >> 16, div_u64(((u64)sof & 0xffff) * 1000000LLU, 65536),
@@ -768,7 +858,7 @@ void uvc_video_clock_update(struct uvc_streaming *stream,
goto done;
y1 = NSEC_PER_SEC;
- y2 = (u32)ktime_to_ns(ktime_sub(last->host_time, first->host_time)) + y1;
+ y2 = ktime_to_ns(ktime_sub(last->host_time, first->host_time)) + y1;
/*
* Interpolated and host SOF timestamps can wrap around at slightly
@@ -789,7 +879,7 @@ void uvc_video_clock_update(struct uvc_streaming *stream,
timestamp = ktime_to_ns(first->host_time) + y - y1;
uvc_dbg(stream->dev, CLOCK,
- "%s: SOF %u.%06llu y %llu ts %llu buf ts %llu (x1 %u/%u/%u x2 %u/%u/%u y1 %u y2 %u)\n",
+ "%s: SOF %u.%06llu y %llu ts %llu buf ts %llu (x1 %u/%u/%u x2 %u/%u/%u y1 %u y2 %llu)\n",
stream->dev->name,
sof >> 16, div_u64(((u64)sof & 0xffff) * 1000000LLU, 65536),
y, timestamp, vbuf->vb2_buf.timestamp,
@@ -1053,6 +1143,7 @@ static void uvc_video_stats_stop(struct uvc_streaming *stream)
static int uvc_video_decode_start(struct uvc_streaming *stream,
struct uvc_buffer *buf, const u8 *data, int len)
{
+ u8 header_len;
u8 fid;
/*
@@ -1066,6 +1157,7 @@ static int uvc_video_decode_start(struct uvc_streaming *stream,
return -EINVAL;
}
+ header_len = data[0];
fid = data[1] & UVC_STREAM_FID;
/*
@@ -1147,9 +1239,31 @@ static int uvc_video_decode_start(struct uvc_streaming *stream,
return -EAGAIN;
}
+ /*
+ * Some cameras, when running two parallel streams (one MJPEG alongside
+ * another non-MJPEG stream), are known to lose the EOF packet for a frame.
+ * We can detect the end of a frame by checking for a new SOI marker, as
+ * the SOI always lies on the packet boundary between two frames for
+ * these devices.
+ */
+ if (stream->dev->quirks & UVC_QUIRK_MJPEG_NO_EOF &&
+ (stream->cur_format->fcc == V4L2_PIX_FMT_MJPEG ||
+ stream->cur_format->fcc == V4L2_PIX_FMT_JPEG)) {
+ const u8 *packet = data + header_len;
+
+ if (len >= header_len + 2 &&
+ packet[0] == 0xff && packet[1] == JPEG_MARKER_SOI &&
+ buf->bytesused != 0) {
+ buf->state = UVC_BUF_STATE_READY;
+ buf->error = 1;
+ stream->last_fid ^= UVC_STREAM_FID;
+ return -EAGAIN;
+ }
+ }
+
stream->last_fid = fid;
- return data[0];
+ return header_len;
}
static inline enum dma_data_direction uvc_stream_dir(
@@ -2071,7 +2185,7 @@ int uvc_video_resume(struct uvc_streaming *stream, int reset)
stream->frozen = 0;
- uvc_video_clock_reset(stream);
+ uvc_video_clock_reset(&stream->clock);
if (!uvc_queue_streaming(&stream->queue))
return 0;
@@ -2220,7 +2334,7 @@ int uvc_video_start_streaming(struct uvc_streaming *stream)
{
int ret;
- ret = uvc_video_clock_init(stream);
+ ret = uvc_video_clock_init(&stream->clock);
if (ret < 0)
return ret;
@@ -2238,7 +2352,7 @@ int uvc_video_start_streaming(struct uvc_streaming *stream)
error_video:
usb_set_interface(stream->dev->udev, stream->intfnum, 0);
error_commit:
- uvc_video_clock_cleanup(stream);
+ uvc_video_clock_cleanup(&stream->clock);
return ret;
}
@@ -2266,5 +2380,5 @@ void uvc_video_stop_streaming(struct uvc_streaming *stream)
usb_clear_halt(stream->dev->udev, pipe);
}
- uvc_video_clock_cleanup(stream);
+ uvc_video_clock_cleanup(&stream->clock);
}
diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
index 6fb0a78b1b00..5e388f05f3fc 100644
--- a/drivers/media/usb/uvc/uvcvideo.h
+++ b/drivers/media/usb/uvc/uvcvideo.h
@@ -73,6 +73,10 @@
#define UVC_QUIRK_FORCE_Y8 0x00000800
#define UVC_QUIRK_FORCE_BPP 0x00001000
#define UVC_QUIRK_WAKE_AUTOSUSPEND 0x00002000
+#define UVC_QUIRK_NO_RESET_RESUME 0x00004000
+#define UVC_QUIRK_DISABLE_AUTOSUSPEND 0x00008000
+#define UVC_QUIRK_INVALID_DEVICE_SOF 0x00010000
+#define UVC_QUIRK_MJPEG_NO_EOF 0x00020000
/* Format flags */
#define UVC_FMT_FLAG_COMPRESSED 0x00000001
@@ -84,7 +88,9 @@
struct gpio_desc;
struct sg_table;
+struct uvc_control;
struct uvc_device;
+struct uvc_video_chain;
/*
* TODO: Put the most frequently accessed fields at the beginning of
@@ -123,6 +129,9 @@ struct uvc_control_mapping {
s32 master_manual;
u32 slave_ids[2];
+ 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,
@@ -226,6 +235,7 @@ struct uvc_entity {
u8 *bmControls;
struct gpio_desc *gpio_privacy;
int irq;
+ bool initialized;
} gpio;
};
@@ -308,7 +318,6 @@ struct uvc_buffer {
};
#define UVC_QUEUE_DISCONNECTED (1 << 0)
-#define UVC_QUEUE_DROP_CORRUPTED (1 << 1)
struct uvc_video_queue {
struct vb2_queue queue;
@@ -329,7 +338,11 @@ struct uvc_video_chain {
struct uvc_entity *processing; /* Processing unit */
struct uvc_entity *selector; /* Selector unit */
- struct mutex ctrl_mutex; /* Protects ctrl.info */
+ struct mutex ctrl_mutex; /*
+ * Protects ctrl.info,
+ * ctrl.handle and
+ * uvc_fh.pending_async_ctrls
+ */
struct v4l2_prio_state prio; /* V4L2 priority state */
u32 caps; /* V4L2 chain-wide caps */
@@ -498,6 +511,7 @@ struct uvc_streaming {
unsigned int head;
unsigned int count;
unsigned int size;
+ unsigned int last_sof_overflow;
u16 last_sof;
u16 sof_offset;
@@ -522,7 +536,6 @@ struct uvc_device_info {
u32 quirks;
u32 meta_format;
u16 uvc_version;
- const struct uvc_control_mapping **mappings;
};
struct uvc_status_streaming {
@@ -555,8 +568,6 @@ struct uvc_device {
const struct uvc_device_info *info;
- struct mutex lock; /* Protects users */
- unsigned int users;
atomic_t nmappings;
/* Video control interface */
@@ -578,6 +589,8 @@ struct uvc_device {
struct usb_host_endpoint *int_ep;
struct urb *int_urb;
struct uvc_status *status;
+ struct mutex status_lock; /* Protects status_users */
+ unsigned int status_users;
bool flush_status;
struct input_dev *input;
@@ -604,6 +617,7 @@ struct uvc_fh {
struct uvc_video_chain *chain;
struct uvc_streaming *stream;
enum uvc_handle_state state;
+ unsigned int pending_async_ctrls;
};
struct uvc_driver {
@@ -666,8 +680,7 @@ extern struct uvc_driver uvc_driver;
struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id);
/* Video buffers queue management. */
-int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type,
- int drop_corrupted);
+int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type);
void uvc_queue_release(struct uvc_video_queue *queue);
int uvc_request_buffers(struct uvc_video_queue *queue,
struct v4l2_requestbuffers *rb);
@@ -744,12 +757,12 @@ int uvc_register_video_device(struct uvc_device *dev,
int uvc_status_init(struct uvc_device *dev);
void uvc_status_unregister(struct uvc_device *dev);
void uvc_status_cleanup(struct uvc_device *dev);
-int uvc_status_start(struct uvc_device *dev, gfp_t flags);
-void uvc_status_stop(struct uvc_device *dev);
+int uvc_status_resume(struct uvc_device *dev);
+void uvc_status_suspend(struct uvc_device *dev);
+int uvc_status_get(struct uvc_device *dev);
+void uvc_status_put(struct uvc_device *dev);
/* Controls */
-extern const struct uvc_control_mapping uvc_ctrl_power_line_mapping_limited;
-extern const struct uvc_control_mapping uvc_ctrl_power_line_mapping_uvc11;
extern const struct v4l2_subscribed_event_ops uvc_ctrl_sub_ev_ops;
int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
@@ -789,6 +802,8 @@ int uvc_ctrl_is_accessible(struct uvc_video_chain *chain, u32 v4l2_id,
int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
struct uvc_xu_control_query *xqry);
+void uvc_ctrl_cleanup_fh(struct uvc_fh *handle);
+
/* Utility functions */
struct usb_host_endpoint *uvc_find_endpoint(struct usb_host_interface *alts,
u8 epaddr);