aboutsummaryrefslogtreecommitdiff
path: root/drivers/media/usb
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/usb')
-rw-r--r--drivers/media/usb/Kconfig1
-rw-r--r--drivers/media/usb/Makefile1
-rw-r--r--drivers/media/usb/au0828/au0828-cards.c23
-rw-r--r--drivers/media/usb/au0828/au0828-core.c13
-rw-r--r--drivers/media/usb/au0828/au0828-dvb.c169
-rw-r--r--drivers/media/usb/au0828/au0828-video.c4
-rw-r--r--drivers/media/usb/au0828/au0828.h8
-rw-r--r--drivers/media/usb/b2c2/flexcop-usb.c6
-rw-r--r--drivers/media/usb/cpia2/cpia2_usb.c2
-rw-r--r--drivers/media/usb/cx231xx/Kconfig2
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-417.c2
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-audio.c5
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-cards.c112
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-i2c.c23
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-input.c2
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-pcb-cfg.c4
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-video.c6
-rw-r--r--drivers/media/usb/dvb-usb-v2/Kconfig9
-rw-r--r--drivers/media/usb/dvb-usb-v2/Makefile3
-rw-r--r--drivers/media/usb/dvb-usb-v2/af9015.c3
-rw-r--r--drivers/media/usb/dvb-usb-v2/af9035.c186
-rw-r--r--drivers/media/usb/dvb-usb-v2/af9035.h2
-rw-r--r--drivers/media/usb/dvb-usb-v2/anysee.c3
-rw-r--r--drivers/media/usb/dvb-usb-v2/az6007.c63
-rw-r--r--drivers/media/usb/dvb-usb-v2/dvb_usb_core.c8
-rw-r--r--drivers/media/usb/dvb-usb-v2/ec168.c2
-rw-r--r--drivers/media/usb/dvb-usb-v2/it913x.c825
-rw-r--r--drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c4
-rw-r--r--drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h2
-rw-r--r--drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.c2
-rw-r--r--drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.h2
-rw-r--r--drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.c2
-rw-r--r--drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.h2
-rw-r--r--drivers/media/usb/dvb-usb-v2/mxl111sf-phy.c2
-rw-r--r--drivers/media/usb/dvb-usb-v2/mxl111sf-phy.h2
-rw-r--r--drivers/media/usb/dvb-usb-v2/mxl111sf-reg.h2
-rw-r--r--drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c4
-rw-r--r--drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.h4
-rw-r--r--drivers/media/usb/dvb-usb-v2/mxl111sf.c20
-rw-r--r--drivers/media/usb/dvb-usb-v2/mxl111sf.h2
-rw-r--r--drivers/media/usb/dvb-usb-v2/rtl28xxu.c209
-rw-r--r--drivers/media/usb/dvb-usb-v2/rtl28xxu.h3
-rw-r--r--drivers/media/usb/dvb-usb/az6027.c11
-rw-r--r--drivers/media/usb/dvb-usb/cxusb.c54
-rw-r--r--drivers/media/usb/dvb-usb/dib0700.h2
-rw-r--r--drivers/media/usb/dvb-usb/dib0700_core.c43
-rw-r--r--drivers/media/usb/dvb-usb/dib0700_devices.c2
-rw-r--r--drivers/media/usb/dvb-usb/dibusb-common.c10
-rw-r--r--drivers/media/usb/dvb-usb/dvb-usb-remote.c2
-rw-r--r--drivers/media/usb/dvb-usb/dw2102.c538
-rw-r--r--drivers/media/usb/dvb-usb/technisat-usb2.c30
-rw-r--r--drivers/media/usb/em28xx/Kconfig12
-rw-r--r--drivers/media/usb/em28xx/Makefile5
-rw-r--r--drivers/media/usb/em28xx/em28xx-audio.c522
-rw-r--r--drivers/media/usb/em28xx/em28xx-camera.c84
-rw-r--r--drivers/media/usb/em28xx/em28xx-cards.c828
-rw-r--r--drivers/media/usb/em28xx/em28xx-core.c440
-rw-r--r--drivers/media/usb/em28xx/em28xx-dvb.c451
-rw-r--r--drivers/media/usb/em28xx/em28xx-i2c.c215
-rw-r--r--drivers/media/usb/em28xx/em28xx-input.c264
-rw-r--r--drivers/media/usb/em28xx/em28xx-reg.h11
-rw-r--r--drivers/media/usb/em28xx/em28xx-v4l.h20
-rw-r--r--drivers/media/usb/em28xx/em28xx-vbi.c11
-rw-r--r--drivers/media/usb/em28xx/em28xx-video.c1131
-rw-r--r--drivers/media/usb/em28xx/em28xx.h284
-rw-r--r--drivers/media/usb/gspca/Kconfig10
-rw-r--r--drivers/media/usb/gspca/Makefile2
-rw-r--r--drivers/media/usb/gspca/conex.c3
-rw-r--r--drivers/media/usb/gspca/cpia1.c4
-rw-r--r--drivers/media/usb/gspca/dtcs033.c441
-rw-r--r--drivers/media/usb/gspca/gl860/gl860-mi2020.c464
-rw-r--r--drivers/media/usb/gspca/gl860/gl860.c2
-rw-r--r--drivers/media/usb/gspca/gspca.c48
-rw-r--r--drivers/media/usb/gspca/gspca.h10
-rw-r--r--drivers/media/usb/gspca/jeilinj.c5
-rw-r--r--drivers/media/usb/gspca/jl2005bcd.c2
-rw-r--r--drivers/media/usb/gspca/jpeg.h4
-rw-r--r--drivers/media/usb/gspca/kinect.c7
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_mt9m111.c2
-rw-r--r--drivers/media/usb/gspca/mars.c7
-rw-r--r--drivers/media/usb/gspca/mr97310a.c6
-rw-r--r--drivers/media/usb/gspca/nw80x.c11
-rw-r--r--drivers/media/usb/gspca/ov519.c52
-rw-r--r--drivers/media/usb/gspca/ov534.c5
-rw-r--r--drivers/media/usb/gspca/ov534_9.c334
-rw-r--r--drivers/media/usb/gspca/pac207.c6
-rw-r--r--drivers/media/usb/gspca/pac7302.c3
-rw-r--r--drivers/media/usb/gspca/pac7311.c6
-rw-r--r--drivers/media/usb/gspca/se401.c6
-rw-r--r--drivers/media/usb/gspca/sn9c20x.c7
-rw-r--r--drivers/media/usb/gspca/sonixb.c9
-rw-r--r--drivers/media/usb/gspca/sonixj.c3
-rw-r--r--drivers/media/usb/gspca/spca1528.c3
-rw-r--r--drivers/media/usb/gspca/spca500.c3
-rw-r--r--drivers/media/usb/gspca/sq905c.c2
-rw-r--r--drivers/media/usb/gspca/sq930x.c3
-rw-r--r--drivers/media/usb/gspca/stk014.c5
-rw-r--r--drivers/media/usb/gspca/stk1135.c79
-rw-r--r--drivers/media/usb/gspca/stv0680.c2
-rw-r--r--drivers/media/usb/gspca/stv06xx/stv06xx.c2
-rw-r--r--drivers/media/usb/gspca/stv06xx/stv06xx_pb0100.c2
-rw-r--r--drivers/media/usb/gspca/stv06xx/stv06xx_vv6410.c2
-rw-r--r--drivers/media/usb/gspca/sunplus.c4
-rw-r--r--drivers/media/usb/gspca/topro.c23
-rw-r--r--drivers/media/usb/gspca/tv8532.c7
-rw-r--r--drivers/media/usb/gspca/vicam.c8
-rw-r--r--drivers/media/usb/gspca/w996Xcf.c28
-rw-r--r--drivers/media/usb/gspca/xirlink_cit.c46
-rw-r--r--drivers/media/usb/gspca/zc3xx.c5
-rw-r--r--drivers/media/usb/hdpvr/hdpvr-core.c15
-rw-r--r--drivers/media/usb/hdpvr/hdpvr-video.c6
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-hdw.c4
-rw-r--r--drivers/media/usb/pwc/pwc-if.c29
-rw-r--r--drivers/media/usb/s2255/Kconfig2
-rw-r--r--drivers/media/usb/s2255/s2255drv.c1276
-rw-r--r--drivers/media/usb/siano/smsusb.c45
-rw-r--r--drivers/media/usb/sn9c102/Kconfig14
-rw-r--r--drivers/media/usb/sn9c102/Makefile15
-rw-r--r--drivers/media/usb/sn9c102/sn9c102.h214
-rw-r--r--drivers/media/usb/sn9c102/sn9c102_config.h86
-rw-r--r--drivers/media/usb/sn9c102/sn9c102_core.c3434
-rw-r--r--drivers/media/usb/sn9c102/sn9c102_devtable.h147
-rw-r--r--drivers/media/usb/sn9c102/sn9c102_hv7131d.c264
-rw-r--r--drivers/media/usb/sn9c102/sn9c102_hv7131r.c363
-rw-r--r--drivers/media/usb/sn9c102/sn9c102_mi0343.c352
-rw-r--r--drivers/media/usb/sn9c102/sn9c102_mi0360.c453
-rw-r--r--drivers/media/usb/sn9c102/sn9c102_mt9v111.c260
-rw-r--r--drivers/media/usb/sn9c102/sn9c102_ov7630.c626
-rw-r--r--drivers/media/usb/sn9c102/sn9c102_ov7660.c538
-rw-r--r--drivers/media/usb/sn9c102/sn9c102_pas106b.c302
-rw-r--r--drivers/media/usb/sn9c102/sn9c102_pas202bcb.c335
-rw-r--r--drivers/media/usb/sn9c102/sn9c102_sensor.h307
-rw-r--r--drivers/media/usb/sn9c102/sn9c102_tas5110c1b.c154
-rw-r--r--drivers/media/usb/sn9c102/sn9c102_tas5110d.c119
-rw-r--r--drivers/media/usb/sn9c102/sn9c102_tas5130d1b.c165
-rw-r--r--drivers/media/usb/stk1160/stk1160-ac97.c8
-rw-r--r--drivers/media/usb/stk1160/stk1160-core.c10
-rw-r--r--drivers/media/usb/stk1160/stk1160-v4l.c10
-rw-r--r--drivers/media/usb/stk1160/stk1160.h1
-rw-r--r--drivers/media/usb/stkwebcam/stk-webcam.c7
-rw-r--r--drivers/media/usb/tlg2300/pd-alsa.c3
-rw-r--r--drivers/media/usb/tlg2300/pd-main.c2
-rw-r--r--drivers/media/usb/tm6000/tm6000-alsa.c8
-rw-r--r--drivers/media/usb/tm6000/tm6000-cards.c2
-rw-r--r--drivers/media/usb/tm6000/tm6000-dvb.c2
-rw-r--r--drivers/media/usb/tm6000/tm6000-input.c2
-rw-r--r--drivers/media/usb/tm6000/tm6000-stds.c2
-rw-r--r--drivers/media/usb/tm6000/tm6000-video.c2
-rw-r--r--drivers/media/usb/ttusb-dec/ttusb_dec.c152
-rw-r--r--drivers/media/usb/usbtv/Makefile3
-rw-r--r--drivers/media/usb/usbtv/usbtv-core.c134
-rw-r--r--drivers/media/usb/usbtv/usbtv-video.c (renamed from drivers/media/usb/usbtv/usbtv.c)310
-rw-r--r--drivers/media/usb/usbtv/usbtv.h99
-rw-r--r--drivers/media/usb/usbvision/usbvision-video.c2
-rw-r--r--drivers/media/usb/usbvision/usbvision.h8
-rw-r--r--drivers/media/usb/uvc/uvc_ctrl.c4
-rw-r--r--drivers/media/usb/uvc/uvc_driver.c42
-rw-r--r--drivers/media/usb/uvc/uvc_queue.c29
-rw-r--r--drivers/media/usb/uvc/uvc_v4l2.c11
-rw-r--r--drivers/media/usb/uvc/uvc_video.c64
-rw-r--r--drivers/media/usb/uvc/uvcvideo.h16
161 files changed, 6464 insertions, 12396 deletions
diff --git a/drivers/media/usb/Kconfig b/drivers/media/usb/Kconfig
index cfe8056b91a..39d824e2bb6 100644
--- a/drivers/media/usb/Kconfig
+++ b/drivers/media/usb/Kconfig
@@ -17,7 +17,6 @@ source "drivers/media/usb/cpia2/Kconfig"
source "drivers/media/usb/zr364xx/Kconfig"
source "drivers/media/usb/stkwebcam/Kconfig"
source "drivers/media/usb/s2255/Kconfig"
-source "drivers/media/usb/sn9c102/Kconfig"
source "drivers/media/usb/usbtv/Kconfig"
endif
diff --git a/drivers/media/usb/Makefile b/drivers/media/usb/Makefile
index 0935f47497a..7ac4b143dce 100644
--- a/drivers/media/usb/Makefile
+++ b/drivers/media/usb/Makefile
@@ -10,7 +10,6 @@ obj-$(CONFIG_USB_VIDEO_CLASS) += uvc/
obj-$(CONFIG_USB_GSPCA) += gspca/
obj-$(CONFIG_USB_PWC) += pwc/
obj-$(CONFIG_VIDEO_CPIA2) += cpia2/
-obj-$(CONFIG_USB_SN9C102) += sn9c102/
obj-$(CONFIG_VIDEO_AU0828) += au0828/
obj-$(CONFIG_VIDEO_HDPVR) += hdpvr/
obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/
diff --git a/drivers/media/usb/au0828/au0828-cards.c b/drivers/media/usb/au0828/au0828-cards.c
index dd32decb237..7fdadf9bc90 100644
--- a/drivers/media/usb/au0828/au0828-cards.c
+++ b/drivers/media/usb/au0828/au0828-cards.c
@@ -108,7 +108,7 @@ struct au0828_board au0828_boards[] = {
.name = "DViCO FusionHDTV USB",
.tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
- .i2c_clk_divider = AU0828_I2C_CLK_250KHZ,
+ .i2c_clk_divider = AU0828_I2C_CLK_20KHZ,
},
[AU0828_BOARD_HAUPPAUGE_WOODBURY] = {
.name = "Hauppauge Woodbury",
@@ -270,18 +270,25 @@ void au0828_gpio_setup(struct au0828_dev *dev)
* 9 - XC5000 Tuner
*/
- /* Into reset */
+ /* Set relevant GPIOs as outputs (leave the EEPROM W/P
+ as an input since we will never touch it and it has
+ a pullup) */
au0828_write(dev, REG_003, 0x02);
au0828_write(dev, REG_002, 0x80 | 0x20 | 0x10);
+
+ /* Into reset */
au0828_write(dev, REG_001, 0x0);
au0828_write(dev, REG_000, 0x0);
- msleep(100);
+ msleep(50);
- /* Out of reset (leave the cs5340 in reset until needed) */
- au0828_write(dev, REG_003, 0x02);
- au0828_write(dev, REG_001, 0x02);
- au0828_write(dev, REG_002, 0x80 | 0x20 | 0x10);
- au0828_write(dev, REG_000, 0x80 | 0x40 | 0x20);
+ /* Bring power supply out of reset */
+ au0828_write(dev, REG_000, 0x80);
+ msleep(50);
+
+ /* Bring xc5000 and au8522 out of reset (leave the
+ cs5340 in reset until needed) */
+ au0828_write(dev, REG_001, 0x02); /* xc5000 */
+ au0828_write(dev, REG_000, 0x80 | 0x20); /* PS + au8522 */
msleep(250);
break;
diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c
index bd9d19a73ef..ab45a6f9dcc 100644
--- a/drivers/media/usb/au0828/au0828-core.c
+++ b/drivers/media/usb/au0828/au0828-core.c
@@ -173,9 +173,8 @@ static int au0828_usb_probe(struct usb_interface *interface,
const struct usb_device_id *id)
{
int ifnum;
-#ifdef CONFIG_VIDEO_AU0828_V4L2
- int retval;
-#endif
+ int retval = 0;
+
struct au0828_dev *dev;
struct usb_device *usbdev = interface_to_usbdev(interface);
@@ -257,7 +256,11 @@ static int au0828_usb_probe(struct usb_interface *interface,
#endif
/* Digital TV */
- au0828_dvb_register(dev);
+ retval = au0828_dvb_register(dev);
+ if (retval)
+ pr_err("%s() au0282_dev_register failed\n",
+ __func__);
+
/* Store the pointer to the au0828_dev so it can be accessed in
au0828_usb_disconnect */
@@ -268,7 +271,7 @@ static int au0828_usb_probe(struct usb_interface *interface,
mutex_unlock(&dev->lock);
- return 0;
+ return retval;
}
static struct usb_driver au0828_usb_driver = {
diff --git a/drivers/media/usb/au0828/au0828-dvb.c b/drivers/media/usb/au0828/au0828-dvb.c
index 9a6f15613a3..d8b5d948027 100644
--- a/drivers/media/usb/au0828/au0828-dvb.c
+++ b/drivers/media/usb/au0828/au0828-dvb.c
@@ -33,6 +33,10 @@
#include "mxl5007t.h"
#include "tda18271.h"
+static int preallocate_big_buffers;
+module_param_named(preallocate_big_buffers, preallocate_big_buffers, int, 0644);
+MODULE_PARM_DESC(preallocate_big_buffers, "Preallocate the larger transfer buffers at module load time");
+
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
#define _AU0828_BULKPIPE 0x83
@@ -110,16 +114,20 @@ static void urb_completion(struct urb *purb)
int ptype = usb_pipetype(purb->pipe);
unsigned char *ptr;
- dprintk(2, "%s()\n", __func__);
+ dprintk(2, "%s: %d\n", __func__, purb->actual_length);
- if (!dev)
+ if (!dev) {
+ dprintk(2, "%s: no dev!\n", __func__);
return;
+ }
- if (dev->urb_streaming == 0)
+ if (dev->urb_streaming == 0) {
+ dprintk(2, "%s: not streaming!\n", __func__);
return;
+ }
if (ptype != PIPE_BULK) {
- printk(KERN_ERR "%s() Unsupported URB type %d\n",
+ printk(KERN_ERR "%s: Unsupported URB type %d\n",
__func__, ptype);
return;
}
@@ -153,9 +161,13 @@ static int stop_urb_transfer(struct au0828_dev *dev)
dev->urb_streaming = 0;
for (i = 0; i < URB_COUNT; i++) {
- usb_kill_urb(dev->urbs[i]);
- kfree(dev->urbs[i]->transfer_buffer);
- usb_free_urb(dev->urbs[i]);
+ if (dev->urbs[i]) {
+ usb_kill_urb(dev->urbs[i]);
+ if (!preallocate_big_buffers)
+ kfree(dev->urbs[i]->transfer_buffer);
+
+ usb_free_urb(dev->urbs[i]);
+ }
}
return 0;
@@ -181,10 +193,18 @@ static int start_urb_transfer(struct au0828_dev *dev)
purb = dev->urbs[i];
- purb->transfer_buffer = kzalloc(URB_BUFSIZE, GFP_KERNEL);
+ if (preallocate_big_buffers)
+ purb->transfer_buffer = dev->dig_transfer_buffer[i];
+ else
+ purb->transfer_buffer = kzalloc(URB_BUFSIZE,
+ GFP_KERNEL);
+
if (!purb->transfer_buffer) {
usb_free_urb(purb);
dev->urbs[i] = NULL;
+ printk(KERN_ERR
+ "%s: failed big buffer allocation, err = %d\n",
+ __func__, ret);
goto err;
}
@@ -217,6 +237,25 @@ err:
return ret;
}
+static void au0828_start_transport(struct au0828_dev *dev)
+{
+ au0828_write(dev, 0x608, 0x90);
+ au0828_write(dev, 0x609, 0x72);
+ au0828_write(dev, 0x60a, 0x71);
+ au0828_write(dev, 0x60b, 0x01);
+
+}
+
+static void au0828_stop_transport(struct au0828_dev *dev, int full_stop)
+{
+ if (full_stop) {
+ au0828_write(dev, 0x608, 0x00);
+ au0828_write(dev, 0x609, 0x00);
+ au0828_write(dev, 0x60a, 0x00);
+ }
+ au0828_write(dev, 0x60b, 0x00);
+}
+
static int au0828_dvb_start_feed(struct dvb_demux_feed *feed)
{
struct dvb_demux *demux = feed->demux;
@@ -231,13 +270,17 @@ static int au0828_dvb_start_feed(struct dvb_demux_feed *feed)
if (dvb) {
mutex_lock(&dvb->lock);
+ dvb->start_count++;
+ dprintk(1, "%s(), start_count: %d, stop_count: %d\n", __func__,
+ dvb->start_count, dvb->stop_count);
if (dvb->feeding++ == 0) {
/* Start transport */
- au0828_write(dev, 0x608, 0x90);
- au0828_write(dev, 0x609, 0x72);
- au0828_write(dev, 0x60a, 0x71);
- au0828_write(dev, 0x60b, 0x01);
+ au0828_start_transport(dev);
ret = start_urb_transfer(dev);
+ if (ret < 0) {
+ au0828_stop_transport(dev, 0);
+ dvb->feeding--; /* We ran out of memory... */
+ }
}
mutex_unlock(&dvb->lock);
}
@@ -255,11 +298,19 @@ static int au0828_dvb_stop_feed(struct dvb_demux_feed *feed)
dprintk(1, "%s()\n", __func__);
if (dvb) {
+ cancel_work_sync(&dev->restart_streaming);
+
mutex_lock(&dvb->lock);
- if (--dvb->feeding == 0) {
- /* Stop transport */
- ret = stop_urb_transfer(dev);
- au0828_write(dev, 0x60b, 0x00);
+ dvb->stop_count++;
+ dprintk(1, "%s(), start_count: %d, stop_count: %d\n", __func__,
+ dvb->start_count, dvb->stop_count);
+ if (dvb->feeding > 0) {
+ dvb->feeding--;
+ if (dvb->feeding == 0) {
+ /* Stop transport */
+ ret = stop_urb_transfer(dev);
+ au0828_stop_transport(dev, 0);
+ }
}
mutex_unlock(&dvb->lock);
}
@@ -282,21 +333,50 @@ static void au0828_restart_dvb_streaming(struct work_struct *work)
/* Stop transport */
stop_urb_transfer(dev);
- au0828_write(dev, 0x608, 0x00);
- au0828_write(dev, 0x609, 0x00);
- au0828_write(dev, 0x60a, 0x00);
- au0828_write(dev, 0x60b, 0x00);
+ au0828_stop_transport(dev, 1);
/* Start transport */
- au0828_write(dev, 0x608, 0x90);
- au0828_write(dev, 0x609, 0x72);
- au0828_write(dev, 0x60a, 0x71);
- au0828_write(dev, 0x60b, 0x01);
+ au0828_start_transport(dev);
start_urb_transfer(dev);
mutex_unlock(&dvb->lock);
}
+static int au0828_set_frontend(struct dvb_frontend *fe)
+{
+ struct au0828_dev *dev = fe->dvb->priv;
+ struct au0828_dvb *dvb = &dev->dvb;
+ int ret, was_streaming;
+
+ mutex_lock(&dvb->lock);
+ was_streaming = dev->urb_streaming;
+ if (was_streaming) {
+ au0828_stop_transport(dev, 1);
+
+ /*
+ * We can't hold a mutex here, as the restart_streaming
+ * kthread may also hold it.
+ */
+ mutex_unlock(&dvb->lock);
+ cancel_work_sync(&dev->restart_streaming);
+ mutex_lock(&dvb->lock);
+
+ stop_urb_transfer(dev);
+ }
+ mutex_unlock(&dvb->lock);
+
+ ret = dvb->set_frontend(fe);
+
+ if (was_streaming) {
+ mutex_lock(&dvb->lock);
+ au0828_start_transport(dev);
+ start_urb_transfer(dev);
+ mutex_unlock(&dvb->lock);
+ }
+
+ return ret;
+}
+
static int dvb_register(struct au0828_dev *dev)
{
struct au0828_dvb *dvb = &dev->dvb;
@@ -304,6 +384,23 @@ static int dvb_register(struct au0828_dev *dev)
dprintk(1, "%s()\n", __func__);
+ if (preallocate_big_buffers) {
+ int i;
+ for (i = 0; i < URB_COUNT; i++) {
+ dev->dig_transfer_buffer[i] = kzalloc(URB_BUFSIZE,
+ GFP_KERNEL);
+
+ if (!dev->dig_transfer_buffer[i]) {
+ result = -ENOMEM;
+
+ printk(KERN_ERR
+ "%s: failed buffer allocation (errno = %d)\n",
+ DRIVER_NAME, result);
+ goto fail_adapter;
+ }
+ }
+ }
+
INIT_WORK(&dev->restart_streaming, au0828_restart_dvb_streaming);
/* register adapter */
@@ -324,6 +421,10 @@ static int dvb_register(struct au0828_dev *dev)
goto fail_frontend;
}
+ /* Hook dvb frontend */
+ dvb->set_frontend = dvb->frontend->ops.set_frontend;
+ dvb->frontend->ops.set_frontend = au0828_set_frontend;
+
/* register demux stuff */
dvb->demux.dmx.capabilities =
DMX_TS_FILTERING | DMX_SECTION_FILTERING |
@@ -375,6 +476,9 @@ static int dvb_register(struct au0828_dev *dev)
/* register network adapter */
dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx);
+
+ dvb->start_count = 0;
+ dvb->stop_count = 0;
return 0;
fail_fe_conn:
@@ -391,6 +495,13 @@ fail_frontend:
dvb_frontend_detach(dvb->frontend);
dvb_unregister_adapter(&dvb->adapter);
fail_adapter:
+
+ if (preallocate_big_buffers) {
+ int i;
+ for (i = 0; i < URB_COUNT; i++)
+ kfree(dev->dig_transfer_buffer[i]);
+ }
+
return result;
}
@@ -403,6 +514,8 @@ void au0828_dvb_unregister(struct au0828_dev *dev)
if (dvb->frontend == NULL)
return;
+ cancel_work_sync(&dev->restart_streaming);
+
dvb_net_release(&dvb->net);
dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
@@ -411,6 +524,14 @@ void au0828_dvb_unregister(struct au0828_dev *dev)
dvb_unregister_frontend(dvb->frontend);
dvb_frontend_detach(dvb->frontend);
dvb_unregister_adapter(&dvb->adapter);
+
+ if (preallocate_big_buffers) {
+ int i;
+ for (i = 0; i < URB_COUNT; i++)
+ kfree(dev->dig_transfer_buffer[i]);
+ }
+
+
}
/* All the DVB attach calls go here, this function get's modified
diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c
index f6154546b5c..9038194513c 100644
--- a/drivers/media/usb/au0828/au0828-video.c
+++ b/drivers/media/usb/au0828/au0828-video.c
@@ -1109,7 +1109,7 @@ static void au0828_init_tuner(struct au0828_dev *dev)
/* If we've never sent the standard in tuner core, do so now.
We don't do this at device probe because we don't want to
incur the cost of a firmware load */
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->std);
+ v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_std, dev->std);
v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
i2c_gate_ctrl(dev, 0);
}
@@ -1368,7 +1368,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm)
have to make the au0828 bridge adjust the size of its capture
buffer, which is currently hardcoded at 720x480 */
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, norm);
+ v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_std, norm);
i2c_gate_ctrl(dev, 0);
diff --git a/drivers/media/usb/au0828/au0828.h b/drivers/media/usb/au0828/au0828.h
index ef1f57f22be..7112b9d956f 100644
--- a/drivers/media/usb/au0828/au0828.h
+++ b/drivers/media/usb/au0828/au0828.h
@@ -102,6 +102,10 @@ struct au0828_dvb {
struct dmx_frontend fe_mem;
struct dvb_net net;
int feeding;
+ int start_count;
+ int stop_count;
+
+ int (*set_frontend)(struct dvb_frontend *fe);
};
enum au0828_stream_state {
@@ -260,6 +264,10 @@ struct au0828_dev {
/* USB / URB Related */
int urb_streaming;
struct urb *urbs[URB_COUNT];
+
+ /* Preallocated transfer digital transfer buffers */
+
+ char *dig_transfer_buffer[URB_COUNT];
};
/* ----------------------------------------------------------- */
diff --git a/drivers/media/usb/b2c2/flexcop-usb.c b/drivers/media/usb/b2c2/flexcop-usb.c
index 8b6275f8590..0bd96906339 100644
--- a/drivers/media/usb/b2c2/flexcop-usb.c
+++ b/drivers/media/usb/b2c2/flexcop-usb.c
@@ -390,7 +390,7 @@ static void flexcop_usb_transfer_exit(struct flexcop_usb *fc_usb)
}
if (fc_usb->iso_buffer != NULL)
- pci_free_consistent(NULL,
+ usb_free_coherent(fc_usb->udev,
fc_usb->buffer_size, fc_usb->iso_buffer,
fc_usb->dma_addr);
}
@@ -407,8 +407,8 @@ static int flexcop_usb_transfer_init(struct flexcop_usb *fc_usb)
"each of %d bytes size = %d.\n", B2C2_USB_NUM_ISO_URB,
B2C2_USB_FRAMES_PER_ISO, frame_size, bufsize);
- fc_usb->iso_buffer = pci_alloc_consistent(NULL,
- bufsize, &fc_usb->dma_addr);
+ fc_usb->iso_buffer = usb_alloc_coherent(fc_usb->udev,
+ bufsize, GFP_KERNEL, &fc_usb->dma_addr);
if (fc_usb->iso_buffer == NULL)
return -ENOMEM;
diff --git a/drivers/media/usb/cpia2/cpia2_usb.c b/drivers/media/usb/cpia2/cpia2_usb.c
index be171928360..351a78a84c3 100644
--- a/drivers/media/usb/cpia2/cpia2_usb.c
+++ b/drivers/media/usb/cpia2/cpia2_usb.c
@@ -209,7 +209,7 @@ static void cpia2_usb_complete(struct urb *urb)
{
int i;
unsigned char *cdata;
- static int frame_ready = false;
+ static bool frame_ready = false;
struct camera_data *cam = (struct camera_data *) urb->context;
if (urb->status!=0) {
diff --git a/drivers/media/usb/cx231xx/Kconfig b/drivers/media/usb/cx231xx/Kconfig
index 86feeeaf61c..f14c5e89a56 100644
--- a/drivers/media/usb/cx231xx/Kconfig
+++ b/drivers/media/usb/cx231xx/Kconfig
@@ -45,6 +45,8 @@ config VIDEO_CX231XX_DVB
select MEDIA_TUNER_XC5000 if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT
select DVB_MB86A20S if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_LGDT3305 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_TDA18271C2DD if MEDIA_SUBDRV_AUTOSELECT
---help---
This adds support for DVB cards based on the
diff --git a/drivers/media/usb/cx231xx/cx231xx-417.c b/drivers/media/usb/cx231xx/cx231xx-417.c
index 2f63029e7a3..30a0c69fb42 100644
--- a/drivers/media/usb/cx231xx/cx231xx-417.c
+++ b/drivers/media/usb/cx231xx/cx231xx-417.c
@@ -1516,7 +1516,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id)
dev->ts1.height = 576;
cx2341x_handler_set_50hz(&dev->mpeg_ctrl_handler, true);
}
- call_all(dev, core, s_std, dev->norm);
+ call_all(dev, video, s_std, dev->norm);
/* do mode control overrides */
cx231xx_do_mode_ctrl_overrides(dev);
diff --git a/drivers/media/usb/cx231xx/cx231xx-audio.c b/drivers/media/usb/cx231xx/cx231xx-audio.c
index 81a1d971d79..9b925874d39 100644
--- a/drivers/media/usb/cx231xx/cx231xx-audio.c
+++ b/drivers/media/usb/cx231xx/cx231xx-audio.c
@@ -665,8 +665,8 @@ static int cx231xx_audio_init(struct cx231xx *dev)
cx231xx_info("cx231xx-audio.c: probing for cx231xx "
"non standard usbaudio\n");
- err = snd_card_create(index[devnr], "Cx231xx Audio", THIS_MODULE,
- 0, &card);
+ err = snd_card_new(&dev->udev->dev, index[devnr], "Cx231xx Audio",
+ THIS_MODULE, 0, &card);
if (err < 0)
return err;
@@ -682,7 +682,6 @@ static int cx231xx_audio_init(struct cx231xx *dev)
pcm->info_flags = 0;
pcm->private_data = dev;
strcpy(pcm->name, "Conexant cx231xx Capture");
- snd_card_set_dev(card, &dev->udev->dev);
strcpy(card->driver, "Cx231xx-Audio");
strcpy(card->shortname, "Cx231xx Audio");
strcpy(card->longname, "Conexant cx231xx Audio");
diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c
index a384f80f595..2ee03e4ddd8 100644
--- a/drivers/media/usb/cx231xx/cx231xx-cards.c
+++ b/drivers/media/usb/cx231xx/cx231xx-cards.c
@@ -709,6 +709,8 @@ 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, 0x6109),
+ .driver_info = CX231XX_BOARD_PV_XCAPTURE_USB},
{USB_DEVICE(0x0572, 0x5A3C),
.driver_info = CX231XX_BOARD_UNKNOWN},
{USB_DEVICE(0x0572, 0x58A2),
@@ -978,7 +980,6 @@ static int cx231xx_init_dev(struct cx231xx *dev, struct usb_device *udev,
int minor)
{
int retval = -ENOMEM;
- int errCode;
unsigned int maxh, maxw;
dev->udev = udev;
@@ -1014,8 +1015,8 @@ static int cx231xx_init_dev(struct cx231xx *dev, struct usb_device *udev,
/* Cx231xx pre card setup */
cx231xx_pre_card_setup(dev);
- errCode = cx231xx_config(dev);
- if (errCode) {
+ retval = cx231xx_config(dev);
+ if (retval) {
cx231xx_errdev("error configuring device\n");
return -ENOMEM;
}
@@ -1024,12 +1025,11 @@ static int cx231xx_init_dev(struct cx231xx *dev, struct usb_device *udev,
dev->norm = dev->board.norm;
/* register i2c bus */
- errCode = cx231xx_dev_init(dev);
- if (errCode < 0) {
- cx231xx_dev_uninit(dev);
+ retval = cx231xx_dev_init(dev);
+ if (retval) {
cx231xx_errdev("%s: cx231xx_i2c_register - errCode [%d]!\n",
- __func__, errCode);
- return errCode;
+ __func__, retval);
+ goto err_dev_init;
}
/* Do board specific init */
@@ -1047,11 +1047,11 @@ static int cx231xx_init_dev(struct cx231xx *dev, struct usb_device *udev,
dev->interlaced = 0;
dev->video_input = 0;
- errCode = cx231xx_config(dev);
- if (errCode < 0) {
+ retval = cx231xx_config(dev);
+ if (retval) {
cx231xx_errdev("%s: cx231xx_config - errCode [%d]!\n",
- __func__, errCode);
- return errCode;
+ __func__, retval);
+ goto err_dev_init;
}
/* init video dma queues */
@@ -1075,9 +1075,9 @@ static int cx231xx_init_dev(struct cx231xx *dev, struct usb_device *udev,
}
retval = cx231xx_register_analog_devices(dev);
- if (retval < 0) {
- cx231xx_release_resources(dev);
- return retval;
+ if (retval) {
+ cx231xx_release_analog_resources(dev);
+ goto err_analog;
}
cx231xx_ir_init(dev);
@@ -1085,6 +1085,11 @@ static int cx231xx_init_dev(struct cx231xx *dev, struct usb_device *udev,
cx231xx_init_extension(dev);
return 0;
+err_analog:
+ cx231xx_remove_from_devlist(dev);
+err_dev_init:
+ cx231xx_dev_uninit(dev);
+ return retval;
}
#if defined(CONFIG_MODULES) && defined(MODULE)
@@ -1132,7 +1137,6 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
char *speed;
struct usb_interface_assoc_descriptor *assoc_desc;
- udev = usb_get_dev(interface_to_usbdev(interface));
ifnum = interface->altsetting[0].desc.bInterfaceNumber;
/*
@@ -1161,6 +1165,8 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
return -ENOMEM;
}
+ udev = usb_get_dev(interface_to_usbdev(interface));
+
snprintf(dev->name, 29, "cx231xx #%d", nr);
dev->devno = nr;
dev->model = id->driver_info;
@@ -1223,10 +1229,8 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
if (assoc_desc->bFirstInterface != ifnum) {
cx231xx_err(DRIVER_NAME ": Not found "
"matching IAD interface\n");
- clear_bit(dev->devno, &cx231xx_devused);
- kfree(dev);
- dev = NULL;
- return -ENODEV;
+ retval = -ENODEV;
+ goto err_if;
}
cx231xx_info("registering interface %d\n", ifnum);
@@ -1242,22 +1246,13 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
retval = v4l2_device_register(&interface->dev, &dev->v4l2_dev);
if (retval) {
cx231xx_errdev("v4l2_device_register failed\n");
- clear_bit(dev->devno, &cx231xx_devused);
- kfree(dev);
- dev = NULL;
- return -EIO;
+ retval = -EIO;
+ goto err_v4l2;
}
/* allocate device struct */
retval = cx231xx_init_dev(dev, udev, nr);
- if (retval) {
- clear_bit(dev->devno, &cx231xx_devused);
- v4l2_device_unregister(&dev->v4l2_dev);
- kfree(dev);
- dev = NULL;
- usb_set_intfdata(interface, NULL);
-
- return retval;
- }
+ if (retval)
+ goto err_init;
/* compute alternate max packet sizes for video */
uif = udev->actconfig->interface[dev->current_pcb_config.
@@ -1275,11 +1270,8 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
if (dev->video_mode.alt_max_pkt_size == NULL) {
cx231xx_errdev("out of memory!\n");
- clear_bit(dev->devno, &cx231xx_devused);
- v4l2_device_unregister(&dev->v4l2_dev);
- kfree(dev);
- dev = NULL;
- return -ENOMEM;
+ retval = -ENOMEM;
+ goto err_video_alt;
}
for (i = 0; i < dev->video_mode.num_alt; i++) {
@@ -1309,11 +1301,8 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
if (dev->vbi_mode.alt_max_pkt_size == NULL) {
cx231xx_errdev("out of memory!\n");
- clear_bit(dev->devno, &cx231xx_devused);
- v4l2_device_unregister(&dev->v4l2_dev);
- kfree(dev);
- dev = NULL;
- return -ENOMEM;
+ retval = -ENOMEM;
+ goto err_vbi_alt;
}
for (i = 0; i < dev->vbi_mode.num_alt; i++) {
@@ -1344,11 +1333,8 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
if (dev->sliced_cc_mode.alt_max_pkt_size == NULL) {
cx231xx_errdev("out of memory!\n");
- clear_bit(dev->devno, &cx231xx_devused);
- v4l2_device_unregister(&dev->v4l2_dev);
- kfree(dev);
- dev = NULL;
- return -ENOMEM;
+ retval = -ENOMEM;
+ goto err_sliced_cc_alt;
}
for (i = 0; i < dev->sliced_cc_mode.num_alt; i++) {
@@ -1380,11 +1366,8 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
if (dev->ts1_mode.alt_max_pkt_size == NULL) {
cx231xx_errdev("out of memory!\n");
- clear_bit(dev->devno, &cx231xx_devused);
- v4l2_device_unregister(&dev->v4l2_dev);
- kfree(dev);
- dev = NULL;
- return -ENOMEM;
+ retval = -ENOMEM;
+ goto err_ts1_alt;
}
for (i = 0; i < dev->ts1_mode.num_alt; i++) {
@@ -1411,6 +1394,29 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
request_modules(dev);
return 0;
+err_ts1_alt:
+ kfree(dev->sliced_cc_mode.alt_max_pkt_size);
+err_sliced_cc_alt:
+ kfree(dev->vbi_mode.alt_max_pkt_size);
+err_vbi_alt:
+ kfree(dev->video_mode.alt_max_pkt_size);
+err_video_alt:
+ /* cx231xx_uninit_dev: */
+ cx231xx_close_extension(dev);
+ cx231xx_ir_exit(dev);
+ cx231xx_release_analog_resources(dev);
+ cx231xx_417_unregister(dev);
+ cx231xx_remove_from_devlist(dev);
+ cx231xx_dev_uninit(dev);
+err_init:
+ v4l2_device_unregister(&dev->v4l2_dev);
+err_v4l2:
+ usb_set_intfdata(interface, NULL);
+err_if:
+ usb_put_dev(udev);
+ clear_bit(dev->devno, &cx231xx_devused);
+ kfree(dev);
+ return retval;
}
/*
diff --git a/drivers/media/usb/cx231xx/cx231xx-i2c.c b/drivers/media/usb/cx231xx/cx231xx-i2c.c
index 96a5a096539..7c0f797f105 100644
--- a/drivers/media/usb/cx231xx/cx231xx-i2c.c
+++ b/drivers/media/usb/cx231xx/cx231xx-i2c.c
@@ -371,9 +371,9 @@ static int cx231xx_i2c_xfer(struct i2c_adapter *i2c_adap,
mutex_lock(&dev->i2c_lock);
for (i = 0; i < num; i++) {
- addr = msgs[i].addr >> 1;
+ addr = msgs[i].addr;
- dprintk2(2, "%s %s addr=%x len=%d:",
+ dprintk2(2, "%s %s addr=0x%x len=%d:",
(msgs[i].flags & I2C_M_RD) ? "read" : "write",
i == num - 1 ? "stop" : "nonstop", addr, msgs[i].len);
if (!msgs[i].len) {
@@ -390,32 +390,41 @@ static int cx231xx_i2c_xfer(struct i2c_adapter *i2c_adap,
rc = cx231xx_i2c_recv_bytes(i2c_adap, &msgs[i]);
if (i2c_debug >= 2) {
for (byte = 0; byte < msgs[i].len; byte++)
- printk(" %02x", msgs[i].buf[byte]);
+ printk(KERN_CONT " %02x", msgs[i].buf[byte]);
}
} else if (i + 1 < num && (msgs[i + 1].flags & I2C_M_RD) &&
msgs[i].addr == msgs[i + 1].addr
&& (msgs[i].len <= 2) && (bus->nr < 3)) {
+ /* write bytes */
+ if (i2c_debug >= 2) {
+ for (byte = 0; byte < msgs[i].len; byte++)
+ printk(KERN_CONT " %02x", msgs[i].buf[byte]);
+ printk(KERN_CONT "\n");
+ }
/* read bytes */
+ dprintk2(2, "plus %s %s addr=0x%x len=%d:",
+ (msgs[i+1].flags & I2C_M_RD) ? "read" : "write",
+ i+1 == num - 1 ? "stop" : "nonstop", addr, msgs[i+1].len);
rc = cx231xx_i2c_recv_bytes_with_saddr(i2c_adap,
&msgs[i],
&msgs[i + 1]);
if (i2c_debug >= 2) {
- for (byte = 0; byte < msgs[i].len; byte++)
- printk(" %02x", msgs[i].buf[byte]);
+ for (byte = 0; byte < msgs[i+1].len; byte++)
+ printk(KERN_CONT " %02x", msgs[i+1].buf[byte]);
}
i++;
} else {
/* write bytes */
if (i2c_debug >= 2) {
for (byte = 0; byte < msgs[i].len; byte++)
- printk(" %02x", msgs[i].buf[byte]);
+ printk(KERN_CONT " %02x", msgs[i].buf[byte]);
}
rc = cx231xx_i2c_send_bytes(i2c_adap, &msgs[i]);
}
if (rc < 0)
goto err;
if (i2c_debug >= 2)
- printk("\n");
+ printk(KERN_CONT "\n");
}
mutex_unlock(&dev->i2c_lock);
return num;
diff --git a/drivers/media/usb/cx231xx/cx231xx-input.c b/drivers/media/usb/cx231xx/cx231xx-input.c
index 0f7b4244682..46d52fac868 100644
--- a/drivers/media/usb/cx231xx/cx231xx-input.c
+++ b/drivers/media/usb/cx231xx/cx231xx-input.c
@@ -1,7 +1,7 @@
/*
* cx231xx IR glue driver
*
- * Copyright (C) 2010 Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (C) 2010 Mauro Carvalho Chehab
*
* Polaris (cx231xx) has its support for IR's with a design close to MCE.
* however, a few designs are using an external I2C chip for IR, instead
diff --git a/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.c b/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.c
index d7308ab7a90..2a34ceee480 100644
--- a/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.c
+++ b/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.c
@@ -28,7 +28,7 @@ MODULE_PARM_DESC(pcb_debug, "enable pcb config debug messages [video]");
/******************************************************************************/
-struct pcb_config cx231xx_Scenario[] = {
+static struct pcb_config cx231xx_Scenario[] = {
{
INDEX_SELFPOWER_DIGITAL_ONLY, /* index */
USB_SELF_POWER, /* power_type */
@@ -672,7 +672,7 @@ u32 initialize_cx231xx(struct cx231xx *dev)
pcb config it is related to */
cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, BOARD_CFG_STAT, data, 4);
- config_info = le32_to_cpu(*((u32 *) data));
+ config_info = le32_to_cpu(*((__le32 *)data));
usb_speed = (u8) (config_info & 0x1);
/* Verify this device belongs to Bus power or Self power device */
diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c
index 99062610171..1f8751379e2 100644
--- a/drivers/media/usb/cx231xx/cx231xx-video.c
+++ b/drivers/media/usb/cx231xx/cx231xx-video.c
@@ -1009,7 +1009,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm)
dev->width = 720;
dev->height = (dev->norm & V4L2_STD_625_50) ? 576 : 480;
- call_all(dev, core, s_std, dev->norm);
+ call_all(dev, video, s_std, dev->norm);
/* We need to reset basic properties in the decoder related to
resolution (since a standard change effects things like the number
@@ -1108,7 +1108,7 @@ int cx231xx_s_input(struct file *file, void *priv, unsigned int i)
/* There's a tuner, so reset the standard and put it on the
last known frequency (since it was probably powered down
until now */
- call_all(dev, core, s_std, dev->norm);
+ call_all(dev, video, s_std, dev->norm);
}
return 0;
@@ -2099,7 +2099,7 @@ int cx231xx_register_analog_devices(struct cx231xx *dev)
/* Set the initial input */
video_mux(dev, dev->video_input);
- call_all(dev, core, s_std, dev->norm);
+ call_all(dev, video, s_std, dev->norm);
v4l2_ctrl_handler_init(&dev->ctrl_handler, 10);
v4l2_ctrl_handler_init(&dev->radio_ctrl_handler, 5);
diff --git a/drivers/media/usb/dvb-usb-v2/Kconfig b/drivers/media/usb/dvb-usb-v2/Kconfig
index 2059d0c86ad..037e519bbaa 100644
--- a/drivers/media/usb/dvb-usb-v2/Kconfig
+++ b/drivers/media/usb/dvb-usb-v2/Kconfig
@@ -100,13 +100,6 @@ config DVB_USB_GL861
Say Y here to support the MSI Megasky 580 (55801) DVB-T USB2.0
receiver with USB ID 0db0:5581.
-config DVB_USB_IT913X
- tristate "ITE IT913X DVB-T USB2.0 support"
- depends on DVB_USB_V2
- select DVB_IT913X_FE
- help
- Say Y here to support the ITE IT913X DVB-T USB2.0
-
config DVB_USB_LME2510
tristate "LME DM04/QQBOX DVB-S USB2.0 support"
depends on DVB_USB_V2
@@ -133,7 +126,7 @@ config DVB_USB_MXL111SF
config DVB_USB_RTL28XXU
tristate "Realtek RTL28xxU DVB USB support"
- depends on DVB_USB_V2
+ depends on DVB_USB_V2 && I2C_MUX
select DVB_RTL2830
select DVB_RTL2832
select MEDIA_TUNER_QT1010 if MEDIA_SUBDRV_AUTOSELECT
diff --git a/drivers/media/usb/dvb-usb-v2/Makefile b/drivers/media/usb/dvb-usb-v2/Makefile
index 2c06714b9ef..bc38f03394c 100644
--- a/drivers/media/usb/dvb-usb-v2/Makefile
+++ b/drivers/media/usb/dvb-usb-v2/Makefile
@@ -22,9 +22,6 @@ obj-$(CONFIG_DVB_USB_CE6230) += dvb-usb-ce6230.o
dvb-usb-ec168-objs := ec168.o
obj-$(CONFIG_DVB_USB_EC168) += dvb-usb-ec168.o
-dvb-usb-it913x-objs := it913x.o
-obj-$(CONFIG_DVB_USB_IT913X) += dvb-usb-it913x.o
-
dvb-usb-lmedm04-objs := lmedm04.o
obj-$(CONFIG_DVB_USB_LME2510) += dvb-usb-lmedm04.o
diff --git a/drivers/media/usb/dvb-usb-v2/af9015.c b/drivers/media/usb/dvb-usb-v2/af9015.c
index d556042cf31..da47d2392f2 100644
--- a/drivers/media/usb/dvb-usb-v2/af9015.c
+++ b/drivers/media/usb/dvb-usb-v2/af9015.c
@@ -397,12 +397,13 @@ error:
return ret;
}
+#define AF9015_EEPROM_SIZE 256
+
/* hash (and dump) eeprom */
static int af9015_eeprom_hash(struct dvb_usb_device *d)
{
struct af9015_state *state = d_to_priv(d);
int ret, i;
- static const unsigned int AF9015_EEPROM_SIZE = 256;
u8 buf[AF9015_EEPROM_SIZE];
struct req_t req = {READ_I2C, AF9015_I2C_EEPROM, 0, 0, 1, 1, NULL};
diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c
index 1ea17dc2a76..7b9b75f6077 100644
--- a/drivers/media/usb/dvb-usb-v2/af9035.c
+++ b/drivers/media/usb/dvb-usb-v2/af9035.c
@@ -21,6 +21,9 @@
#include "af9035.h"
+/* Max transfer size done by I2C transfer functions */
+#define MAX_XFER_SIZE 64
+
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
static u16 af9035_checksum(const u8 *buf, size_t len)
@@ -126,9 +129,15 @@ exit:
/* write multiple registers */
static int af9035_wr_regs(struct dvb_usb_device *d, u32 reg, u8 *val, int len)
{
- u8 wbuf[6 + len];
+ u8 wbuf[MAX_XFER_SIZE];
u8 mbox = (reg >> 16) & 0xff;
- struct usb_req req = { CMD_MEM_WR, mbox, sizeof(wbuf), wbuf, 0, NULL };
+ struct usb_req req = { CMD_MEM_WR, mbox, 6 + len, wbuf, 0, NULL };
+
+ if (6 + len > sizeof(wbuf)) {
+ dev_warn(&d->udev->dev, "%s: i2c wr: len=%d is too big!\n",
+ KBUILD_MODNAME, len);
+ return -EOPNOTSUPP;
+ }
wbuf[0] = len;
wbuf[1] = 2;
@@ -228,9 +237,17 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap,
msg[1].len);
} else {
/* I2C */
- u8 buf[5 + msg[0].len];
- struct usb_req req = { CMD_I2C_RD, 0, sizeof(buf),
+ u8 buf[MAX_XFER_SIZE];
+ struct usb_req req = { CMD_I2C_RD, 0, 5 + msg[0].len,
buf, msg[1].len, msg[1].buf };
+
+ if (5 + msg[0].len > sizeof(buf)) {
+ dev_warn(&d->udev->dev,
+ "%s: i2c xfer: len=%d is too big!\n",
+ KBUILD_MODNAME, msg[0].len);
+ ret = -EOPNOTSUPP;
+ goto unlock;
+ }
req.mbox |= ((msg[0].addr & 0x80) >> 3);
buf[0] = msg[1].len;
buf[1] = msg[0].addr << 1;
@@ -257,9 +274,17 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap,
msg[0].len - 3);
} else {
/* I2C */
- u8 buf[5 + msg[0].len];
- struct usb_req req = { CMD_I2C_WR, 0, sizeof(buf), buf,
- 0, NULL };
+ u8 buf[MAX_XFER_SIZE];
+ struct usb_req req = { CMD_I2C_WR, 0, 5 + msg[0].len,
+ buf, 0, NULL };
+
+ if (5 + msg[0].len > sizeof(buf)) {
+ dev_warn(&d->udev->dev,
+ "%s: i2c xfer: len=%d is too big!\n",
+ KBUILD_MODNAME, msg[0].len);
+ ret = -EOPNOTSUPP;
+ goto unlock;
+ }
req.mbox |= ((msg[0].addr & 0x80) >> 3);
buf[0] = msg[0].len;
buf[1] = msg[0].addr << 1;
@@ -296,6 +321,7 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap,
ret = -EOPNOTSUPP;
}
+unlock:
mutex_unlock(&d->i2c_mutex);
if (ret < 0)
@@ -549,6 +575,10 @@ static int af9035_download_firmware(struct dvb_usb_device *d,
if (ret < 0)
goto err;
+ /* use default I2C address if eeprom has no address set */
+ if (!tmp)
+ tmp = 0x3a;
+
if (state->chip_type == 0x9135) {
ret = af9035_wr_reg(d, 0x004bfb, tmp);
if (ret < 0)
@@ -611,6 +641,7 @@ static int af9035_read_config(struct dvb_usb_device *d)
/* demod I2C "address" */
state->af9033_config[0].i2c_addr = 0x38;
+ state->af9033_config[1].i2c_addr = 0x3a;
state->af9033_config[0].adc_multiplier = AF9033_ADC_MULTIPLIER_2X;
state->af9033_config[1].adc_multiplier = AF9033_ADC_MULTIPLIER_2X;
state->af9033_config[0].ts_mode = AF9033_TS_MODE_USB;
@@ -658,7 +689,9 @@ static int af9035_read_config(struct dvb_usb_device *d)
if (ret < 0)
goto err;
- state->af9033_config[1].i2c_addr = tmp;
+ if (tmp)
+ state->af9033_config[1].i2c_addr = tmp;
+
dev_dbg(&d->udev->dev, "%s: 2nd demod I2C addr=%02x\n",
__func__, tmp);
}
@@ -671,15 +704,41 @@ static int af9035_read_config(struct dvb_usb_device *d)
if (ret < 0)
goto err;
- if (tmp == 0x00)
- dev_dbg(&d->udev->dev,
- "%s: [%d]tuner not set, using default\n",
- __func__, i);
- else
+ dev_dbg(&d->udev->dev, "%s: [%d]tuner=%02x\n",
+ __func__, i, tmp);
+
+ /* tuner sanity check */
+ if (state->chip_type == 0x9135) {
+ if (state->chip_version == 0x02) {
+ /* IT9135 BX (v2) */
+ switch (tmp) {
+ case AF9033_TUNER_IT9135_60:
+ case AF9033_TUNER_IT9135_61:
+ case AF9033_TUNER_IT9135_62:
+ state->af9033_config[i].tuner = tmp;
+ break;
+ }
+ } else {
+ /* IT9135 AX (v1) */
+ switch (tmp) {
+ case AF9033_TUNER_IT9135_38:
+ case AF9033_TUNER_IT9135_51:
+ case AF9033_TUNER_IT9135_52:
+ state->af9033_config[i].tuner = tmp;
+ break;
+ }
+ }
+ } else {
+ /* AF9035 */
state->af9033_config[i].tuner = tmp;
+ }
- dev_dbg(&d->udev->dev, "%s: [%d]tuner=%02x\n",
- __func__, i, state->af9033_config[i].tuner);
+ if (state->af9033_config[i].tuner != tmp) {
+ dev_info(&d->udev->dev,
+ "%s: [%d] overriding tuner from %02x to %02x\n",
+ KBUILD_MODNAME, i, tmp,
+ state->af9033_config[i].tuner);
+ }
switch (state->af9033_config[i].tuner) {
case AF9033_TUNER_TUA9001:
@@ -912,12 +971,7 @@ static int af9035_frontend_callback(void *adapter_priv, int component,
static int af9035_get_adapter_count(struct dvb_usb_device *d)
{
struct state *state = d_to_priv(d);
-
- /* disable 2nd adapter as we don't have PID filters implemented */
- if (d->udev->speed == USB_SPEED_FULL)
- return 1;
- else
- return state->dual_mode + 1;
+ return state->dual_mode + 1;
}
static int af9035_frontend_attach(struct dvb_usb_adapter *adap)
@@ -935,7 +989,7 @@ static int af9035_frontend_attach(struct dvb_usb_adapter *adap)
/* attach demodulator */
adap->fe[0] = dvb_attach(af9033_attach, &state->af9033_config[adap->id],
- &d->i2c_adap);
+ &d->i2c_adap, &state->ops);
if (adap->fe[0] == NULL) {
ret = -ENODEV;
goto err;
@@ -1343,58 +1397,19 @@ static int af9035_get_stream_config(struct dvb_frontend *fe, u8 *ts_type,
return 0;
}
-/*
- * FIXME: PID filter is property of demodulator and should be moved to the
- * correct driver. Also we support only adapter #0 PID filter and will
- * disable adapter #1 if USB1.1 is used.
- */
static int af9035_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
{
- struct dvb_usb_device *d = adap_to_d(adap);
- int ret;
-
- dev_dbg(&d->udev->dev, "%s: onoff=%d\n", __func__, onoff);
-
- ret = af9035_wr_reg_mask(d, 0x80f993, onoff, 0x01);
- if (ret < 0)
- goto err;
-
- return 0;
-
-err:
- dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+ struct state *state = adap_to_priv(adap);
- return ret;
+ return state->ops.pid_filter_ctrl(adap->fe[0], onoff);
}
static int af9035_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid,
int onoff)
{
- struct dvb_usb_device *d = adap_to_d(adap);
- int ret;
- u8 wbuf[2] = {(pid >> 0) & 0xff, (pid >> 8) & 0xff};
-
- dev_dbg(&d->udev->dev, "%s: index=%d pid=%04x onoff=%d\n",
- __func__, index, pid, onoff);
-
- ret = af9035_wr_regs(d, 0x80f996, wbuf, 2);
- if (ret < 0)
- goto err;
-
- ret = af9035_wr_reg(d, 0x80f994, onoff);
- if (ret < 0)
- goto err;
-
- ret = af9035_wr_reg(d, 0x80f995, index);
- if (ret < 0)
- goto err;
-
- return 0;
-
-err:
- dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+ struct state *state = adap_to_priv(adap);
- return ret;
+ return state->ops.pid_filter(adap->fe[0], index, pid, onoff);
}
static int af9035_probe(struct usb_interface *intf,
@@ -1468,6 +1483,13 @@ static const struct dvb_usb_device_properties af9035_props = {
.stream = DVB_USB_STREAM_BULK(0x84, 6, 87 * 188),
}, {
+ .caps = DVB_USB_ADAP_HAS_PID_FILTER |
+ DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+
+ .pid_filter_count = 32,
+ .pid_filter_ctrl = af9035_pid_filter_ctrl,
+ .pid_filter = af9035_pid_filter,
+
.stream = DVB_USB_STREAM_BULK(0x85, 6, 87 * 188),
},
},
@@ -1502,15 +1524,37 @@ static const struct usb_device_id af9035_id_table[] = {
{ DVB_USB_DEVICE(USB_VID_TERRATEC, 0x00aa,
&af9035_props, "TerraTec Cinergy T Stick (rev. 2)", NULL) },
/* IT9135 devices */
-#if 0
- { DVB_USB_DEVICE(0x048d, 0x9135,
- &af9035_props, "IT9135 reference design", NULL) },
- { DVB_USB_DEVICE(0x048d, 0x9006,
- &af9035_props, "IT9135 reference design", NULL) },
-#endif
+ { DVB_USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9135,
+ &af9035_props, "ITE 9135 Generic", RC_MAP_IT913X_V1) },
+ { DVB_USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9135_9005,
+ &af9035_props, "ITE 9135(9005) Generic", RC_MAP_IT913X_V2) },
+ { DVB_USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9135_9006,
+ &af9035_props, "ITE 9135(9006) Generic", RC_MAP_IT913X_V1) },
+ { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A835B_1835,
+ &af9035_props, "Avermedia A835B(1835)", RC_MAP_IT913X_V2) },
+ { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A835B_2835,
+ &af9035_props, "Avermedia A835B(2835)", RC_MAP_IT913X_V2) },
+ { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A835B_3835,
+ &af9035_props, "Avermedia A835B(3835)", RC_MAP_IT913X_V2) },
+ { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A835B_4835,
+ &af9035_props, "Avermedia A835B(4835)", RC_MAP_IT913X_V2) },
+ { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_H335,
+ &af9035_props, "Avermedia H335", RC_MAP_IT913X_V2) },
+ { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB499_2T_T09,
+ &af9035_props, "Kworld UB499-2T T09", RC_MAP_IT913X_V1) },
+ { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV22_IT9137,
+ &af9035_props, "Sveon STV22 Dual DVB-T HDTV",
+ RC_MAP_IT913X_V1) },
+ { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_CTVDIGDUAL_V2,
+ &af9035_props, "Digital Dual TV Receiver CTVDIGDUAL_V2",
+ RC_MAP_IT913X_V1) },
/* XXX: that same ID [0ccd:0099] is used by af9015 driver too */
{ DVB_USB_DEVICE(USB_VID_TERRATEC, 0x0099,
&af9035_props, "TerraTec Cinergy T Stick Dual RC (rev. 2)", NULL) },
+ { DVB_USB_DEVICE(USB_VID_LEADTEK, 0x6a05,
+ &af9035_props, "Leadtek WinFast DTV Dongle Dual", NULL) },
+ { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xf900,
+ &af9035_props, "Hauppauge WinTV-MiniStick 2", NULL) },
{ }
};
MODULE_DEVICE_TABLE(usb, af9035_id_table);
diff --git a/drivers/media/usb/dvb-usb-v2/af9035.h b/drivers/media/usb/dvb-usb-v2/af9035.h
index a1c68d829b8..c21902fdd4c 100644
--- a/drivers/media/usb/dvb-usb-v2/af9035.h
+++ b/drivers/media/usb/dvb-usb-v2/af9035.h
@@ -62,6 +62,8 @@ struct state {
u8 dual_mode:1;
u16 eeprom_addr;
struct af9033_config af9033_config[2];
+
+ struct af9033_ops ops;
};
static const u32 clock_lut_af9035[] = {
diff --git a/drivers/media/usb/dvb-usb-v2/anysee.c b/drivers/media/usb/dvb-usb-v2/anysee.c
index 90cfa35ef6e..eeab79bdd2a 100644
--- a/drivers/media/usb/dvb-usb-v2/anysee.c
+++ b/drivers/media/usb/dvb-usb-v2/anysee.c
@@ -442,6 +442,7 @@ static struct cxd2820r_config anysee_cxd2820r_config = {
* IOD[0] ZL10353 1=enabled
* IOE[0] tuner 0=enabled
* tuner is behind ZL10353 I2C-gate
+ * tuner is behind TDA10023 I2C-gate
*
* E7 TC VID=1c73 PID=861f HW=18 FW=0.7 AMTCI=0.5 "anysee-E7TC(LP)"
* PCB: 508TC (rev0.6)
@@ -956,7 +957,7 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
if (fe && adap->fe[1]) {
/* attach tuner for 2nd FE */
- fe = dvb_attach(dvb_pll_attach, adap->fe[0],
+ fe = dvb_attach(dvb_pll_attach, adap->fe[1],
(0xc0 >> 1), &d->i2c_adap,
DVB_PLL_SAMSUNG_DTOS403IH102A);
}
diff --git a/drivers/media/usb/dvb-usb-v2/az6007.c b/drivers/media/usb/dvb-usb-v2/az6007.c
index 44c64ef361b..c3c4b98733b 100644
--- a/drivers/media/usb/dvb-usb-v2/az6007.c
+++ b/drivers/media/usb/dvb-usb-v2/az6007.c
@@ -7,7 +7,7 @@
* http://linux.terratec.de/files/TERRATEC_H7/20110323_TERRATEC_H7_Linux.tar.gz
* The original driver's license is GPL, as declared with MODULE_LICENSE()
*
- * Copyright (c) 2010-2012 Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010-2012 Mauro Carvalho Chehab
* Driver modified by in order to work with upstream drxk driver, and
* tons of bugs got fixed, and converted to use dvb-usb-v2.
*
@@ -68,6 +68,19 @@ static struct drxk_config terratec_h7_drxk = {
.microcode_name = "dvb-usb-terratec-h7-drxk.fw",
};
+static struct drxk_config cablestar_hdci_drxk = {
+ .adr = 0x29,
+ .parallel_ts = true,
+ .dynamic_clk = true,
+ .single_master = true,
+ .enable_merr_cfg = true,
+ .no_i2c_bridge = false,
+ .chunk_size = 64,
+ .mpeg_out_clk_strength = 0x02,
+ .qam_demod_parameter_count = 2,
+ .microcode_name = "dvb-usb-technisat-cablestar-hdci-drxk.fw",
+};
+
static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable)
{
struct az6007_device_state *st = fe_to_priv(fe);
@@ -630,6 +643,27 @@ static int az6007_frontend_attach(struct dvb_usb_adapter *adap)
return 0;
}
+static int az6007_cablestar_hdci_frontend_attach(struct dvb_usb_adapter *adap)
+{
+ struct az6007_device_state *st = adap_to_priv(adap);
+ struct dvb_usb_device *d = adap_to_d(adap);
+
+ pr_debug("attaching demod drxk\n");
+
+ adap->fe[0] = dvb_attach(drxk_attach, &cablestar_hdci_drxk,
+ &d->i2c_adap);
+ if (!adap->fe[0])
+ return -EINVAL;
+
+ adap->fe[0]->sec_priv = adap;
+ st->gate_ctrl = adap->fe[0]->ops.i2c_gate_ctrl;
+ adap->fe[0]->ops.i2c_gate_ctrl = drxk_gate_ctrl;
+
+ az6007_ci_init(adap);
+
+ return 0;
+}
+
static int az6007_tuner_attach(struct dvb_usb_adapter *adap)
{
struct dvb_usb_device *d = adap_to_d(adap);
@@ -868,6 +902,29 @@ static struct dvb_usb_device_properties az6007_props = {
}
};
+static struct dvb_usb_device_properties az6007_cablestar_hdci_props = {
+ .driver_name = KBUILD_MODNAME,
+ .owner = THIS_MODULE,
+ .firmware = AZ6007_FIRMWARE,
+
+ .adapter_nr = adapter_nr,
+ .size_of_priv = sizeof(struct az6007_device_state),
+ .i2c_algo = &az6007_i2c_algo,
+ .tuner_attach = az6007_tuner_attach,
+ .frontend_attach = az6007_cablestar_hdci_frontend_attach,
+ .streaming_ctrl = az6007_streaming_ctrl,
+/* ditch get_rc_config as it can't work (TS35 remote, I believe it's rc5) */
+ .get_rc_config = NULL,
+ .read_mac_address = az6007_read_mac_addr,
+ .download_firmware = az6007_download_firmware,
+ .identify_state = az6007_identify_state,
+ .power_ctrl = az6007_power_ctrl,
+ .num_adapters = 1,
+ .adapter = {
+ { .stream = DVB_USB_STREAM_BULK(0x02, 10, 4096), }
+ }
+};
+
static struct usb_device_id az6007_usb_table[] = {
{DVB_USB_DEVICE(USB_VID_AZUREWAVE, USB_PID_AZUREWAVE_6007,
&az6007_props, "Azurewave 6007", RC_MAP_EMPTY)},
@@ -875,6 +932,8 @@ static struct usb_device_id az6007_usb_table[] = {
&az6007_props, "Terratec H7", RC_MAP_NEC_TERRATEC_CINERGY_XS)},
{DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_H7_2,
&az6007_props, "Terratec H7", RC_MAP_NEC_TERRATEC_CINERGY_XS)},
+ {DVB_USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_USB2_CABLESTAR_HDCI,
+ &az6007_cablestar_hdci_props, "Technisat CableStar Combo HD CI", RC_MAP_EMPTY)},
{0},
};
@@ -916,7 +975,7 @@ static struct usb_driver az6007_usb_driver = {
module_usb_driver(az6007_usb_driver);
MODULE_AUTHOR("Henry Wang <Henry.wang@AzureWave.com>");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
MODULE_DESCRIPTION("Driver for AzureWave 6007 DVB-C/T USB2.0 and clones");
MODULE_VERSION("2.0");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
index 8a054d66e70..e3558061893 100644
--- a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
+++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
@@ -164,7 +164,7 @@ static int dvb_usbv2_remote_init(struct dvb_usb_device *d)
dev->driver_name = (char *) d->props->driver_name;
dev->map_name = d->rc.map_name;
dev->driver_type = d->rc.driver_type;
- dev->allowed_protos = d->rc.allowed_protos;
+ rc_set_allowed_protocols(dev, d->rc.allowed_protos);
dev->change_protocol = d->rc.change_protocol;
dev->priv = d;
@@ -399,7 +399,7 @@ static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
/* clear 'streaming' status bit */
clear_bit(ADAP_STREAMING, &adap->state_bits);
- smp_mb__after_clear_bit();
+ smp_mb__after_atomic();
wake_up_bit(&adap->state_bits, ADAP_STREAMING);
skip_feed_stop:
@@ -550,7 +550,7 @@ static int dvb_usb_fe_init(struct dvb_frontend *fe)
err:
if (!adap->suspend_resume_active) {
clear_bit(ADAP_INIT, &adap->state_bits);
- smp_mb__after_clear_bit();
+ smp_mb__after_atomic();
wake_up_bit(&adap->state_bits, ADAP_INIT);
}
@@ -591,7 +591,7 @@ err:
if (!adap->suspend_resume_active) {
adap->active_fe = -1;
clear_bit(ADAP_SLEEP, &adap->state_bits);
- smp_mb__after_clear_bit();
+ smp_mb__after_atomic();
wake_up_bit(&adap->state_bits, ADAP_SLEEP);
}
diff --git a/drivers/media/usb/dvb-usb-v2/ec168.c b/drivers/media/usb/dvb-usb-v2/ec168.c
index 5c68f3918bc..0c2b377704f 100644
--- a/drivers/media/usb/dvb-usb-v2/ec168.c
+++ b/drivers/media/usb/dvb-usb-v2/ec168.c
@@ -170,7 +170,7 @@ static int ec168_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
error:
mutex_unlock(&d->i2c_mutex);
- return i;
+ return ret;
}
static u32 ec168_i2c_func(struct i2c_adapter *adapter)
diff --git a/drivers/media/usb/dvb-usb-v2/it913x.c b/drivers/media/usb/dvb-usb-v2/it913x.c
deleted file mode 100644
index 1cb6899cf79..00000000000
--- a/drivers/media/usb/dvb-usb-v2/it913x.c
+++ /dev/null
@@ -1,825 +0,0 @@
-/*
- * DVB USB compliant linux driver for ITE IT9135 and IT9137
- *
- * Copyright (C) 2011 Malcolm Priestley (tvboxspy@gmail.com)
- * IT9135 (C) ITE Tech Inc.
- * IT9137 (C) ITE Tech Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License Version 2, as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *
- * see Documentation/dvb/README.dvb-usb for more information
- * see Documentation/dvb/it9137.txt for firmware information
- *
- */
-#define DVB_USB_LOG_PREFIX "it913x"
-
-#include <linux/usb.h>
-#include <linux/usb/input.h>
-#include <media/rc-core.h>
-
-#include "dvb_usb.h"
-#include "it913x-fe.h"
-
-/* debug */
-static int dvb_usb_it913x_debug;
-#define it_debug(var, level, args...) \
- do { if ((var & level)) pr_debug(DVB_USB_LOG_PREFIX": " args); \
-} while (0)
-#define deb_info(level, args...) it_debug(dvb_usb_it913x_debug, level, args)
-#define info(args...) pr_info(DVB_USB_LOG_PREFIX": " args)
-
-module_param_named(debug, dvb_usb_it913x_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able)).");
-
-static int dvb_usb_it913x_firmware;
-module_param_named(firmware, dvb_usb_it913x_firmware, int, 0644);
-MODULE_PARM_DESC(firmware, "set firmware 0=auto "\
- "1=IT9137 2=IT9135 V1 3=IT9135 V2");
-#define FW_IT9137 "dvb-usb-it9137-01.fw"
-#define FW_IT9135_V1 "dvb-usb-it9135-01.fw"
-#define FW_IT9135_V2 "dvb-usb-it9135-02.fw"
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-struct it913x_state {
- struct ite_config it913x_config;
- u8 pid_filter_onoff;
- bool proprietary_ir;
- int cmd_counter;
-};
-
-static u16 check_sum(u8 *p, u8 len)
-{
- u16 sum = 0;
- u8 i = 1;
- while (i < len)
- sum += (i++ & 1) ? (*p++) << 8 : *p++;
- return ~sum;
-}
-
-static int it913x_io(struct dvb_usb_device *d, u8 mode, u8 pro,
- u8 cmd, u32 reg, u8 addr, u8 *data, u8 len)
-{
- struct it913x_state *st = d->priv;
- int ret = 0, i, buf_size = 1;
- u8 *buff;
- u8 rlen;
- u16 chk_sum;
-
- buff = kzalloc(256, GFP_KERNEL);
- if (!buff) {
- info("USB Buffer Failed");
- return -ENOMEM;
- }
-
- buff[buf_size++] = pro;
- buff[buf_size++] = cmd;
- buff[buf_size++] = st->cmd_counter;
-
- switch (mode) {
- case READ_LONG:
- case WRITE_LONG:
- buff[buf_size++] = len;
- buff[buf_size++] = 2;
- buff[buf_size++] = (reg >> 24);
- buff[buf_size++] = (reg >> 16) & 0xff;
- buff[buf_size++] = (reg >> 8) & 0xff;
- buff[buf_size++] = reg & 0xff;
- break;
- case READ_SHORT:
- buff[buf_size++] = addr;
- break;
- case WRITE_SHORT:
- buff[buf_size++] = len;
- buff[buf_size++] = addr;
- buff[buf_size++] = (reg >> 8) & 0xff;
- buff[buf_size++] = reg & 0xff;
- break;
- case READ_DATA:
- case WRITE_DATA:
- break;
- case WRITE_CMD:
- mode = 7;
- break;
- default:
- kfree(buff);
- return -EINVAL;
- }
-
- if (mode & 1) {
- for (i = 0; i < len ; i++)
- buff[buf_size++] = data[i];
- }
- chk_sum = check_sum(&buff[1], buf_size);
-
- buff[buf_size++] = chk_sum >> 8;
- buff[0] = buf_size;
- buff[buf_size++] = (chk_sum & 0xff);
-
- ret = dvb_usbv2_generic_rw(d, buff, buf_size, buff, (mode & 1) ?
- 5 : len + 5);
- if (ret < 0)
- goto error;
-
- rlen = (mode & 0x1) ? 0x1 : len;
-
- if (mode & 1)
- ret = buff[2];
- else
- memcpy(data, &buff[3], rlen);
-
- st->cmd_counter++;
-
-error: kfree(buff);
-
- return ret;
-}
-
-static int it913x_wr_reg(struct dvb_usb_device *d, u8 pro, u32 reg , u8 data)
-{
- int ret;
- u8 b[1];
- b[0] = data;
- ret = it913x_io(d, WRITE_LONG, pro,
- CMD_DEMOD_WRITE, reg, 0, b, sizeof(b));
-
- return ret;
-}
-
-static int it913x_read_reg(struct dvb_usb_device *d, u32 reg)
-{
- int ret;
- u8 data[1];
-
- ret = it913x_io(d, READ_LONG, DEV_0,
- CMD_DEMOD_READ, reg, 0, &data[0], sizeof(data));
-
- return (ret < 0) ? ret : data[0];
-}
-
-static int it913x_query(struct dvb_usb_device *d, u8 pro)
-{
- struct it913x_state *st = d->priv;
- int ret, i;
- u8 data[4];
- u8 ver;
-
- for (i = 0; i < 5; i++) {
- ret = it913x_io(d, READ_LONG, pro, CMD_DEMOD_READ,
- 0x1222, 0, &data[0], 3);
- ver = data[0];
- if (ver > 0 && ver < 3)
- break;
- msleep(100);
- }
-
- if (ver < 1 || ver > 2) {
- info("Failed to identify chip version applying 1");
- st->it913x_config.chip_ver = 0x1;
- st->it913x_config.chip_type = 0x9135;
- return 0;
- }
-
- st->it913x_config.chip_ver = ver;
- st->it913x_config.chip_type = (u16)(data[2] << 8) + data[1];
-
- info("Chip Version=%02x Chip Type=%04x", st->it913x_config.chip_ver,
- st->it913x_config.chip_type);
-
- ret = it913x_io(d, READ_SHORT, pro,
- CMD_QUERYINFO, 0, 0x1, &data[0], 4);
-
- st->it913x_config.firmware = (data[0] << 24) | (data[1] << 16) |
- (data[2] << 8) | data[3];
-
- return ret;
-}
-
-static int it913x_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
-{
- struct dvb_usb_device *d = adap_to_d(adap);
- struct it913x_state *st = adap_to_priv(adap);
- int ret;
- u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD;
-
- mutex_lock(&d->i2c_mutex);
-
- deb_info(1, "PID_C (%02x)", onoff);
-
- st->pid_filter_onoff = adap->pid_filtering;
- ret = it913x_wr_reg(d, pro, PID_EN, st->pid_filter_onoff);
-
- mutex_unlock(&d->i2c_mutex);
- return ret;
-}
-
-static int it913x_pid_filter(struct dvb_usb_adapter *adap,
- int index, u16 pid, int onoff)
-{
- struct dvb_usb_device *d = adap_to_d(adap);
- struct it913x_state *st = adap_to_priv(adap);
- int ret;
- u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD;
-
- mutex_lock(&d->i2c_mutex);
-
- deb_info(1, "PID_F (%02x)", onoff);
-
- ret = it913x_wr_reg(d, pro, PID_LSB, (u8)(pid & 0xff));
-
- ret |= it913x_wr_reg(d, pro, PID_MSB, (u8)(pid >> 8));
-
- ret |= it913x_wr_reg(d, pro, PID_INX_EN, (u8)onoff);
-
- ret |= it913x_wr_reg(d, pro, PID_INX, (u8)(index & 0x1f));
-
- if (d->udev->speed == USB_SPEED_HIGH && pid == 0x2000) {
- ret |= it913x_wr_reg(d , pro, PID_EN, !onoff);
- st->pid_filter_onoff = !onoff;
- } else
- st->pid_filter_onoff =
- adap->pid_filtering;
-
- mutex_unlock(&d->i2c_mutex);
- return 0;
-}
-
-
-static int it913x_return_status(struct dvb_usb_device *d)
-{
- struct it913x_state *st = d->priv;
- int ret = it913x_query(d, DEV_0);
- if (st->it913x_config.firmware > 0)
- info("Firmware Version %d", st->it913x_config.firmware);
-
- return ret;
-}
-
-static int it913x_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
- int num)
-{
- struct dvb_usb_device *d = i2c_get_adapdata(adap);
- static u8 data[256];
- int ret;
- u32 reg;
- u8 pro;
-
- mutex_lock(&d->i2c_mutex);
-
- deb_info(2, "num of messages %d address %02x", num, msg[0].addr);
-
- pro = (msg[0].addr & 0x2) ? DEV_0_DMOD : 0x0;
- pro |= (msg[0].addr & 0x20) ? DEV_1 : DEV_0;
- memcpy(data, msg[0].buf, msg[0].len);
- reg = (data[0] << 24) + (data[1] << 16) +
- (data[2] << 8) + data[3];
- if (num == 2) {
- ret = it913x_io(d, READ_LONG, pro,
- CMD_DEMOD_READ, reg, 0, data, msg[1].len);
- memcpy(msg[1].buf, data, msg[1].len);
- } else
- ret = it913x_io(d, WRITE_LONG, pro, CMD_DEMOD_WRITE,
- reg, 0, &data[4], msg[0].len - 4);
-
- mutex_unlock(&d->i2c_mutex);
-
- return ret;
-}
-
-static u32 it913x_i2c_func(struct i2c_adapter *adapter)
-{
- return I2C_FUNC_I2C;
-}
-
-static struct i2c_algorithm it913x_i2c_algo = {
- .master_xfer = it913x_i2c_xfer,
- .functionality = it913x_i2c_func,
-};
-
-/* Callbacks for DVB USB */
-#if IS_ENABLED(CONFIG_RC_CORE)
-static int it913x_rc_query(struct dvb_usb_device *d)
-{
- u8 ibuf[4];
- int ret;
- u32 key;
- /* Avoid conflict with frontends*/
- mutex_lock(&d->i2c_mutex);
-
- ret = it913x_io(d, READ_LONG, PRO_LINK, CMD_IR_GET,
- 0, 0, &ibuf[0], sizeof(ibuf));
-
- if ((ibuf[2] + ibuf[3]) == 0xff) {
- key = ibuf[2];
- key += ibuf[0] << 16;
- key += ibuf[1] << 8;
- deb_info(1, "NEC Extended Key =%08x", key);
- if (d->rc_dev != NULL)
- rc_keydown(d->rc_dev, key, 0);
- }
-
- mutex_unlock(&d->i2c_mutex);
-
- return ret;
-}
-
-static int it913x_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc)
-{
- struct it913x_state *st = d->priv;
-
- if (st->proprietary_ir == false) {
- rc->map_name = NULL;
- return 0;
- }
-
- rc->allowed_protos = RC_BIT_NEC;
- rc->query = it913x_rc_query;
- rc->interval = 250;
-
- return 0;
-}
-#else
- #define it913x_get_rc_config NULL
-#endif
-
-/* Firmware sets raw */
-static const char fw_it9135_v1[] = FW_IT9135_V1;
-static const char fw_it9135_v2[] = FW_IT9135_V2;
-static const char fw_it9137[] = FW_IT9137;
-
-static void ite_get_firmware_name(struct dvb_usb_device *d,
- const char **name)
-{
- struct it913x_state *st = d->priv;
- int sw;
- /* auto switch */
- if (le16_to_cpu(d->udev->descriptor.idVendor) == USB_VID_KWORLD_2)
- sw = IT9137_FW;
- else if (st->it913x_config.chip_ver == 1)
- sw = IT9135_V1_FW;
- else
- sw = IT9135_V2_FW;
-
- /* force switch */
- if (dvb_usb_it913x_firmware != IT9135_AUTO)
- sw = dvb_usb_it913x_firmware;
-
- switch (sw) {
- case IT9135_V1_FW:
- st->it913x_config.firmware_ver = 1;
- st->it913x_config.adc_x2 = 1;
- st->it913x_config.read_slevel = false;
- *name = fw_it9135_v1;
- break;
- case IT9135_V2_FW:
- st->it913x_config.firmware_ver = 1;
- st->it913x_config.adc_x2 = 1;
- st->it913x_config.read_slevel = false;
- *name = fw_it9135_v2;
- switch (st->it913x_config.tuner_id_0) {
- case IT9135_61:
- case IT9135_62:
- break;
- default:
- info("Unknown tuner ID applying default 0x60");
- case IT9135_60:
- st->it913x_config.tuner_id_0 = IT9135_60;
- }
- break;
- case IT9137_FW:
- default:
- st->it913x_config.firmware_ver = 0;
- st->it913x_config.adc_x2 = 0;
- st->it913x_config.read_slevel = true;
- *name = fw_it9137;
- }
-
- return;
-}
-
-#define TS_MPEG_PKT_SIZE 188
-#define EP_LOW 21
-#define TS_BUFFER_SIZE_PID (EP_LOW*TS_MPEG_PKT_SIZE)
-#define EP_HIGH 348
-#define TS_BUFFER_SIZE_MAX (EP_HIGH*TS_MPEG_PKT_SIZE)
-
-static int it913x_get_stream_config(struct dvb_frontend *fe, u8 *ts_type,
- struct usb_data_stream_properties *stream)
-{
- struct dvb_usb_adapter *adap = fe_to_adap(fe);
- if (adap->pid_filtering)
- stream->u.bulk.buffersize = TS_BUFFER_SIZE_PID;
- else
- stream->u.bulk.buffersize = TS_BUFFER_SIZE_MAX;
-
- return 0;
-}
-
-static int it913x_select_config(struct dvb_usb_device *d)
-{
- struct it913x_state *st = d->priv;
- int ret, reg;
-
- ret = it913x_return_status(d);
- if (ret < 0)
- return ret;
-
- if (st->it913x_config.chip_ver == 0x02
- && st->it913x_config.chip_type == 0x9135)
- reg = it913x_read_reg(d, 0x461d);
- else
- reg = it913x_read_reg(d, 0x461b);
-
- if (reg < 0)
- return reg;
-
- if (reg == 0) {
- st->it913x_config.dual_mode = 0;
- st->it913x_config.tuner_id_0 = IT9135_38;
- st->proprietary_ir = true;
- } else {
- /* TS mode */
- reg = it913x_read_reg(d, 0x49c5);
- if (reg < 0)
- return reg;
- st->it913x_config.dual_mode = reg;
-
- /* IR mode type */
- reg = it913x_read_reg(d, 0x49ac);
- if (reg < 0)
- return reg;
- if (reg == 5) {
- info("Remote propriety (raw) mode");
- st->proprietary_ir = true;
- } else if (reg == 1) {
- info("Remote HID mode NOT SUPPORTED");
- st->proprietary_ir = false;
- }
-
- /* Tuner_id */
- reg = it913x_read_reg(d, 0x49d0);
- if (reg < 0)
- return reg;
- st->it913x_config.tuner_id_0 = reg;
- }
-
- info("Dual mode=%x Tuner Type=%x", st->it913x_config.dual_mode,
- st->it913x_config.tuner_id_0);
-
- return ret;
-}
-
-static int it913x_streaming_ctrl(struct dvb_frontend *fe, int onoff)
-{
- struct dvb_usb_adapter *adap = fe_to_adap(fe);
- struct dvb_usb_device *d = adap_to_d(adap);
- struct it913x_state *st = fe_to_priv(fe);
- int ret = 0;
- u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD;
-
- deb_info(1, "STM (%02x)", onoff);
-
- if (!onoff) {
- mutex_lock(&d->i2c_mutex);
-
- ret = it913x_wr_reg(d, pro, PID_RST, 0x1);
-
- mutex_unlock(&d->i2c_mutex);
- st->pid_filter_onoff =
- adap->pid_filtering;
-
- }
-
- return ret;
-}
-
-static int it913x_identify_state(struct dvb_usb_device *d, const char **name)
-{
- struct it913x_state *st = d->priv;
- int ret;
- u8 reg;
-
- /* Read and select config */
- ret = it913x_select_config(d);
- if (ret < 0)
- return ret;
-
- ite_get_firmware_name(d, name);
-
- if (st->it913x_config.firmware > 0)
- return WARM;
-
- if (st->it913x_config.dual_mode) {
- st->it913x_config.tuner_id_1 = it913x_read_reg(d, 0x49e0);
- ret = it913x_wr_reg(d, DEV_0, GPIOH1_EN, 0x1);
- ret |= it913x_wr_reg(d, DEV_0, GPIOH1_ON, 0x1);
- ret |= it913x_wr_reg(d, DEV_0, GPIOH1_O, 0x1);
- msleep(50);
- ret |= it913x_wr_reg(d, DEV_0, GPIOH1_O, 0x0);
- msleep(50);
- reg = it913x_read_reg(d, GPIOH1_O);
- if (reg == 0) {
- ret |= it913x_wr_reg(d, DEV_0, GPIOH1_O, 0x1);
- ret |= it913x_return_status(d);
- if (ret != 0)
- ret = it913x_wr_reg(d, DEV_0,
- GPIOH1_O, 0x0);
- }
- }
-
- reg = it913x_read_reg(d, IO_MUX_POWER_CLK);
-
- if (st->it913x_config.dual_mode) {
- ret |= it913x_wr_reg(d, DEV_0, 0x4bfb, CHIP2_I2C_ADDR);
- if (st->it913x_config.firmware_ver == 1)
- ret |= it913x_wr_reg(d, DEV_0, 0xcfff, 0x1);
- else
- ret |= it913x_wr_reg(d, DEV_0, CLK_O_EN, 0x1);
- } else {
- ret |= it913x_wr_reg(d, DEV_0, 0x4bfb, 0x0);
- if (st->it913x_config.firmware_ver == 1)
- ret |= it913x_wr_reg(d, DEV_0, 0xcfff, 0x0);
- else
- ret |= it913x_wr_reg(d, DEV_0, CLK_O_EN, 0x0);
- }
-
- ret |= it913x_wr_reg(d, DEV_0, I2C_CLK, I2C_CLK_100);
-
- return (ret < 0) ? ret : COLD;
-}
-
-static int it913x_download_firmware(struct dvb_usb_device *d,
- const struct firmware *fw)
-{
- struct it913x_state *st = d->priv;
- int ret = 0, i = 0, pos = 0;
- u8 packet_size, min_pkt;
- u8 *fw_data;
-
- ret = it913x_wr_reg(d, DEV_0, I2C_CLK, I2C_CLK_100);
-
- info("FRM Starting Firmware Download");
-
- /* Multi firmware loader */
- /* This uses scatter write firmware headers */
- /* The firmware must start with 03 XX 00 */
- /* and be the extact firmware length */
-
- if (st->it913x_config.chip_ver == 2)
- min_pkt = 0x11;
- else
- min_pkt = 0x19;
-
- while (i <= fw->size) {
- if (((fw->data[i] == 0x3) && (fw->data[i + 2] == 0x0))
- || (i == fw->size)) {
- packet_size = i - pos;
- if ((packet_size > min_pkt) || (i == fw->size)) {
- fw_data = (u8 *)(fw->data + pos);
- pos += packet_size;
- if (packet_size > 0) {
- ret = it913x_io(d, WRITE_DATA,
- DEV_0, CMD_SCATTER_WRITE, 0,
- 0, fw_data, packet_size);
- if (ret < 0)
- break;
- }
- udelay(1000);
- }
- }
- i++;
- }
-
- if (ret < 0)
- info("FRM Firmware Download Failed (%d)" , ret);
- else
- info("FRM Firmware Download Completed - Resetting Device");
-
- msleep(30);
-
- ret = it913x_io(d, WRITE_CMD, DEV_0, CMD_BOOT, 0, 0, NULL, 0);
- if (ret < 0)
- info("FRM Device not responding to reboot");
-
- ret = it913x_return_status(d);
- if (st->it913x_config.firmware == 0) {
- info("FRM Failed to reboot device");
- return -ENODEV;
- }
-
- msleep(30);
-
- ret = it913x_wr_reg(d, DEV_0, I2C_CLK, I2C_CLK_400);
-
- msleep(30);
-
- /* Tuner function */
- if (st->it913x_config.dual_mode)
- ret |= it913x_wr_reg(d, DEV_0_DMOD , 0xec4c, 0xa0);
- else
- ret |= it913x_wr_reg(d, DEV_0_DMOD , 0xec4c, 0x68);
-
- if ((st->it913x_config.chip_ver == 1) &&
- (st->it913x_config.chip_type == 0x9135)) {
- ret |= it913x_wr_reg(d, DEV_0, PADODPU, 0x0);
- ret |= it913x_wr_reg(d, DEV_0, AGC_O_D, 0x0);
- if (st->it913x_config.dual_mode) {
- ret |= it913x_wr_reg(d, DEV_1, PADODPU, 0x0);
- ret |= it913x_wr_reg(d, DEV_1, AGC_O_D, 0x0);
- }
- }
-
- return (ret < 0) ? -ENODEV : 0;
-}
-
-static int it913x_name(struct dvb_usb_adapter *adap)
-{
- struct dvb_usb_device *d = adap_to_d(adap);
- const char *desc = d->name;
- char *fe_name[] = {"_1", "_2", "_3", "_4"};
- char *name = adap->fe[0]->ops.info.name;
-
- strlcpy(name, desc, 128);
- strlcat(name, fe_name[adap->id], 128);
-
- return 0;
-}
-
-static int it913x_frontend_attach(struct dvb_usb_adapter *adap)
-{
- struct dvb_usb_device *d = adap_to_d(adap);
- struct it913x_state *st = d->priv;
- int ret = 0;
- u8 adap_addr = I2C_BASE_ADDR + (adap->id << 5);
- u16 ep_size = (adap->pid_filtering) ? TS_BUFFER_SIZE_PID / 4 :
- TS_BUFFER_SIZE_MAX / 4;
- u8 pkt_size = 0x80;
-
- if (d->udev->speed != USB_SPEED_HIGH)
- pkt_size = 0x10;
-
- st->it913x_config.adf = it913x_read_reg(d, IO_MUX_POWER_CLK);
-
- adap->fe[0] = dvb_attach(it913x_fe_attach,
- &d->i2c_adap, adap_addr, &st->it913x_config);
-
- if (adap->id == 0 && adap->fe[0]) {
- it913x_wr_reg(d, DEV_0_DMOD, MP2_SW_RST, 0x1);
- it913x_wr_reg(d, DEV_0_DMOD, MP2IF2_SW_RST, 0x1);
- it913x_wr_reg(d, DEV_0, EP0_TX_EN, 0x0f);
- it913x_wr_reg(d, DEV_0, EP0_TX_NAK, 0x1b);
- if (st->proprietary_ir == false) /* Enable endpoint 3 */
- it913x_wr_reg(d, DEV_0, EP0_TX_EN, 0x3f);
- else
- it913x_wr_reg(d, DEV_0, EP0_TX_EN, 0x2f);
- it913x_wr_reg(d, DEV_0, EP4_TX_LEN_LSB,
- ep_size & 0xff);
- it913x_wr_reg(d, DEV_0, EP4_TX_LEN_MSB, ep_size >> 8);
- ret = it913x_wr_reg(d, DEV_0, EP4_MAX_PKT, pkt_size);
- } else if (adap->id == 1 && adap->fe[0]) {
- if (st->proprietary_ir == false)
- it913x_wr_reg(d, DEV_0, EP0_TX_EN, 0x7f);
- else
- it913x_wr_reg(d, DEV_0, EP0_TX_EN, 0x6f);
- it913x_wr_reg(d, DEV_0, EP5_TX_LEN_LSB,
- ep_size & 0xff);
- it913x_wr_reg(d, DEV_0, EP5_TX_LEN_MSB, ep_size >> 8);
- it913x_wr_reg(d, DEV_0, EP5_MAX_PKT, pkt_size);
- it913x_wr_reg(d, DEV_0_DMOD, MP2IF2_EN, 0x1);
- it913x_wr_reg(d, DEV_1_DMOD, MP2IF_SERIAL, 0x1);
- it913x_wr_reg(d, DEV_1, TOP_HOSTB_SER_MODE, 0x1);
- it913x_wr_reg(d, DEV_0_DMOD, TSIS_ENABLE, 0x1);
- it913x_wr_reg(d, DEV_0_DMOD, MP2_SW_RST, 0x0);
- it913x_wr_reg(d, DEV_0_DMOD, MP2IF2_SW_RST, 0x0);
- it913x_wr_reg(d, DEV_0_DMOD, MP2IF2_HALF_PSB, 0x0);
- it913x_wr_reg(d, DEV_0_DMOD, MP2IF_STOP_EN, 0x1);
- it913x_wr_reg(d, DEV_1_DMOD, MPEG_FULL_SPEED, 0x0);
- ret = it913x_wr_reg(d, DEV_1_DMOD, MP2IF_STOP_EN, 0x0);
- } else
- return -ENODEV;
-
- ret |= it913x_name(adap);
-
- return ret;
-}
-
-/* DVB USB Driver */
-static int it913x_get_adapter_count(struct dvb_usb_device *d)
-{
- struct it913x_state *st = d->priv;
- if (st->it913x_config.dual_mode)
- return 2;
- return 1;
-}
-
-static struct dvb_usb_device_properties it913x_properties = {
- .driver_name = KBUILD_MODNAME,
- .owner = THIS_MODULE,
- .bInterfaceNumber = 0,
- .generic_bulk_ctrl_endpoint = 0x02,
- .generic_bulk_ctrl_endpoint_response = 0x81,
-
- .adapter_nr = adapter_nr,
- .size_of_priv = sizeof(struct it913x_state),
-
- .identify_state = it913x_identify_state,
- .i2c_algo = &it913x_i2c_algo,
-
- .download_firmware = it913x_download_firmware,
-
- .frontend_attach = it913x_frontend_attach,
- .get_rc_config = it913x_get_rc_config,
- .get_stream_config = it913x_get_stream_config,
- .get_adapter_count = it913x_get_adapter_count,
- .streaming_ctrl = it913x_streaming_ctrl,
-
-
- .adapter = {
- {
- .caps = DVB_USB_ADAP_HAS_PID_FILTER|
- DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
- .pid_filter_count = 32,
- .pid_filter = it913x_pid_filter,
- .pid_filter_ctrl = it913x_pid_filter_ctrl,
- .stream =
- DVB_USB_STREAM_BULK(0x84, 10, TS_BUFFER_SIZE_MAX),
- },
- {
- .caps = DVB_USB_ADAP_HAS_PID_FILTER|
- DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
- .pid_filter_count = 32,
- .pid_filter = it913x_pid_filter,
- .pid_filter_ctrl = it913x_pid_filter_ctrl,
- .stream =
- DVB_USB_STREAM_BULK(0x85, 10, TS_BUFFER_SIZE_MAX),
- }
- }
-};
-
-static const struct usb_device_id it913x_id_table[] = {
- { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB499_2T_T09,
- &it913x_properties, "Kworld UB499-2T T09(IT9137)",
- RC_MAP_IT913X_V1) },
- { DVB_USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9135,
- &it913x_properties, "ITE 9135 Generic",
- RC_MAP_IT913X_V1) },
- { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV22_IT9137,
- &it913x_properties, "Sveon STV22 Dual DVB-T HDTV(IT9137)",
- RC_MAP_IT913X_V1) },
- { DVB_USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9135_9005,
- &it913x_properties, "ITE 9135(9005) Generic",
- RC_MAP_IT913X_V2) },
- { DVB_USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9135_9006,
- &it913x_properties, "ITE 9135(9006) Generic",
- RC_MAP_IT913X_V1) },
- { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A835B_1835,
- &it913x_properties, "Avermedia A835B(1835)",
- RC_MAP_IT913X_V2) },
- { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A835B_2835,
- &it913x_properties, "Avermedia A835B(2835)",
- RC_MAP_IT913X_V2) },
- { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A835B_3835,
- &it913x_properties, "Avermedia A835B(3835)",
- RC_MAP_IT913X_V2) },
- { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A835B_4835,
- &it913x_properties, "Avermedia A835B(4835)",
- RC_MAP_IT913X_V2) },
- { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_CTVDIGDUAL_V2,
- &it913x_properties, "Digital Dual TV Receiver CTVDIGDUAL_V2",
- RC_MAP_IT913X_V1) },
- {} /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE(usb, it913x_id_table);
-
-static struct usb_driver it913x_driver = {
- .name = KBUILD_MODNAME,
- .probe = dvb_usbv2_probe,
- .disconnect = dvb_usbv2_disconnect,
- .suspend = dvb_usbv2_suspend,
- .resume = dvb_usbv2_resume,
- .id_table = it913x_id_table,
-};
-
-module_usb_driver(it913x_driver);
-
-MODULE_AUTHOR("Malcolm Priestley <tvboxspy@gmail.com>");
-MODULE_DESCRIPTION("it913x USB 2 Driver");
-MODULE_VERSION("1.33");
-MODULE_LICENSE("GPL");
-MODULE_FIRMWARE(FW_IT9135_V1);
-MODULE_FIRMWARE(FW_IT9135_V2);
-MODULE_FIRMWARE(FW_IT9137);
-
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c b/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c
index d83df4bb72d..0a98d04c53e 100644
--- a/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c
@@ -1,7 +1,7 @@
/*
* mxl111sf-demod.c - driver for the MaxLinear MXL111SF DVB-T demodulator
*
- * Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com>
+ * Copyright (C) 2010-2014 Michael Krufky <mkrufky@linuxtv.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -601,7 +601,7 @@ struct dvb_frontend *mxl111sf_demod_attach(struct mxl111sf_state *mxl_state,
EXPORT_SYMBOL_GPL(mxl111sf_demod_attach);
MODULE_DESCRIPTION("MaxLinear MxL111SF DVB-T demodulator driver");
-MODULE_AUTHOR("Michael Krufky <mkrufky@kernellabs.com>");
+MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
MODULE_LICENSE("GPL");
MODULE_VERSION("0.1");
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h b/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h
index 3f3f8bfd190..2d4530f5be5 100644
--- a/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h
@@ -1,7 +1,7 @@
/*
* mxl111sf-demod.h - driver for the MaxLinear MXL111SF DVB-T demodulator
*
- * Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com>
+ * Copyright (C) 2010-2014 Michael Krufky <mkrufky@linuxtv.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.c b/drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.c
index e4121cb8f5e..a619410adde 100644
--- a/drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.c
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.c
@@ -1,7 +1,7 @@
/*
* mxl111sf-gpio.c - driver for the MaxLinear MXL111SF
*
- * Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com>
+ * Copyright (C) 2010-2014 Michael Krufky <mkrufky@linuxtv.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.h b/drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.h
index 0220f54299a..b85a5772d77 100644
--- a/drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.h
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.h
@@ -1,7 +1,7 @@
/*
* mxl111sf-gpio.h - driver for the MaxLinear MXL111SF
*
- * Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com>
+ * Copyright (C) 2010-2014 Michael Krufky <mkrufky@linuxtv.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.c b/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.c
index 34434557ef6..a101d06eb14 100644
--- a/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.c
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.c
@@ -1,7 +1,7 @@
/*
* mxl111sf-i2c.c - driver for the MaxLinear MXL111SF
*
- * Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com>
+ * Copyright (C) 2010-2014 Michael Krufky <mkrufky@linuxtv.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.h b/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.h
index a57a45ffb9e..465762145ad 100644
--- a/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.h
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.h
@@ -1,7 +1,7 @@
/*
* mxl111sf-i2c.h - driver for the MaxLinear MXL111SF
*
- * Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com>
+ * Copyright (C) 2010-2014 Michael Krufky <mkrufky@linuxtv.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-phy.c b/drivers/media/usb/dvb-usb-v2/mxl111sf-phy.c
index b741b3a7a32..f6b348024be 100644
--- a/drivers/media/usb/dvb-usb-v2/mxl111sf-phy.c
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-phy.c
@@ -1,7 +1,7 @@
/*
* mxl111sf-phy.c - driver for the MaxLinear MXL111SF
*
- * Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com>
+ * Copyright (C) 2010-2014 Michael Krufky <mkrufky@linuxtv.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-phy.h b/drivers/media/usb/dvb-usb-v2/mxl111sf-phy.h
index f0756071d34..0643738de7d 100644
--- a/drivers/media/usb/dvb-usb-v2/mxl111sf-phy.h
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-phy.h
@@ -1,7 +1,7 @@
/*
* mxl111sf-phy.h - driver for the MaxLinear MXL111SF
*
- * Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com>
+ * Copyright (C) 2010-2014 Michael Krufky <mkrufky@linuxtv.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-reg.h b/drivers/media/usb/dvb-usb-v2/mxl111sf-reg.h
index 17831b0fb9d..89bf115e927 100644
--- a/drivers/media/usb/dvb-usb-v2/mxl111sf-reg.h
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-reg.h
@@ -1,7 +1,7 @@
/*
* mxl111sf-reg.h - driver for the MaxLinear MXL111SF
*
- * Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com>
+ * Copyright (C) 2010-2014 Michael Krufky <mkrufky@linuxtv.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c b/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c
index 879c529640f..a8d2c705367 100644
--- a/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c
@@ -1,7 +1,7 @@
/*
* mxl111sf-tuner.c - driver for the MaxLinear MXL111SF CMOS tuner
*
- * Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com>
+ * Copyright (C) 2010-2014 Michael Krufky <mkrufky@linuxtv.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -512,7 +512,7 @@ struct dvb_frontend *mxl111sf_tuner_attach(struct dvb_frontend *fe,
EXPORT_SYMBOL_GPL(mxl111sf_tuner_attach);
MODULE_DESCRIPTION("MaxLinear MxL111SF CMOS tuner driver");
-MODULE_AUTHOR("Michael Krufky <mkrufky@kernellabs.com>");
+MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
MODULE_LICENSE("GPL");
MODULE_VERSION("0.1");
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.h b/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.h
index 90f583e5d6a..2046db22519 100644
--- a/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.h
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.h
@@ -1,7 +1,7 @@
/*
* mxl111sf-tuner.h - driver for the MaxLinear MXL111SF CMOS tuner
*
- * Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com>
+ * Copyright (C) 2010-2014 Michael Krufky <mkrufky@linuxtv.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -68,7 +68,7 @@ struct dvb_frontend *mxl111sf_tuner_attach(struct dvb_frontend *fe,
#else
static inline
struct dvb_frontend *mxl111sf_tuner_attach(struct dvb_frontend *fe,
- struct mxl111sf_state *mxl_state
+ struct mxl111sf_state *mxl_state,
struct mxl111sf_tuner_config *cfg)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf.c b/drivers/media/usb/dvb-usb-v2/mxl111sf.c
index e97964ef7f5..c7304fa8ab7 100644
--- a/drivers/media/usb/dvb-usb-v2/mxl111sf.c
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 Michael Krufky (mkrufky@kernellabs.com)
+ * Copyright (C) 2010-2014 Michael Krufky (mkrufky@linuxtv.org)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -23,6 +23,9 @@
#include "lgdt3305.h"
#include "lg2160.h"
+/* Max transfer size done by I2C transfer functions */
+#define MAX_XFER_SIZE 64
+
int dvb_usb_mxl111sf_debug;
module_param_named(debug, dvb_usb_mxl111sf_debug, int, 0644);
MODULE_PARM_DESC(debug, "set debugging level "
@@ -57,7 +60,12 @@ int mxl111sf_ctrl_msg(struct dvb_usb_device *d,
{
int wo = (rbuf == NULL || rlen == 0); /* write-only */
int ret;
- u8 sndbuf[1+wlen];
+ u8 sndbuf[MAX_XFER_SIZE];
+
+ if (1 + wlen > sizeof(sndbuf)) {
+ pr_warn("%s: len=%d is too big!\n", __func__, wlen);
+ return -EOPNOTSUPP;
+ }
pr_debug("%s(wlen = %d, rlen = %d)\n", __func__, wlen, rlen);
@@ -97,7 +105,7 @@ int mxl111sf_read_reg(struct mxl111sf_state *state, u8 addr, u8 *data)
ret = -EINVAL;
}
- pr_debug("R: (0x%02x, 0x%02x)\n", addr, *data);
+ pr_debug("R: (0x%02x, 0x%02x)\n", addr, buf[1]);
fail:
return ret;
}
@@ -258,7 +266,7 @@ static int mxl111sf_adap_fe_init(struct dvb_frontend *fe)
struct mxl111sf_adap_state *adap_state = &state->adap_state[fe->id];
int err;
- /* exit if we didnt initialize the driver yet */
+ /* exit if we didn't initialize the driver yet */
if (!state->chip_id) {
mxl_debug("driver not yet initialized, exit.");
goto fail;
@@ -314,7 +322,7 @@ static int mxl111sf_adap_fe_sleep(struct dvb_frontend *fe)
struct mxl111sf_adap_state *adap_state = &state->adap_state[fe->id];
int err;
- /* exit if we didnt initialize the driver yet */
+ /* exit if we didn't initialize the driver yet */
if (!state->chip_id) {
mxl_debug("driver not yet initialized, exit.");
goto fail;
@@ -1413,7 +1421,7 @@ static struct usb_driver mxl111sf_usb_driver = {
module_usb_driver(mxl111sf_usb_driver);
-MODULE_AUTHOR("Michael Krufky <mkrufky@kernellabs.com>");
+MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
MODULE_DESCRIPTION("Driver for MaxLinear MxL111SF");
MODULE_VERSION("1.0");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf.h b/drivers/media/usb/dvb-usb-v2/mxl111sf.h
index 9816de86e48..8516c011b7c 100644
--- a/drivers/media/usb/dvb-usb-v2/mxl111sf.h
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 Michael Krufky (mkrufky@kernellabs.com)
+ * Copyright (C) 2010-2014 Michael Krufky (mkrufky@linuxtv.org)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
index c0cd0848631..a676e445284 100644
--- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
+++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
@@ -35,6 +35,48 @@
#include "tua9001.h"
#include "r820t.h"
+/*
+ * RTL2832_SDR module is in staging. That logic is added in order to avoid any
+ * hard dependency to drivers/staging/ directory as we want compile mainline
+ * driver even whole staging directory is missing.
+ */
+#include <media/v4l2-subdev.h>
+
+#if IS_ENABLED(CONFIG_DVB_RTL2832_SDR)
+struct dvb_frontend *rtl2832_sdr_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c, const struct rtl2832_config *cfg,
+ struct v4l2_subdev *sd);
+#else
+static inline struct dvb_frontend *rtl2832_sdr_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c, const struct rtl2832_config *cfg,
+ struct v4l2_subdev *sd)
+{
+ return NULL;
+}
+#endif
+
+#ifdef CONFIG_MEDIA_ATTACH
+#define dvb_attach_sdr(FUNCTION, ARGS...) ({ \
+ void *__r = NULL; \
+ typeof(&FUNCTION) __a = symbol_request(FUNCTION); \
+ if (__a) { \
+ __r = (void *) __a(ARGS); \
+ if (__r == NULL) \
+ symbol_put(FUNCTION); \
+ } \
+ __r; \
+})
+
+#else
+#define dvb_attach_sdr(FUNCTION, ARGS...) ({ \
+ FUNCTION(ARGS); \
+})
+
+#endif
+
+static int rtl28xxu_disable_rc;
+module_param_named(disable_rc, rtl28xxu_disable_rc, int, 0644);
+MODULE_PARM_DESC(disable_rc, "disable RTL2832U remote controller");
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
static int rtl28xxu_ctrl_msg(struct dvb_usb_device *d, struct rtl28xxu_req *req)
@@ -377,6 +419,7 @@ static int rtl2832u_read_config(struct dvb_usb_device *d)
struct rtl28xxu_req req_e4000 = {0x02c8, CMD_I2C_RD, 1, buf};
struct rtl28xxu_req req_tda18272 = {0x00c0, CMD_I2C_RD, 2, buf};
struct rtl28xxu_req req_r820t = {0x0034, CMD_I2C_RD, 1, buf};
+ struct rtl28xxu_req req_r828d = {0x0074, CMD_I2C_RD, 1, buf};
dev_dbg(&d->udev->dev, "%s:\n", __func__);
@@ -489,6 +532,15 @@ static int rtl2832u_read_config(struct dvb_usb_device *d)
goto found;
}
+ /* check R828D ID register; reg=00 val=69 */
+ ret = rtl28xxu_ctrl_msg(d, &req_r828d);
+ if (ret == 0 && buf[0] == 0x69) {
+ priv->tuner = TUNER_RTL2832_R828D;
+ priv->tuner_name = "R828D";
+ goto found;
+ }
+
+
found:
dev_dbg(&d->udev->dev, "%s: tuner=%s\n", __func__, priv->tuner_name);
@@ -503,7 +555,7 @@ err:
return ret;
}
-static struct rtl2830_config rtl28xxu_rtl2830_mt2060_config = {
+static const struct rtl2830_config rtl28xxu_rtl2830_mt2060_config = {
.i2c_addr = 0x10, /* 0x20 */
.xtal = 28800000,
.ts_mode = 0,
@@ -514,7 +566,7 @@ static struct rtl2830_config rtl28xxu_rtl2830_mt2060_config = {
};
-static struct rtl2830_config rtl28xxu_rtl2830_qt1010_config = {
+static const struct rtl2830_config rtl28xxu_rtl2830_qt1010_config = {
.i2c_addr = 0x10, /* 0x20 */
.xtal = 28800000,
.ts_mode = 0,
@@ -524,7 +576,7 @@ static struct rtl2830_config rtl28xxu_rtl2830_qt1010_config = {
.agc_targ_val = 0x2d,
};
-static struct rtl2830_config rtl28xxu_rtl2830_mxl5005s_config = {
+static const struct rtl2830_config rtl28xxu_rtl2830_mxl5005s_config = {
.i2c_addr = 0x10, /* 0x20 */
.xtal = 28800000,
.ts_mode = 0,
@@ -538,7 +590,7 @@ static int rtl2831u_frontend_attach(struct dvb_usb_adapter *adap)
{
struct dvb_usb_device *d = adap_to_d(adap);
struct rtl28xxu_priv *priv = d_to_priv(d);
- struct rtl2830_config *rtl2830_config;
+ const struct rtl2830_config *rtl2830_config;
int ret;
dev_dbg(&d->udev->dev, "%s:\n", __func__);
@@ -573,33 +625,31 @@ err:
return ret;
}
-static struct rtl2832_config rtl28xxu_rtl2832_fc0012_config = {
+static const struct rtl2832_config rtl28xxu_rtl2832_fc0012_config = {
.i2c_addr = 0x10, /* 0x20 */
.xtal = 28800000,
- .if_dvbt = 0,
.tuner = TUNER_RTL2832_FC0012
};
-static struct rtl2832_config rtl28xxu_rtl2832_fc0013_config = {
+static const struct rtl2832_config rtl28xxu_rtl2832_fc0013_config = {
.i2c_addr = 0x10, /* 0x20 */
.xtal = 28800000,
- .if_dvbt = 0,
.tuner = TUNER_RTL2832_FC0013
};
-static struct rtl2832_config rtl28xxu_rtl2832_tua9001_config = {
+static const struct rtl2832_config rtl28xxu_rtl2832_tua9001_config = {
.i2c_addr = 0x10, /* 0x20 */
.xtal = 28800000,
.tuner = TUNER_RTL2832_TUA9001,
};
-static struct rtl2832_config rtl28xxu_rtl2832_e4000_config = {
+static const struct rtl2832_config rtl28xxu_rtl2832_e4000_config = {
.i2c_addr = 0x10, /* 0x20 */
.xtal = 28800000,
.tuner = TUNER_RTL2832_E4000,
};
-static struct rtl2832_config rtl28xxu_rtl2832_r820t_config = {
+static const struct rtl2832_config rtl28xxu_rtl2832_r820t_config = {
.i2c_addr = 0x10,
.xtal = 28800000,
.tuner = TUNER_RTL2832_R820T,
@@ -723,7 +773,7 @@ static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap)
int ret;
struct dvb_usb_device *d = adap_to_d(adap);
struct rtl28xxu_priv *priv = d_to_priv(d);
- struct rtl2832_config *rtl2832_config;
+ const struct rtl2832_config *rtl2832_config;
dev_dbg(&d->udev->dev, "%s:\n", __func__);
@@ -745,6 +795,7 @@ static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap)
rtl2832_config = &rtl28xxu_rtl2832_e4000_config;
break;
case TUNER_RTL2832_R820T:
+ case TUNER_RTL2832_R828D:
rtl2832_config = &rtl28xxu_rtl2832_r820t_config;
break;
default:
@@ -761,6 +812,9 @@ static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap)
goto err;
}
+ /* RTL2832 I2C repeater */
+ priv->demod_i2c_adapter = rtl2832_get_i2c_adapter(adap->fe[0]);
+
/* set fe callback */
adap->fe[0]->callback = rtl2832u_frontend_callback;
@@ -840,11 +894,6 @@ err:
return ret;
}
-static const struct e4000_config rtl2832u_e4000_config = {
- .i2c_addr = 0x64,
- .clock = 28800000,
-};
-
static const struct fc2580_config rtl2832u_fc2580_config = {
.i2c_addr = 0x56,
.clock = 16384000,
@@ -866,15 +915,26 @@ static const struct r820t_config rtl2832u_r820t_config = {
.rafael_chip = CHIP_R820T,
};
+static const struct r820t_config rtl2832u_r828d_config = {
+ .i2c_addr = 0x3a,
+ .xtal = 16000000,
+ .max_i2c_msg_len = 2,
+ .rafael_chip = CHIP_R828D,
+};
+
static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
{
int ret;
struct dvb_usb_device *d = adap_to_d(adap);
struct rtl28xxu_priv *priv = d_to_priv(d);
- struct dvb_frontend *fe;
+ struct dvb_frontend *fe = NULL;
+ struct i2c_board_info info;
+ struct i2c_client *client;
dev_dbg(&d->udev->dev, "%s:\n", __func__);
+ memset(&info, 0, sizeof(struct i2c_board_info));
+
switch (priv->tuner) {
case TUNER_RTL2832_FC0012:
fe = dvb_attach(fc0012_attach, adap->fe[0],
@@ -884,7 +944,10 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
* that to the tuner driver */
adap->fe[0]->ops.read_signal_strength =
adap->fe[0]->ops.tuner_ops.get_rf_strength;
- return 0;
+
+ /* attach SDR */
+ dvb_attach_sdr(rtl2832_sdr_attach, adap->fe[0], &d->i2c_adap,
+ &rtl28xxu_rtl2832_fc0012_config, NULL);
break;
case TUNER_RTL2832_FC0013:
fe = dvb_attach(fc0013_attach, adap->fe[0],
@@ -893,10 +956,43 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
/* fc0013 also supports signal strength reading */
adap->fe[0]->ops.read_signal_strength =
adap->fe[0]->ops.tuner_ops.get_rf_strength;
- return 0;
- case TUNER_RTL2832_E4000:
- fe = dvb_attach(e4000_attach, adap->fe[0], &d->i2c_adap,
- &rtl2832u_e4000_config);
+
+ /* attach SDR */
+ dvb_attach_sdr(rtl2832_sdr_attach, adap->fe[0], &d->i2c_adap,
+ &rtl28xxu_rtl2832_fc0013_config, NULL);
+ break;
+ case TUNER_RTL2832_E4000: {
+ struct v4l2_subdev *sd;
+ struct i2c_adapter *i2c_adap_internal =
+ rtl2832_get_private_i2c_adapter(adap->fe[0]);
+ struct e4000_config e4000_config = {
+ .fe = adap->fe[0],
+ .clock = 28800000,
+ };
+
+ strlcpy(info.type, "e4000", I2C_NAME_SIZE);
+ info.addr = 0x64;
+ info.platform_data = &e4000_config;
+
+ request_module(info.type);
+ client = i2c_new_device(priv->demod_i2c_adapter, &info);
+ if (client == NULL || client->dev.driver == NULL)
+ break;
+
+ if (!try_module_get(client->dev.driver->owner)) {
+ i2c_unregister_device(client);
+ break;
+ }
+
+ priv->client = client;
+ sd = i2c_get_clientdata(client);
+ i2c_set_adapdata(i2c_adap_internal, d);
+
+ /* attach SDR */
+ dvb_attach_sdr(rtl2832_sdr_attach, adap->fe[0],
+ i2c_adap_internal,
+ &rtl28xxu_rtl2832_e4000_config, sd);
+ }
break;
case TUNER_RTL2832_FC2580:
fe = dvb_attach(fc2580_attach, adap->fe[0], &d->i2c_adap,
@@ -922,14 +1018,38 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
/* Use tuner to get the signal strength */
adap->fe[0]->ops.read_signal_strength =
adap->fe[0]->ops.tuner_ops.get_rf_strength;
+
+ /* attach SDR */
+ dvb_attach_sdr(rtl2832_sdr_attach, adap->fe[0], &d->i2c_adap,
+ &rtl28xxu_rtl2832_r820t_config, NULL);
+ break;
+ case TUNER_RTL2832_R828D:
+ /* power off mn88472 demod on GPIO0 */
+ ret = rtl28xx_wr_reg_mask(d, SYS_GPIO_OUT_VAL, 0x00, 0x01);
+ if (ret)
+ goto err;
+
+ ret = rtl28xx_wr_reg_mask(d, SYS_GPIO_DIR, 0x00, 0x01);
+ if (ret)
+ goto err;
+
+ ret = rtl28xx_wr_reg_mask(d, SYS_GPIO_OUT_EN, 0x01, 0x01);
+ if (ret)
+ goto err;
+
+ fe = dvb_attach(r820t_attach, adap->fe[0], &d->i2c_adap,
+ &rtl2832u_r828d_config);
+
+ /* Use tuner to get the signal strength */
+ adap->fe[0]->ops.read_signal_strength =
+ adap->fe[0]->ops.tuner_ops.get_rf_strength;
break;
default:
- fe = NULL;
dev_err(&d->udev->dev, "%s: unknown tuner=%d\n", KBUILD_MODNAME,
priv->tuner);
}
- if (fe == NULL) {
+ if (fe == NULL && priv->client == NULL) {
ret = -ENODEV;
goto err;
}
@@ -974,6 +1094,22 @@ err:
return ret;
}
+static void rtl28xxu_exit(struct dvb_usb_device *d)
+{
+ struct rtl28xxu_priv *priv = d->priv;
+ struct i2c_client *client = priv->client;
+
+ dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
+ /* remove I2C tuner */
+ if (client) {
+ module_put(client->dev.driver->owner);
+ i2c_unregister_device(client);
+ }
+
+ return;
+}
+
static int rtl2831u_power_ctrl(struct dvb_usb_device *d, int onoff)
{
int ret;
@@ -1283,6 +1419,10 @@ err:
static int rtl2832u_get_rc_config(struct dvb_usb_device *d,
struct dvb_usb_rc *rc)
{
+ /* disable IR interrupts in order to avoid SDR sample loss */
+ if (rtl28xxu_disable_rc)
+ return rtl28xx_wr_reg(d, IR_RX_IE, 0x00);
+
/* load empty to enable rc */
if (!rc->map_name)
rc->map_name = RC_MAP_EMPTY;
@@ -1332,6 +1472,7 @@ static const struct dvb_usb_device_properties rtl2832u_props = {
.frontend_attach = rtl2832u_frontend_attach,
.tuner_attach = rtl2832u_tuner_attach,
.init = rtl28xxu_init,
+ .exit = rtl28xxu_exit,
.get_rc_config = rtl2832u_get_rc_config,
.num_adapters = 1,
@@ -1343,6 +1484,7 @@ static const struct dvb_usb_device_properties rtl2832u_props = {
};
static const struct usb_device_id rtl28xxu_id_table[] = {
+ /* RTL2831U devices: */
{ DVB_USB_DEVICE(USB_VID_REALTEK, USB_PID_REALTEK_RTL2831U,
&rtl2831u_props, "Realtek RTL2831U reference design", NULL) },
{ DVB_USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_FREECOM_DVBT,
@@ -1350,6 +1492,7 @@ static const struct usb_device_id rtl28xxu_id_table[] = {
{ DVB_USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_FREECOM_DVBT_2,
&rtl2831u_props, "Freecom USB2.0 DVB-T", NULL) },
+ /* RTL2832U devices: */
{ DVB_USB_DEVICE(USB_VID_REALTEK, 0x2832,
&rtl2832u_props, "Realtek RTL2832U reference design", NULL) },
{ DVB_USB_DEVICE(USB_VID_REALTEK, 0x2838,
@@ -1362,12 +1505,16 @@ static const struct usb_device_id rtl28xxu_id_table[] = {
&rtl2832u_props, "TerraTec NOXON DAB Stick", NULL) },
{ DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_NOXON_DAB_STICK_REV2,
&rtl2832u_props, "TerraTec NOXON DAB Stick (rev 2)", NULL) },
+ { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_NOXON_DAB_STICK_REV3,
+ &rtl2832u_props, "TerraTec NOXON DAB Stick (rev 3)", NULL) },
{ DVB_USB_DEVICE(USB_VID_GTEK, USB_PID_TREKSTOR_TERRES_2_0,
&rtl2832u_props, "Trekstor DVB-T Stick Terres 2.0", NULL) },
{ DVB_USB_DEVICE(USB_VID_DEXATEK, 0x1101,
&rtl2832u_props, "Dexatek DK DVB-T Dongle", NULL) },
{ DVB_USB_DEVICE(USB_VID_LEADTEK, 0x6680,
&rtl2832u_props, "DigitalNow Quad DVB-T Receiver", NULL) },
+ { DVB_USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_MINID,
+ &rtl2832u_props, "Leadtek Winfast DTV Dongle Mini D", NULL) },
{ DVB_USB_DEVICE(USB_VID_TERRATEC, 0x00d3,
&rtl2832u_props, "TerraTec Cinergy T Stick RC (Rev. 3)", NULL) },
{ DVB_USB_DEVICE(USB_VID_DEXATEK, 0x1102,
@@ -1388,6 +1535,18 @@ static const struct usb_device_id rtl28xxu_id_table[] = {
&rtl2832u_props, "Leadtek WinFast DTV Dongle mini", NULL) },
{ DVB_USB_DEVICE(USB_VID_GTEK, USB_PID_CPYTO_REDI_PC50A,
&rtl2832u_props, "Crypto ReDi PC 50 A", NULL) },
+ { DVB_USB_DEVICE(USB_VID_KYE, 0x707f,
+ &rtl2832u_props, "Genius TVGo DVB-T03", NULL) },
+ { DVB_USB_DEVICE(USB_VID_KWORLD_2, 0xd395,
+ &rtl2832u_props, "Peak DVB-T USB", NULL) },
+ { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV20_RTL2832U,
+ &rtl2832u_props, "Sveon STV20", NULL) },
+ { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV27,
+ &rtl2832u_props, "Sveon STV27", NULL) },
+
+ /* RTL2832P devices: */
+ { DVB_USB_DEVICE(USB_VID_HANFTEK, 0x0131,
+ &rtl2832u_props, "Astrometa DVB-T2", NULL) },
{ }
};
MODULE_DEVICE_TABLE(usb, rtl28xxu_id_table);
diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.h b/drivers/media/usb/dvb-usb-v2/rtl28xxu.h
index 729b3540c2f..a26cab10f38 100644
--- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.h
+++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.h
@@ -55,7 +55,9 @@ struct rtl28xxu_priv {
u8 tuner;
char *tuner_name;
u8 page; /* integrated demod active register page */
+ struct i2c_adapter *demod_i2c_adapter;
bool rc_active;
+ struct i2c_client *client;
};
enum rtl28xxu_chip_id {
@@ -83,6 +85,7 @@ enum rtl28xxu_tuner {
TUNER_RTL2832_TDA18272,
TUNER_RTL2832_FC0013,
TUNER_RTL2832_R820T,
+ TUNER_RTL2832_R828D,
};
struct rtl28xxu_req {
diff --git a/drivers/media/usb/dvb-usb/az6027.c b/drivers/media/usb/dvb-usb/az6027.c
index ea2d5ee8657..0df52ab32a7 100644
--- a/drivers/media/usb/dvb-usb/az6027.c
+++ b/drivers/media/usb/dvb-usb/az6027.c
@@ -254,7 +254,7 @@ static const struct stb0899_s1_reg az6027_stb0899_s1_init_3[] = {
-struct stb0899_config az6027_stb0899_config = {
+static struct stb0899_config az6027_stb0899_config = {
.init_dev = az6027_stb0899_s1_init_1,
.init_s2_demod = stb0899_s2_init_2,
.init_s1_demod = az6027_stb0899_s1_init_3,
@@ -291,7 +291,7 @@ struct stb0899_config az6027_stb0899_config = {
.tuner_set_rfsiggain = NULL,
};
-struct stb6100_config az6027_stb6100_config = {
+static struct stb6100_config az6027_stb6100_config = {
.tuner_address = 0xc0,
.refclock = 27000000,
};
@@ -1088,6 +1088,7 @@ static struct usb_device_id az6027_usb_table[] = {
{ USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_USB2_HDCI_V1) },
{ USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_USB2_HDCI_V2) },
{ USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_SAT) },
+ { USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_SAT_V2) },
{ },
};
@@ -1136,7 +1137,7 @@ static struct dvb_usb_device_properties az6027_properties = {
.i2c_algo = &az6027_i2c_algo,
- .num_device_descs = 6,
+ .num_device_descs = 7,
.devices = {
{
.name = "AZUREWAVE DVB-S/S2 USB2.0 (AZ6027)",
@@ -1162,6 +1163,10 @@ static struct dvb_usb_device_properties az6027_properties = {
.name = "Elgato EyeTV Sat",
.cold_ids = { &az6027_usb_table[5], NULL },
.warm_ids = { NULL },
+ }, {
+ .name = "Elgato EyeTV Sat",
+ .cold_ids = { &az6027_usb_table[6], NULL },
+ .warm_ids = { NULL },
},
{ NULL },
}
diff --git a/drivers/media/usb/dvb-usb/cxusb.c b/drivers/media/usb/dvb-usb/cxusb.c
index 3940bb0f9ef..a1c641e1836 100644
--- a/drivers/media/usb/dvb-usb/cxusb.c
+++ b/drivers/media/usb/dvb-usb/cxusb.c
@@ -43,6 +43,9 @@
#include "lgs8gxx.h"
#include "atbm8830.h"
+/* Max transfer size done by I2C transfer functions */
+#define MAX_XFER_SIZE 64
+
/* debug */
static int dvb_usb_cxusb_debug;
module_param_named(debug, dvb_usb_cxusb_debug, int, 0644);
@@ -57,7 +60,14 @@ static int cxusb_ctrl_msg(struct dvb_usb_device *d,
u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen)
{
int wo = (rbuf == NULL || rlen == 0); /* write-only */
- u8 sndbuf[1+wlen];
+ u8 sndbuf[MAX_XFER_SIZE];
+
+ if (1 + wlen > sizeof(sndbuf)) {
+ warn("i2c wr: len=%d is too big!\n",
+ wlen);
+ return -EOPNOTSUPP;
+ }
+
memset(sndbuf, 0, 1+wlen);
sndbuf[0] = cmd;
@@ -139,6 +149,7 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
int num)
{
struct dvb_usb_device *d = i2c_get_adapdata(adap);
+ int ret;
int i;
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
@@ -158,7 +169,14 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
if (msg[i].flags & I2C_M_RD) {
/* read only */
- u8 obuf[3], ibuf[1+msg[i].len];
+ u8 obuf[3], ibuf[MAX_XFER_SIZE];
+
+ if (1 + msg[i].len > sizeof(ibuf)) {
+ warn("i2c rd: len=%d is too big!\n",
+ msg[i].len);
+ ret = -EOPNOTSUPP;
+ goto unlock;
+ }
obuf[0] = 0;
obuf[1] = msg[i].len;
obuf[2] = msg[i].addr;
@@ -172,7 +190,20 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
} else if (i+1 < num && (msg[i+1].flags & I2C_M_RD) &&
msg[i].addr == msg[i+1].addr) {
/* write to then read from same address */
- u8 obuf[3+msg[i].len], ibuf[1+msg[i+1].len];
+ u8 obuf[MAX_XFER_SIZE], ibuf[MAX_XFER_SIZE];
+
+ if (3 + msg[i].len > sizeof(obuf)) {
+ warn("i2c wr: len=%d is too big!\n",
+ msg[i].len);
+ ret = -EOPNOTSUPP;
+ goto unlock;
+ }
+ if (1 + msg[i + 1].len > sizeof(ibuf)) {
+ warn("i2c rd: len=%d is too big!\n",
+ msg[i + 1].len);
+ ret = -EOPNOTSUPP;
+ goto unlock;
+ }
obuf[0] = msg[i].len;
obuf[1] = msg[i+1].len;
obuf[2] = msg[i].addr;
@@ -191,7 +222,14 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
i++;
} else {
/* write only */
- u8 obuf[2+msg[i].len], ibuf;
+ u8 obuf[MAX_XFER_SIZE], ibuf;
+
+ if (2 + msg[i].len > sizeof(obuf)) {
+ warn("i2c wr: len=%d is too big!\n",
+ msg[i].len);
+ ret = -EOPNOTSUPP;
+ goto unlock;
+ }
obuf[0] = msg[i].addr;
obuf[1] = msg[i].len;
memcpy(&obuf[2], msg[i].buf, msg[i].len);
@@ -204,8 +242,14 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
}
}
+ if (i == num)
+ ret = num;
+ else
+ ret = -EREMOTEIO;
+
+unlock:
mutex_unlock(&d->i2c_mutex);
- return i == num ? num : -EREMOTEIO;
+ return ret;
}
static u32 cxusb_i2c_func(struct i2c_adapter *adapter)
diff --git a/drivers/media/usb/dvb-usb/dib0700.h b/drivers/media/usb/dvb-usb/dib0700.h
index 637b6123f39..927617d9561 100644
--- a/drivers/media/usb/dvb-usb/dib0700.h
+++ b/drivers/media/usb/dvb-usb/dib0700.h
@@ -59,7 +59,7 @@ extern int dib0700_set_gpio(struct dvb_usb_device *, enum dib07x0_gpios gpio, u8
extern int dib0700_ctrl_clock(struct dvb_usb_device *d, u32 clk_MHz, u8 clock_out_gp3);
extern int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen);
extern int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw);
-extern int dib0700_rc_setup(struct dvb_usb_device *d);
+extern int dib0700_rc_setup(struct dvb_usb_device *d, struct usb_interface *intf);
extern int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff);
extern struct i2c_algorithm dib0700_i2c_algo;
extern int dib0700_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props,
diff --git a/drivers/media/usb/dvb-usb/dib0700_core.c b/drivers/media/usb/dvb-usb/dib0700_core.c
index bf2a908d74c..c14285fa827 100644
--- a/drivers/media/usb/dvb-usb/dib0700_core.c
+++ b/drivers/media/usb/dvb-usb/dib0700_core.c
@@ -754,17 +754,20 @@ resubmit:
usb_submit_urb(purb, GFP_ATOMIC);
}
-int dib0700_rc_setup(struct dvb_usb_device *d)
+int dib0700_rc_setup(struct dvb_usb_device *d, struct usb_interface *intf)
{
struct dib0700_state *st = d->priv;
struct urb *purb;
- int ret;
+ const struct usb_endpoint_descriptor *e;
+ int ret, rc_ep = 1;
+ unsigned int pipe = 0;
/* Poll-based. Don't initialize bulk mode */
- if (st->fw_version < 0x10200)
+ if (st->fw_version < 0x10200 || !intf)
return 0;
/* Starting in firmware 1.20, the RC info is provided on a bulk pipe */
+
purb = usb_alloc_urb(0, GFP_KERNEL);
if (purb == NULL) {
err("rc usb alloc urb failed");
@@ -779,9 +782,35 @@ int dib0700_rc_setup(struct dvb_usb_device *d)
}
purb->status = -EINPROGRESS;
- usb_fill_bulk_urb(purb, d->udev, usb_rcvbulkpipe(d->udev, 1),
- purb->transfer_buffer, RC_MSG_SIZE_V1_20,
- dib0700_rc_urb_completion, d);
+
+ /*
+ * Some devices like the Hauppauge NovaTD model 52009 use an interrupt
+ * endpoint, while others use a bulk one.
+ */
+ e = &intf->altsetting[0].endpoint[rc_ep].desc;
+ if (usb_endpoint_dir_in(e)) {
+ if (usb_endpoint_xfer_bulk(e)) {
+ pipe = usb_rcvbulkpipe(d->udev, rc_ep);
+ usb_fill_bulk_urb(purb, d->udev, pipe,
+ purb->transfer_buffer,
+ RC_MSG_SIZE_V1_20,
+ dib0700_rc_urb_completion, d);
+
+ } else if (usb_endpoint_xfer_int(e)) {
+ pipe = usb_rcvintpipe(d->udev, rc_ep);
+ usb_fill_int_urb(purb, d->udev, pipe,
+ purb->transfer_buffer,
+ RC_MSG_SIZE_V1_20,
+ dib0700_rc_urb_completion, d, 1);
+ }
+ }
+
+ if (!pipe) {
+ err("There's no endpoint for remote controller");
+ kfree(purb->transfer_buffer);
+ usb_free_urb(purb);
+ return 0;
+ }
ret = usb_submit_urb(purb, GFP_ATOMIC);
if (ret) {
@@ -820,7 +849,7 @@ static int dib0700_probe(struct usb_interface *intf,
else
dev->props.rc.core.bulk_mode = false;
- dib0700_rc_setup(dev);
+ dib0700_rc_setup(dev, intf);
return 0;
}
diff --git a/drivers/media/usb/dvb-usb/dib0700_devices.c b/drivers/media/usb/dvb-usb/dib0700_devices.c
index 829323e42ca..10e0db8d185 100644
--- a/drivers/media/usb/dvb-usb/dib0700_devices.c
+++ b/drivers/media/usb/dvb-usb/dib0700_devices.c
@@ -514,7 +514,7 @@ static int dib0700_rc_query_old_firmware(struct dvb_usb_device *d)
/* info("%d: %2X %2X %2X %2X",dvb_usb_dib0700_ir_proto,(int)key[3-2],(int)key[3-3],(int)key[3-1],(int)key[3]); */
- dib0700_rc_setup(d); /* reset ir sensor data to prevent false events */
+ dib0700_rc_setup(d, NULL); /* reset ir sensor data to prevent false events */
d->last_event = 0;
switch (d->props.rc.core.protocol) {
diff --git a/drivers/media/usb/dvb-usb/dibusb-common.c b/drivers/media/usb/dvb-usb/dibusb-common.c
index c2dded92f1d..6d68af0c49c 100644
--- a/drivers/media/usb/dvb-usb/dibusb-common.c
+++ b/drivers/media/usb/dvb-usb/dibusb-common.c
@@ -12,6 +12,9 @@
#include <linux/kconfig.h>
#include "dibusb.h"
+/* Max transfer size done by I2C transfer functions */
+#define MAX_XFER_SIZE 64
+
static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "set debugging level (1=info (|-able))." DVB_USB_DEBUG_STATUS);
@@ -105,11 +108,16 @@ EXPORT_SYMBOL(dibusb2_0_power_ctrl);
static int dibusb_i2c_msg(struct dvb_usb_device *d, u8 addr,
u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
{
- u8 sndbuf[wlen+4]; /* lead(1) devaddr,direction(1) addr(2) data(wlen) (len(2) (when reading)) */
+ u8 sndbuf[MAX_XFER_SIZE]; /* lead(1) devaddr,direction(1) addr(2) data(wlen) (len(2) (when reading)) */
/* write only ? */
int wo = (rbuf == NULL || rlen == 0),
len = 2 + wlen + (wo ? 0 : 2);
+ if (4 + wlen > sizeof(sndbuf)) {
+ warn("i2c wr: len=%d is too big!\n", wlen);
+ return -EOPNOTSUPP;
+ }
+
sndbuf[0] = wo ? DIBUSB_REQ_I2C_WRITE : DIBUSB_REQ_I2C_READ;
sndbuf[1] = (addr << 1) | (wo ? 0 : 1);
diff --git a/drivers/media/usb/dvb-usb/dvb-usb-remote.c b/drivers/media/usb/dvb-usb/dvb-usb-remote.c
index 41bacff2496..4058aea9272 100644
--- a/drivers/media/usb/dvb-usb/dvb-usb-remote.c
+++ b/drivers/media/usb/dvb-usb/dvb-usb-remote.c
@@ -272,7 +272,7 @@ static int rc_core_dvb_usb_remote_init(struct dvb_usb_device *d)
dev->driver_name = d->props.rc.core.module_name;
dev->map_name = d->props.rc.core.rc_codes;
dev->change_protocol = d->props.rc.core.change_protocol;
- dev->allowed_protos = d->props.rc.core.allowed_protos;
+ rc_set_allowed_protocols(dev, d->props.rc.core.allowed_protos);
dev->driver_type = d->props.rc.core.driver_type;
usb_to_input_id(d->udev, &dev->input_id);
dev->input_name = "IR-receiver inside an USB DVB receiver";
diff --git a/drivers/media/usb/dvb-usb/dw2102.c b/drivers/media/usb/dvb-usb/dw2102.c
index 6e237b6dd0a..ae0f56a32e4 100644
--- a/drivers/media/usb/dvb-usb/dw2102.c
+++ b/drivers/media/usb/dvb-usb/dw2102.c
@@ -2,7 +2,7 @@
* DVBWorld DVB-S 2101, 2102, DVB-S2 2104, DVB-C 3101,
* TeVii S600, S630, S650, S660, S480, S421, S632
* Prof 1100, 7500,
- * Geniatech SU3000 Cards
+ * Geniatech SU3000, T220 Cards
* Copyright (C) 2008-2012 Igor M. Liplianin (liplianin@me.by)
*
* This program is free software; you can redistribute it and/or modify it
@@ -29,6 +29,11 @@
#include "stb6100.h"
#include "stb6100_proc.h"
#include "m88rs2000.h"
+#include "tda18271.h"
+#include "cxd2820r.h"
+
+/* Max transfer size done by I2C transfer functions */
+#define MAX_XFER_SIZE 64
#ifndef USB_PID_DW2102
#define USB_PID_DW2102 0x2102
@@ -107,11 +112,6 @@
"Please see linux/Documentation/dvb/ for more details " \
"on firmware-problems."
-struct rc_map_dvb_usb_table_table {
- struct rc_map_table *rc_keys;
- int rc_keys_size;
-};
-
struct su3000_state {
u8 initialized;
};
@@ -126,12 +126,6 @@ module_param_named(debug, dvb_usb_dw2102_debug, int, 0644);
MODULE_PARM_DESC(debug, "set debugging level (1=info 2=xfer 4=rc(or-able))."
DVB_USB_DEBUG_STATUS);
-/* keymaps */
-static int ir_keymap;
-module_param_named(keymap, ir_keymap, int, 0644);
-MODULE_PARM_DESC(keymap, "set keymap 0=default 1=dvbworld 2=tevii 3=tbs ..."
- " 256=none");
-
/* demod probe */
static int demod_probe = 1;
module_param_named(demod, demod_probe, int, 0644);
@@ -298,6 +292,7 @@ static int dw2102_serit_i2c_transfer(struct i2c_adapter *adap,
static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num)
{
struct dvb_usb_device *d = i2c_get_adapdata(adap);
+ int ret;
if (!d)
return -ENODEV;
@@ -308,7 +303,15 @@ static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg ms
case 2: {
/* read */
/* first write first register number */
- u8 ibuf[msg[1].len + 2], obuf[3];
+ u8 ibuf[MAX_XFER_SIZE], obuf[3];
+
+ if (2 + msg[1].len > sizeof(ibuf)) {
+ warn("i2c rd: len=%d is too big!\n",
+ msg[1].len);
+ ret = -EOPNOTSUPP;
+ goto unlock;
+ }
+
obuf[0] = msg[0].addr << 1;
obuf[1] = msg[0].len;
obuf[2] = msg[0].buf[0];
@@ -325,7 +328,15 @@ static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg ms
switch (msg[0].addr) {
case 0x68: {
/* write to register */
- u8 obuf[msg[0].len + 2];
+ u8 obuf[MAX_XFER_SIZE];
+
+ if (2 + msg[0].len > sizeof(obuf)) {
+ warn("i2c wr: len=%d is too big!\n",
+ msg[1].len);
+ ret = -EOPNOTSUPP;
+ goto unlock;
+ }
+
obuf[0] = msg[0].addr << 1;
obuf[1] = msg[0].len;
memcpy(obuf + 2, msg[0].buf, msg[0].len);
@@ -335,7 +346,15 @@ static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg ms
}
case 0x61: {
/* write to tuner */
- u8 obuf[msg[0].len + 2];
+ u8 obuf[MAX_XFER_SIZE];
+
+ if (2 + msg[0].len > sizeof(obuf)) {
+ warn("i2c wr: len=%d is too big!\n",
+ msg[1].len);
+ ret = -EOPNOTSUPP;
+ goto unlock;
+ }
+
obuf[0] = msg[0].addr << 1;
obuf[1] = msg[0].len;
memcpy(obuf + 2, msg[0].buf, msg[0].len);
@@ -362,15 +381,17 @@ static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg ms
break;
}
+ ret = num;
+unlock:
mutex_unlock(&d->i2c_mutex);
- return num;
+ return ret;
}
static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num)
{
struct dvb_usb_device *d = i2c_get_adapdata(adap);
- int len, i, j;
+ int len, i, j, ret;
if (!d)
return -ENODEV;
@@ -401,7 +422,15 @@ static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], i
default: {
if (msg[j].flags == I2C_M_RD) {
/* read registers */
- u8 ibuf[msg[j].len + 2];
+ u8 ibuf[MAX_XFER_SIZE];
+
+ if (2 + msg[j].len > sizeof(ibuf)) {
+ warn("i2c rd: len=%d is too big!\n",
+ msg[j].len);
+ ret = -EOPNOTSUPP;
+ goto unlock;
+ }
+
dw210x_op_rw(d->udev, 0xc3,
(msg[j].addr << 1) + 1, 0,
ibuf, msg[j].len + 2,
@@ -430,7 +459,15 @@ static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], i
} while (len > 0);
} else {
/* write registers */
- u8 obuf[msg[j].len + 2];
+ u8 obuf[MAX_XFER_SIZE];
+
+ if (2 + msg[j].len > sizeof(obuf)) {
+ warn("i2c wr: len=%d is too big!\n",
+ msg[j].len);
+ ret = -EOPNOTSUPP;
+ goto unlock;
+ }
+
obuf[0] = msg[j].addr << 1;
obuf[1] = msg[j].len;
memcpy(obuf + 2, msg[j].buf, msg[j].len);
@@ -443,15 +480,18 @@ static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], i
}
}
+ ret = num;
+unlock:
mutex_unlock(&d->i2c_mutex);
- return num;
+ return ret;
}
static int dw3101_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
int num)
{
struct dvb_usb_device *d = i2c_get_adapdata(adap);
+ int ret;
int i;
if (!d)
@@ -463,7 +503,14 @@ static int dw3101_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
case 2: {
/* read */
/* first write first register number */
- u8 ibuf[msg[1].len + 2], obuf[3];
+ u8 ibuf[MAX_XFER_SIZE], obuf[3];
+
+ if (2 + msg[1].len > sizeof(ibuf)) {
+ warn("i2c rd: len=%d is too big!\n",
+ msg[1].len);
+ ret = -EOPNOTSUPP;
+ goto unlock;
+ }
obuf[0] = msg[0].addr << 1;
obuf[1] = msg[0].len;
obuf[2] = msg[0].buf[0];
@@ -481,7 +528,14 @@ static int dw3101_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
case 0x60:
case 0x0c: {
/* write to register */
- u8 obuf[msg[0].len + 2];
+ u8 obuf[MAX_XFER_SIZE];
+
+ if (2 + msg[0].len > sizeof(obuf)) {
+ warn("i2c wr: len=%d is too big!\n",
+ msg[0].len);
+ ret = -EOPNOTSUPP;
+ goto unlock;
+ }
obuf[0] = msg[0].addr << 1;
obuf[1] = msg[0].len;
memcpy(obuf + 2, msg[0].buf, msg[0].len);
@@ -506,9 +560,11 @@ static int dw3101_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
msg[i].flags == 0 ? ">>>" : "<<<");
debug_dump(msg[i].buf, msg[i].len, deb_xfer);
}
+ ret = num;
+unlock:
mutex_unlock(&d->i2c_mutex);
- return num;
+ return ret;
}
static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
@@ -516,7 +572,7 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
{
struct dvb_usb_device *d = i2c_get_adapdata(adap);
struct usb_device *udev;
- int len, i, j;
+ int len, i, j, ret;
if (!d)
return -ENODEV;
@@ -563,7 +619,15 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
default: {
if (msg[j].flags == I2C_M_RD) {
/* read registers */
- u8 ibuf[msg[j].len];
+ u8 ibuf[MAX_XFER_SIZE];
+
+ if (msg[j].len > sizeof(ibuf)) {
+ warn("i2c rd: len=%d is too big!\n",
+ msg[j].len);
+ ret = -EOPNOTSUPP;
+ goto unlock;
+ }
+
dw210x_op_rw(d->udev, 0x91, 0, 0,
ibuf, msg[j].len,
DW210X_READ_MSG);
@@ -590,7 +654,15 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
} while (len > 0);
} else if (j < (num - 1)) {
/* write register addr before read */
- u8 obuf[msg[j].len + 2];
+ u8 obuf[MAX_XFER_SIZE];
+
+ if (2 + msg[j].len > sizeof(obuf)) {
+ warn("i2c wr: len=%d is too big!\n",
+ msg[j].len);
+ ret = -EOPNOTSUPP;
+ goto unlock;
+ }
+
obuf[0] = msg[j + 1].len;
obuf[1] = (msg[j].addr << 1);
memcpy(obuf + 2, msg[j].buf, msg[j].len);
@@ -602,7 +674,14 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
break;
} else {
/* write registers */
- u8 obuf[msg[j].len + 2];
+ u8 obuf[MAX_XFER_SIZE];
+
+ if (2 + msg[j].len > sizeof(obuf)) {
+ warn("i2c wr: len=%d is too big!\n",
+ msg[j].len);
+ ret = -EOPNOTSUPP;
+ goto unlock;
+ }
obuf[0] = msg[j].len + 1;
obuf[1] = (msg[j].addr << 1);
memcpy(obuf + 2, msg[j].buf, msg[j].len);
@@ -615,9 +694,11 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
}
}
}
+ ret = num;
+unlock:
mutex_unlock(&d->i2c_mutex);
- return num;
+ return ret;
}
static int su3000_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
@@ -955,9 +1036,10 @@ static struct ds3000_config dw2104_ds3000_config = {
.demod_address = 0x68,
};
-static struct ts2020_config dw2104_ts2020_config = {
+static struct ts2020_config dw2104_ts2020_config = {
.tuner_address = 0x60,
.clk_out_div = 1,
+ .frequency_div = 1060000,
};
static struct ds3000_config s660_ds3000_config = {
@@ -966,6 +1048,12 @@ static struct ds3000_config s660_ds3000_config = {
.set_lock_led = dw210x_led_ctrl,
};
+static struct ts2020_config s660_ts2020_config = {
+ .tuner_address = 0x60,
+ .clk_out_div = 1,
+ .frequency_div = 1146000,
+};
+
static struct stv0900_config dw2104a_stv0900_config = {
.demod_address = 0x6a,
.demod_mode = 0,
@@ -1018,6 +1106,16 @@ static struct ds3000_config su3000_ds3000_config = {
.set_lock_led = dw210x_led_ctrl,
};
+static struct cxd2820r_config cxd2820r_config = {
+ .i2c_address = 0x6c, /* (0xd8 >> 1) */
+ .ts_mode = 0x38,
+};
+
+static struct tda18271_config tda18271_config = {
+ .output_opt = TDA18271_OUTPUT_LT_OFF,
+ .gate = TDA18271_GATE_DIGITAL,
+};
+
static u8 m88rs2000_inittab[] = {
DEMOD_WRITE, 0x9a, 0x30,
DEMOD_WRITE, 0x00, 0x01,
@@ -1205,7 +1303,7 @@ static int ds3000_frontend_attach(struct dvb_usb_adapter *d)
if (d->fe_adap[0].fe == NULL)
return -EIO;
- dvb_attach(ts2020_attach, d->fe_adap[0].fe, &dw2104_ts2020_config,
+ dvb_attach(ts2020_attach, d->fe_adap[0].fe, &s660_ts2020_config,
&d->dev->i2c_adap);
st->old_set_voltage = d->fe_adap[0].fe->ops.set_voltage;
@@ -1213,7 +1311,7 @@ static int ds3000_frontend_attach(struct dvb_usb_adapter *d)
dw210x_op_rw(d->dev->udev, 0x8a, 0, 0, obuf, 2, DW210X_WRITE_MSG);
- info("Attached ds3000+ds2020!\n");
+ info("Attached ds3000+ts2020!\n");
return 0;
}
@@ -1287,6 +1385,49 @@ static int su3000_frontend_attach(struct dvb_usb_adapter *d)
return -EIO;
}
+static int t220_frontend_attach(struct dvb_usb_adapter *d)
+{
+ u8 obuf[3] = { 0xe, 0x80, 0 };
+ u8 ibuf[] = { 0 };
+
+ if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
+ err("command 0x0e transfer failed.");
+
+ obuf[0] = 0xe;
+ obuf[1] = 0x83;
+ obuf[2] = 0;
+
+ if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
+ err("command 0x0e transfer failed.");
+
+ msleep(100);
+
+ obuf[0] = 0xe;
+ obuf[1] = 0x80;
+ obuf[2] = 1;
+
+ if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
+ err("command 0x0e transfer failed.");
+
+ obuf[0] = 0x51;
+
+ if (dvb_usb_generic_rw(d->dev, obuf, 1, ibuf, 1, 0) < 0)
+ err("command 0x51 transfer failed.");
+
+ d->fe_adap[0].fe = dvb_attach(cxd2820r_attach, &cxd2820r_config,
+ &d->dev->i2c_adap, NULL);
+ if (d->fe_adap[0].fe != NULL) {
+ if (dvb_attach(tda18271_attach, d->fe_adap[0].fe, 0x60,
+ &d->dev->i2c_adap, &tda18271_config)) {
+ info("Attached TDA18271HD/CXD2820R!\n");
+ return 0;
+ }
+ }
+
+ info("Failed to attach TDA18271HD/CXD2820R!\n");
+ return -EIO;
+}
+
static int m88rs2000_frontend_attach(struct dvb_usb_adapter *d)
{
u8 obuf[] = { 0x51 };
@@ -1327,174 +1468,29 @@ static int dw3101_tuner_attach(struct dvb_usb_adapter *adap)
return 0;
}
-static struct rc_map_table rc_map_dw210x_table[] = {
- { 0xf80a, KEY_POWER2 }, /*power*/
- { 0xf80c, KEY_MUTE }, /*mute*/
- { 0xf811, KEY_1 },
- { 0xf812, KEY_2 },
- { 0xf813, KEY_3 },
- { 0xf814, KEY_4 },
- { 0xf815, KEY_5 },
- { 0xf816, KEY_6 },
- { 0xf817, KEY_7 },
- { 0xf818, KEY_8 },
- { 0xf819, KEY_9 },
- { 0xf810, KEY_0 },
- { 0xf81c, KEY_CHANNELUP }, /*ch+*/
- { 0xf80f, KEY_CHANNELDOWN }, /*ch-*/
- { 0xf81a, KEY_VOLUMEUP }, /*vol+*/
- { 0xf80e, KEY_VOLUMEDOWN }, /*vol-*/
- { 0xf804, KEY_RECORD }, /*rec*/
- { 0xf809, KEY_FAVORITES }, /*fav*/
- { 0xf808, KEY_REWIND }, /*rewind*/
- { 0xf807, KEY_FASTFORWARD }, /*fast*/
- { 0xf80b, KEY_PAUSE }, /*pause*/
- { 0xf802, KEY_ESC }, /*cancel*/
- { 0xf803, KEY_TAB }, /*tab*/
- { 0xf800, KEY_UP }, /*up*/
- { 0xf81f, KEY_OK }, /*ok*/
- { 0xf801, KEY_DOWN }, /*down*/
- { 0xf805, KEY_CAMERA }, /*cap*/
- { 0xf806, KEY_STOP }, /*stop*/
- { 0xf840, KEY_ZOOM }, /*full*/
- { 0xf81e, KEY_TV }, /*tvmode*/
- { 0xf81b, KEY_LAST }, /*recall*/
-};
-
-static struct rc_map_table rc_map_tevii_table[] = {
- { 0xf80a, KEY_POWER },
- { 0xf80c, KEY_MUTE },
- { 0xf811, KEY_1 },
- { 0xf812, KEY_2 },
- { 0xf813, KEY_3 },
- { 0xf814, KEY_4 },
- { 0xf815, KEY_5 },
- { 0xf816, KEY_6 },
- { 0xf817, KEY_7 },
- { 0xf818, KEY_8 },
- { 0xf819, KEY_9 },
- { 0xf810, KEY_0 },
- { 0xf81c, KEY_MENU },
- { 0xf80f, KEY_VOLUMEDOWN },
- { 0xf81a, KEY_LAST },
- { 0xf80e, KEY_OPEN },
- { 0xf804, KEY_RECORD },
- { 0xf809, KEY_VOLUMEUP },
- { 0xf808, KEY_CHANNELUP },
- { 0xf807, KEY_PVR },
- { 0xf80b, KEY_TIME },
- { 0xf802, KEY_RIGHT },
- { 0xf803, KEY_LEFT },
- { 0xf800, KEY_UP },
- { 0xf81f, KEY_OK },
- { 0xf801, KEY_DOWN },
- { 0xf805, KEY_TUNER },
- { 0xf806, KEY_CHANNELDOWN },
- { 0xf840, KEY_PLAYPAUSE },
- { 0xf81e, KEY_REWIND },
- { 0xf81b, KEY_FAVORITES },
- { 0xf81d, KEY_BACK },
- { 0xf84d, KEY_FASTFORWARD },
- { 0xf844, KEY_EPG },
- { 0xf84c, KEY_INFO },
- { 0xf841, KEY_AB },
- { 0xf843, KEY_AUDIO },
- { 0xf845, KEY_SUBTITLE },
- { 0xf84a, KEY_LIST },
- { 0xf846, KEY_F1 },
- { 0xf847, KEY_F2 },
- { 0xf85e, KEY_F3 },
- { 0xf85c, KEY_F4 },
- { 0xf852, KEY_F5 },
- { 0xf85a, KEY_F6 },
- { 0xf856, KEY_MODE },
- { 0xf858, KEY_SWITCHVIDEOMODE },
-};
-
-static struct rc_map_table rc_map_tbs_table[] = {
- { 0xf884, KEY_POWER },
- { 0xf894, KEY_MUTE },
- { 0xf887, KEY_1 },
- { 0xf886, KEY_2 },
- { 0xf885, KEY_3 },
- { 0xf88b, KEY_4 },
- { 0xf88a, KEY_5 },
- { 0xf889, KEY_6 },
- { 0xf88f, KEY_7 },
- { 0xf88e, KEY_8 },
- { 0xf88d, KEY_9 },
- { 0xf892, KEY_0 },
- { 0xf896, KEY_CHANNELUP },
- { 0xf891, KEY_CHANNELDOWN },
- { 0xf893, KEY_VOLUMEUP },
- { 0xf88c, KEY_VOLUMEDOWN },
- { 0xf883, KEY_RECORD },
- { 0xf898, KEY_PAUSE },
- { 0xf899, KEY_OK },
- { 0xf89a, KEY_SHUFFLE },
- { 0xf881, KEY_UP },
- { 0xf890, KEY_LEFT },
- { 0xf882, KEY_RIGHT },
- { 0xf888, KEY_DOWN },
- { 0xf895, KEY_FAVORITES },
- { 0xf897, KEY_SUBTITLE },
- { 0xf89d, KEY_ZOOM },
- { 0xf89f, KEY_EXIT },
- { 0xf89e, KEY_MENU },
- { 0xf89c, KEY_EPG },
- { 0xf880, KEY_PREVIOUS },
- { 0xf89b, KEY_MODE }
-};
+static int dw2102_rc_query(struct dvb_usb_device *d)
+{
+ u8 key[2];
+ struct i2c_msg msg = {
+ .addr = DW2102_RC_QUERY,
+ .flags = I2C_M_RD,
+ .buf = key,
+ .len = 2
+ };
-static struct rc_map_table rc_map_su3000_table[] = {
- { 0x25, KEY_POWER }, /* right-bottom Red */
- { 0x0a, KEY_MUTE }, /* -/-- */
- { 0x01, KEY_1 },
- { 0x02, KEY_2 },
- { 0x03, KEY_3 },
- { 0x04, KEY_4 },
- { 0x05, KEY_5 },
- { 0x06, KEY_6 },
- { 0x07, KEY_7 },
- { 0x08, KEY_8 },
- { 0x09, KEY_9 },
- { 0x00, KEY_0 },
- { 0x20, KEY_UP }, /* CH+ */
- { 0x21, KEY_DOWN }, /* CH+ */
- { 0x12, KEY_VOLUMEUP }, /* Brightness Up */
- { 0x13, KEY_VOLUMEDOWN },/* Brightness Down */
- { 0x1f, KEY_RECORD },
- { 0x17, KEY_PLAY },
- { 0x16, KEY_PAUSE },
- { 0x0b, KEY_STOP },
- { 0x27, KEY_FASTFORWARD },/* >> */
- { 0x26, KEY_REWIND }, /* << */
- { 0x0d, KEY_OK }, /* Mute */
- { 0x11, KEY_LEFT }, /* VOL- */
- { 0x10, KEY_RIGHT }, /* VOL+ */
- { 0x29, KEY_BACK }, /* button under 9 */
- { 0x2c, KEY_MENU }, /* TTX */
- { 0x2b, KEY_EPG }, /* EPG */
- { 0x1e, KEY_RED }, /* OSD */
- { 0x0e, KEY_GREEN }, /* Window */
- { 0x2d, KEY_YELLOW }, /* button under << */
- { 0x0f, KEY_BLUE }, /* bottom yellow button */
- { 0x14, KEY_AUDIO }, /* Snapshot */
- { 0x38, KEY_TV }, /* TV/Radio */
- { 0x0c, KEY_ESC } /* upper Red button */
-};
+ 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]);
+ rc_keydown(d->rc_dev, key[0], 1);
+ }
+ }
-static struct rc_map_dvb_usb_table_table keys_tables[] = {
- { rc_map_dw210x_table, ARRAY_SIZE(rc_map_dw210x_table) },
- { rc_map_tevii_table, ARRAY_SIZE(rc_map_tevii_table) },
- { rc_map_tbs_table, ARRAY_SIZE(rc_map_tbs_table) },
- { rc_map_su3000_table, ARRAY_SIZE(rc_map_su3000_table) },
-};
+ return 0;
+}
-static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+static int prof_rc_query(struct dvb_usb_device *d)
{
- struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table;
- int keymap_size = d->props.rc.legacy.rc_map_size;
u8 key[2];
struct i2c_msg msg = {
.addr = DW2102_RC_QUERY,
@@ -1502,32 +1498,34 @@ static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
.buf = key,
.len = 2
};
- int i;
- /* override keymap */
- if ((ir_keymap > 0) && (ir_keymap <= ARRAY_SIZE(keys_tables))) {
- keymap = keys_tables[ir_keymap - 1].rc_keys ;
- keymap_size = keys_tables[ir_keymap - 1].rc_keys_size;
- } else if (ir_keymap > ARRAY_SIZE(keys_tables))
- return 0; /* none */
-
- *state = REMOTE_NO_KEY_PRESSED;
- if (d->props.i2c_algo->master_xfer(&d->i2c_adap, &msg, 1) == 1) {
- for (i = 0; i < keymap_size ; i++) {
- if (rc5_data(&keymap[i]) == msg.buf[0]) {
- *state = REMOTE_KEY_PRESSED;
- *event = keymap[i].keycode;
- break;
- }
+ 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]);
+ rc_keydown(d->rc_dev, key[0]^0xff, 1);
}
+ }
- if ((*state) == REMOTE_KEY_PRESSED)
- deb_rc("%s: found rc key: %x, %x, event: %x\n",
- __func__, key[0], key[1], (*event));
- else if (key[0] != 0xff)
- deb_rc("%s: unknown rc key: %x, %x\n",
- __func__, key[0], key[1]);
+ return 0;
+}
+static int su3000_rc_query(struct dvb_usb_device *d)
+{
+ u8 key[2];
+ struct i2c_msg msg = {
+ .addr = DW2102_RC_QUERY,
+ .flags = I2C_M_RD,
+ .buf = key,
+ .len = 2
+ };
+
+ 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]);
+ rc_keydown(d->rc_dev, key[1] << 8 | key[0], 1);
+ }
}
return 0;
@@ -1553,6 +1551,7 @@ enum dw2102_table_entry {
TEVII_S632,
TERRATEC_CINERGY_S2_R2,
GOTVIEW_SAT_HD,
+ GENIATECH_T220,
};
static struct usb_device_id dw2102_table[] = {
@@ -1575,6 +1574,7 @@ static struct usb_device_id dw2102_table[] = {
[TEVII_S632] = {USB_DEVICE(0x9022, USB_PID_TEVII_S632)},
[TERRATEC_CINERGY_S2_R2] = {USB_DEVICE(USB_VID_TERRATEC, 0x00b0)},
[GOTVIEW_SAT_HD] = {USB_DEVICE(0x1FE1, USB_PID_GOTVIEW_SAT_HD)},
+ [GENIATECH_T220] = {USB_DEVICE(0x1f4d, 0xD220)},
{ }
};
@@ -1634,9 +1634,7 @@ static int dw2102_load_firmware(struct usb_device *dev,
/* init registers */
switch (dev->descriptor.idProduct) {
case USB_PID_TEVII_S650:
- dw2104_properties.rc.legacy.rc_map_table = rc_map_tevii_table;
- dw2104_properties.rc.legacy.rc_map_size =
- ARRAY_SIZE(rc_map_tevii_table);
+ dw2104_properties.rc.core.rc_codes = RC_MAP_TEVII_NEC;
case USB_PID_DW2104:
reset = 1;
dw210x_op_rw(dev, 0xc4, 0x0000, 0, &reset, 1,
@@ -1700,10 +1698,11 @@ static struct dvb_usb_device_properties dw2102_properties = {
.i2c_algo = &dw2102_serit_i2c_algo,
- .rc.legacy = {
- .rc_map_table = rc_map_dw210x_table,
- .rc_map_size = ARRAY_SIZE(rc_map_dw210x_table),
+ .rc.core = {
.rc_interval = 150,
+ .rc_codes = RC_MAP_DM1105_NEC,
+ .module_name = "dw2102",
+ .allowed_protos = RC_BIT_NEC,
.rc_query = dw2102_rc_query,
},
@@ -1754,10 +1753,11 @@ static struct dvb_usb_device_properties dw2104_properties = {
.no_reconnect = 1,
.i2c_algo = &dw2104_i2c_algo,
- .rc.legacy = {
- .rc_map_table = rc_map_dw210x_table,
- .rc_map_size = ARRAY_SIZE(rc_map_dw210x_table),
+ .rc.core = {
.rc_interval = 150,
+ .rc_codes = RC_MAP_DM1105_NEC,
+ .module_name = "dw2102",
+ .allowed_protos = RC_BIT_NEC,
.rc_query = dw2102_rc_query,
},
@@ -1804,10 +1804,11 @@ static struct dvb_usb_device_properties dw3101_properties = {
.no_reconnect = 1,
.i2c_algo = &dw3101_i2c_algo,
- .rc.legacy = {
- .rc_map_table = rc_map_dw210x_table,
- .rc_map_size = ARRAY_SIZE(rc_map_dw210x_table),
+ .rc.core = {
.rc_interval = 150,
+ .rc_codes = RC_MAP_DM1105_NEC,
+ .module_name = "dw2102",
+ .allowed_protos = RC_BIT_NEC,
.rc_query = dw2102_rc_query,
},
@@ -1852,10 +1853,11 @@ static struct dvb_usb_device_properties s6x0_properties = {
.no_reconnect = 1,
.i2c_algo = &s6x0_i2c_algo,
- .rc.legacy = {
- .rc_map_table = rc_map_tevii_table,
- .rc_map_size = ARRAY_SIZE(rc_map_tevii_table),
+ .rc.core = {
.rc_interval = 150,
+ .rc_codes = RC_MAP_TEVII_NEC,
+ .module_name = "dw2102",
+ .allowed_protos = RC_BIT_NEC,
.rc_query = dw2102_rc_query,
},
@@ -1945,11 +1947,12 @@ static struct dvb_usb_device_properties su3000_properties = {
.identify_state = su3000_identify_state,
.i2c_algo = &su3000_i2c_algo,
- .rc.legacy = {
- .rc_map_table = rc_map_su3000_table,
- .rc_map_size = ARRAY_SIZE(rc_map_su3000_table),
+ .rc.core = {
.rc_interval = 150,
- .rc_query = dw2102_rc_query,
+ .rc_codes = RC_MAP_SU3000,
+ .module_name = "dw2102",
+ .allowed_protos = RC_BIT_RC5,
+ .rc_query = su3000_rc_query,
},
.read_mac_address = su3000_read_mac_address,
@@ -2000,6 +2003,55 @@ static struct dvb_usb_device_properties su3000_properties = {
}
};
+static struct dvb_usb_device_properties t220_properties = {
+ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+ .usb_ctrl = DEVICE_SPECIFIC,
+ .size_of_priv = sizeof(struct su3000_state),
+ .power_ctrl = su3000_power_ctrl,
+ .num_adapters = 1,
+ .identify_state = su3000_identify_state,
+ .i2c_algo = &su3000_i2c_algo,
+
+ .rc.core = {
+ .rc_interval = 150,
+ .rc_codes = RC_MAP_SU3000,
+ .module_name = "dw2102",
+ .allowed_protos = RC_BIT_RC5,
+ .rc_query = su3000_rc_query,
+ },
+
+ .read_mac_address = su3000_read_mac_address,
+
+ .generic_bulk_ctrl_endpoint = 0x01,
+
+ .adapter = {
+ {
+ .num_frontends = 1,
+ .fe = { {
+ .streaming_ctrl = su3000_streaming_ctrl,
+ .frontend_attach = t220_frontend_attach,
+ .stream = {
+ .type = USB_BULK,
+ .count = 8,
+ .endpoint = 0x82,
+ .u = {
+ .bulk = {
+ .buffersize = 4096,
+ }
+ }
+ }
+ } },
+ }
+ },
+ .num_device_descs = 1,
+ .devices = {
+ { "Geniatech T220 DVB-T/T2 USB2.0",
+ { &dw2102_table[GENIATECH_T220], NULL },
+ { NULL },
+ },
+ }
+};
+
static int dw2102_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
@@ -2011,8 +2063,8 @@ static int dw2102_probe(struct usb_interface *intf,
/* fill only different fields */
p1100->firmware = P1100_FIRMWARE;
p1100->devices[0] = d1100;
- p1100->rc.legacy.rc_map_table = rc_map_tbs_table;
- p1100->rc.legacy.rc_map_size = ARRAY_SIZE(rc_map_tbs_table);
+ p1100->rc.core.rc_query = prof_rc_query;
+ p1100->rc.core.rc_codes = RC_MAP_TBS_NEC;
p1100->adapter->fe[0].frontend_attach = stv0288_frontend_attach;
s660 = kmemdup(&s6x0_properties,
@@ -2037,8 +2089,8 @@ static int dw2102_probe(struct usb_interface *intf,
}
p7500->firmware = P7500_FIRMWARE;
p7500->devices[0] = d7500;
- p7500->rc.legacy.rc_map_table = rc_map_tbs_table;
- p7500->rc.legacy.rc_map_size = ARRAY_SIZE(rc_map_tbs_table);
+ p7500->rc.core.rc_query = prof_rc_query;
+ p7500->rc.core.rc_codes = RC_MAP_TBS_NEC;
p7500->adapter->fe[0].frontend_attach = prof_7500_frontend_attach;
@@ -2072,7 +2124,9 @@ static int dw2102_probe(struct usb_interface *intf,
0 == dvb_usb_device_init(intf, s421,
THIS_MODULE, NULL, adapter_nr) ||
0 == dvb_usb_device_init(intf, &su3000_properties,
- THIS_MODULE, NULL, adapter_nr))
+ THIS_MODULE, NULL, adapter_nr) ||
+ 0 == dvb_usb_device_init(intf, &t220_properties,
+ THIS_MODULE, NULL, adapter_nr))
return 0;
return -ENODEV;
@@ -2092,7 +2146,7 @@ MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101, 2102, DVB-S2 2104,"
" DVB-C 3101 USB2.0,"
" TeVii S600, S630, S650, S660, S480, S421, S632"
" Prof 1100, 7500 USB2.0,"
- " Geniatech SU3000 devices");
+ " Geniatech SU3000, T220 devices");
MODULE_VERSION("0.1");
MODULE_LICENSE("GPL");
MODULE_FIRMWARE(DW2101_FIRMWARE);
diff --git a/drivers/media/usb/dvb-usb/technisat-usb2.c b/drivers/media/usb/dvb-usb/technisat-usb2.c
index 40832a1aef6..d947e037900 100644
--- a/drivers/media/usb/dvb-usb/technisat-usb2.c
+++ b/drivers/media/usb/dvb-usb/technisat-usb2.c
@@ -102,7 +102,7 @@ static int technisat_usb2_i2c_access(struct usb_device *udev,
if (rxlen > 62) {
err("i2c RX buffer can't exceed 62 bytes (dev 0x%02x)",
device_addr);
- txlen = 62;
+ rxlen = 62;
}
b[0] = I2C_SPEED_100KHZ_BIT;
@@ -214,10 +214,10 @@ static void technisat_usb2_frontend_reset(struct usb_device *udev)
/* LED control */
enum technisat_usb2_led_state {
- LED_OFF,
- LED_BLINK,
- LED_ON,
- LED_UNDEFINED
+ TECH_LED_OFF,
+ TECH_LED_BLINK,
+ TECH_LED_ON,
+ TECH_LED_UNDEFINED
};
static int technisat_usb2_set_led(struct dvb_usb_device *d, int red, enum technisat_usb2_led_state state)
@@ -229,14 +229,14 @@ static int technisat_usb2_set_led(struct dvb_usb_device *d, int red, enum techni
0
};
- if (disable_led_control && state != LED_OFF)
+ if (disable_led_control && state != TECH_LED_OFF)
return 0;
switch (state) {
- case LED_ON:
+ case TECH_LED_ON:
led[1] = 0x82;
break;
- case LED_BLINK:
+ case TECH_LED_BLINK:
led[1] = 0x82;
if (red) {
led[2] = 0x02;
@@ -251,7 +251,7 @@ static int technisat_usb2_set_led(struct dvb_usb_device *d, int red, enum techni
break;
default:
- case LED_OFF:
+ case TECH_LED_OFF:
led[1] = 0x80;
break;
}
@@ -310,11 +310,11 @@ static void technisat_usb2_green_led_control(struct work_struct *work)
goto schedule;
if (ber > 1000)
- technisat_usb2_set_led(state->dev, 0, LED_BLINK);
+ technisat_usb2_set_led(state->dev, 0, TECH_LED_BLINK);
else
- technisat_usb2_set_led(state->dev, 0, LED_ON);
+ technisat_usb2_set_led(state->dev, 0, TECH_LED_ON);
} else
- technisat_usb2_set_led(state->dev, 0, LED_OFF);
+ technisat_usb2_set_led(state->dev, 0, TECH_LED_OFF);
}
schedule:
@@ -365,9 +365,9 @@ static int technisat_usb2_power_ctrl(struct dvb_usb_device *d, int level)
return 0;
/* green led is turned off in any case - will be turned on when tuning */
- technisat_usb2_set_led(d, 0, LED_OFF);
+ technisat_usb2_set_led(d, 0, TECH_LED_OFF);
/* red led is turned on all the time */
- technisat_usb2_set_led(d, 1, LED_ON);
+ technisat_usb2_set_led(d, 1, TECH_LED_ON);
return 0;
}
@@ -667,7 +667,7 @@ static int technisat_usb2_rc_query(struct dvb_usb_device *d)
return 0;
if (!disable_led_control)
- technisat_usb2_set_led(d, 1, LED_BLINK);
+ technisat_usb2_set_led(d, 1, TECH_LED_BLINK);
return 0;
}
diff --git a/drivers/media/usb/em28xx/Kconfig b/drivers/media/usb/em28xx/Kconfig
index ca5ee6aceb6..f5d7198753c 100644
--- a/drivers/media/usb/em28xx/Kconfig
+++ b/drivers/media/usb/em28xx/Kconfig
@@ -1,8 +1,12 @@
config VIDEO_EM28XX
- tristate "Empia EM28xx USB video capture support"
+ tristate "Empia EM28xx USB devices support"
depends on VIDEO_DEV && I2C
select VIDEO_TUNER
select VIDEO_TVEEPROM
+
+config VIDEO_EM28XX_V4L2
+ tristate "Empia EM28xx analog TV, video capture and/or webcam support"
+ depends on VIDEO_EM28XX
select VIDEOBUF2_VMALLOC
select VIDEO_SAA711X if MEDIA_SUBDRV_AUTOSELECT
select VIDEO_TVP5150 if MEDIA_SUBDRV_AUTOSELECT
@@ -49,6 +53,12 @@ config VIDEO_EM28XX_DVB
select DVB_MB86A20S if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_QT1010 if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_TDA18212 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_M88DS3103 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_M88TS2022 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_DRX39XYJ if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_SI2168 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_SI2157 if MEDIA_SUBDRV_AUTOSELECT
---help---
This adds support for DVB cards based on the
Empiatech em28xx chips.
diff --git a/drivers/media/usb/em28xx/Makefile b/drivers/media/usb/em28xx/Makefile
index ad6d4855794..3f850d5063d 100644
--- a/drivers/media/usb/em28xx/Makefile
+++ b/drivers/media/usb/em28xx/Makefile
@@ -1,10 +1,11 @@
-em28xx-y += em28xx-video.o em28xx-i2c.o em28xx-cards.o
-em28xx-y += em28xx-core.o em28xx-vbi.o em28xx-camera.o
+em28xx-y += em28xx-core.o em28xx-i2c.o em28xx-cards.o em28xx-camera.o
+em28xx-v4l-objs := em28xx-video.o em28xx-vbi.o
em28xx-alsa-objs := em28xx-audio.o
em28xx-rc-objs := em28xx-input.o
obj-$(CONFIG_VIDEO_EM28XX) += em28xx.o
+obj-$(CONFIG_VIDEO_EM28XX_V4L2) += em28xx-v4l.o
obj-$(CONFIG_VIDEO_EM28XX_ALSA) += em28xx-alsa.o
obj-$(CONFIG_VIDEO_EM28XX_DVB) += em28xx-dvb.o
obj-$(CONFIG_VIDEO_EM28XX_RC) += em28xx-rc.o
diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
index 2fdb66ee44a..e881ef7b644 100644
--- a/drivers/media/usb/em28xx/em28xx-audio.c
+++ b/drivers/media/usb/em28xx/em28xx-audio.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2006 Markus Rechberger <mrechberger@gmail.com>
*
- * Copyright (C) 2007-2011 Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (C) 2007-2014 Mauro Carvalho Chehab
* - Port to work with the in-kernel driver
* - Cleanups, fixes, alsa-controls, etc.
*
@@ -50,6 +50,9 @@ static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "activates debug info");
+#define EM28XX_MAX_AUDIO_BUFS 5
+#define EM28XX_MIN_AUDIO_PACKETS 64
+
#define dprintk(fmt, arg...) do { \
if (debug) \
printk(KERN_INFO "em28xx-audio %s: " fmt, \
@@ -63,17 +66,13 @@ static int em28xx_deinit_isoc_audio(struct em28xx *dev)
int i;
dprintk("Stopping isoc\n");
- for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
+ for (i = 0; i < dev->adev.num_urb; i++) {
+ struct urb *urb = dev->adev.urb[i];
+
if (!irqs_disabled())
- usb_kill_urb(dev->adev.urb[i]);
+ usb_kill_urb(urb);
else
- usb_unlink_urb(dev->adev.urb[i]);
-
- usb_free_urb(dev->adev.urb[i]);
- dev->adev.urb[i] = NULL;
-
- kfree(dev->adev.transfer_buffer[i]);
- dev->adev.transfer_buffer[i] = NULL;
+ usb_unlink_urb(urb);
}
return 0;
@@ -91,6 +90,12 @@ static void em28xx_audio_isocirq(struct urb *urb)
struct snd_pcm_substream *substream;
struct snd_pcm_runtime *runtime;
+ if (dev->disconnected) {
+ dprintk("device disconnected while streaming. URB status=%d.\n", urb->status);
+ atomic_set(&dev->adev.stream_started, 0);
+ return;
+ }
+
switch (urb->status) {
case 0: /* success */
case -ETIMEDOUT: /* NAK */
@@ -104,7 +109,7 @@ static void em28xx_audio_isocirq(struct urb *urb)
break;
}
- if (atomic_read(&dev->stream_started) == 0)
+ if (atomic_read(&dev->adev.stream_started) == 0)
return;
if (dev->adev.capture_pcm_substream) {
@@ -158,65 +163,29 @@ static void em28xx_audio_isocirq(struct urb *urb)
urb->status = 0;
status = usb_submit_urb(urb, GFP_ATOMIC);
- if (status < 0) {
+ if (status < 0)
em28xx_errdev("resubmit of audio urb failed (error=%i)\n",
status);
- }
return;
}
static int em28xx_init_audio_isoc(struct em28xx *dev)
{
int i, errCode;
- const int sb_size = EM28XX_NUM_AUDIO_PACKETS *
- EM28XX_AUDIO_MAX_PACKET_SIZE;
dprintk("Starting isoc transfers\n");
- for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
- struct urb *urb;
- int j, k;
-
- dev->adev.transfer_buffer[i] = kmalloc(sb_size, GFP_ATOMIC);
- if (!dev->adev.transfer_buffer[i])
- return -ENOMEM;
+ /* Start streaming */
+ for (i = 0; i < dev->adev.num_urb; i++) {
+ memset(dev->adev.transfer_buffer[i], 0x80,
+ dev->adev.urb[i]->transfer_buffer_length);
- memset(dev->adev.transfer_buffer[i], 0x80, sb_size);
- urb = usb_alloc_urb(EM28XX_NUM_AUDIO_PACKETS, GFP_ATOMIC);
- if (!urb) {
- em28xx_errdev("usb_alloc_urb failed!\n");
- for (j = 0; j < i; j++) {
- usb_free_urb(dev->adev.urb[j]);
- kfree(dev->adev.transfer_buffer[j]);
- }
- return -ENOMEM;
- }
-
- urb->dev = dev->udev;
- urb->context = dev;
- urb->pipe = usb_rcvisocpipe(dev->udev, EM28XX_EP_AUDIO);
- urb->transfer_flags = URB_ISO_ASAP;
- urb->transfer_buffer = dev->adev.transfer_buffer[i];
- urb->interval = 1;
- urb->complete = em28xx_audio_isocirq;
- urb->number_of_packets = EM28XX_NUM_AUDIO_PACKETS;
- urb->transfer_buffer_length = sb_size;
-
- for (j = k = 0; j < EM28XX_NUM_AUDIO_PACKETS;
- j++, k += EM28XX_AUDIO_MAX_PACKET_SIZE) {
- urb->iso_frame_desc[j].offset = k;
- urb->iso_frame_desc[j].length =
- EM28XX_AUDIO_MAX_PACKET_SIZE;
- }
- dev->adev.urb[i] = urb;
- }
-
- for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
errCode = usb_submit_urb(dev->adev.urb[i], GFP_ATOMIC);
if (errCode) {
- em28xx_errdev("submit of audio urb failed\n");
+ em28xx_errdev("submit of audio urb failed (error=%i)\n",
+ errCode);
em28xx_deinit_isoc_audio(dev);
- atomic_set(&dev->stream_started, 0);
+ atomic_set(&dev->adev.stream_started, 0);
return errCode;
}
@@ -255,15 +224,26 @@ static struct snd_pcm_hardware snd_em28xx_hw_capture = {
.formats = SNDRV_PCM_FMTBIT_S16_LE,
- .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_KNOT,
+ .rates = SNDRV_PCM_RATE_48000,
.rate_min = 48000,
.rate_max = 48000,
.channels_min = 2,
.channels_max = 2,
.buffer_bytes_max = 62720 * 8, /* just about the value in usbaudio.c */
- .period_bytes_min = 64, /* 12544/2, */
- .period_bytes_max = 12544,
+
+
+ /*
+ * The period is 12.288 bytes. Allow a 10% of variation along its
+ * value, in order to avoid overruns/underruns due to some clock
+ * drift.
+ *
+ * FIXME: This period assumes 64 packets, and a 48000 PCM rate.
+ * Calculate it dynamically.
+ */
+ .period_bytes_min = 11059,
+ .period_bytes_max = 13516,
+
.periods_min = 2,
.periods_max = 98, /* 12544, */
};
@@ -272,9 +252,7 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream)
{
struct em28xx *dev = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
- int ret = 0;
-
- dprintk("opening device and trying to acquire exclusive lock\n");
+ int nonblock, ret = 0;
if (!dev) {
em28xx_err("BUG: em28xx can't find device struct."
@@ -282,29 +260,59 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream)
return -ENODEV;
}
+ if (dev->disconnected)
+ return -ENODEV;
+
+ dprintk("opening device and trying to acquire exclusive lock\n");
+
+ nonblock = !!(substream->f_flags & O_NONBLOCK);
+ if (nonblock) {
+ if (!mutex_trylock(&dev->lock))
+ return -EAGAIN;
+ } else
+ mutex_lock(&dev->lock);
+
runtime->hw = snd_em28xx_hw_capture;
- if ((dev->alt == 0 || dev->audio_ifnum) && dev->adev.users == 0) {
- if (dev->audio_ifnum)
- dev->alt = 1;
- else
- dev->alt = 7;
- dprintk("changing alternate number on interface %d to %d\n",
- dev->audio_ifnum, dev->alt);
- usb_set_interface(dev->udev, dev->audio_ifnum, dev->alt);
+ if (dev->adev.users == 0) {
+ if (dev->alt == 0 || dev->is_audio_only) {
+ if (dev->is_audio_only)
+ /* audio is on a separate interface */
+ dev->alt = 1;
+ else
+ /* audio is on the same interface as video */
+ dev->alt = 7;
+ /*
+ * FIXME: The intention seems to be to select
+ * the alt setting with the largest
+ * wMaxPacketSize for the video endpoint.
+ * At least dev->alt should be used instead, but
+ * we should probably not touch it at all if it
+ * is already >0, because wMaxPacketSize of the
+ * audio endpoints seems to be the same for all.
+ */
+ dprintk("changing alternate number on interface %d to %d\n",
+ dev->ifnum, dev->alt);
+ usb_set_interface(dev->udev, dev->ifnum, dev->alt);
+ }
/* Sets volume, mute, etc */
dev->mute = 0;
- mutex_lock(&dev->lock);
ret = em28xx_audio_analog_set(dev);
if (ret < 0)
goto err;
-
- dev->adev.users++;
- mutex_unlock(&dev->lock);
}
+ kref_get(&dev->ref);
+ dev->adev.users++;
+ mutex_unlock(&dev->lock);
+
+ /* Dynamically adjust the period size */
snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+ snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
+ dev->adev.period * 95 / 100,
+ dev->adev.period * 105 / 100);
+
dev->adev.capture_pcm_substream = substream;
return 0;
@@ -324,9 +332,9 @@ static int snd_em28xx_pcm_close(struct snd_pcm_substream *substream)
dev->mute = 1;
mutex_lock(&dev->lock);
dev->adev.users--;
- if (atomic_read(&dev->stream_started) > 0) {
- atomic_set(&dev->stream_started, 0);
- schedule_work(&dev->wq_trigger);
+ if (atomic_read(&dev->adev.stream_started) > 0) {
+ atomic_set(&dev->adev.stream_started, 0);
+ schedule_work(&dev->adev.wq_trigger);
}
em28xx_audio_analog_set(dev);
@@ -336,6 +344,7 @@ static int snd_em28xx_pcm_close(struct snd_pcm_substream *substream)
substream->runtime->dma_area = NULL;
}
mutex_unlock(&dev->lock);
+ kref_put(&dev->ref, em28xx_free_device);
return 0;
}
@@ -344,6 +353,10 @@ static int snd_em28xx_hw_capture_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params)
{
int ret;
+ struct em28xx *dev = snd_pcm_substream_chip(substream);
+
+ if (dev->disconnected)
+ return -ENODEV;
dprintk("Setting capture parameters\n");
@@ -368,12 +381,13 @@ static int snd_em28xx_hw_capture_params(struct snd_pcm_substream *substream,
static int snd_em28xx_hw_capture_free(struct snd_pcm_substream *substream)
{
struct em28xx *dev = snd_pcm_substream_chip(substream);
+ struct em28xx_audio *adev = &dev->adev;
dprintk("Stop capture, if needed\n");
- if (atomic_read(&dev->stream_started) > 0) {
- atomic_set(&dev->stream_started, 0);
- schedule_work(&dev->wq_trigger);
+ if (atomic_read(&adev->stream_started) > 0) {
+ atomic_set(&adev->stream_started, 0);
+ schedule_work(&adev->wq_trigger);
}
return 0;
@@ -383,6 +397,9 @@ static int snd_em28xx_prepare(struct snd_pcm_substream *substream)
{
struct em28xx *dev = snd_pcm_substream_chip(substream);
+ if (dev->disconnected)
+ return -ENODEV;
+
dev->adev.hwptr_done_capture = 0;
dev->adev.capture_transfer_done = 0;
@@ -391,9 +408,11 @@ static int snd_em28xx_prepare(struct snd_pcm_substream *substream)
static void audio_trigger(struct work_struct *work)
{
- struct em28xx *dev = container_of(work, struct em28xx, wq_trigger);
+ struct em28xx_audio *adev =
+ container_of(work, struct em28xx_audio, wq_trigger);
+ struct em28xx *dev = container_of(adev, struct em28xx, adev);
- if (atomic_read(&dev->stream_started)) {
+ if (atomic_read(&adev->stream_started)) {
dprintk("starting capture");
em28xx_init_audio_isoc(dev);
} else {
@@ -408,21 +427,24 @@ static int snd_em28xx_capture_trigger(struct snd_pcm_substream *substream,
struct em28xx *dev = snd_pcm_substream_chip(substream);
int retval = 0;
+ if (dev->disconnected)
+ return -ENODEV;
+
switch (cmd) {
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */
case SNDRV_PCM_TRIGGER_RESUME: /* fall through */
case SNDRV_PCM_TRIGGER_START:
- atomic_set(&dev->stream_started, 1);
+ atomic_set(&dev->adev.stream_started, 1);
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */
case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */
case SNDRV_PCM_TRIGGER_STOP:
- atomic_set(&dev->stream_started, 0);
+ atomic_set(&dev->adev.stream_started, 0);
break;
default:
retval = -EINVAL;
}
- schedule_work(&dev->wq_trigger);
+ schedule_work(&dev->adev.wq_trigger);
return retval;
}
@@ -434,6 +456,9 @@ static snd_pcm_uframes_t snd_em28xx_capture_pointer(struct snd_pcm_substream
snd_pcm_uframes_t hwptr_done;
dev = snd_pcm_substream_chip(substream);
+ if (dev->disconnected)
+ return SNDRV_PCM_POS_XRUN;
+
spin_lock_irqsave(&dev->adev.slock, flags);
hwptr_done = dev->adev.hwptr_done_capture;
spin_unlock_irqrestore(&dev->adev.slock, flags);
@@ -455,6 +480,11 @@ static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs,
static int em28xx_vol_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *info)
{
+ struct em28xx *dev = snd_kcontrol_chip(kcontrol);
+
+ if (dev->disconnected)
+ return -ENODEV;
+
info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
info->count = 2;
info->value.integer.min = 0;
@@ -467,11 +497,22 @@ static int em28xx_vol_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *value)
{
struct em28xx *dev = snd_kcontrol_chip(kcontrol);
+ struct snd_pcm_substream *substream = dev->adev.capture_pcm_substream;
u16 val = (0x1f - (value->value.integer.value[0] & 0x1f)) |
(0x1f - (value->value.integer.value[1] & 0x1f)) << 8;
+ int nonblock = 0;
int rc;
- mutex_lock(&dev->lock);
+ if (dev->disconnected)
+ return -ENODEV;
+
+ if (substream)
+ nonblock = !!(substream->f_flags & O_NONBLOCK);
+ if (nonblock) {
+ if (!mutex_trylock(&dev->lock))
+ return -EAGAIN;
+ } else
+ mutex_lock(&dev->lock);
rc = em28xx_read_ac97(dev, kcontrol->private_value);
if (rc < 0)
goto err;
@@ -496,9 +537,20 @@ static int em28xx_vol_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *value)
{
struct em28xx *dev = snd_kcontrol_chip(kcontrol);
+ struct snd_pcm_substream *substream = dev->adev.capture_pcm_substream;
+ int nonblock = 0;
int val;
- mutex_lock(&dev->lock);
+ if (dev->disconnected)
+ return -ENODEV;
+
+ if (substream)
+ nonblock = !!(substream->f_flags & O_NONBLOCK);
+ if (nonblock) {
+ if (!mutex_trylock(&dev->lock))
+ return -EAGAIN;
+ } else
+ mutex_lock(&dev->lock);
val = em28xx_read_ac97(dev, kcontrol->private_value);
mutex_unlock(&dev->lock);
if (val < 0)
@@ -520,9 +572,20 @@ static int em28xx_vol_put_mute(struct snd_kcontrol *kcontrol,
{
struct em28xx *dev = snd_kcontrol_chip(kcontrol);
u16 val = value->value.integer.value[0];
+ struct snd_pcm_substream *substream = dev->adev.capture_pcm_substream;
+ int nonblock = 0;
int rc;
- mutex_lock(&dev->lock);
+ if (dev->disconnected)
+ return -ENODEV;
+
+ if (substream)
+ nonblock = !!(substream->f_flags & O_NONBLOCK);
+ if (nonblock) {
+ if (!mutex_trylock(&dev->lock))
+ return -EAGAIN;
+ } else
+ mutex_lock(&dev->lock);
rc = em28xx_read_ac97(dev, kcontrol->private_value);
if (rc < 0)
goto err;
@@ -550,9 +613,20 @@ static int em28xx_vol_get_mute(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *value)
{
struct em28xx *dev = snd_kcontrol_chip(kcontrol);
+ struct snd_pcm_substream *substream = dev->adev.capture_pcm_substream;
+ int nonblock = 0;
int val;
- mutex_lock(&dev->lock);
+ if (dev->disconnected)
+ return -ENODEV;
+
+ if (substream)
+ nonblock = !!(substream->f_flags & O_NONBLOCK);
+ if (nonblock) {
+ if (!mutex_trylock(&dev->lock))
+ return -EAGAIN;
+ } else
+ mutex_lock(&dev->lock);
val = em28xx_read_ac97(dev, kcontrol->private_value);
mutex_unlock(&dev->lock);
if (val < 0)
@@ -634,49 +708,230 @@ static struct snd_pcm_ops snd_em28xx_pcm_capture = {
.page = snd_pcm_get_vmalloc_page,
};
+static void em28xx_audio_free_urb(struct em28xx *dev)
+{
+ int i;
+
+ for (i = 0; i < dev->adev.num_urb; i++) {
+ struct urb *urb = dev->adev.urb[i];
+
+ if (!urb)
+ continue;
+
+ usb_free_coherent(dev->udev, urb->transfer_buffer_length,
+ dev->adev.transfer_buffer[i],
+ urb->transfer_dma);
+
+ usb_free_urb(urb);
+ }
+ kfree(dev->adev.urb);
+ kfree(dev->adev.transfer_buffer);
+ dev->adev.num_urb = 0;
+}
+
+/* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */
+static int em28xx_audio_ep_packet_size(struct usb_device *udev,
+ struct usb_endpoint_descriptor *e)
+{
+ int size = le16_to_cpu(e->wMaxPacketSize);
+
+ if (udev->speed == USB_SPEED_HIGH)
+ return (size & 0x7ff) * (1 + (((size) >> 11) & 0x03));
+
+ return size & 0x7ff;
+}
+
+static int em28xx_audio_urb_init(struct em28xx *dev)
+{
+ struct usb_interface *intf;
+ struct usb_endpoint_descriptor *e, *ep = NULL;
+ int i, ep_size, interval, num_urb, npackets;
+ int urb_size, bytes_per_transfer;
+ u8 alt;
+
+ if (dev->ifnum)
+ alt = 1;
+ else
+ alt = 7;
+
+ intf = usb_ifnum_to_if(dev->udev, dev->ifnum);
+
+ if (intf->num_altsetting <= alt) {
+ em28xx_errdev("alt %d doesn't exist on interface %d\n",
+ dev->ifnum, alt);
+ return -ENODEV;
+ }
+
+ for (i = 0; i < intf->altsetting[alt].desc.bNumEndpoints; i++) {
+ e = &intf->altsetting[alt].endpoint[i].desc;
+ if (!usb_endpoint_dir_in(e))
+ continue;
+ if (e->bEndpointAddress == EM28XX_EP_AUDIO) {
+ ep = e;
+ break;
+ }
+ }
+
+ if (!ep) {
+ em28xx_errdev("Couldn't find an audio endpoint");
+ return -ENODEV;
+ }
+
+ ep_size = em28xx_audio_ep_packet_size(dev->udev, ep);
+ interval = 1 << (ep->bInterval - 1);
+
+ em28xx_info("Endpoint 0x%02x %s on intf %d alt %d interval = %d, size %d\n",
+ EM28XX_EP_AUDIO, usb_speed_string(dev->udev->speed),
+ dev->ifnum, alt,
+ interval,
+ ep_size);
+
+ /* Calculate the number and size of URBs to better fit the audio samples */
+
+ /*
+ * Estimate the number of bytes per DMA transfer.
+ *
+ * This is given by the bit rate (for now, only 48000 Hz) multiplied
+ * by 2 channels and 2 bytes/sample divided by the number of microframe
+ * intervals and by the microframe rate (125 us)
+ */
+ bytes_per_transfer = DIV_ROUND_UP(48000 * 2 * 2, 125 * interval);
+
+ /*
+ * Estimate the number of transfer URBs. Don't let it go past the
+ * maximum number of URBs that is known to be supported by the device.
+ */
+ num_urb = DIV_ROUND_UP(bytes_per_transfer, ep_size);
+ if (num_urb > EM28XX_MAX_AUDIO_BUFS)
+ num_urb = EM28XX_MAX_AUDIO_BUFS;
+
+ /*
+ * Now that we know the number of bytes per transfer and the number of
+ * URBs, estimate the typical size of an URB, in order to adjust the
+ * minimal number of packets.
+ */
+ urb_size = bytes_per_transfer / num_urb;
+
+ /*
+ * Now, calculate the amount of audio packets to be filled on each
+ * URB. In order to preserve the old behaviour, use a minimal
+ * threshold for this value.
+ */
+ npackets = EM28XX_MIN_AUDIO_PACKETS;
+ if (urb_size > ep_size * npackets)
+ npackets = DIV_ROUND_UP(urb_size, ep_size);
+
+ em28xx_info("Number of URBs: %d, with %d packets and %d size",
+ num_urb, npackets, urb_size);
+
+ /* Estimate the bytes per period */
+ dev->adev.period = urb_size * npackets;
+
+ /* Allocate space to store the number of URBs to be used */
+
+ dev->adev.transfer_buffer = kcalloc(num_urb,
+ sizeof(*dev->adev.transfer_buffer),
+ GFP_ATOMIC);
+ if (!dev->adev.transfer_buffer) {
+ return -ENOMEM;
+ }
+
+ dev->adev.urb = kcalloc(num_urb, sizeof(*dev->adev.urb), GFP_ATOMIC);
+ if (!dev->adev.urb) {
+ kfree(dev->adev.transfer_buffer);
+ return -ENOMEM;
+ }
+
+ /* Alloc memory for each URB and for each transfer buffer */
+ dev->adev.num_urb = num_urb;
+ for (i = 0; i < num_urb; i++) {
+ struct urb *urb;
+ int j, k;
+ void *buf;
+
+ urb = usb_alloc_urb(npackets, GFP_ATOMIC);
+ if (!urb) {
+ em28xx_errdev("usb_alloc_urb failed!\n");
+ em28xx_audio_free_urb(dev);
+ return -ENOMEM;
+ }
+ dev->adev.urb[i] = urb;
+
+ buf = usb_alloc_coherent(dev->udev, npackets * ep_size, GFP_ATOMIC,
+ &urb->transfer_dma);
+ if (!buf) {
+ em28xx_errdev("usb_alloc_coherent failed!\n");
+ em28xx_audio_free_urb(dev);
+ return -ENOMEM;
+ }
+ dev->adev.transfer_buffer[i] = buf;
+
+ urb->dev = dev->udev;
+ urb->context = dev;
+ urb->pipe = usb_rcvisocpipe(dev->udev, EM28XX_EP_AUDIO);
+ urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
+ urb->transfer_buffer = buf;
+ urb->interval = interval;
+ urb->complete = em28xx_audio_isocirq;
+ urb->number_of_packets = npackets;
+ urb->transfer_buffer_length = ep_size * npackets;
+
+ for (j = k = 0; j < npackets; j++, k += ep_size) {
+ urb->iso_frame_desc[j].offset = k;
+ urb->iso_frame_desc[j].length = ep_size;
+ }
+ }
+
+ return 0;
+}
+
static int em28xx_audio_init(struct em28xx *dev)
{
struct em28xx_audio *adev = &dev->adev;
struct snd_pcm *pcm;
struct snd_card *card;
static int devnr;
- int err;
+ int err;
- if (!dev->has_alsa_audio || dev->audio_ifnum < 0) {
+ if (!dev->has_alsa_audio) {
/* This device does not support the extension (in this case
the device is expecting the snd-usb-audio module or
doesn't have analog audio support at all) */
return 0;
}
- printk(KERN_INFO "em28xx-audio.c: probing for em28xx Audio Vendor Class\n");
+ em28xx_info("Binding audio extension\n");
+
+ kref_get(&dev->ref);
+
printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus "
"Rechberger\n");
- printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2007-2011 Mauro Carvalho Chehab\n");
+ printk(KERN_INFO
+ "em28xx-audio.c: Copyright (C) 2007-2014 Mauro Carvalho Chehab\n");
- err = snd_card_create(index[devnr], "Em28xx Audio", THIS_MODULE, 0,
- &card);
+ err = snd_card_new(&dev->udev->dev, index[devnr], "Em28xx Audio",
+ THIS_MODULE, 0, &card);
if (err < 0)
return err;
spin_lock_init(&adev->slock);
+ adev->sndcard = card;
+ adev->udev = dev->udev;
+
err = snd_pcm_new(card, "Em28xx Audio", 0, 0, 1, &pcm);
- if (err < 0) {
- snd_card_free(card);
- return err;
- }
+ if (err < 0)
+ goto card_free;
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_em28xx_pcm_capture);
pcm->info_flags = 0;
pcm->private_data = dev;
strcpy(pcm->name, "Empia 28xx Capture");
- snd_card_set_dev(card, &dev->udev->dev);
strcpy(card->driver, "Em28xx-Audio");
strcpy(card->shortname, "Em28xx Audio");
strcpy(card->longname, "Empia Em28xx Audio");
- INIT_WORK(&dev->wq_trigger, audio_trigger);
+ INIT_WORK(&adev->wq_trigger, audio_trigger);
if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
em28xx_cvol_new(card, dev, "Video", AC97_VIDEO);
@@ -694,15 +949,25 @@ static int em28xx_audio_init(struct em28xx *dev)
em28xx_cvol_new(card, dev, "Surround", AC97_SURROUND_MASTER);
}
+ err = em28xx_audio_urb_init(dev);
+ if (err)
+ goto card_free;
+
err = snd_card_register(card);
- if (err < 0) {
- snd_card_free(card);
- return err;
- }
- adev->sndcard = card;
- adev->udev = dev->udev;
+ if (err < 0)
+ goto urb_free;
+ em28xx_info("Audio extension successfully initialized\n");
return 0;
+
+urb_free:
+ em28xx_audio_free_urb(dev);
+
+card_free:
+ snd_card_free(card);
+ adev->sndcard = NULL;
+
+ return err;
}
static int em28xx_audio_fini(struct em28xx *dev)
@@ -710,18 +975,54 @@ static int em28xx_audio_fini(struct em28xx *dev)
if (dev == NULL)
return 0;
- if (dev->has_alsa_audio != 1) {
+ if (!dev->has_alsa_audio) {
/* This device does not support the extension (in this case
the device is expecting the snd-usb-audio module or
doesn't have analog audio support at all) */
return 0;
}
+ em28xx_info("Closing audio extension");
+
if (dev->adev.sndcard) {
+ snd_card_disconnect(dev->adev.sndcard);
+ flush_work(&dev->adev.wq_trigger);
+
+ em28xx_audio_free_urb(dev);
+
snd_card_free(dev->adev.sndcard);
dev->adev.sndcard = NULL;
}
+ kref_put(&dev->ref, em28xx_free_device);
+ return 0;
+}
+
+static int em28xx_audio_suspend(struct em28xx *dev)
+{
+ if (dev == NULL)
+ return 0;
+
+ if (!dev->has_alsa_audio)
+ return 0;
+
+ em28xx_info("Suspending audio extension");
+ em28xx_deinit_isoc_audio(dev);
+ atomic_set(&dev->adev.stream_started, 0);
+ return 0;
+}
+
+static int em28xx_audio_resume(struct em28xx *dev)
+{
+ if (dev == NULL)
+ return 0;
+
+ if (!dev->has_alsa_audio)
+ return 0;
+
+ em28xx_info("Resuming audio extension");
+ /* Nothing to do other than schedule_work() ?? */
+ schedule_work(&dev->adev.wq_trigger);
return 0;
}
@@ -730,6 +1031,8 @@ static struct em28xx_ops audio_ops = {
.name = "Em28xx Audio Extension",
.init = em28xx_audio_init,
.fini = em28xx_audio_fini,
+ .suspend = em28xx_audio_suspend,
+ .resume = em28xx_audio_resume,
};
static int __init em28xx_alsa_register(void)
@@ -744,8 +1047,9 @@ static void __exit em28xx_alsa_unregister(void)
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Markus Rechberger <mrechberger@gmail.com>");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
-MODULE_DESCRIPTION("Em28xx Audio driver");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
+MODULE_DESCRIPTION(DRIVER_DESC " - audio interface");
+MODULE_VERSION(EM28XX_VERSION);
module_init(em28xx_alsa_register);
module_exit(em28xx_alsa_unregister);
diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c
index 73cc50afa5e..12d4c0326e3 100644
--- a/drivers/media/usb/em28xx/em28xx-camera.c
+++ b/drivers/media/usb/em28xx/em28xx-camera.c
@@ -22,6 +22,7 @@
#include <linux/i2c.h>
#include <media/soc_camera.h>
#include <media/mt9v011.h>
+#include <media/v4l2-clk.h>
#include <media/v4l2-common.h>
#include "em28xx.h"
@@ -47,6 +48,7 @@ static struct soc_camera_link camlink = {
.bus_id = 0,
.flags = 0,
.module_name = "em28xx",
+ .unbalanced_power = true,
};
@@ -118,7 +120,7 @@ static int em28xx_probe_sensor_micron(struct em28xx *dev)
reg = 0x00;
ret = i2c_master_send(&client, &reg, 1);
if (ret < 0) {
- if (ret != -ENODEV)
+ if (ret != -ENXIO)
em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n",
client.addr << 1, ret);
continue;
@@ -216,7 +218,7 @@ static int em28xx_probe_sensor_omnivision(struct em28xx *dev)
reg = 0x1c;
ret = i2c_smbus_read_byte_data(&client, reg);
if (ret < 0) {
- if (ret != -ENODEV)
+ if (ret != -ENXIO)
em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n",
client.addr << 1, ret);
continue;
@@ -325,18 +327,30 @@ int em28xx_detect_sensor(struct em28xx *dev)
int em28xx_init_camera(struct em28xx *dev)
{
+ char clk_name[V4L2_SUBDEV_NAME_SIZE];
+ struct i2c_client *client = &dev->i2c_client[dev->def_i2c_bus];
+ struct i2c_adapter *adap = &dev->i2c_adap[dev->def_i2c_bus];
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
+ int ret = 0;
+
+ v4l2_clk_name_i2c(clk_name, sizeof(clk_name),
+ i2c_adapter_id(adap), client->addr);
+ v4l2->clk = v4l2_clk_register_fixed(clk_name, "mclk", -EINVAL);
+ if (IS_ERR(v4l2->clk))
+ return PTR_ERR(v4l2->clk);
+
switch (dev->em28xx_sensor) {
case EM28XX_MT9V011:
{
struct mt9v011_platform_data pdata;
struct i2c_board_info mt9v011_info = {
.type = "mt9v011",
- .addr = dev->i2c_client[dev->def_i2c_bus].addr,
+ .addr = client->addr,
.platform_data = &pdata,
};
- dev->sensor_xres = 640;
- dev->sensor_yres = 480;
+ v4l2->sensor_xres = 640;
+ v4l2->sensor_yres = 480;
/*
* FIXME: mt9v011 uses I2S speed as xtal clk - at least with
@@ -349,40 +363,41 @@ int em28xx_init_camera(struct em28xx *dev)
*/
dev->board.xclk = EM28XX_XCLK_FREQUENCY_4_3MHZ;
em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk);
- dev->sensor_xtal = 4300000;
- pdata.xtal = dev->sensor_xtal;
+ v4l2->sensor_xtal = 4300000;
+ pdata.xtal = v4l2->sensor_xtal;
if (NULL ==
- v4l2_i2c_new_subdev_board(&dev->v4l2_dev,
- &dev->i2c_adap[dev->def_i2c_bus],
- &mt9v011_info, NULL))
- return -ENODEV;
+ v4l2_i2c_new_subdev_board(&dev->v4l2->v4l2_dev, adap,
+ &mt9v011_info, NULL)) {
+ ret = -ENODEV;
+ break;
+ }
/* probably means GRGB 16 bit bayer */
- dev->vinmode = 0x0d;
- dev->vinctl = 0x00;
+ v4l2->vinmode = 0x0d;
+ v4l2->vinctl = 0x00;
break;
}
case EM28XX_MT9M001:
- dev->sensor_xres = 1280;
- dev->sensor_yres = 1024;
+ v4l2->sensor_xres = 1280;
+ v4l2->sensor_yres = 1024;
em28xx_initialize_mt9m001(dev);
/* probably means BGGR 16 bit bayer */
- dev->vinmode = 0x0c;
- dev->vinctl = 0x00;
+ v4l2->vinmode = 0x0c;
+ v4l2->vinctl = 0x00;
break;
case EM28XX_MT9M111:
- dev->sensor_xres = 640;
- dev->sensor_yres = 512;
+ v4l2->sensor_xres = 640;
+ v4l2->sensor_yres = 512;
dev->board.xclk = EM28XX_XCLK_FREQUENCY_48MHZ;
em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk);
em28xx_initialize_mt9m111(dev);
- dev->vinmode = 0x0a;
- dev->vinctl = 0x00;
+ v4l2->vinmode = 0x0a;
+ v4l2->vinctl = 0x00;
break;
case EM28XX_OV2640:
@@ -391,7 +406,7 @@ int em28xx_init_camera(struct em28xx *dev)
struct i2c_board_info ov2640_info = {
.type = "ov2640",
.flags = I2C_CLIENT_SCCB,
- .addr = dev->i2c_client[dev->def_i2c_bus].addr,
+ .addr = client->addr,
.platform_data = &camlink,
};
struct v4l2_mbus_framefmt fmt;
@@ -404,13 +419,16 @@ int em28xx_init_camera(struct em28xx *dev)
* - adjust bridge xclk
* - disable 16 bit (12 bit) output formats on high resolutions
*/
- dev->sensor_xres = 640;
- dev->sensor_yres = 480;
+ v4l2->sensor_xres = 640;
+ v4l2->sensor_yres = 480;
subdev =
- v4l2_i2c_new_subdev_board(&dev->v4l2_dev,
- &dev->i2c_adap[dev->def_i2c_bus],
+ v4l2_i2c_new_subdev_board(&dev->v4l2->v4l2_dev, adap,
&ov2640_info, NULL);
+ if (NULL == subdev) {
+ ret = -ENODEV;
+ break;
+ }
fmt.code = V4L2_MBUS_FMT_YUYV8_2X8;
fmt.width = 640;
@@ -420,15 +438,21 @@ int em28xx_init_camera(struct em28xx *dev)
/* NOTE: for UXGA=1600x1200 switch to 12MHz */
dev->board.xclk = EM28XX_XCLK_FREQUENCY_24MHZ;
em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk);
- dev->vinmode = 0x08;
- dev->vinctl = 0x00;
+ v4l2->vinmode = 0x08;
+ v4l2->vinctl = 0x00;
break;
}
case EM28XX_NOSENSOR:
default:
- return -EINVAL;
+ ret = -EINVAL;
}
- return 0;
+ if (ret < 0) {
+ v4l2_clk_unregister_fixed(v4l2->clk);
+ v4l2->clk = NULL;
+ }
+
+ return ret;
}
+EXPORT_SYMBOL_GPL(em28xx_init_camera);
diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
index dc65742c4bb..15ad4704555 100644
--- a/drivers/media/usb/em28xx/em28xx-cards.c
+++ b/drivers/media/usb/em28xx/em28xx-cards.c
@@ -66,7 +66,7 @@ MODULE_PARM_DESC(usb_xfer_mode,
/* Bitmask marking allocated devices from 0 to EM28XX_MAXBOARDS - 1 */
-static unsigned long em28xx_devused;
+static DECLARE_BITMAP(em28xx_devused, EM28XX_MAXBOARDS);
struct em28xx_hash_table {
unsigned long hash;
@@ -95,8 +95,8 @@ static struct em28xx_reg_seq default_digital[] = {
/* Board Hauppauge WinTV HVR 900 analog */
static struct em28xx_reg_seq hauppauge_wintv_hvr_900_analog[] = {
{EM2820_R08_GPIO_CTRL, 0x2d, ~EM_GPIO_4, 10},
- {0x05, 0xff, 0x10, 10},
- { -1, -1, -1, -1},
+ { 0x05, 0xff, 0x10, 10},
+ { -1, -1, -1, -1},
};
/* Board Hauppauge WinTV HVR 900 digital */
@@ -104,20 +104,20 @@ static struct em28xx_reg_seq hauppauge_wintv_hvr_900_digital[] = {
{EM2820_R08_GPIO_CTRL, 0x2e, ~EM_GPIO_4, 10},
{EM2880_R04_GPO, 0x04, 0x0f, 10},
{EM2880_R04_GPO, 0x0c, 0x0f, 10},
- { -1, -1, -1, -1},
+ { -1, -1, -1, -1},
};
/* Board Hauppauge WinTV HVR 900 (R2) digital */
static struct em28xx_reg_seq hauppauge_wintv_hvr_900R2_digital[] = {
{EM2820_R08_GPIO_CTRL, 0x2e, ~EM_GPIO_4, 10},
{EM2880_R04_GPO, 0x0c, 0x0f, 10},
- { -1, -1, -1, -1},
+ { -1, -1, -1, -1},
};
/* Boards - EM2880 MSI DIGIVOX AD and EM2880_BOARD_MSI_DIGIVOX_AD_II */
static struct em28xx_reg_seq em2880_msi_digivox_ad_analog[] = {
- {EM2820_R08_GPIO_CTRL, 0x69, ~EM_GPIO_4, 10},
- { -1, -1, -1, -1},
+ {EM2820_R08_GPIO_CTRL, 0x69, ~EM_GPIO_4, 10},
+ { -1, -1, -1, -1},
};
/* Boards - EM2880 MSI DIGIVOX AD and EM2880_BOARD_MSI_DIGIVOX_AD_II */
@@ -132,7 +132,7 @@ static struct em28xx_reg_seq em2882_kworld_315u_digital[] = {
{EM2880_R04_GPO, 0x04, 0xff, 10},
{EM2880_R04_GPO, 0x0c, 0xff, 10},
{EM2820_R08_GPIO_CTRL, 0x7e, 0xff, 10},
- { -1, -1, -1, -1},
+ { -1, -1, -1, -1},
};
static struct em28xx_reg_seq em2882_kworld_315u_tuner_gpio[] = {
@@ -140,19 +140,19 @@ static struct em28xx_reg_seq em2882_kworld_315u_tuner_gpio[] = {
{EM2880_R04_GPO, 0x0c, 0xff, 10},
{EM2880_R04_GPO, 0x08, 0xff, 10},
{EM2880_R04_GPO, 0x0c, 0xff, 10},
- { -1, -1, -1, -1},
+ { -1, -1, -1, -1},
};
static struct em28xx_reg_seq kworld_330u_analog[] = {
{EM2820_R08_GPIO_CTRL, 0x6d, ~EM_GPIO_4, 10},
{EM2880_R04_GPO, 0x00, 0xff, 10},
- { -1, -1, -1, -1},
+ { -1, -1, -1, -1},
};
static struct em28xx_reg_seq kworld_330u_digital[] = {
{EM2820_R08_GPIO_CTRL, 0x6e, ~EM_GPIO_4, 10},
{EM2880_R04_GPO, 0x08, 0xff, 10},
- { -1, -1, -1, -1},
+ { -1, -1, -1, -1},
};
/* Evga inDtube
@@ -170,11 +170,11 @@ static struct em28xx_reg_seq evga_indtube_digital[] = {
{EM2820_R08_GPIO_CTRL, 0x7a, 0xff, 1},
{EM2880_R04_GPO, 0x04, 0xff, 10},
{EM2880_R04_GPO, 0x0c, 0xff, 1},
- { -1, -1, -1, -1},
+ { -1, -1, -1, -1},
};
/*
- * KWorld PlusTV 340U and UB435-Q (ATSC) GPIOs map:
+ * KWorld PlusTV 340U, UB435-Q and UB435-Q V2 (ATSC) GPIOs map:
* EM_GPIO_0 - currently unknown
* EM_GPIO_1 - LED disable/enable (1 = off, 0 = on)
* EM_GPIO_2 - currently unknown
@@ -185,8 +185,16 @@ static struct em28xx_reg_seq evga_indtube_digital[] = {
* EM_GPIO_7 - currently unknown
*/
static struct em28xx_reg_seq kworld_a340_digital[] = {
- {EM2820_R08_GPIO_CTRL, 0x6d, ~EM_GPIO_4, 10},
- { -1, -1, -1, -1},
+ {EM2820_R08_GPIO_CTRL, 0x6d, ~EM_GPIO_4, 10},
+ { -1, -1, -1, -1},
+};
+
+static struct em28xx_reg_seq kworld_ub435q_v3_digital[] = {
+ {EM2874_R80_GPIO_P0_CTRL, 0xff, 0xff, 100},
+ {EM2874_R80_GPIO_P0_CTRL, 0xfe, 0xff, 100},
+ {EM2874_R80_GPIO_P0_CTRL, 0xbe, 0xff, 100},
+ {EM2874_R80_GPIO_P0_CTRL, 0xfe, 0xff, 100},
+ { -1, -1, -1, -1},
};
/* Pinnacle Hybrid Pro eb1a:2881 */
@@ -205,13 +213,24 @@ static struct em28xx_reg_seq pinnacle_hybrid_pro_digital[] = {
static struct em28xx_reg_seq terratec_cinergy_USB_XS_FR_analog[] = {
{EM2820_R08_GPIO_CTRL, 0x6d, ~EM_GPIO_4, 10},
{EM2880_R04_GPO, 0x00, 0xff, 10},
- { -1, -1, -1, -1},
+ { -1, -1, -1, -1},
};
static struct em28xx_reg_seq terratec_cinergy_USB_XS_FR_digital[] = {
{EM2820_R08_GPIO_CTRL, 0x6e, ~EM_GPIO_4, 10},
{EM2880_R04_GPO, 0x08, 0xff, 10},
- { -1, -1, -1, -1},
+ { -1, -1, -1, -1},
+};
+
+/* PCTV HD Mini (80e) GPIOs
+ 0-5: not used
+ 6: demod reset, active low
+ 7: LED on, active high */
+static struct em28xx_reg_seq em2874_pctv_80e_digital[] = {
+ {EM28XX_R06_I2C_CLK, 0x45, 0xff, 10}, /*400 KHz*/
+ {EM2874_R80_GPIO_P0_CTRL, 0x00, 0xff, 100},/*Demod reset*/
+ {EM2874_R80_GPIO_P0_CTRL, 0x40, 0xff, 10},
+ { -1, -1, -1, -1},
};
/* eb1a:2868 Reddo DVB-C USB TV Box
@@ -225,7 +244,7 @@ static struct em28xx_reg_seq reddo_dvb_c_usb_box[] = {
{EM2820_R08_GPIO_CTRL, 0x7f, 0xff, 10},
{EM2820_R08_GPIO_CTRL, 0x6f, 0xff, 10},
{EM2820_R08_GPIO_CTRL, 0xff, 0xff, 10},
- {-1, -1, -1, -1},
+ { -1, -1, -1, -1},
};
/* Callback for the most boards */
@@ -233,23 +252,23 @@ static struct em28xx_reg_seq default_tuner_gpio[] = {
{EM2820_R08_GPIO_CTRL, EM_GPIO_4, EM_GPIO_4, 10},
{EM2820_R08_GPIO_CTRL, 0, EM_GPIO_4, 10},
{EM2820_R08_GPIO_CTRL, EM_GPIO_4, EM_GPIO_4, 10},
- { -1, -1, -1, -1},
+ { -1, -1, -1, -1},
};
/* Mute/unmute */
static struct em28xx_reg_seq compro_unmute_tv_gpio[] = {
- {EM2820_R08_GPIO_CTRL, 5, 7, 10},
- { -1, -1, -1, -1},
+ {EM2820_R08_GPIO_CTRL, 5, 7, 10},
+ { -1, -1, -1, -1},
};
static struct em28xx_reg_seq compro_unmute_svid_gpio[] = {
- {EM2820_R08_GPIO_CTRL, 4, 7, 10},
- { -1, -1, -1, -1},
+ {EM2820_R08_GPIO_CTRL, 4, 7, 10},
+ { -1, -1, -1, -1},
};
static struct em28xx_reg_seq compro_mute_gpio[] = {
- {EM2820_R08_GPIO_CTRL, 6, 7, 10},
- { -1, -1, -1, -1},
+ {EM2820_R08_GPIO_CTRL, 6, 7, 10},
+ { -1, -1, -1, -1},
};
/* Terratec AV350 */
@@ -279,21 +298,21 @@ static struct em28xx_reg_seq vc211a_enable[] = {
static struct em28xx_reg_seq dikom_dk300_digital[] = {
{EM2820_R08_GPIO_CTRL, 0x6e, ~EM_GPIO_4, 10},
{EM2880_R04_GPO, 0x08, 0xff, 10},
- { -1, -1, -1, -1},
+ { -1, -1, -1, -1},
};
/* Reset for the most [digital] boards */
static struct em28xx_reg_seq leadership_digital[] = {
{EM2874_R80_GPIO_P0_CTRL, 0x70, 0xff, 10},
- { -1, -1, -1, -1},
+ { -1, -1, -1, -1},
};
static struct em28xx_reg_seq leadership_reset[] = {
{EM2874_R80_GPIO_P0_CTRL, 0xf0, 0xff, 10},
{EM2874_R80_GPIO_P0_CTRL, 0xb0, 0xff, 10},
{EM2874_R80_GPIO_P0_CTRL, 0xf0, 0xff, 10},
- { -1, -1, -1, -1},
+ { -1, -1, -1, -1},
};
/* 2013:024f PCTV nanoStick T2 290e
@@ -304,7 +323,7 @@ static struct em28xx_reg_seq pctv_290e[] = {
{EM2874_R80_GPIO_P0_CTRL, 0x00, 0xff, 80},
{EM2874_R80_GPIO_P0_CTRL, 0x40, 0xff, 80}, /* GPIO_6 = 1 */
{EM2874_R80_GPIO_P0_CTRL, 0xc0, 0xff, 80}, /* GPIO_7 = 1 */
- {-1, -1, -1, -1},
+ { -1, -1, -1, -1},
};
#if 0
@@ -313,14 +332,14 @@ static struct em28xx_reg_seq terratec_h5_gpio[] = {
{EM2874_R80_GPIO_P0_CTRL, 0xf6, 0xff, 100},
{EM2874_R80_GPIO_P0_CTRL, 0xf2, 0xff, 50},
{EM2874_R80_GPIO_P0_CTRL, 0xf6, 0xff, 50},
- { -1, -1, -1, -1},
+ { -1, -1, -1, -1},
};
static struct em28xx_reg_seq terratec_h5_digital[] = {
{EM2874_R80_GPIO_P0_CTRL, 0xf6, 0xff, 10},
{EM2874_R80_GPIO_P0_CTRL, 0xe6, 0xff, 100},
{EM2874_R80_GPIO_P0_CTRL, 0xa6, 0xff, 10},
- { -1, -1, -1, -1},
+ { -1, -1, -1, -1},
};
#endif
@@ -335,12 +354,12 @@ static struct em28xx_reg_seq terratec_h5_digital[] = {
* GPIO_7 - LED (green LED)
*/
static struct em28xx_reg_seq pctv_460e[] = {
- {EM2874_R80_GPIO_P0_CTRL, 0x01, 0xff, 50},
- {0x0d, 0xff, 0xff, 50},
- {EM2874_R80_GPIO_P0_CTRL, 0x41, 0xff, 50}, /* GPIO_6=1 */
- {0x0d, 0x42, 0xff, 50},
- {EM2874_R80_GPIO_P0_CTRL, 0x61, 0xff, 50}, /* GPIO_5=1 */
- { -1, -1, -1, -1},
+ {EM2874_R80_GPIO_P0_CTRL, 0x01, 0xff, 50},
+ { 0x0d, 0xff, 0xff, 50},
+ {EM2874_R80_GPIO_P0_CTRL, 0x41, 0xff, 50}, /* GPIO_6=1 */
+ { 0x0d, 0x42, 0xff, 50},
+ {EM2874_R80_GPIO_P0_CTRL, 0x61, 0xff, 50}, /* GPIO_5=1 */
+ { -1, -1, -1, -1},
};
static struct em28xx_reg_seq c3tech_digital_duo_digital[] = {
@@ -352,7 +371,29 @@ static struct em28xx_reg_seq c3tech_digital_duo_digital[] = {
{EM2874_R80_GPIO_P0_CTRL, 0xfe, 0xff, 10},
{EM2874_R80_GPIO_P0_CTRL, 0xbe, 0xff, 10},
{EM2874_R80_GPIO_P0_CTRL, 0xfe, 0xff, 20},
- { -1, -1, -1, -1},
+ { -1, -1, -1, -1},
+};
+
+/*
+ * 2013:0258 PCTV DVB-S2 Stick (461e)
+ * GPIO 0 = POWER_ON
+ * GPIO 1 = BOOST
+ * GPIO 2 = VUV_LNB (red LED)
+ * GPIO 3 = #EXT_12V
+ * GPIO 4 = INT_DEM
+ * GPIO 5 = INT_LNB
+ * GPIO 6 = #RESET_DEM
+ * GPIO 7 = P07_LED (green LED)
+ */
+static struct em28xx_reg_seq pctv_461e[] = {
+ {EM2874_R80_GPIO_P0_CTRL, 0x7f, 0xff, 0},
+ {0x0d, 0xff, 0xff, 0},
+ {EM2874_R80_GPIO_P0_CTRL, 0x3f, 0xff, 100}, /* reset demod */
+ {EM2874_R80_GPIO_P0_CTRL, 0x7f, 0xff, 200}, /* reset demod */
+ {0x0d, 0x42, 0xff, 0},
+ {EM2874_R80_GPIO_P0_CTRL, 0xeb, 0xff, 0},
+ {EM2874_R5F_TS_ENABLE, 0x84, 0x84, 0}, /* parallel? | null discard */
+ { -1, -1, -1, -1},
};
#if 0
@@ -361,14 +402,14 @@ static struct em28xx_reg_seq hauppauge_930c_gpio[] = {
{EM2874_R80_GPIO_P0_CTRL, 0x4f, 0xff, 10}, /* xc5000 reset */
{EM2874_R80_GPIO_P0_CTRL, 0x6f, 0xff, 10},
{EM2874_R80_GPIO_P0_CTRL, 0x4f, 0xff, 10},
- { -1, -1, -1, -1},
+ { -1, -1, -1, -1},
};
static struct em28xx_reg_seq hauppauge_930c_digital[] = {
{EM2874_R80_GPIO_P0_CTRL, 0xf6, 0xff, 10},
{EM2874_R80_GPIO_P0_CTRL, 0xe6, 0xff, 100},
{EM2874_R80_GPIO_P0_CTRL, 0xa6, 0xff, 10},
- { -1, -1, -1, -1},
+ { -1, -1, -1, -1},
};
#endif
@@ -378,10 +419,10 @@ static struct em28xx_reg_seq hauppauge_930c_digital[] = {
* GPIO_7 - LED, 0=active
*/
static struct em28xx_reg_seq maxmedia_ub425_tc[] = {
- {EM2874_R80_GPIO_P0_CTRL, 0x83, 0xff, 100},
- {EM2874_R80_GPIO_P0_CTRL, 0xc3, 0xff, 100}, /* GPIO_6 = 1 */
- {EM2874_R80_GPIO_P0_CTRL, 0x43, 0xff, 000}, /* GPIO_7 = 0 */
- {-1, -1, -1, -1},
+ {EM2874_R80_GPIO_P0_CTRL, 0x83, 0xff, 100},
+ {EM2874_R80_GPIO_P0_CTRL, 0xc3, 0xff, 100}, /* GPIO_6 = 1 */
+ {EM2874_R80_GPIO_P0_CTRL, 0x43, 0xff, 000}, /* GPIO_7 = 0 */
+ { -1, -1, -1, -1},
};
/* 2304:0242 PCTV QuatroStick (510e)
@@ -391,10 +432,10 @@ static struct em28xx_reg_seq maxmedia_ub425_tc[] = {
* GPIO_7: LED, 1=active
*/
static struct em28xx_reg_seq pctv_510e[] = {
- {EM2874_R80_GPIO_P0_CTRL, 0x10, 0xff, 100},
- {EM2874_R80_GPIO_P0_CTRL, 0x14, 0xff, 100}, /* GPIO_2 = 1 */
- {EM2874_R80_GPIO_P0_CTRL, 0x54, 0xff, 050}, /* GPIO_6 = 1 */
- { -1, -1, -1, -1},
+ {EM2874_R80_GPIO_P0_CTRL, 0x10, 0xff, 100},
+ {EM2874_R80_GPIO_P0_CTRL, 0x14, 0xff, 100}, /* GPIO_2 = 1 */
+ {EM2874_R80_GPIO_P0_CTRL, 0x54, 0xff, 050}, /* GPIO_6 = 1 */
+ { -1, -1, -1, -1},
};
/* 2013:0251 PCTV QuatroStick nano (520e)
@@ -404,14 +445,111 @@ static struct em28xx_reg_seq pctv_510e[] = {
* GPIO_7: LED, 1=active
*/
static struct em28xx_reg_seq pctv_520e[] = {
- {EM2874_R80_GPIO_P0_CTRL, 0x10, 0xff, 100},
- {EM2874_R80_GPIO_P0_CTRL, 0x14, 0xff, 100}, /* GPIO_2 = 1 */
- {EM2874_R80_GPIO_P0_CTRL, 0x54, 0xff, 050}, /* GPIO_6 = 1 */
- {EM2874_R80_GPIO_P0_CTRL, 0xd4, 0xff, 000}, /* GPIO_7 = 1 */
- { -1, -1, -1, -1},
+ {EM2874_R80_GPIO_P0_CTRL, 0x10, 0xff, 100},
+ {EM2874_R80_GPIO_P0_CTRL, 0x14, 0xff, 100}, /* GPIO_2 = 1 */
+ {EM2874_R80_GPIO_P0_CTRL, 0x54, 0xff, 050}, /* GPIO_6 = 1 */
+ {EM2874_R80_GPIO_P0_CTRL, 0xd4, 0xff, 000}, /* GPIO_7 = 1 */
+ { -1, -1, -1, -1},
+};
+
+/* 1ae7:9003/9004 SpeedLink Vicious And Devine Laplace webcam
+ * reg 0x80/0x84:
+ * GPIO_0: capturing LED, 0=on, 1=off
+ * GPIO_2: AV mute button, 0=pressed, 1=unpressed
+ * GPIO 3: illumination button, 0=pressed, 1=unpressed
+ * GPIO_6: illumination/flash LED, 0=on, 1=off
+ * reg 0x81/0x85:
+ * GPIO_7: snapshot button, 0=pressed, 1=unpressed
+ */
+static struct em28xx_reg_seq speedlink_vad_laplace_reg_seq[] = {
+ {EM2820_R08_GPIO_CTRL, 0xf7, 0xff, 10},
+ {EM2874_R80_GPIO_P0_CTRL, 0xff, 0xb2, 10},
+ { -1, -1, -1, -1},
+};
+
+static struct em28xx_reg_seq pctv_292e[] = {
+ {EM2874_R80_GPIO_P0_CTRL, 0xff, 0xff, 0},
+ {0x0d, 0xff, 0xff, 950},
+ {EM2874_R80_GPIO_P0_CTRL, 0xbd, 0xff, 100},
+ {EM2874_R80_GPIO_P0_CTRL, 0xfd, 0xff, 410},
+ {EM2874_R80_GPIO_P0_CTRL, 0x7d, 0xff, 300},
+ {EM2874_R80_GPIO_P0_CTRL, 0x7c, 0xff, 60},
+ {0x0d, 0x42, 0xff, 50},
+ {EM2874_R5F_TS_ENABLE, 0x85, 0xff, 0},
+ {-1, -1, -1, -1},
};
/*
+ * Button definitions
+ */
+static struct em28xx_button std_snapshot_button[] = {
+ {
+ .role = EM28XX_BUTTON_SNAPSHOT,
+ .reg_r = EM28XX_R0C_USBSUSP,
+ .reg_clearing = EM28XX_R0C_USBSUSP,
+ .mask = EM28XX_R0C_USBSUSP_SNAPSHOT,
+ .inverted = 0,
+ },
+ {-1, 0, 0, 0, 0},
+};
+
+static struct em28xx_button speedlink_vad_laplace_buttons[] = {
+ {
+ .role = EM28XX_BUTTON_SNAPSHOT,
+ .reg_r = EM2874_R85_GPIO_P1_STATE,
+ .mask = 0x80,
+ .inverted = 1,
+ },
+ {
+ .role = EM28XX_BUTTON_ILLUMINATION,
+ .reg_r = EM2874_R84_GPIO_P0_STATE,
+ .mask = 0x08,
+ .inverted = 1,
+ },
+ {-1, 0, 0, 0, 0},
+};
+
+/*
+ * LED definitions
+ */
+static struct em28xx_led speedlink_vad_laplace_leds[] = {
+ {
+ .role = EM28XX_LED_ANALOG_CAPTURING,
+ .gpio_reg = EM2874_R80_GPIO_P0_CTRL,
+ .gpio_mask = 0x01,
+ .inverted = 1,
+ },
+ {
+ .role = EM28XX_LED_ILLUMINATION,
+ .gpio_reg = EM2874_R80_GPIO_P0_CTRL,
+ .gpio_mask = 0x40,
+ .inverted = 1,
+ },
+ {-1, 0, 0, 0},
+};
+
+static struct em28xx_led kworld_ub435q_v3_leds[] = {
+ {
+ .role = EM28XX_LED_DIGITAL_CAPTURING,
+ .gpio_reg = EM2874_R80_GPIO_P0_CTRL,
+ .gpio_mask = 0x80,
+ .inverted = 1,
+ },
+ {-1, 0, 0, 0},
+};
+
+static struct em28xx_led pctv_80e_leds[] = {
+ {
+ .role = EM28XX_LED_DIGITAL_CAPTURING,
+ .gpio_reg = EM2874_R80_GPIO_P0_CTRL,
+ .gpio_mask = 0x80,
+ .inverted = 0,
+ },
+ {-1, 0, 0, 0},
+};
+
+
+/*
* Board definitions
*/
struct em28xx_board em28xx_boards[] = {
@@ -1390,7 +1528,7 @@ struct em28xx_board em28xx_boards[] = {
},
[EM2820_BOARD_PROLINK_PLAYTV_USB2] = {
.name = "SIIG AVTuner-PVR / Pixelview Prolink PlayTV USB 2.0",
- .has_snapshot_button = 1,
+ .buttons = std_snapshot_button,
.tda9887_conf = TDA9887_PRESENT,
.tuner_type = TUNER_YMEC_TVF_5533MF,
.decoder = EM28XX_SAA711X,
@@ -1412,7 +1550,7 @@ struct em28xx_board em28xx_boards[] = {
},
[EM2860_BOARD_SAA711X_REFERENCE_DESIGN] = {
.name = "EM2860/SAA711X Reference Design",
- .has_snapshot_button = 1,
+ .buttons = std_snapshot_button,
.tuner_type = TUNER_ABSENT,
.decoder = EM28XX_SAA711X,
.input = { {
@@ -2019,7 +2157,7 @@ struct em28xx_board em28xx_boards[] = {
},
/* 1b80:e1cc Delock 61959
* Empia EM2874B + Micronas DRX 3913KA2 + NXP TDA18271HDC2
- * mostly the same as MaxMedia UB-425-TC but different remote */
+ * mostly the same as MaxMedia UB-425-TC but different remote */
[EM2874_BOARD_DELOCK_61959] = {
.name = "Delock 61959",
.tuner_type = TUNER_ABSENT,
@@ -2030,7 +2168,84 @@ struct em28xx_board em28xx_boards[] = {
.i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE |
EM28XX_I2C_FREQ_400_KHZ,
},
+ /*
+ * 1b80:e346 KWorld USB ATSC TV Stick UB435-Q V2
+ * Empia EM2874B + LG DT3305 + NXP TDA18271HDC2
+ */
+ [EM2874_BOARD_KWORLD_UB435Q_V2] = {
+ .name = "KWorld USB ATSC TV Stick UB435-Q V2",
+ .tuner_type = TUNER_ABSENT,
+ .has_dvb = 1,
+ .dvb_gpio = kworld_a340_digital,
+ .tuner_gpio = default_tuner_gpio,
+ .def_i2c_bus = 1,
+ },
+ /*
+ * 1b80:e34c KWorld USB ATSC TV Stick UB435-Q V3
+ * Empia EM2874B + LG DT3305 + NXP TDA18271HDC2
+ */
+ [EM2874_BOARD_KWORLD_UB435Q_V3] = {
+ .name = "KWorld USB ATSC TV Stick UB435-Q V3",
+ .tuner_type = TUNER_ABSENT,
+ .has_dvb = 1,
+ .tuner_gpio = kworld_ub435q_v3_digital,
+ .def_i2c_bus = 1,
+ .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE |
+ EM28XX_I2C_FREQ_100_KHZ,
+ .leds = kworld_ub435q_v3_leds,
+ },
+ [EM2874_BOARD_PCTV_HD_MINI_80E] = {
+ .name = "Pinnacle PCTV HD Mini",
+ .tuner_type = TUNER_ABSENT,
+ .has_dvb = 1,
+ .dvb_gpio = em2874_pctv_80e_digital,
+ .decoder = EM28XX_NODECODER,
+ .ir_codes = RC_MAP_PINNACLE_PCTV_HD,
+ .leds = pctv_80e_leds,
+ },
+ /* 1ae7:9003/9004 SpeedLink Vicious And Devine Laplace webcam
+ * Empia EM2765 + OmniVision OV2640 */
+ [EM2765_BOARD_SPEEDLINK_VAD_LAPLACE] = {
+ .name = "SpeedLink Vicious And Devine Laplace webcam",
+ .xclk = EM28XX_XCLK_FREQUENCY_24MHZ,
+ .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE |
+ EM28XX_I2C_FREQ_100_KHZ,
+ .def_i2c_bus = 1,
+ .tuner_type = TUNER_ABSENT,
+ .is_webcam = 1,
+ .input = { {
+ .type = EM28XX_VMUX_COMPOSITE1,
+ .amux = EM28XX_AMUX_VIDEO,
+ .gpio = speedlink_vad_laplace_reg_seq,
+ } },
+ .buttons = speedlink_vad_laplace_buttons,
+ .leds = speedlink_vad_laplace_leds,
+ },
+ /* 2013:0258 PCTV DVB-S2 Stick (461e)
+ * Empia EM28178, Montage M88DS3103, Montage M88TS2022, Allegro A8293 */
+ [EM28178_BOARD_PCTV_461E] = {
+ .def_i2c_bus = 1,
+ .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_400_KHZ,
+ .name = "PCTV DVB-S2 Stick (461e)",
+ .tuner_type = TUNER_ABSENT,
+ .tuner_gpio = pctv_461e,
+ .has_dvb = 1,
+ .ir_codes = RC_MAP_PINNACLE_PCTV_HD,
+ },
+ /* 2013:025f PCTV tripleStick (292e).
+ * Empia EM28178, Silicon Labs Si2168, Silicon Labs Si2157 */
+ [EM28178_BOARD_PCTV_292E] = {
+ .name = "PCTV tripleStick (292e)",
+ .def_i2c_bus = 1,
+ .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_400_KHZ,
+ .tuner_type = TUNER_ABSENT,
+ .tuner_gpio = pctv_292e,
+ .has_dvb = 1,
+ .ir_codes = RC_MAP_PINNACLE_PCTV_HD,
+ },
};
+EXPORT_SYMBOL_GPL(em28xx_boards);
+
const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards);
/* table of devices that work with this driver */
@@ -2161,6 +2376,8 @@ struct usb_device_id em28xx_id_table[] = {
.driver_info = EM2882_BOARD_PINNACLE_HYBRID_PRO_330E },
{ USB_DEVICE(0x2304, 0x0227),
.driver_info = EM2880_BOARD_PINNACLE_PCTV_HD_PRO },
+ { USB_DEVICE(0x2304, 0x023f),
+ .driver_info = EM2874_BOARD_PCTV_HD_MINI_80E },
{ USB_DEVICE(0x0413, 0x6023),
.driver_info = EM2800_BOARD_LEADTEK_WINFAST_USBII },
{ USB_DEVICE(0x093b, 0xa003),
@@ -2173,6 +2390,10 @@ struct usb_device_id em28xx_id_table[] = {
.driver_info = EM2860_BOARD_GADMEI_UTV330 },
{ USB_DEVICE(0x1b80, 0xa340),
.driver_info = EM2870_BOARD_KWORLD_A340 },
+ { USB_DEVICE(0x1b80, 0xe346),
+ .driver_info = EM2874_BOARD_KWORLD_UB435Q_V2 },
+ { USB_DEVICE(0x1b80, 0xe34c),
+ .driver_info = EM2874_BOARD_KWORLD_UB435Q_V3 },
{ USB_DEVICE(0x2013, 0x024f),
.driver_info = EM28174_BOARD_PCTV_290E },
{ USB_DEVICE(0x2013, 0x024c),
@@ -2193,6 +2414,14 @@ struct usb_device_id em28xx_id_table[] = {
.driver_info = EM2884_BOARD_PCTV_520E },
{ USB_DEVICE(0x1b80, 0xe1cc),
.driver_info = EM2874_BOARD_DELOCK_61959 },
+ { USB_DEVICE(0x1ae7, 0x9003),
+ .driver_info = EM2765_BOARD_SPEEDLINK_VAD_LAPLACE },
+ { USB_DEVICE(0x1ae7, 0x9004),
+ .driver_info = EM2765_BOARD_SPEEDLINK_VAD_LAPLACE },
+ { USB_DEVICE(0x2013, 0x0258),
+ .driver_info = EM28178_BOARD_PCTV_461E },
+ { USB_DEVICE(0x2013, 0x025f),
+ .driver_info = EM28178_BOARD_PCTV_292E },
{ },
};
MODULE_DEVICE_TABLE(usb, em28xx_id_table);
@@ -2224,24 +2453,6 @@ static struct em28xx_hash_table em28xx_i2c_hash[] = {
};
/* NOTE: introduce a separate hash table for devices with 16 bit eeproms */
-/* I2C possible address to saa7115, tvp5150, msp3400, tvaudio */
-static unsigned short saa711x_addrs[] = {
- 0x4a >> 1, 0x48 >> 1, /* SAA7111, SAA7111A and SAA7113 */
- 0x42 >> 1, 0x40 >> 1, /* SAA7114, SAA7115 and SAA7118 */
- I2C_CLIENT_END };
-
-static unsigned short tvp5150_addrs[] = {
- 0xb8 >> 1,
- 0xba >> 1,
- I2C_CLIENT_END
-};
-
-static unsigned short msp3400_addrs[] = {
- 0x80 >> 1,
- 0x88 >> 1,
- I2C_CLIENT_END
-};
-
int em28xx_tuner_callback(void *ptr, int component, int command, int arg)
{
struct em28xx_i2c_bus *i2c_bus = ptr;
@@ -2393,113 +2604,6 @@ static void em28xx_pre_card_setup(struct em28xx *dev)
em28xx_set_mode(dev, EM28XX_SUSPEND);
}
-static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl)
-{
- memset(ctl, 0, sizeof(*ctl));
-
- ctl->fname = XC2028_DEFAULT_FIRMWARE;
- ctl->max_len = 64;
- ctl->mts = em28xx_boards[dev->model].mts_firmware;
-
- switch (dev->model) {
- case EM2880_BOARD_EMPIRE_DUAL_TV:
- case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
- case EM2882_BOARD_TERRATEC_HYBRID_XS:
- ctl->demod = XC3028_FE_ZARLINK456;
- break;
- case EM2880_BOARD_TERRATEC_HYBRID_XS:
- case EM2880_BOARD_TERRATEC_HYBRID_XS_FR:
- case EM2881_BOARD_PINNACLE_HYBRID_PRO:
- ctl->demod = XC3028_FE_ZARLINK456;
- break;
- case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2:
- case EM2882_BOARD_PINNACLE_HYBRID_PRO_330E:
- ctl->demod = XC3028_FE_DEFAULT;
- break;
- case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600:
- ctl->demod = XC3028_FE_DEFAULT;
- ctl->fname = XC3028L_DEFAULT_FIRMWARE;
- break;
- case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850:
- case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950:
- case EM2880_BOARD_PINNACLE_PCTV_HD_PRO:
- /* FIXME: Better to specify the needed IF */
- ctl->demod = XC3028_FE_DEFAULT;
- break;
- case EM2883_BOARD_KWORLD_HYBRID_330U:
- case EM2882_BOARD_DIKOM_DK300:
- case EM2882_BOARD_KWORLD_VS_DVBT:
- ctl->demod = XC3028_FE_CHINA;
- ctl->fname = XC2028_DEFAULT_FIRMWARE;
- break;
- case EM2882_BOARD_EVGA_INDTUBE:
- ctl->demod = XC3028_FE_CHINA;
- ctl->fname = XC3028L_DEFAULT_FIRMWARE;
- break;
- default:
- ctl->demod = XC3028_FE_OREN538;
- }
-}
-
-static void em28xx_tuner_setup(struct em28xx *dev)
-{
- struct tuner_setup tun_setup;
- struct v4l2_frequency f;
-
- if (dev->tuner_type == TUNER_ABSENT)
- return;
-
- memset(&tun_setup, 0, sizeof(tun_setup));
-
- tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
- tun_setup.tuner_callback = em28xx_tuner_callback;
-
- if (dev->board.radio.type) {
- tun_setup.type = dev->board.radio.type;
- tun_setup.addr = dev->board.radio_addr;
-
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup);
- }
-
- if ((dev->tuner_type != TUNER_ABSENT) && (dev->tuner_type)) {
- tun_setup.type = dev->tuner_type;
- tun_setup.addr = dev->tuner_addr;
-
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup);
- }
-
- if (dev->tda9887_conf) {
- struct v4l2_priv_tun_config tda9887_cfg;
-
- tda9887_cfg.tuner = TUNER_TDA9887;
- tda9887_cfg.priv = &dev->tda9887_conf;
-
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config, &tda9887_cfg);
- }
-
- if (dev->tuner_type == TUNER_XC2028) {
- struct v4l2_priv_tun_config xc2028_cfg;
- struct xc2028_ctrl ctl;
-
- memset(&xc2028_cfg, 0, sizeof(xc2028_cfg));
- memset(&ctl, 0, sizeof(ctl));
-
- em28xx_setup_xc3028(dev, &ctl);
-
- xc2028_cfg.tuner = TUNER_XC2028;
- xc2028_cfg.priv = &ctl;
-
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config, &xc2028_cfg);
- }
-
- /* configure tuner */
- f.tuner = 0;
- f.type = V4L2_TUNER_ANALOG_TV;
- f.frequency = 9076; /* just a magic number */
- dev->ctl_freq = f.frequency;
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
-}
-
static int em28xx_hint_board(struct em28xx *dev)
{
int i;
@@ -2603,8 +2707,6 @@ static void em28xx_card_setup(struct em28xx *dev)
if (dev->board.is_webcam) {
if (em28xx_detect_sensor(dev) < 0)
dev->board.is_webcam = 0;
- else
- dev->progressive = 1;
}
switch (dev->model) {
@@ -2639,11 +2741,6 @@ static void em28xx_card_setup(struct em28xx *dev)
dev->board.name, dev->model);
dev->tuner_type = em28xx_boards[dev->model].tuner_type;
- if (em28xx_boards[dev->model].tuner_addr)
- dev->tuner_addr = em28xx_boards[dev->model].tuner_addr;
-
- if (em28xx_boards[dev->model].tda9887_conf)
- dev->tda9887_conf = em28xx_boards[dev->model].tda9887_conf;
/* request some modules */
switch (dev->model) {
@@ -2753,57 +2850,56 @@ static void em28xx_card_setup(struct em28xx *dev)
/* Allow override tuner type by a module parameter */
if (tuner >= 0)
dev->tuner_type = tuner;
+}
- /* request some modules */
- if (dev->board.has_msp34xx)
- v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
- "msp3400", 0, msp3400_addrs);
-
- if (dev->board.decoder == EM28XX_SAA711X)
- v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
- "saa7115_auto", 0, saa711x_addrs);
-
- if (dev->board.decoder == EM28XX_TVP5150)
- v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
- "tvp5150", 0, tvp5150_addrs);
-
- if (dev->board.adecoder == EM28XX_TVAUDIO)
- v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
- "tvaudio", dev->board.tvaudio_addr, NULL);
-
- if (dev->board.tuner_type != TUNER_ABSENT) {
- int has_demod = (dev->tda9887_conf & TDA9887_PRESENT);
-
- if (dev->board.radio.type)
- v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
- "tuner", dev->board.radio_addr, NULL);
-
- if (has_demod)
- v4l2_i2c_new_subdev(&dev->v4l2_dev,
- &dev->i2c_adap[dev->def_i2c_bus], "tuner",
- 0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
- if (dev->tuner_addr == 0) {
- enum v4l2_i2c_tuner_type type =
- has_demod ? ADDRS_TV_WITH_DEMOD : ADDRS_TV;
- struct v4l2_subdev *sd;
-
- sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
- &dev->i2c_adap[dev->def_i2c_bus], "tuner",
- 0, v4l2_i2c_tuner_addrs(type));
-
- if (sd)
- dev->tuner_addr = v4l2_i2c_subdev_addr(sd);
- } else {
- v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
- "tuner", dev->tuner_addr, NULL);
- }
- }
+void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl)
+{
+ memset(ctl, 0, sizeof(*ctl));
- em28xx_tuner_setup(dev);
+ ctl->fname = XC2028_DEFAULT_FIRMWARE;
+ ctl->max_len = 64;
+ ctl->mts = em28xx_boards[dev->model].mts_firmware;
- em28xx_init_camera(dev);
+ switch (dev->model) {
+ case EM2880_BOARD_EMPIRE_DUAL_TV:
+ case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
+ case EM2882_BOARD_TERRATEC_HYBRID_XS:
+ ctl->demod = XC3028_FE_ZARLINK456;
+ break;
+ case EM2880_BOARD_TERRATEC_HYBRID_XS:
+ case EM2880_BOARD_TERRATEC_HYBRID_XS_FR:
+ case EM2881_BOARD_PINNACLE_HYBRID_PRO:
+ ctl->demod = XC3028_FE_ZARLINK456;
+ break;
+ case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2:
+ case EM2882_BOARD_PINNACLE_HYBRID_PRO_330E:
+ ctl->demod = XC3028_FE_DEFAULT;
+ break;
+ case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600:
+ ctl->demod = XC3028_FE_DEFAULT;
+ ctl->fname = XC3028L_DEFAULT_FIRMWARE;
+ break;
+ case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850:
+ case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950:
+ case EM2880_BOARD_PINNACLE_PCTV_HD_PRO:
+ /* FIXME: Better to specify the needed IF */
+ ctl->demod = XC3028_FE_DEFAULT;
+ break;
+ case EM2883_BOARD_KWORLD_HYBRID_330U:
+ case EM2882_BOARD_DIKOM_DK300:
+ case EM2882_BOARD_KWORLD_VS_DVBT:
+ ctl->demod = XC3028_FE_CHINA;
+ ctl->fname = XC2028_DEFAULT_FIRMWARE;
+ break;
+ case EM2882_BOARD_EVGA_INDTUBE:
+ ctl->demod = XC3028_FE_CHINA;
+ ctl->fname = XC3028L_DEFAULT_FIRMWARE;
+ break;
+ default:
+ ctl->demod = XC3028_FE_OREN538;
+ }
}
-
+EXPORT_SYMBOL_GPL(em28xx_setup_xc3028);
static void request_module_async(struct work_struct *work)
{
@@ -2816,17 +2912,30 @@ static void request_module_async(struct work_struct *work)
* can be initialised right now. Otherwise, the module init
* code will do it.
*/
+
+ /*
+ * Devicdes with an audio-only interface also have a V4L/DVB/RC
+ * interface. Don't register extensions twice on those devices.
+ */
+ if (dev->is_audio_only) {
+#if defined(CONFIG_MODULES) && defined(MODULE)
+ request_module("em28xx-alsa");
+#endif
+ return;
+ }
+
em28xx_init_extension(dev);
#if defined(CONFIG_MODULES) && defined(MODULE)
+ if (dev->has_video)
+ request_module("em28xx-v4l");
if (dev->has_audio_class)
request_module("snd-usb-audio");
else if (dev->has_alsa_audio)
request_module("em28xx-alsa");
-
if (dev->board.has_dvb)
request_module("em28xx-dvb");
- if (dev->board.has_snapshot_button ||
+ if (dev->board.buttons ||
((dev->board.ir_codes || dev->board.has_ir_i2c) && !disable_ir))
request_module("em28xx-rc");
#endif /* CONFIG_MODULES */
@@ -2848,26 +2957,45 @@ static void flush_request_modules(struct em28xx *dev)
* unregisters the v4l2,i2c and usb devices
* called when the device gets disconnected or at module unload
*/
-void em28xx_release_resources(struct em28xx *dev)
+static void em28xx_release_resources(struct em28xx *dev)
{
/*FIXME: I2C IR should be disconnected */
- em28xx_release_analog_resources(dev);
+ mutex_lock(&dev->lock);
if (dev->def_i2c_bus)
em28xx_i2c_unregister(dev, 1);
em28xx_i2c_unregister(dev, 0);
- v4l2_ctrl_handler_free(&dev->ctrl_handler);
-
- v4l2_device_unregister(&dev->v4l2_dev);
-
usb_put_dev(dev->udev);
/* Mark device as unused */
- clear_bit(dev->devno, &em28xx_devused);
+ clear_bit(dev->devno, em28xx_devused);
+
+ mutex_unlock(&dev->lock);
};
+/**
+ * em28xx_free_device() - Free em28xx device
+ *
+ * @ref: struct kref for em28xx device
+ *
+ * This is called when all extensions and em28xx core unregisters a device
+ */
+void em28xx_free_device(struct kref *ref)
+{
+ struct em28xx *dev = kref_to_dev(ref);
+
+ em28xx_info("Freeing device\n");
+
+ if (!dev->disconnected)
+ em28xx_release_resources(dev);
+
+ kfree(dev->alt_max_pkt_size_isoc);
+ kfree(dev);
+}
+EXPORT_SYMBOL_GPL(em28xx_free_device);
+
/*
* em28xx_init_dev()
* allocates and inits the device structs, registers i2c bus and v4l device
@@ -2876,14 +3004,11 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
struct usb_interface *interface,
int minor)
{
- struct v4l2_ctrl_handler *hdl = &dev->ctrl_handler;
int retval;
static const char *default_chip_name = "em28xx";
const char *chip_name = default_chip_name;
dev->udev = udev;
- mutex_init(&dev->vb_queue_lock);
- mutex_init(&dev->vb_vbi_queue_lock);
mutex_init(&dev->ctrl_urb_lock);
spin_lock_init(&dev->slock);
@@ -2951,6 +3076,11 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
dev->wait_after_write = 0;
dev->eeprom_addrwidth_16bit = 1;
break;
+ case CHIP_ID_EM28178:
+ chip_name = "em28178";
+ dev->wait_after_write = 0;
+ dev->eeprom_addrwidth_16bit = 1;
+ break;
case CHIP_ID_EM2883:
chip_name = "em2882/3";
dev->wait_after_write = 0;
@@ -2966,6 +3096,16 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
}
}
+ if (dev->chip_id == CHIP_ID_EM2870 ||
+ dev->chip_id == CHIP_ID_EM2874 ||
+ dev->chip_id == CHIP_ID_EM28174 ||
+ dev->chip_id == CHIP_ID_EM28178) {
+ /* Digital only device - don't load any alsa module */
+ dev->audio_mode.has_audio = false;
+ dev->has_audio_class = false;
+ dev->has_alsa_audio = false;
+ }
+
if (chip_name != default_chip_name)
printk(KERN_INFO DRIVER_NAME
": chip ID is %s\n", chip_name);
@@ -2998,15 +3138,6 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
}
}
- retval = v4l2_device_register(&interface->dev, &dev->v4l2_dev);
- if (retval < 0) {
- em28xx_errdev("Call to v4l2_device_register() failed!\n");
- return retval;
- }
-
- v4l2_ctrl_handler_init(hdl, 8);
- dev->v4l2_dev.ctrl_handler = hdl;
-
rt_mutex_init(&dev->i2c_bus_lock);
/* register i2c bus 0 */
@@ -3017,7 +3148,7 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
if (retval < 0) {
em28xx_errdev("%s: em28xx_i2c_register bus 0 - error [%d]!\n",
__func__, retval);
- goto unregister_dev;
+ return retval;
}
/* register i2c bus 1 */
@@ -3031,88 +3162,17 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
if (retval < 0) {
em28xx_errdev("%s: em28xx_i2c_register bus 1 - error [%d]!\n",
__func__, retval);
- goto unregister_dev;
- }
- }
-
- /*
- * Default format, used for tvp5150 or saa711x output formats
- */
- dev->vinmode = 0x10;
- dev->vinctl = EM28XX_VINCTRL_INTERLACED |
- EM28XX_VINCTRL_CCIR656_ENABLE;
-
- /* Do board specific init and eeprom reading */
- em28xx_card_setup(dev);
-
- /* Configure audio */
- retval = em28xx_audio_setup(dev);
- if (retval < 0) {
- em28xx_errdev("%s: Error while setting audio - error [%d]!\n",
- __func__, retval);
- goto fail;
- }
- if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
- v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
- V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
- v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
- V4L2_CID_AUDIO_VOLUME, 0, 0x1f, 1, 0x1f);
- } else {
- /* install the em28xx notify callback */
- v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_MUTE),
- em28xx_ctrl_notify, dev);
- v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_VOLUME),
- em28xx_ctrl_notify, dev);
- }
-
- /* wake i2c devices */
- em28xx_wake_i2c(dev);
- /* init video dma queues */
- INIT_LIST_HEAD(&dev->vidq.active);
- INIT_LIST_HEAD(&dev->vbiq.active);
+ em28xx_i2c_unregister(dev, 0);
- if (dev->board.has_msp34xx) {
- /* Send a reset to other chips via gpio */
- retval = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xf7);
- if (retval < 0) {
- em28xx_errdev("%s: em28xx_write_reg - "
- "msp34xx(1) failed! error [%d]\n",
- __func__, retval);
- goto fail;
- }
- msleep(3);
-
- retval = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xff);
- if (retval < 0) {
- em28xx_errdev("%s: em28xx_write_reg - "
- "msp34xx(2) failed! error [%d]\n",
- __func__, retval);
- goto fail;
+ return retval;
}
- msleep(3);
}
- retval = em28xx_register_analog_devices(dev);
- if (retval < 0) {
- goto fail;
- }
-
- /* Save some power by putting tuner to sleep */
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0);
+ /* Do board specific init and eeprom reading */
+ em28xx_card_setup(dev);
return 0;
-
-fail:
- if (dev->def_i2c_bus)
- em28xx_i2c_unregister(dev, 1);
- em28xx_i2c_unregister(dev, 0);
- v4l2_ctrl_handler_free(&dev->ctrl_handler);
-
-unregister_dev:
- v4l2_device_unregister(&dev->v4l2_dev);
-
- return retval;
}
/* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */
@@ -3137,7 +3197,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
/* Check to see next free device and mark as used */
do {
- nr = find_first_zero_bit(&em28xx_devused, EM28XX_MAXBOARDS);
+ nr = find_first_zero_bit(em28xx_devused, EM28XX_MAXBOARDS);
if (nr >= EM28XX_MAXBOARDS) {
/* No free device slots */
printk(DRIVER_NAME ": Supports only %i em28xx boards.\n",
@@ -3145,7 +3205,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
retval = -ENOMEM;
goto err_no_slot;
}
- } while (test_and_set_bit(nr, &em28xx_devused));
+ } while (test_and_set_bit(nr, em28xx_devused));
/* Don't register audio interfaces */
if (interface->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) {
@@ -3315,7 +3375,9 @@ static int em28xx_usb_probe(struct usb_interface *interface,
dev->alt = -1;
dev->is_audio_only = has_audio && !(has_video || has_dvb);
dev->has_alsa_audio = has_audio;
- dev->audio_ifnum = ifnum;
+ dev->audio_mode.has_audio = has_audio;
+ dev->has_video = has_video;
+ dev->ifnum = ifnum;
/* Checks if audio is provided by some interface */
for (i = 0; i < udev->config->desc.bNumInterfaces; i++) {
@@ -3352,15 +3414,11 @@ static int em28xx_usb_probe(struct usb_interface *interface,
/* save our data pointer in this interface device */
usb_set_intfdata(interface, dev);
- /* initialize videobuf2 stuff */
- em28xx_vb2_setup(dev);
-
/* allocate device struct */
mutex_init(&dev->lock);
- mutex_lock(&dev->lock);
retval = em28xx_init_dev(dev, udev, interface, nr);
if (retval) {
- goto unlock_and_free;
+ goto err_free;
}
if (usb_xfer_mode < 0) {
@@ -3374,57 +3432,34 @@ static int em28xx_usb_probe(struct usb_interface *interface,
/* Select USB transfer types to use */
if (has_video) {
- if (!dev->analog_ep_isoc || (try_bulk && dev->analog_ep_bulk))
- dev->analog_xfer_bulk = 1;
+ if (!dev->analog_ep_isoc || (try_bulk && dev->analog_ep_bulk))
+ dev->analog_xfer_bulk = 1;
em28xx_info("analog set to %s mode.\n",
dev->analog_xfer_bulk ? "bulk" : "isoc");
}
if (has_dvb) {
- if (!dev->dvb_ep_isoc || (try_bulk && dev->dvb_ep_bulk))
- dev->dvb_xfer_bulk = 1;
-
+ if (!dev->dvb_ep_isoc || (try_bulk && dev->dvb_ep_bulk))
+ dev->dvb_xfer_bulk = 1;
em28xx_info("dvb set to %s mode.\n",
dev->dvb_xfer_bulk ? "bulk" : "isoc");
-
- /* pre-allocate DVB usb transfer buffers */
- if (dev->dvb_xfer_bulk) {
- retval = em28xx_alloc_urbs(dev, EM28XX_DIGITAL_MODE,
- dev->dvb_xfer_bulk,
- EM28XX_DVB_NUM_BUFS,
- 512,
- EM28XX_DVB_BULK_PACKET_MULTIPLIER);
- } else {
- retval = em28xx_alloc_urbs(dev, EM28XX_DIGITAL_MODE,
- dev->dvb_xfer_bulk,
- EM28XX_DVB_NUM_BUFS,
- dev->dvb_max_pkt_size_isoc,
- EM28XX_DVB_NUM_ISOC_PACKETS);
- }
- if (retval) {
- printk(DRIVER_NAME
- ": Failed to pre-allocate USB transfer buffers for DVB.\n");
- goto unlock_and_free;
- }
}
+ kref_init(&dev->ref);
+
request_modules(dev);
/* Should be the last thing to do, to avoid newer udev's to
open the device before fully initializing it
*/
- mutex_unlock(&dev->lock);
return 0;
-unlock_and_free:
- mutex_unlock(&dev->lock);
-
err_free:
kfree(dev->alt_max_pkt_size_isoc);
kfree(dev);
err:
- clear_bit(nr, &em28xx_devused);
+ clear_bit(nr, em28xx_devused);
err_no_slot:
usb_put_dev(udev);
@@ -3448,47 +3483,46 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
dev->disconnected = 1;
- if (dev->is_audio_only) {
- mutex_lock(&dev->lock);
- em28xx_close_extension(dev);
- mutex_unlock(&dev->lock);
- return;
- }
-
- em28xx_info("disconnecting %s\n", dev->vdev->name);
+ em28xx_info("Disconnecting %s\n", dev->name);
flush_request_modules(dev);
- mutex_lock(&dev->lock);
-
- v4l2_device_disconnect(&dev->v4l2_dev);
-
- if (dev->users) {
- em28xx_warn("device %s is open! Deregistration and memory deallocation are deferred on close.\n",
- video_device_node_name(dev->vdev));
+ em28xx_close_extension(dev);
- em28xx_uninit_usb_xfer(dev, EM28XX_ANALOG_MODE);
- em28xx_uninit_usb_xfer(dev, EM28XX_DIGITAL_MODE);
- }
+ em28xx_release_resources(dev);
+ kref_put(&dev->ref, em28xx_free_device);
+}
- em28xx_close_extension(dev);
- /* NOTE: must be called BEFORE the resources are released */
+static int em28xx_usb_suspend(struct usb_interface *interface,
+ pm_message_t message)
+{
+ struct em28xx *dev;
- if (!dev->users)
- em28xx_release_resources(dev);
+ dev = usb_get_intfdata(interface);
+ if (!dev)
+ return 0;
+ em28xx_suspend_extension(dev);
+ return 0;
+}
- mutex_unlock(&dev->lock);
+static int em28xx_usb_resume(struct usb_interface *interface)
+{
+ struct em28xx *dev;
- if (!dev->users) {
- kfree(dev->alt_max_pkt_size_isoc);
- kfree(dev);
- }
+ dev = usb_get_intfdata(interface);
+ if (!dev)
+ return 0;
+ em28xx_resume_extension(dev);
+ return 0;
}
static struct usb_driver em28xx_usb_driver = {
.name = "em28xx",
.probe = em28xx_usb_probe,
.disconnect = em28xx_usb_disconnect,
+ .suspend = em28xx_usb_suspend,
+ .resume = em28xx_usb_resume,
+ .reset_resume = em28xx_usb_resume,
.id_table = em28xx_id_table,
};
diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c
index fc157af5234..523d7e92bf4 100644
--- a/drivers/media/usb/em28xx/em28xx-core.c
+++ b/drivers/media/usb/em28xx/em28xx-core.c
@@ -23,6 +23,7 @@
*/
#include <linux/init.h>
+#include <linux/jiffies.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/slab.h>
@@ -33,6 +34,16 @@
#include "em28xx.h"
+#define DRIVER_AUTHOR "Ludovico Cavedon <cavedon@sssup.it>, " \
+ "Markus Rechberger <mrechberger@gmail.com>, " \
+ "Mauro Carvalho Chehab <mchehab@infradead.org>, " \
+ "Sascha Sommer <saschasommer@freenet.de>"
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+MODULE_VERSION(EM28XX_VERSION);
+
/* #define ENABLE_DEBUG_ISOC_FRAMES */
static unsigned int core_debug;
@@ -53,14 +64,6 @@ MODULE_PARM_DESC(reg_debug, "enable debug messages [URB reg]");
printk(KERN_INFO "%s %s :"fmt, \
dev->name, __func__ , ##arg); } while (0)
-static int alt;
-module_param(alt, int, 0644);
-MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint");
-
-static unsigned int disable_vbi;
-module_param(disable_vbi, int, 0644);
-MODULE_PARM_DESC(disable_vbi, "disable vbi support");
-
/* FIXME */
#define em28xx_isocdbg(fmt, arg...) do {\
if (core_debug) \
@@ -226,21 +229,42 @@ int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val,
EXPORT_SYMBOL_GPL(em28xx_write_reg_bits);
/*
+ * em28xx_toggle_reg_bits()
+ * toggles/inverts the bits (specified by bitmask) of a register
+ */
+int em28xx_toggle_reg_bits(struct em28xx *dev, u16 reg, u8 bitmask)
+{
+ int oldval;
+ u8 newval;
+
+ oldval = em28xx_read_reg(dev, reg);
+ if (oldval < 0)
+ return oldval;
+
+ newval = (~oldval & bitmask) | (oldval & ~bitmask);
+
+ return em28xx_write_reg(dev, reg, newval);
+}
+EXPORT_SYMBOL_GPL(em28xx_toggle_reg_bits);
+
+/*
* em28xx_is_ac97_ready()
* Checks if ac97 is ready
*/
static int em28xx_is_ac97_ready(struct em28xx *dev)
{
- int ret, i;
+ unsigned long timeout = jiffies + msecs_to_jiffies(EM28XX_AC97_XFER_TIMEOUT);
+ int ret;
/* Wait up to 50 ms for AC97 command to complete */
- for (i = 0; i < 10; i++, msleep(5)) {
+ while (time_is_after_jiffies(timeout)) {
ret = em28xx_read_reg(dev, EM28XX_R43_AC97BUSY);
if (ret < 0)
return ret;
if (!(ret & 0x01))
return 0;
+ msleep(5);
}
em28xx_warn("AC97 command still being executed: not handled properly!\n");
@@ -482,16 +506,8 @@ int em28xx_audio_setup(struct em28xx *dev)
int vid1, vid2, feat, cfg;
u32 vid;
- if (dev->chip_id == CHIP_ID_EM2870 || dev->chip_id == CHIP_ID_EM2874
- || dev->chip_id == CHIP_ID_EM28174) {
- /* Digital only device - don't load any alsa module */
- dev->audio_mode.has_audio = false;
- dev->has_audio_class = false;
- dev->has_alsa_audio = false;
+ if (!dev->audio_mode.has_audio)
return 0;
- }
-
- dev->audio_mode.has_audio = true;
/* See how this device is configured */
cfg = em28xx_read_reg(dev, EM28XX_R00_CHIPCFG);
@@ -504,17 +520,19 @@ int em28xx_audio_setup(struct em28xx *dev)
dev->has_alsa_audio = false;
dev->audio_mode.has_audio = false;
return 0;
- } else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) ==
- EM28XX_CHIPCFG_I2S_3_SAMPRATES) {
- em28xx_info("I2S Audio (3 sample rates)\n");
- dev->audio_mode.i2s_3rates = 1;
- } else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) ==
- EM28XX_CHIPCFG_I2S_5_SAMPRATES) {
- em28xx_info("I2S Audio (5 sample rates)\n");
- dev->audio_mode.i2s_5rates = 1;
- }
-
- if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) != EM28XX_CHIPCFG_AC97) {
+ } else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) != EM28XX_CHIPCFG_AC97) {
+ if (dev->chip_id < CHIP_ID_EM2860 &&
+ (cfg & EM28XX_CHIPCFG_AUDIOMASK) ==
+ EM2820_CHIPCFG_I2S_1_SAMPRATE)
+ dev->audio_mode.i2s_samplerates = 1;
+ else if (dev->chip_id >= CHIP_ID_EM2860 &&
+ (cfg & EM28XX_CHIPCFG_AUDIOMASK) ==
+ EM2860_CHIPCFG_I2S_5_SAMPRATES)
+ dev->audio_mode.i2s_samplerates = 5;
+ else
+ dev->audio_mode.i2s_samplerates = 3;
+ em28xx_info("I2S Audio (%d sample rate(s))\n",
+ dev->audio_mode.i2s_samplerates);
/* Skip the code that does AC97 vendor detection */
dev->audio_mode.ac97 = EM28XX_NO_AC97;
goto init_audio;
@@ -582,295 +600,81 @@ init_audio:
}
EXPORT_SYMBOL_GPL(em28xx_audio_setup);
-int em28xx_colorlevels_set_default(struct em28xx *dev)
+const struct em28xx_led *em28xx_find_led(struct em28xx *dev,
+ enum em28xx_led_role role)
{
- em28xx_write_reg(dev, EM28XX_R20_YGAIN, CONTRAST_DEFAULT);
- em28xx_write_reg(dev, EM28XX_R21_YOFFSET, BRIGHTNESS_DEFAULT);
- em28xx_write_reg(dev, EM28XX_R22_UVGAIN, SATURATION_DEFAULT);
- em28xx_write_reg(dev, EM28XX_R23_UOFFSET, BLUE_BALANCE_DEFAULT);
- em28xx_write_reg(dev, EM28XX_R24_VOFFSET, RED_BALANCE_DEFAULT);
- em28xx_write_reg(dev, EM28XX_R25_SHARPNESS, SHARPNESS_DEFAULT);
-
- em28xx_write_reg(dev, EM28XX_R14_GAMMA, 0x20);
- em28xx_write_reg(dev, EM28XX_R15_RGAIN, 0x20);
- em28xx_write_reg(dev, EM28XX_R16_GGAIN, 0x20);
- em28xx_write_reg(dev, EM28XX_R17_BGAIN, 0x20);
- em28xx_write_reg(dev, EM28XX_R18_ROFFSET, 0x00);
- em28xx_write_reg(dev, EM28XX_R19_GOFFSET, 0x00);
- return em28xx_write_reg(dev, EM28XX_R1A_BOFFSET, 0x00);
+ if (dev->board.leds) {
+ u8 k = 0;
+ while (dev->board.leds[k].role >= 0 &&
+ dev->board.leds[k].role < EM28XX_NUM_LED_ROLES) {
+ if (dev->board.leds[k].role == role)
+ return &dev->board.leds[k];
+ k++;
+ }
+ }
+ return NULL;
}
+EXPORT_SYMBOL_GPL(em28xx_find_led);
int em28xx_capture_start(struct em28xx *dev, int start)
{
int rc;
+ const struct em28xx_led *led = NULL;
if (dev->chip_id == CHIP_ID_EM2874 ||
dev->chip_id == CHIP_ID_EM2884 ||
- dev->chip_id == CHIP_ID_EM28174) {
+ dev->chip_id == CHIP_ID_EM28174 ||
+ dev->chip_id == CHIP_ID_EM28178) {
/* The Transport Stream Enable Register moved in em2874 */
- if (!start) {
- rc = em28xx_write_reg_bits(dev, EM2874_R5F_TS_ENABLE,
- 0x00,
- EM2874_TS1_CAPTURE_ENABLE);
- return rc;
- }
-
- /* Enable Transport Stream */
rc = em28xx_write_reg_bits(dev, EM2874_R5F_TS_ENABLE,
- EM2874_TS1_CAPTURE_ENABLE,
+ start ?
+ EM2874_TS1_CAPTURE_ENABLE : 0x00,
EM2874_TS1_CAPTURE_ENABLE);
- return rc;
- }
-
-
- /* FIXME: which is the best order? */
- /* video registers are sampled by VREF */
- rc = em28xx_write_reg_bits(dev, EM28XX_R0C_USBSUSP,
- start ? 0x10 : 0x00, 0x10);
- if (rc < 0)
- return rc;
-
- if (!start) {
- /* disable video capture */
- rc = em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x27);
- return rc;
- }
-
- if (dev->board.is_webcam)
- rc = em28xx_write_reg(dev, 0x13, 0x0c);
-
- /* enable video capture */
- rc = em28xx_write_reg(dev, 0x48, 0x00);
-
- if (dev->mode == EM28XX_ANALOG_MODE)
- rc = em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x67);
- else
- rc = em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x37);
-
- msleep(6);
-
- return rc;
-}
-
-int em28xx_vbi_supported(struct em28xx *dev)
-{
- /* Modprobe option to manually disable */
- if (disable_vbi == 1)
- return 0;
-
- if (dev->board.is_webcam)
- return 0;
-
- /* FIXME: check subdevices for VBI support */
-
- if (dev->chip_id == CHIP_ID_EM2860 ||
- dev->chip_id == CHIP_ID_EM2883)
- return 1;
+ } else {
+ /* FIXME: which is the best order? */
+ /* video registers are sampled by VREF */
+ rc = em28xx_write_reg_bits(dev, EM28XX_R0C_USBSUSP,
+ start ? 0x10 : 0x00, 0x10);
+ if (rc < 0)
+ return rc;
- /* Version of em28xx that does not support VBI */
- return 0;
-}
+ if (start) {
+ if (dev->board.is_webcam)
+ rc = em28xx_write_reg(dev, 0x13, 0x0c);
-int em28xx_set_outfmt(struct em28xx *dev)
-{
- int ret;
- u8 fmt, vinctrl;
-
- fmt = dev->format->reg;
- if (!dev->is_em25xx)
- fmt |= 0x20;
- /*
- * NOTE: it's not clear if this is really needed !
- * The datasheets say bit 5 is a reserved bit and devices seem to work
- * fine without it. But the Windows driver sets it for em2710/50+em28xx
- * devices and we've always been setting it, too.
- *
- * em2765 (em25xx, em276x/7x/8x) devices do NOT work with this bit set,
- * it's likely used for an additional (compressed ?) format there.
- */
- ret = em28xx_write_reg(dev, EM28XX_R27_OUTFMT, fmt);
- if (ret < 0)
- return ret;
+ /* Enable video capture */
+ rc = em28xx_write_reg(dev, 0x48, 0x00);
+ if (rc < 0)
+ return rc;
- ret = em28xx_write_reg(dev, EM28XX_R10_VINMODE, dev->vinmode);
- if (ret < 0)
- return ret;
+ if (dev->mode == EM28XX_ANALOG_MODE)
+ rc = em28xx_write_reg(dev,
+ EM28XX_R12_VINENABLE, 0x67);
+ else
+ rc = em28xx_write_reg(dev,
+ EM28XX_R12_VINENABLE, 0x37);
+ if (rc < 0)
+ return rc;
- vinctrl = dev->vinctl;
- if (em28xx_vbi_supported(dev) == 1) {
- vinctrl |= EM28XX_VINCTRL_VBI_RAW;
- em28xx_write_reg(dev, EM28XX_R34_VBI_START_H, 0x00);
- em28xx_write_reg(dev, EM28XX_R36_VBI_WIDTH, dev->vbi_width/4);
- em28xx_write_reg(dev, EM28XX_R37_VBI_HEIGHT, dev->vbi_height);
- if (dev->norm & V4L2_STD_525_60) {
- /* NTSC */
- em28xx_write_reg(dev, EM28XX_R35_VBI_START_V, 0x09);
- } else if (dev->norm & V4L2_STD_625_50) {
- /* PAL */
- em28xx_write_reg(dev, EM28XX_R35_VBI_START_V, 0x07);
+ msleep(6);
+ } else {
+ /* disable video capture */
+ rc = em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x27);
}
}
- return em28xx_write_reg(dev, EM28XX_R11_VINCTRL, vinctrl);
-}
-
-static int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax,
- u8 ymin, u8 ymax)
-{
- em28xx_coredbg("em28xx Scale: (%d,%d)-(%d,%d)\n",
- xmin, ymin, xmax, ymax);
-
- em28xx_write_regs(dev, EM28XX_R28_XMIN, &xmin, 1);
- em28xx_write_regs(dev, EM28XX_R29_XMAX, &xmax, 1);
- em28xx_write_regs(dev, EM28XX_R2A_YMIN, &ymin, 1);
- return em28xx_write_regs(dev, EM28XX_R2B_YMAX, &ymax, 1);
-}
-
-static void em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart,
- u16 width, u16 height)
-{
- u8 cwidth = width >> 2;
- u8 cheight = height >> 2;
- u8 overflow = (height >> 9 & 0x02) | (width >> 10 & 0x01);
- /* NOTE: size limit: 2047x1023 = 2MPix */
-
- em28xx_coredbg("capture area set to (%d,%d): %dx%d\n",
- hstart, vstart,
- ((overflow & 2) << 9 | cwidth << 2),
- ((overflow & 1) << 10 | cheight << 2));
-
- em28xx_write_regs(dev, EM28XX_R1C_HSTART, &hstart, 1);
- em28xx_write_regs(dev, EM28XX_R1D_VSTART, &vstart, 1);
- em28xx_write_regs(dev, EM28XX_R1E_CWIDTH, &cwidth, 1);
- em28xx_write_regs(dev, EM28XX_R1F_CHEIGHT, &cheight, 1);
- em28xx_write_regs(dev, EM28XX_R1B_OFLOW, &overflow, 1);
-
- /* FIXME: function/meaning of these registers ? */
- /* FIXME: align width+height to multiples of 4 ?! */
- if (dev->is_em25xx) {
- em28xx_write_reg(dev, 0x34, width >> 4);
- em28xx_write_reg(dev, 0x35, height >> 4);
- }
-}
-
-static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v)
-{
- u8 mode;
- /* the em2800 scaler only supports scaling down to 50% */
-
- if (dev->board.is_em2800) {
- mode = (v ? 0x20 : 0x00) | (h ? 0x10 : 0x00);
- } else {
- u8 buf[2];
-
- buf[0] = h;
- buf[1] = h >> 8;
- em28xx_write_regs(dev, EM28XX_R30_HSCALELOW, (char *)buf, 2);
-
- buf[0] = v;
- buf[1] = v >> 8;
- em28xx_write_regs(dev, EM28XX_R32_VSCALELOW, (char *)buf, 2);
- /* it seems that both H and V scalers must be active
- to work correctly */
- mode = (h || v) ? 0x30 : 0x00;
- }
- return em28xx_write_reg_bits(dev, EM28XX_R26_COMPR, mode, 0x30);
-}
-
-/* FIXME: this only function read values from dev */
-int em28xx_resolution_set(struct em28xx *dev)
-{
- int width, height;
- width = norm_maxw(dev);
- height = norm_maxh(dev);
-
- /* Properly setup VBI */
- dev->vbi_width = 720;
- if (dev->norm & V4L2_STD_525_60)
- dev->vbi_height = 12;
- else
- dev->vbi_height = 18;
-
- em28xx_set_outfmt(dev);
-
- em28xx_accumulator_set(dev, 1, (width - 4) >> 2, 1, (height - 4) >> 2);
-
- /* If we don't set the start position to 2 in VBI mode, we end up
- with line 20/21 being YUYV encoded instead of being in 8-bit
- greyscale. The core of the issue is that line 21 (and line 23 for
- PAL WSS) are inside of active video region, and as a result they
- get the pixelformatting associated with that area. So by cropping
- it out, we end up with the same format as the rest of the VBI
- region */
- if (em28xx_vbi_supported(dev) == 1)
- em28xx_capture_area_set(dev, 0, 2, width, height);
+ if (dev->mode == EM28XX_ANALOG_MODE)
+ led = em28xx_find_led(dev, EM28XX_LED_ANALOG_CAPTURING);
else
- em28xx_capture_area_set(dev, 0, 0, width, height);
-
- return em28xx_scaler_set(dev, dev->hscale, dev->vscale);
-}
+ led = em28xx_find_led(dev, EM28XX_LED_DIGITAL_CAPTURING);
-/* Set USB alternate setting for analog video */
-int em28xx_set_alternate(struct em28xx *dev)
-{
- int errCode;
- int i;
- unsigned int min_pkt_size = dev->width * 2 + 4;
-
- /* NOTE: for isoc transfers, only alt settings > 0 are allowed
- bulk transfers seem to work only with alt=0 ! */
- dev->alt = 0;
- if ((alt > 0) && (alt < dev->num_alt)) {
- em28xx_coredbg("alternate forced to %d\n", dev->alt);
- dev->alt = alt;
- goto set_alt;
- }
- if (dev->analog_xfer_bulk)
- goto set_alt;
+ if (led)
+ em28xx_write_reg_bits(dev, led->gpio_reg,
+ (!start ^ led->inverted) ?
+ ~led->gpio_mask : led->gpio_mask,
+ led->gpio_mask);
- /* When image size is bigger than a certain value,
- the frame size should be increased, otherwise, only
- green screen will be received.
- */
- if (dev->width * 2 * dev->height > 720 * 240 * 2)
- min_pkt_size *= 2;
-
- for (i = 0; i < dev->num_alt; i++) {
- /* stop when the selected alt setting offers enough bandwidth */
- if (dev->alt_max_pkt_size_isoc[i] >= min_pkt_size) {
- dev->alt = i;
- break;
- /* otherwise make sure that we end up with the maximum bandwidth
- because the min_pkt_size equation might be wrong...
- */
- } else if (dev->alt_max_pkt_size_isoc[i] >
- dev->alt_max_pkt_size_isoc[dev->alt])
- dev->alt = i;
- }
-
-set_alt:
- /* NOTE: for bulk transfers, we need to call usb_set_interface()
- * even if the previous settings were the same. Otherwise streaming
- * fails with all urbs having status = -EOVERFLOW ! */
- if (dev->analog_xfer_bulk) {
- dev->max_pkt_size = 512; /* USB 2.0 spec */
- dev->packet_multiplier = EM28XX_BULK_PACKET_MULTIPLIER;
- } else { /* isoc */
- em28xx_coredbg("minimum isoc packet size: %u (alt=%d)\n",
- min_pkt_size, dev->alt);
- dev->max_pkt_size =
- dev->alt_max_pkt_size_isoc[dev->alt];
- dev->packet_multiplier = EM28XX_NUM_ISOC_PACKETS;
- }
- em28xx_coredbg("setting alternate %d with wMaxPacketSize=%u\n",
- dev->alt, dev->max_pkt_size);
- errCode = usb_set_interface(dev->udev, 0, dev->alt);
- if (errCode < 0) {
- em28xx_errdev("cannot change alternate number to %d (error=%i)\n",
- dev->alt, errCode);
- return errCode;
- }
- return 0;
+ return rc;
}
int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio)
@@ -1238,18 +1042,6 @@ int em28xx_init_usb_xfer(struct em28xx *dev, enum em28xx_mode mode,
EXPORT_SYMBOL_GPL(em28xx_init_usb_xfer);
/*
- * em28xx_wake_i2c()
- * configure i2c attached devices
- */
-void em28xx_wake_i2c(struct em28xx *dev)
-{
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, reset, 0);
- v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing,
- INPUT(dev->ctl_input)->vmux, 0, 0);
- v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0);
-}
-
-/*
* Device control list
*/
@@ -1272,7 +1064,7 @@ int em28xx_register_extension(struct em28xx_ops *ops)
ops->init(dev);
}
mutex_unlock(&em28xx_devlist_mutex);
- printk(KERN_INFO "Em28xx: Initialized (%s) extension\n", ops->name);
+ printk(KERN_INFO "em28xx: Registered (%s) extension\n", ops->name);
return 0;
}
EXPORT_SYMBOL(em28xx_register_extension);
@@ -1316,3 +1108,31 @@ void em28xx_close_extension(struct em28xx *dev)
list_del(&dev->devlist);
mutex_unlock(&em28xx_devlist_mutex);
}
+
+int em28xx_suspend_extension(struct em28xx *dev)
+{
+ const struct em28xx_ops *ops = NULL;
+
+ em28xx_info("Suspending extensions");
+ mutex_lock(&em28xx_devlist_mutex);
+ list_for_each_entry(ops, &em28xx_extension_devlist, next) {
+ if (ops->suspend)
+ ops->suspend(dev);
+ }
+ mutex_unlock(&em28xx_devlist_mutex);
+ return 0;
+}
+
+int em28xx_resume_extension(struct em28xx *dev)
+{
+ const struct em28xx_ops *ops = NULL;
+
+ em28xx_info("Resuming extensions");
+ mutex_lock(&em28xx_devlist_mutex);
+ list_for_each_entry(ops, &em28xx_extension_devlist, next) {
+ if (ops->resume)
+ ops->resume(dev);
+ }
+ mutex_unlock(&em28xx_devlist_mutex);
+ return 0;
+}
diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
index bb1e8dca80c..a121ed9561f 100644
--- a/drivers/media/usb/em28xx/em28xx-dvb.c
+++ b/drivers/media/usb/em28xx/em28xx-dvb.c
@@ -41,6 +41,7 @@
#include "mt352.h"
#include "mt352_priv.h" /* FIXME */
#include "tda1002x.h"
+#include "drx39xyj/drx39xxj.h"
#include "tda18271.h"
#include "s921.h"
#include "drxd.h"
@@ -48,13 +49,20 @@
#include "tda18271c2dd.h"
#include "drxk.h"
#include "tda10071.h"
+#include "tda18212.h"
#include "a8293.h"
#include "qt1010.h"
#include "mb86a20s.h"
+#include "m88ds3103.h"
+#include "m88ts2022.h"
+#include "si2168.h"
+#include "si2157.h"
-MODULE_DESCRIPTION("driver for em28xx based DVB cards");
MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION(DRIVER_DESC " - digital TV interface");
+MODULE_VERSION(EM28XX_VERSION);
+
static unsigned int debug;
module_param(debug, int, 0644);
@@ -87,6 +95,8 @@ struct em28xx_dvb {
struct semaphore pll_mutex;
bool dont_attach_fe1;
int lna_gpio;
+ struct i2c_client *i2c_client_demod;
+ struct i2c_client *i2c_client_tuner;
};
@@ -156,6 +166,8 @@ static inline int em28xx_dvb_urb_data_copy(struct em28xx *dev, struct urb *urb)
if (urb->status != -EPROTO)
continue;
}
+ if (!urb->actual_length)
+ continue;
dvb_dmx_swfilter(&dev->dvb->demux, urb->transfer_buffer,
urb->actual_length);
} else {
@@ -165,6 +177,8 @@ static inline int em28xx_dvb_urb_data_copy(struct em28xx *dev, struct urb *urb)
if (urb->iso_frame_desc[i].status != -EPROTO)
continue;
}
+ if (!urb->iso_frame_desc[i].actual_length)
+ continue;
dvb_dmx_swfilter(&dev->dvb->demux,
urb->transfer_buffer +
urb->iso_frame_desc[i].offset,
@@ -198,15 +212,15 @@ static int em28xx_start_streaming(struct em28xx_dvb *dvb)
dvb_alt = dev->dvb_alt_isoc;
}
- usb_set_interface(dev->udev, 0, dvb_alt);
+ usb_set_interface(dev->udev, dev->ifnum, dvb_alt);
rc = em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
if (rc < 0)
return rc;
- dprintk(1, "Using %d buffers each with %d x %d bytes\n",
+ dprintk(1, "Using %d buffers each with %d x %d bytes, alternate %d\n",
EM28XX_DVB_NUM_BUFS,
packet_multiplier,
- dvb_max_packet_size);
+ dvb_max_packet_size, dvb_alt);
return em28xx_init_usb_xfer(dev, EM28XX_DIGITAL_MODE,
dev->dvb_xfer_bulk,
@@ -271,7 +285,7 @@ static int em28xx_stop_feed(struct dvb_demux_feed *feed)
static int em28xx_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire)
{
struct em28xx_i2c_bus *i2c_bus = fe->dvb->priv;
- struct em28xx *dev = i2c_bus->dev;
+ struct em28xx *dev = i2c_bus->dev;
if (acquire)
return em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
@@ -298,6 +312,30 @@ static struct lgdt3305_config em2870_lgdt3304_dev = {
.qam_if_khz = 4000,
};
+static struct lgdt3305_config em2874_lgdt3305_dev = {
+ .i2c_addr = 0x0e,
+ .demod_chip = LGDT3305,
+ .spectral_inversion = 1,
+ .deny_i2c_rptr = 0,
+ .mpeg_mode = LGDT3305_MPEG_SERIAL,
+ .tpclk_edge = LGDT3305_TPCLK_FALLING_EDGE,
+ .tpvalid_polarity = LGDT3305_TP_VALID_HIGH,
+ .vsb_if_khz = 3250,
+ .qam_if_khz = 4000,
+};
+
+static struct lgdt3305_config em2874_lgdt3305_nogate_dev = {
+ .i2c_addr = 0x0e,
+ .demod_chip = LGDT3305,
+ .spectral_inversion = 1,
+ .deny_i2c_rptr = 1,
+ .mpeg_mode = LGDT3305_MPEG_SERIAL,
+ .tpclk_edge = LGDT3305_TPCLK_FALLING_EDGE,
+ .tpvalid_polarity = LGDT3305_TP_VALID_HIGH,
+ .vsb_if_khz = 3600,
+ .qam_if_khz = 3600,
+};
+
static struct s921_config sharp_isdbt = {
.demod_address = 0x30 >> 1
};
@@ -329,6 +367,17 @@ static struct tda18271_config kworld_a340_config = {
.std_map = &kworld_a340_std_map,
};
+static struct tda18271_config kworld_ub435q_v2_config = {
+ .std_map = &kworld_a340_std_map,
+ .gate = TDA18271_GATE_DIGITAL,
+};
+
+static struct tda18212_config kworld_ub435q_v3_config = {
+ .i2c_address = 0x60,
+ .if_atsc_vsb = 3600,
+ .if_atsc_qam = 3600,
+};
+
static struct zl10353_config em28xx_zl10353_xc3028_no_i2c_gate = {
.demod_address = (0x1e >> 1),
.no_tuner = 1,
@@ -353,7 +402,6 @@ static struct drxk_config terratec_h5_drxk = {
.no_i2c_bridge = 1,
.microcode_name = "dvb-usb-terratec-h5-drxk.fw",
.qam_demod_parameter_count = 2,
- .load_firmware_sync = true,
};
static struct drxk_config hauppauge_930c_drxk = {
@@ -363,7 +411,6 @@ static struct drxk_config hauppauge_930c_drxk = {
.microcode_name = "dvb-usb-hauppauge-hvr930c-drxk.fw",
.chunk_size = 56,
.qam_demod_parameter_count = 2,
- .load_firmware_sync = true,
};
static struct drxk_config terratec_htc_stick_drxk = {
@@ -377,14 +424,15 @@ static struct drxk_config terratec_htc_stick_drxk = {
.antenna_dvbt = true,
/* The windows driver uses the same. This will disable LNA. */
.antenna_gpio = 0x6,
- .load_firmware_sync = true,
};
static struct drxk_config maxmedia_ub425_tc_drxk = {
.adr = 0x29,
.single_master = 1,
.no_i2c_bridge = 1,
- .load_firmware_sync = true,
+ .microcode_name = "dvb-demod-drxk-01.fw",
+ .chunk_size = 62,
+ .qam_demod_parameter_count = 2,
};
static struct drxk_config pctv_520e_drxk = {
@@ -395,7 +443,6 @@ static struct drxk_config pctv_520e_drxk = {
.chunk_size = 58,
.antenna_dvbt = true, /* disable LNA */
.antenna_gpio = (1 << 2), /* disable LNA */
- .load_firmware_sync = true,
};
static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable)
@@ -424,7 +471,7 @@ static void hauppauge_hvr930c_init(struct em28xx *dev)
{EM2874_R80_GPIO_P0_CTRL, 0xff, 0xff, 0x65},
{EM2874_R80_GPIO_P0_CTRL, 0xfb, 0xff, 0x32},
{EM2874_R80_GPIO_P0_CTRL, 0xff, 0xff, 0xb8},
- { -1, -1, -1, -1},
+ { -1, -1, -1, -1},
};
struct em28xx_reg_seq hauppauge_hvr930c_end[] = {
{EM2874_R80_GPIO_P0_CTRL, 0xef, 0xff, 0x01},
@@ -439,7 +486,7 @@ static void hauppauge_hvr930c_init(struct em28xx *dev)
{EM2874_R80_GPIO_P0_CTRL, 0xcf, 0xff, 0x0b},
{EM2874_R80_GPIO_P0_CTRL, 0xef, 0xff, 0x65},
- { -1, -1, -1, -1},
+ { -1, -1, -1, -1},
};
struct {
@@ -491,13 +538,13 @@ static void terratec_h5_init(struct em28xx *dev)
{EM2874_R80_GPIO_P0_CTRL, 0xf6, 0xff, 100},
{EM2874_R80_GPIO_P0_CTRL, 0xf2, 0xff, 50},
{EM2874_R80_GPIO_P0_CTRL, 0xf6, 0xff, 100},
- { -1, -1, -1, -1},
+ { -1, -1, -1, -1},
};
struct em28xx_reg_seq terratec_h5_end[] = {
{EM2874_R80_GPIO_P0_CTRL, 0xe6, 0xff, 100},
{EM2874_R80_GPIO_P0_CTRL, 0xa6, 0xff, 50},
{EM2874_R80_GPIO_P0_CTRL, 0xe6, 0xff, 100},
- { -1, -1, -1, -1},
+ { -1, -1, -1, -1},
};
struct {
unsigned char r[4];
@@ -547,12 +594,12 @@ static void terratec_htc_stick_init(struct em28xx *dev)
{EM2874_R80_GPIO_P0_CTRL, 0xf6, 0xff, 100},
{EM2874_R80_GPIO_P0_CTRL, 0xe6, 0xff, 50},
{EM2874_R80_GPIO_P0_CTRL, 0xf6, 0xff, 100},
- { -1, -1, -1, -1},
+ { -1, -1, -1, -1},
};
struct em28xx_reg_seq terratec_htc_stick_end[] = {
{EM2874_R80_GPIO_P0_CTRL, 0xb6, 0xff, 100},
{EM2874_R80_GPIO_P0_CTRL, 0xf6, 0xff, 50},
- { -1, -1, -1, -1},
+ { -1, -1, -1, -1},
};
/*
@@ -594,13 +641,13 @@ static void terratec_htc_usb_xs_init(struct em28xx *dev)
{EM2874_R80_GPIO_P0_CTRL, 0xb2, 0xff, 100},
{EM2874_R80_GPIO_P0_CTRL, 0xb2, 0xff, 50},
{EM2874_R80_GPIO_P0_CTRL, 0xb6, 0xff, 100},
- { -1, -1, -1, -1},
+ { -1, -1, -1, -1},
};
struct em28xx_reg_seq terratec_htc_usb_xs_end[] = {
{EM2874_R80_GPIO_P0_CTRL, 0xa6, 0xff, 100},
{EM2874_R80_GPIO_P0_CTRL, 0xa6, 0xff, 50},
{EM2874_R80_GPIO_P0_CTRL, 0xe6, 0xff, 100},
- { -1, -1, -1, -1},
+ { -1, -1, -1, -1},
};
/*
@@ -673,7 +720,8 @@ static void pctv_520e_init(struct em28xx *dev)
static int em28xx_pctv_290e_set_lna(struct dvb_frontend *fe)
{
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
- struct em28xx *dev = fe->dvb->priv;
+ struct em28xx_i2c_bus *i2c_bus = fe->dvb->priv;
+ struct em28xx *dev = i2c_bus->dev;
#ifdef CONFIG_GPIOLIB
struct em28xx_dvb *dvb = dev->dvb;
int ret;
@@ -698,6 +746,21 @@ static int em28xx_pctv_290e_set_lna(struct dvb_frontend *fe)
#endif
}
+static int em28xx_pctv_292e_set_lna(struct dvb_frontend *fe)
+{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ struct em28xx_i2c_bus *i2c_bus = fe->dvb->priv;
+ struct em28xx *dev = i2c_bus->dev;
+ u8 lna;
+
+ if (c->lna == 1)
+ lna = 0x01;
+ else
+ lna = 0x00;
+
+ return em28xx_write_reg_bits(dev, EM2874_R80_GPIO_P0_CTRL, lna, 0x01);
+}
+
static int em28xx_mt352_terratec_xs_init(struct dvb_frontend *fe)
{
/* Values extracted from a USB trace of the Terratec Windows driver */
@@ -788,6 +851,28 @@ static struct tda18271_config c3tech_duo_tda18271_config = {
.small_i2c = TDA18271_03_BYTE_CHUNK_INIT,
};
+static const struct m88ds3103_config pctv_461e_m88ds3103_config = {
+ .i2c_addr = 0x68,
+ .clock = 27000000,
+ .i2c_wr_max = 33,
+ .clock_out = 0,
+ .ts_mode = M88DS3103_TS_PARALLEL_16,
+ .agc = 0x99,
+};
+
+
+static struct tda18271_std_map drx_j_std_map = {
+ .atsc_6 = { .if_freq = 5000, .agc_mode = 3, .std = 0, .if_lvl = 1,
+ .rfagc_top = 0x37, },
+ .qam_6 = { .if_freq = 5380, .agc_mode = 3, .std = 3, .if_lvl = 1,
+ .rfagc_top = 0x37, },
+};
+
+static struct tda18271_config pinnacle_80e_dvb_config = {
+ .std_map = &drx_j_std_map,
+ .gate = TDA18271_GATE_DIGITAL,
+ .role = TDA18271_MASTER,
+};
/* ------------------------------------------------------------------ */
@@ -795,11 +880,16 @@ static int em28xx_attach_xc3028(u8 addr, struct em28xx *dev)
{
struct dvb_frontend *fe;
struct xc2028_config cfg;
+ struct xc2028_ctrl ctl;
memset(&cfg, 0, sizeof(cfg));
cfg.i2c_adap = &dev->i2c_adap[dev->def_i2c_bus];
cfg.i2c_addr = addr;
+ memset(&ctl, 0, sizeof(ctl));
+ em28xx_setup_xc3028(dev, &ctl);
+ cfg.ctrl = &ctl;
+
if (!dev->dvb->fe[0]) {
em28xx_errdev("/2: dvb frontend not attached. "
"Can't attach xc3028\n");
@@ -959,14 +1049,19 @@ static int em28xx_dvb_init(struct em28xx *dev)
int result = 0, mfe_shared = 0;
struct em28xx_dvb *dvb;
+ if (dev->is_audio_only) {
+ /* Shouldn't initialize IR for this interface */
+ return 0;
+ }
+
if (!dev->board.has_dvb) {
/* This device does not support the extension */
- printk(KERN_INFO "em28xx_dvb: This device does not support the extension\n");
return 0;
}
- dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL);
+ em28xx_info("Binding DVB extension\n");
+ dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL);
if (dvb == NULL) {
em28xx_info("em28xx_dvb: memory allocation failed\n");
return -ENOMEM;
@@ -974,6 +1069,27 @@ static int em28xx_dvb_init(struct em28xx *dev)
dev->dvb = dvb;
dvb->fe[0] = dvb->fe[1] = NULL;
+ /* pre-allocate DVB usb transfer buffers */
+ if (dev->dvb_xfer_bulk) {
+ result = em28xx_alloc_urbs(dev, EM28XX_DIGITAL_MODE,
+ dev->dvb_xfer_bulk,
+ EM28XX_DVB_NUM_BUFS,
+ 512,
+ EM28XX_DVB_BULK_PACKET_MULTIPLIER);
+ } else {
+ result = em28xx_alloc_urbs(dev, EM28XX_DIGITAL_MODE,
+ dev->dvb_xfer_bulk,
+ EM28XX_DVB_NUM_BUFS,
+ dev->dvb_max_pkt_size_isoc,
+ EM28XX_DVB_NUM_ISOC_PACKETS);
+ }
+ if (result) {
+ em28xx_errdev("em28xx_dvb: failed to pre-allocate USB transfer buffers for DVB.\n");
+ kfree(dvb);
+ dev->dvb = NULL;
+ return result;
+ }
+
mutex_lock(&dev->lock);
em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
/* init frontend */
@@ -1227,18 +1343,14 @@ static int em28xx_dvb_init(struct em28xx *dev)
dvb->fe[0]->ops.i2c_gate_ctrl = NULL;
/* attach tuner */
- if (!dvb_attach(tda18271c2dd_attach, dvb->fe[0],
- &dev->i2c_adap[dev->def_i2c_bus], 0x60)) {
+ if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
+ &dev->i2c_adap[dev->def_i2c_bus],
+ &em28xx_cxd2820r_tda18271_config)) {
dvb_frontend_detach(dvb->fe[0]);
result = -EINVAL;
goto out_free;
}
}
-
- /* TODO: we need drx-3913k firmware in order to support DVB-T */
- em28xx_info("MaxMedia UB425-TC/Delock 61959: only DVB-C " \
- "supported by that driver version\n");
-
break;
case EM2884_BOARD_PCTV_510E:
case EM2884_BOARD_PCTV_520E:
@@ -1297,6 +1409,168 @@ static int em28xx_dvb_init(struct em28xx *dev)
goto out_free;
}
break;
+ case EM2874_BOARD_KWORLD_UB435Q_V2:
+ dvb->fe[0] = dvb_attach(lgdt3305_attach,
+ &em2874_lgdt3305_dev,
+ &dev->i2c_adap[dev->def_i2c_bus]);
+ if (!dvb->fe[0]) {
+ result = -EINVAL;
+ goto out_free;
+ }
+
+ /* Attach the demodulator. */
+ if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
+ &dev->i2c_adap[dev->def_i2c_bus],
+ &kworld_ub435q_v2_config)) {
+ result = -EINVAL;
+ goto out_free;
+ }
+ break;
+ case EM2874_BOARD_KWORLD_UB435Q_V3:
+ dvb->fe[0] = dvb_attach(lgdt3305_attach,
+ &em2874_lgdt3305_nogate_dev,
+ &dev->i2c_adap[dev->def_i2c_bus]);
+ if (!dvb->fe[0]) {
+ result = -EINVAL;
+ goto out_free;
+ }
+
+ /* Attach the demodulator. */
+ if (!dvb_attach(tda18212_attach, dvb->fe[0],
+ &dev->i2c_adap[dev->def_i2c_bus],
+ &kworld_ub435q_v3_config)) {
+ result = -EINVAL;
+ goto out_free;
+ }
+ break;
+ case EM2874_BOARD_PCTV_HD_MINI_80E:
+ dvb->fe[0] = dvb_attach(drx39xxj_attach, &dev->i2c_adap[dev->def_i2c_bus]);
+ if (dvb->fe[0] != NULL) {
+ dvb->fe[0] = dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
+ &dev->i2c_adap[dev->def_i2c_bus],
+ &pinnacle_80e_dvb_config);
+ if (!dvb->fe[0]) {
+ result = -EINVAL;
+ goto out_free;
+ }
+ }
+ break;
+ case EM28178_BOARD_PCTV_461E:
+ {
+ /* demod I2C adapter */
+ struct i2c_adapter *i2c_adapter;
+ struct i2c_client *client;
+ struct i2c_board_info info;
+ struct m88ts2022_config m88ts2022_config = {
+ .clock = 27000000,
+ };
+ memset(&info, 0, sizeof(struct i2c_board_info));
+
+ /* attach demod */
+ dvb->fe[0] = dvb_attach(m88ds3103_attach,
+ &pctv_461e_m88ds3103_config,
+ &dev->i2c_adap[dev->def_i2c_bus],
+ &i2c_adapter);
+ if (dvb->fe[0] == NULL) {
+ result = -ENODEV;
+ goto out_free;
+ }
+
+ /* attach tuner */
+ m88ts2022_config.fe = dvb->fe[0];
+ strlcpy(info.type, "m88ts2022", I2C_NAME_SIZE);
+ info.addr = 0x60;
+ info.platform_data = &m88ts2022_config;
+ request_module("m88ts2022");
+ client = i2c_new_device(i2c_adapter, &info);
+ if (client == NULL || client->dev.driver == NULL) {
+ dvb_frontend_detach(dvb->fe[0]);
+ result = -ENODEV;
+ goto out_free;
+ }
+
+ if (!try_module_get(client->dev.driver->owner)) {
+ i2c_unregister_device(client);
+ dvb_frontend_detach(dvb->fe[0]);
+ result = -ENODEV;
+ goto out_free;
+ }
+
+ /* delegate signal strength measurement to tuner */
+ dvb->fe[0]->ops.read_signal_strength =
+ dvb->fe[0]->ops.tuner_ops.get_rf_strength;
+
+ /* attach SEC */
+ if (!dvb_attach(a8293_attach, dvb->fe[0],
+ &dev->i2c_adap[dev->def_i2c_bus],
+ &em28xx_a8293_config)) {
+ module_put(client->dev.driver->owner);
+ i2c_unregister_device(client);
+ dvb_frontend_detach(dvb->fe[0]);
+ result = -ENODEV;
+ goto out_free;
+ }
+
+ dvb->i2c_client_tuner = client;
+ }
+ break;
+ case EM28178_BOARD_PCTV_292E:
+ {
+ struct i2c_adapter *adapter;
+ struct i2c_client *client;
+ struct i2c_board_info info;
+ struct si2168_config si2168_config;
+ struct si2157_config si2157_config;
+
+ /* attach demod */
+ si2168_config.i2c_adapter = &adapter;
+ si2168_config.fe = &dvb->fe[0];
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ strlcpy(info.type, "si2168", I2C_NAME_SIZE);
+ info.addr = 0x64;
+ info.platform_data = &si2168_config;
+ request_module(info.type);
+ client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &info);
+ if (client == NULL || client->dev.driver == NULL) {
+ result = -ENODEV;
+ goto out_free;
+ }
+
+ if (!try_module_get(client->dev.driver->owner)) {
+ i2c_unregister_device(client);
+ result = -ENODEV;
+ goto out_free;
+ }
+
+ dvb->i2c_client_demod = client;
+
+ /* attach tuner */
+ si2157_config.fe = dvb->fe[0];
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ strlcpy(info.type, "si2157", I2C_NAME_SIZE);
+ info.addr = 0x60;
+ info.platform_data = &si2157_config;
+ request_module(info.type);
+ client = i2c_new_device(adapter, &info);
+ if (client == NULL || client->dev.driver == NULL) {
+ module_put(dvb->i2c_client_demod->dev.driver->owner);
+ i2c_unregister_device(dvb->i2c_client_demod);
+ result = -ENODEV;
+ goto out_free;
+ }
+
+ if (!try_module_get(client->dev.driver->owner)) {
+ i2c_unregister_device(client);
+ module_put(dvb->i2c_client_demod->dev.driver->owner);
+ i2c_unregister_device(dvb->i2c_client_demod);
+ result = -ENODEV;
+ goto out_free;
+ }
+
+ dvb->i2c_client_tuner = client;
+ dvb->fe[0]->ops.set_lna = em28xx_pctv_292e_set_lna;
+ }
+ break;
default:
em28xx_errdev("/2: The frontend of your DVB/ATSC card"
" isn't supported yet\n");
@@ -1321,7 +1595,10 @@ static int em28xx_dvb_init(struct em28xx *dev)
/* MFE lock */
dvb->adapter.mfe_shared = mfe_shared;
- em28xx_info("Successfully loaded em28xx-dvb\n");
+ em28xx_info("DVB extension successfully initialized\n");
+
+ kref_get(&dev->ref);
+
ret:
em28xx_set_mode(dev, EM28XX_SUSPEND);
mutex_unlock(&dev->lock);
@@ -1342,21 +1619,121 @@ static inline void prevent_sleep(struct dvb_frontend_ops *ops)
static int em28xx_dvb_fini(struct em28xx *dev)
{
+ struct em28xx_dvb *dvb;
+ struct i2c_client *client;
+
+ if (dev->is_audio_only) {
+ /* Shouldn't initialize IR for this interface */
+ return 0;
+ }
+
if (!dev->board.has_dvb) {
/* This device does not support the extension */
return 0;
}
+ if (!dev->dvb)
+ return 0;
+
+ em28xx_info("Closing DVB extension");
+
+ dvb = dev->dvb;
+ client = dvb->i2c_client_tuner;
+
+ em28xx_uninit_usb_xfer(dev, EM28XX_DIGITAL_MODE);
+
+ if (dev->disconnected) {
+ /* We cannot tell the device to sleep
+ * once it has been unplugged. */
+ if (dvb->fe[0])
+ prevent_sleep(&dvb->fe[0]->ops);
+ if (dvb->fe[1])
+ prevent_sleep(&dvb->fe[1]->ops);
+ }
+
+ /* remove I2C tuner */
+ if (client) {
+ module_put(client->dev.driver->owner);
+ i2c_unregister_device(client);
+ }
+
+ /* remove I2C demod */
+ client = dvb->i2c_client_demod;
+ if (client) {
+ module_put(client->dev.driver->owner);
+ i2c_unregister_device(client);
+ }
+
+ em28xx_unregister_dvb(dvb);
+ kfree(dvb);
+ dev->dvb = NULL;
+ kref_put(&dev->ref, em28xx_free_device);
+
+ return 0;
+}
+
+static int em28xx_dvb_suspend(struct em28xx *dev)
+{
+ int ret = 0;
+
+ if (dev->is_audio_only)
+ return 0;
+
+ if (!dev->board.has_dvb)
+ return 0;
+
+ em28xx_info("Suspending DVB extension");
if (dev->dvb) {
struct em28xx_dvb *dvb = dev->dvb;
- if (dev->disconnected) {
- /* We cannot tell the device to sleep
- * once it has been unplugged. */
- if (dvb->fe[0])
- prevent_sleep(&dvb->fe[0]->ops);
- if (dvb->fe[1])
- prevent_sleep(&dvb->fe[1]->ops);
+ if (dvb->fe[0]) {
+ ret = dvb_frontend_suspend(dvb->fe[0]);
+ em28xx_info("fe0 suspend %d", ret);
+ }
+ if (dvb->fe[1]) {
+ dvb_frontend_suspend(dvb->fe[1]);
+ em28xx_info("fe1 suspend %d", ret);
+ }
+ }
+
+ return 0;
+}
+
+static int em28xx_dvb_resume(struct em28xx *dev)
+{
+ int ret = 0;
+
+ if (dev->is_audio_only)
+ return 0;
+
+ if (!dev->board.has_dvb)
+ return 0;
+
+ em28xx_info("Resuming DVB extension");
+ if (dev->dvb) {
+ struct em28xx_dvb *dvb = dev->dvb;
+ struct i2c_client *client = dvb->i2c_client_tuner;
+
+ if (dvb->fe[0]) {
+ ret = dvb_frontend_resume(dvb->fe[0]);
+ em28xx_info("fe0 resume %d", ret);
+ }
+
+ if (dvb->fe[1]) {
+ ret = dvb_frontend_resume(dvb->fe[1]);
+ em28xx_info("fe1 resume %d", ret);
+ }
+ /* remove I2C tuner */
+ if (client) {
+ module_put(client->dev.driver->owner);
+ i2c_unregister_device(client);
+ }
+
+ /* remove I2C demod */
+ client = dvb->i2c_client_demod;
+ if (client) {
+ module_put(client->dev.driver->owner);
+ i2c_unregister_device(client);
}
em28xx_unregister_dvb(dvb);
@@ -1372,6 +1749,8 @@ static struct em28xx_ops dvb_ops = {
.name = "Em28xx dvb Extension",
.init = em28xx_dvb_init,
.fini = em28xx_dvb_fini,
+ .suspend = em28xx_dvb_suspend,
+ .resume = em28xx_dvb_resume,
};
static int __init em28xx_dvb_register(void)
diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c
index c4ff9739a7a..b58d4ebf641 100644
--- a/drivers/media/usb/em28xx/em28xx-i2c.c
+++ b/drivers/media/usb/em28xx/em28xx-i2c.c
@@ -26,6 +26,7 @@
#include <linux/kernel.h>
#include <linux/usb.h>
#include <linux/i2c.h>
+#include <linux/jiffies.h>
#include "em28xx.h"
#include "tuner-xc2028.h"
@@ -40,7 +41,7 @@ MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time");
static unsigned int i2c_debug;
module_param(i2c_debug, int, 0644);
-MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
+MODULE_PARM_DESC(i2c_debug, "i2c debug message level (1: normal debug, 2: show I2C transfers)");
/*
* em2800_i2c_send_bytes()
@@ -48,8 +49,8 @@ MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
*/
static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
{
+ unsigned long timeout = jiffies + msecs_to_jiffies(EM28XX_I2C_XFER_TIMEOUT);
int ret;
- int write_timeout;
u8 b2[6];
if (len < 1 || len > 4)
@@ -74,22 +75,26 @@ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
return (ret < 0) ? ret : -EIO;
}
/* wait for completion */
- for (write_timeout = EM2800_I2C_XFER_TIMEOUT; write_timeout > 0;
- write_timeout -= 5) {
+ while (time_is_after_jiffies(timeout)) {
ret = dev->em28xx_read_reg(dev, 0x05);
- if (ret == 0x80 + len - 1) {
+ if (ret == 0x80 + len - 1)
return len;
- } else if (ret == 0x94 + len - 1) {
- return -ENODEV;
- } else if (ret < 0) {
+ if (ret == 0x94 + len - 1) {
+ if (i2c_debug == 1)
+ em28xx_warn("R05 returned 0x%02x: I2C ACK error\n",
+ ret);
+ return -ENXIO;
+ }
+ if (ret < 0) {
em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
ret);
return ret;
}
msleep(5);
}
- em28xx_warn("write to i2c device at 0x%x timed out\n", addr);
- return -EIO;
+ if (i2c_debug)
+ em28xx_warn("write to i2c device at 0x%x timed out\n", addr);
+ return -ETIMEDOUT;
}
/*
@@ -98,9 +103,9 @@ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
*/
static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
{
+ unsigned long timeout = jiffies + msecs_to_jiffies(EM28XX_I2C_XFER_TIMEOUT);
u8 buf2[4];
int ret;
- int read_timeout;
int i;
if (len < 1 || len > 4)
@@ -117,22 +122,28 @@ static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
}
/* wait for completion */
- for (read_timeout = EM2800_I2C_XFER_TIMEOUT; read_timeout > 0;
- read_timeout -= 5) {
+ while (time_is_after_jiffies(timeout)) {
ret = dev->em28xx_read_reg(dev, 0x05);
- if (ret == 0x84 + len - 1) {
+ if (ret == 0x84 + len - 1)
break;
- } else if (ret == 0x94 + len - 1) {
- return -ENODEV;
- } else if (ret < 0) {
+ if (ret == 0x94 + len - 1) {
+ if (i2c_debug == 1)
+ em28xx_warn("R05 returned 0x%02x: I2C ACK error\n",
+ ret);
+ return -ENXIO;
+ }
+ if (ret < 0) {
em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
ret);
return ret;
}
msleep(5);
}
- if (ret != 0x84 + len - 1)
- em28xx_warn("read from i2c device at 0x%x timed out\n", addr);
+ if (ret != 0x84 + len - 1) {
+ if (i2c_debug)
+ em28xx_warn("read from i2c device at 0x%x timed out\n",
+ addr);
+ }
/* get the received message */
ret = dev->em28xx_read_reg_req_len(dev, 0x00, 4-len, buf2, len);
@@ -168,7 +179,8 @@ static int em2800_i2c_check_for_device(struct em28xx *dev, u8 addr)
static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
u16 len, int stop)
{
- int write_timeout, ret;
+ unsigned long timeout = jiffies + msecs_to_jiffies(EM28XX_I2C_XFER_TIMEOUT);
+ int ret;
if (len < 1 || len > 64)
return -EOPNOTSUPP;
@@ -191,16 +203,19 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
}
}
- /* Check success of the i2c operation */
- for (write_timeout = EM2800_I2C_XFER_TIMEOUT; write_timeout > 0;
- write_timeout -= 5) {
+ /* wait for completion */
+ while (time_is_after_jiffies(timeout)) {
ret = dev->em28xx_read_reg(dev, 0x05);
- if (ret == 0) { /* success */
+ if (ret == 0) /* success */
return len;
- } else if (ret == 0x10) {
- return -ENODEV;
- } else if (ret < 0) {
- em28xx_warn("failed to read i2c transfer status from bridge (error=%i)\n",
+ if (ret == 0x10) {
+ if (i2c_debug == 1)
+ em28xx_warn("I2C ACK error on writing to addr 0x%02x\n",
+ addr);
+ return -ENXIO;
+ }
+ if (ret < 0) {
+ em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
ret);
return ret;
}
@@ -211,7 +226,17 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
* (even with high payload) ...
*/
}
- em28xx_warn("write to i2c device at 0x%x timed out\n", addr);
+
+ if (ret == 0x02 || ret == 0x04) {
+ /* NOTE: these errors seem to be related to clock stretching */
+ if (i2c_debug)
+ em28xx_warn("write to i2c device at 0x%x timed out (status=%i)\n",
+ addr, ret);
+ return -ETIMEDOUT;
+ }
+
+ em28xx_warn("write to i2c device at 0x%x failed with unknown error (status=%i)\n",
+ addr, ret);
return -EIO;
}
@@ -242,26 +267,37 @@ static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len)
* bytes if we are on bus B AND there was no write attempt to the
* specified slave address before AND no device is present at the
* requested slave address.
- * Anyway, the next check will fail with -ENODEV in this case, so avoid
+ * Anyway, the next check will fail with -ENXIO in this case, so avoid
* spamming the system log on device probing and do nothing here.
*/
/* Check success of the i2c operation */
ret = dev->em28xx_read_reg(dev, 0x05);
+ if (ret == 0) /* success */
+ return len;
if (ret < 0) {
- em28xx_warn("failed to read i2c transfer status from bridge (error=%i)\n",
+ em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
ret);
return ret;
}
- if (ret > 0) {
- if (ret == 0x10) {
- return -ENODEV;
- } else {
- em28xx_warn("unknown i2c error (status=%i)\n", ret);
- return -EIO;
- }
+ if (ret == 0x10) {
+ if (i2c_debug == 1)
+ em28xx_warn("I2C ACK error on writing to addr 0x%02x\n",
+ addr);
+ return -ENXIO;
}
- return len;
+
+ if (ret == 0x02 || ret == 0x04) {
+ /* NOTE: these errors seem to be related to clock stretching */
+ if (i2c_debug)
+ em28xx_warn("write to i2c device at 0x%x timed out (status=%i)\n",
+ addr, ret);
+ return -ETIMEDOUT;
+ }
+
+ em28xx_warn("write to i2c device at 0x%x failed with unknown error (status=%i)\n",
+ addr, ret);
+ return -EIO;
}
/*
@@ -316,8 +352,12 @@ static int em25xx_bus_B_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
*/
if (!ret)
return len;
- else if (ret > 0)
- return -ENODEV;
+ else if (ret > 0) {
+ if (i2c_debug == 1)
+ em28xx_warn("Bus B R08 returned 0x%02x: I2C ACK error\n",
+ ret);
+ return -ENXIO;
+ }
return ret;
/*
@@ -355,7 +395,7 @@ static int em25xx_bus_B_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf,
* bytes if we are on bus B AND there was no write attempt to the
* specified slave address before AND no device is present at the
* requested slave address.
- * Anyway, the next check will fail with -ENODEV in this case, so avoid
+ * Anyway, the next check will fail with -ENXIO in this case, so avoid
* spamming the system log on device probing and do nothing here.
*/
@@ -367,8 +407,12 @@ static int em25xx_bus_B_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf,
*/
if (!ret)
return len;
- else if (ret > 0)
- return -ENODEV;
+ else if (ret > 0) {
+ if (i2c_debug == 1)
+ em28xx_warn("Bus B R08 returned 0x%02x: I2C ACK error\n",
+ ret);
+ return -ENXIO;
+ }
return ret;
/*
@@ -409,10 +453,6 @@ static inline int i2c_check_for_device(struct em28xx_i2c_bus *i2c_bus, u16 addr)
rc = em2800_i2c_check_for_device(dev, addr);
else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM25XX_BUS_B)
rc = em25xx_bus_B_check_for_device(dev, addr);
- if (rc == -ENODEV) {
- if (i2c_debug)
- printk(" no device\n");
- }
return rc;
}
@@ -421,7 +461,7 @@ static inline int i2c_recv_bytes(struct em28xx_i2c_bus *i2c_bus,
{
struct em28xx *dev = i2c_bus->dev;
u16 addr = msg.addr << 1;
- int byte, rc = -EOPNOTSUPP;
+ int rc = -EOPNOTSUPP;
if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM28XX)
rc = em28xx_i2c_recv_bytes(dev, addr, msg.buf, msg.len);
@@ -429,10 +469,6 @@ static inline int i2c_recv_bytes(struct em28xx_i2c_bus *i2c_bus,
rc = em2800_i2c_recv_bytes(dev, addr, msg.buf, msg.len);
else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM25XX_BUS_B)
rc = em25xx_bus_B_recv_bytes(dev, addr, msg.buf, msg.len);
- if (i2c_debug) {
- for (byte = 0; byte < msg.len; byte++)
- printk(" %02x", msg.buf[byte]);
- }
return rc;
}
@@ -441,12 +477,8 @@ static inline int i2c_send_bytes(struct em28xx_i2c_bus *i2c_bus,
{
struct em28xx *dev = i2c_bus->dev;
u16 addr = msg.addr << 1;
- int byte, rc = -EOPNOTSUPP;
+ int rc = -EOPNOTSUPP;
- if (i2c_debug) {
- for (byte = 0; byte < msg.len; byte++)
- printk(" %02x", msg.buf[byte]);
- }
if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM28XX)
rc = em28xx_i2c_send_bytes(dev, addr, msg.buf, msg.len, stop);
else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM2800)
@@ -491,33 +523,53 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap,
}
for (i = 0; i < num; i++) {
addr = msgs[i].addr << 1;
- if (i2c_debug)
+ if (i2c_debug > 1)
printk(KERN_DEBUG "%s at %s: %s %s addr=%02x len=%d:",
dev->name, __func__ ,
(msgs[i].flags & I2C_M_RD) ? "read" : "write",
i == num - 1 ? "stop" : "nonstop",
addr, msgs[i].len);
- if (!msgs[i].len) { /* no len: check only for device presence */
+ if (!msgs[i].len) {
+ /*
+ * no len: check only for device presence
+ * This code is only called during device probe.
+ */
rc = i2c_check_for_device(i2c_bus, addr);
- if (rc == -ENODEV) {
+ if (rc < 0) {
+ if (rc == -ENXIO) {
+ if (i2c_debug > 1)
+ printk(KERN_CONT " no device\n");
+ rc = -ENODEV;
+ } else {
+ if (i2c_debug > 1)
+ printk(KERN_CONT " ERROR: %i\n", rc);
+ }
rt_mutex_unlock(&dev->i2c_bus_lock);
return rc;
}
} else if (msgs[i].flags & I2C_M_RD) {
/* read bytes */
rc = i2c_recv_bytes(i2c_bus, msgs[i]);
+
+ if (i2c_debug > 1 && rc >= 0)
+ printk(KERN_CONT " %*ph",
+ msgs[i].len, msgs[i].buf);
} else {
+ if (i2c_debug > 1)
+ printk(KERN_CONT " %*ph",
+ msgs[i].len, msgs[i].buf);
+
/* write bytes */
rc = i2c_send_bytes(i2c_bus, msgs[i], i == num - 1);
}
if (rc < 0) {
- if (i2c_debug)
- printk(" ERROR: %i\n", rc);
+ if (i2c_debug > 1)
+ printk(KERN_CONT " ERROR: %i\n", rc);
rt_mutex_unlock(&dev->i2c_bus_lock);
return rc;
}
- if (i2c_debug)
- printk("\n");
+ if (i2c_debug > 1)
+ printk(KERN_CONT "\n");
}
rt_mutex_unlock(&dev->i2c_bus_lock);
@@ -600,7 +652,7 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus,
* calculation and returned device dataset. Simplifies the code a lot,
* but we might have to deal with multiple sizes in the future !
*/
- int i, err;
+ int err;
struct em28xx_eeprom *dev_config;
u8 buf, *data;
@@ -631,20 +683,14 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus,
goto error;
}
- /* Display eeprom content */
- for (i = 0; i < len; i++) {
- if (0 == (i % 16)) {
- if (dev->eeprom_addrwidth_16bit)
- em28xx_info("i2c eeprom %04x:", i);
- else
- em28xx_info("i2c eeprom %02x:", i);
- }
- printk(" %02x", data[i]);
- if (15 == (i % 16))
- printk("\n");
+ if (i2c_debug) {
+ /* Display eeprom content */
+ print_hex_dump(KERN_INFO, "eeprom ", DUMP_PREFIX_OFFSET,
+ 16, 1, data, len, true);
+
+ if (dev->eeprom_addrwidth_16bit)
+ em28xx_info("eeprom %06x: ... (skipped)\n", 256);
}
- if (dev->eeprom_addrwidth_16bit)
- em28xx_info("i2c eeprom %04x: ... (skipped)\n", i);
if (dev->eeprom_addrwidth_16bit &&
data[0] == 0x26 && data[3] == 0x00) {
@@ -736,10 +782,16 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus,
em28xx_info("\tAC97 audio (5 sample rates)\n");
break;
case 2:
- em28xx_info("\tI2S audio, sample rate=32k\n");
+ if (dev->chip_id < CHIP_ID_EM2860)
+ em28xx_info("\tI2S audio, sample rate=32k\n");
+ else
+ em28xx_info("\tI2S audio, 3 sample rates\n");
break;
case 3:
- em28xx_info("\tI2S audio, 3 sample rates\n");
+ if (dev->chip_id < CHIP_ID_EM2860)
+ em28xx_info("\tI2S audio, 3 sample rates\n");
+ else
+ em28xx_info("\tI2S audio, 5 sample rates\n");
break;
}
@@ -887,7 +939,6 @@ int em28xx_i2c_register(struct em28xx *dev, unsigned bus,
dev->i2c_bus[bus].algo_type = algo_type;
dev->i2c_bus[bus].dev = dev;
dev->i2c_adap[bus].algo_data = &dev->i2c_bus[bus];
- i2c_set_adapdata(&dev->i2c_adap[bus], &dev->v4l2_dev);
retval = i2c_add_adapter(&dev->i2c_adap[bus]);
if (retval < 0) {
diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c
index ea181e4b68c..56ef49df4f8 100644
--- a/drivers/media/usb/em28xx/em28xx-input.c
+++ b/drivers/media/usb/em28xx/em28xx-input.c
@@ -30,8 +30,9 @@
#include "em28xx.h"
-#define EM28XX_SNAPSHOT_KEY KEY_CAMERA
-#define EM28XX_SBUTTON_QUERY_INTERVAL 500
+#define EM28XX_SNAPSHOT_KEY KEY_CAMERA
+#define EM28XX_BUTTONS_DEBOUNCED_QUERY_INTERVAL 500 /* [ms] */
+#define EM28XX_BUTTONS_VOLATILE_QUERY_INTERVAL 100 /* [ms] */
static unsigned int ir_debug;
module_param(ir_debug, int, 0644);
@@ -442,6 +443,7 @@ static int em28xx_ir_change_protocol(struct rc_dev *rc_dev, u64 *rc_type)
case CHIP_ID_EM2884:
case CHIP_ID_EM2874:
case CHIP_ID_EM28174:
+ case CHIP_ID_EM28178:
return em2874_ir_change_protocol(rc_dev, rc_type);
default:
printk("Unrecognized em28xx chip id 0x%02x: IR not supported\n",
@@ -470,54 +472,98 @@ static int em28xx_probe_i2c_ir(struct em28xx *dev)
}
/**********************************************************
- Handle Webcam snapshot button
+ Handle buttons
**********************************************************/
-static void em28xx_query_sbutton(struct work_struct *work)
+static void em28xx_query_buttons(struct work_struct *work)
{
- /* Poll the register and see if the button is depressed */
struct em28xx *dev =
- container_of(work, struct em28xx, sbutton_query_work.work);
- int ret;
-
- ret = em28xx_read_reg(dev, EM28XX_R0C_USBSUSP);
-
- if (ret & EM28XX_R0C_USBSUSP_SNAPSHOT) {
- u8 cleared;
- /* Button is depressed, clear the register */
- cleared = ((u8) ret) & ~EM28XX_R0C_USBSUSP_SNAPSHOT;
- em28xx_write_regs(dev, EM28XX_R0C_USBSUSP, &cleared, 1);
-
- /* Not emulate the keypress */
- input_report_key(dev->sbutton_input_dev, EM28XX_SNAPSHOT_KEY,
- 1);
- /* Now unpress the key */
- input_report_key(dev->sbutton_input_dev, EM28XX_SNAPSHOT_KEY,
- 0);
+ container_of(work, struct em28xx, buttons_query_work.work);
+ u8 i, j;
+ int regval;
+ bool is_pressed, was_pressed;
+ const struct em28xx_led *led;
+
+ /* Poll and evaluate all addresses */
+ for (i = 0; i < dev->num_button_polling_addresses; i++) {
+ /* Read value from register */
+ regval = em28xx_read_reg(dev, dev->button_polling_addresses[i]);
+ if (regval < 0)
+ continue;
+ /* Check states of the buttons and act */
+ j = 0;
+ while (dev->board.buttons[j].role >= 0 &&
+ dev->board.buttons[j].role < EM28XX_NUM_BUTTON_ROLES) {
+ struct em28xx_button *button = &dev->board.buttons[j];
+ /* Check if button uses the current address */
+ if (button->reg_r != dev->button_polling_addresses[i]) {
+ j++;
+ continue;
+ }
+ /* Determine if button is and was pressed last time */
+ is_pressed = regval & button->mask;
+ was_pressed = dev->button_polling_last_values[i]
+ & button->mask;
+ if (button->inverted) {
+ is_pressed = !is_pressed;
+ was_pressed = !was_pressed;
+ }
+ /* Clear button state (if needed) */
+ if (is_pressed && button->reg_clearing)
+ em28xx_write_reg(dev, button->reg_clearing,
+ (~regval & button->mask)
+ | (regval & ~button->mask));
+ /* Handle button state */
+ if (!is_pressed || was_pressed) {
+ j++;
+ continue;
+ }
+ switch (button->role) {
+ case EM28XX_BUTTON_SNAPSHOT:
+ /* Emulate the keypress */
+ input_report_key(dev->sbutton_input_dev,
+ EM28XX_SNAPSHOT_KEY, 1);
+ /* Unpress the key */
+ input_report_key(dev->sbutton_input_dev,
+ EM28XX_SNAPSHOT_KEY, 0);
+ break;
+ case EM28XX_BUTTON_ILLUMINATION:
+ led = em28xx_find_led(dev,
+ EM28XX_LED_ILLUMINATION);
+ /* Switch illumination LED on/off */
+ if (led)
+ em28xx_toggle_reg_bits(dev,
+ led->gpio_reg,
+ led->gpio_mask);
+ break;
+ default:
+ WARN_ONCE(1, "BUG: unhandled button role.");
+ }
+ /* Next button */
+ j++;
+ }
+ /* Save current value for comparison during the next polling */
+ dev->button_polling_last_values[i] = regval;
}
-
/* Schedule next poll */
- schedule_delayed_work(&dev->sbutton_query_work,
- msecs_to_jiffies(EM28XX_SBUTTON_QUERY_INTERVAL));
+ schedule_delayed_work(&dev->buttons_query_work,
+ msecs_to_jiffies(dev->button_polling_interval));
}
-static void em28xx_register_snapshot_button(struct em28xx *dev)
+static int em28xx_register_snapshot_button(struct em28xx *dev)
{
struct input_dev *input_dev;
int err;
em28xx_info("Registering snapshot button...\n");
input_dev = input_allocate_device();
- if (!input_dev) {
- em28xx_errdev("input_allocate_device failed\n");
- return;
- }
+ if (!input_dev)
+ return -ENOMEM;
usb_make_path(dev->udev, dev->snapshot_button_path,
sizeof(dev->snapshot_button_path));
strlcat(dev->snapshot_button_path, "/sbutton",
sizeof(dev->snapshot_button_path));
- INIT_DELAYED_WORK(&dev->sbutton_query_work, em28xx_query_sbutton);
input_dev->name = "em28xx snapshot button";
input_dev->phys = dev->snapshot_button_path;
@@ -535,25 +581,86 @@ static void em28xx_register_snapshot_button(struct em28xx *dev)
if (err) {
em28xx_errdev("input_register_device failed\n");
input_free_device(input_dev);
- return;
+ return err;
}
dev->sbutton_input_dev = input_dev;
- schedule_delayed_work(&dev->sbutton_query_work,
- msecs_to_jiffies(EM28XX_SBUTTON_QUERY_INTERVAL));
- return;
+ return 0;
+}
+static void em28xx_init_buttons(struct em28xx *dev)
+{
+ u8 i = 0, j = 0;
+ bool addr_new = 0;
+
+ dev->button_polling_interval = EM28XX_BUTTONS_DEBOUNCED_QUERY_INTERVAL;
+ while (dev->board.buttons[i].role >= 0 &&
+ dev->board.buttons[i].role < EM28XX_NUM_BUTTON_ROLES) {
+ struct em28xx_button *button = &dev->board.buttons[i];
+ /* Check if polling address is already on the list */
+ addr_new = 1;
+ for (j = 0; j < dev->num_button_polling_addresses; j++) {
+ if (button->reg_r == dev->button_polling_addresses[j]) {
+ addr_new = 0;
+ break;
+ }
+ }
+ /* Check if max. number of polling addresses is exceeded */
+ if (addr_new && dev->num_button_polling_addresses
+ >= EM28XX_NUM_BUTTON_ADDRESSES_MAX) {
+ WARN_ONCE(1, "BUG: maximum number of button polling addresses exceeded.");
+ goto next_button;
+ }
+ /* Button role specific checks and actions */
+ if (button->role == EM28XX_BUTTON_SNAPSHOT) {
+ /* Register input device */
+ if (em28xx_register_snapshot_button(dev) < 0)
+ goto next_button;
+ } else if (button->role == EM28XX_BUTTON_ILLUMINATION) {
+ /* Check sanity */
+ if (!em28xx_find_led(dev, EM28XX_LED_ILLUMINATION)) {
+ em28xx_errdev("BUG: illumination button defined, but no illumination LED.\n");
+ goto next_button;
+ }
+ }
+ /* Add read address to list of polling addresses */
+ if (addr_new) {
+ unsigned int index = dev->num_button_polling_addresses;
+ dev->button_polling_addresses[index] = button->reg_r;
+ dev->num_button_polling_addresses++;
+ }
+ /* Reduce polling interval if necessary */
+ if (!button->reg_clearing)
+ dev->button_polling_interval =
+ EM28XX_BUTTONS_VOLATILE_QUERY_INTERVAL;
+next_button:
+ /* Next button */
+ i++;
+ }
+
+ /* Start polling */
+ if (dev->num_button_polling_addresses) {
+ memset(dev->button_polling_last_values, 0,
+ EM28XX_NUM_BUTTON_ADDRESSES_MAX);
+ INIT_DELAYED_WORK(&dev->buttons_query_work,
+ em28xx_query_buttons);
+ schedule_delayed_work(&dev->buttons_query_work,
+ msecs_to_jiffies(dev->button_polling_interval));
+ }
}
-static void em28xx_deregister_snapshot_button(struct em28xx *dev)
+static void em28xx_shutdown_buttons(struct em28xx *dev)
{
+ /* Cancel polling */
+ cancel_delayed_work_sync(&dev->buttons_query_work);
+ /* Clear polling addresses list */
+ dev->num_button_polling_addresses = 0;
+ /* Deregister input devices */
if (dev->sbutton_input_dev != NULL) {
em28xx_info("Deregistering snapshot button\n");
- cancel_delayed_work_sync(&dev->sbutton_query_work);
input_unregister_device(dev->sbutton_input_dev);
dev->sbutton_input_dev = NULL;
}
- return;
}
static int em28xx_ir_init(struct em28xx *dev)
@@ -564,8 +671,15 @@ static int em28xx_ir_init(struct em28xx *dev)
u64 rc_type;
u16 i2c_rc_dev_addr = 0;
- if (dev->board.has_snapshot_button)
- em28xx_register_snapshot_button(dev);
+ if (dev->is_audio_only) {
+ /* Shouldn't initialize IR for this interface */
+ return 0;
+ }
+
+ kref_get(&dev->ref);
+
+ if (dev->board.buttons)
+ em28xx_init_buttons(dev);
if (dev->board.has_ir_i2c) {
i2c_rc_dev_addr = em28xx_probe_i2c_ir(dev);
@@ -583,6 +697,8 @@ static int em28xx_ir_init(struct em28xx *dev)
return 0;
}
+ em28xx_info("Registering input extension\n");
+
ir = kzalloc(sizeof(*ir), GFP_KERNEL);
rc = rc_allocate_device();
if (!ir || !rc)
@@ -611,7 +727,7 @@ static int em28xx_ir_init(struct em28xx *dev)
case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2:
rc->map_name = RC_MAP_HAUPPAUGE;
ir->get_key_i2c = em28xx_get_key_em_haup;
- rc->allowed_protos = RC_BIT_RC5;
+ rc_set_allowed_protocols(rc, RC_BIT_RC5);
break;
case EM2820_BOARD_LEADTEK_WINFAST_USBII_DELUXE:
rc->map_name = RC_MAP_WINFAST_USBII_DELUXE;
@@ -627,15 +743,16 @@ static int em28xx_ir_init(struct em28xx *dev)
switch (dev->chip_id) {
case CHIP_ID_EM2860:
case CHIP_ID_EM2883:
- rc->allowed_protos = RC_BIT_RC5 | RC_BIT_NEC;
+ rc_set_allowed_protocols(rc, RC_BIT_RC5 | RC_BIT_NEC);
ir->get_key = default_polling_getkey;
break;
case CHIP_ID_EM2884:
case CHIP_ID_EM2874:
case CHIP_ID_EM28174:
+ case CHIP_ID_EM28178:
ir->get_key = em2874_polling_getkey;
- rc->allowed_protos = RC_BIT_RC5 | RC_BIT_NEC |
- RC_BIT_RC6_0;
+ rc_set_allowed_protocols(rc, RC_BIT_RC5 | RC_BIT_NEC |
+ RC_BIT_RC6_0);
break;
default:
err = -ENODEV;
@@ -675,6 +792,8 @@ static int em28xx_ir_init(struct em28xx *dev)
if (err)
goto error;
+ em28xx_info("Input extension successfully initalized\n");
+
return 0;
error:
@@ -688,11 +807,18 @@ static int em28xx_ir_fini(struct em28xx *dev)
{
struct em28xx_IR *ir = dev->ir;
- em28xx_deregister_snapshot_button(dev);
+ if (dev->is_audio_only) {
+ /* Shouldn't initialize IR for this interface */
+ return 0;
+ }
+
+ em28xx_info("Closing input extension");
+
+ em28xx_shutdown_buttons(dev);
/* skip detach on non attached boards */
if (!ir)
- return 0;
+ goto ref_put;
if (ir->rc)
rc_unregister_device(ir->rc);
@@ -700,6 +826,45 @@ static int em28xx_ir_fini(struct em28xx *dev)
/* done */
kfree(ir);
dev->ir = NULL;
+
+ref_put:
+ kref_put(&dev->ref, em28xx_free_device);
+
+ return 0;
+}
+
+static int em28xx_ir_suspend(struct em28xx *dev)
+{
+ struct em28xx_IR *ir = dev->ir;
+
+ if (dev->is_audio_only)
+ return 0;
+
+ em28xx_info("Suspending input extension");
+ if (ir)
+ cancel_delayed_work_sync(&ir->work);
+ cancel_delayed_work_sync(&dev->buttons_query_work);
+ /* is canceling delayed work sufficient or does the rc event
+ kthread needs stopping? kthread is stopped in
+ ir_raw_event_unregister() */
+ return 0;
+}
+
+static int em28xx_ir_resume(struct em28xx *dev)
+{
+ struct em28xx_IR *ir = dev->ir;
+
+ if (dev->is_audio_only)
+ return 0;
+
+ em28xx_info("Resuming input extension");
+ /* if suspend calls ir_raw_event_unregister(), the should call
+ ir_raw_event_register() */
+ if (ir)
+ schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling));
+ if (dev->num_button_polling_addresses)
+ schedule_delayed_work(&dev->buttons_query_work,
+ msecs_to_jiffies(dev->button_polling_interval));
return 0;
}
@@ -708,6 +873,8 @@ static struct em28xx_ops rc_ops = {
.name = "Em28xx Input Extension",
.init = em28xx_ir_init,
.fini = em28xx_ir_fini,
+ .suspend = em28xx_ir_suspend,
+ .resume = em28xx_ir_resume,
};
static int __init em28xx_rc_register(void)
@@ -721,8 +888,9 @@ static void __exit em28xx_rc_unregister(void)
}
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
-MODULE_DESCRIPTION("Em28xx Input driver");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
+MODULE_DESCRIPTION(DRIVER_DESC " - input interface");
+MODULE_VERSION(EM28XX_VERSION);
module_init(em28xx_rc_register);
module_exit(em28xx_rc_unregister);
diff --git a/drivers/media/usb/em28xx/em28xx-reg.h b/drivers/media/usb/em28xx/em28xx-reg.h
index 0e047784796..311fb349daf 100644
--- a/drivers/media/usb/em28xx/em28xx-reg.h
+++ b/drivers/media/usb/em28xx/em28xx-reg.h
@@ -25,10 +25,12 @@
#define EM28XX_R00_CHIPCFG 0x00
/* em28xx Chip Configuration 0x00 */
-#define EM28XX_CHIPCFG_VENDOR_AUDIO 0x80
-#define EM28XX_CHIPCFG_I2S_VOLUME_CAPABLE 0x40
-#define EM28XX_CHIPCFG_I2S_5_SAMPRATES 0x30
-#define EM28XX_CHIPCFG_I2S_3_SAMPRATES 0x20
+#define EM2860_CHIPCFG_VENDOR_AUDIO 0x80
+#define EM2860_CHIPCFG_I2S_VOLUME_CAPABLE 0x40
+#define EM2820_CHIPCFG_I2S_3_SAMPRATES 0x30
+#define EM2860_CHIPCFG_I2S_5_SAMPRATES 0x30
+#define EM2820_CHIPCFG_I2S_1_SAMPRATE 0x20
+#define EM2860_CHIPCFG_I2S_3_SAMPRATES 0x20
#define EM28XX_CHIPCFG_AC97 0x10
#define EM28XX_CHIPCFG_AUDIOMASK 0x30
@@ -245,6 +247,7 @@ enum em28xx_chip_id {
CHIP_ID_EM2874 = 65,
CHIP_ID_EM2884 = 68,
CHIP_ID_EM28174 = 113,
+ CHIP_ID_EM28178 = 114,
};
/*
diff --git a/drivers/media/usb/em28xx/em28xx-v4l.h b/drivers/media/usb/em28xx/em28xx-v4l.h
new file mode 100644
index 00000000000..432862c20bb
--- /dev/null
+++ b/drivers/media/usb/em28xx/em28xx-v4l.h
@@ -0,0 +1,20 @@
+/*
+ em28xx-video.c - driver for Empia EM2800/EM2820/2840 USB
+ video capture devices
+
+ Copyright (C) 2013-2014 Mauro Carvalho Chehab <m.chehab@samsung.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+ */
+
+
+int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count);
+void em28xx_stop_vbi_streaming(struct vb2_queue *vq);
+extern struct vb2_ops em28xx_vbi_qops;
diff --git a/drivers/media/usb/em28xx/em28xx-vbi.c b/drivers/media/usb/em28xx/em28xx-vbi.c
index 39f39c527c1..6d7f657f6f5 100644
--- a/drivers/media/usb/em28xx/em28xx-vbi.c
+++ b/drivers/media/usb/em28xx/em28xx-vbi.c
@@ -27,6 +27,7 @@
#include <linux/init.h>
#include "em28xx.h"
+#include "em28xx-v4l.h"
static unsigned int vbibufs = 5;
module_param(vbibufs, int, 0644);
@@ -46,12 +47,13 @@ static int vbi_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
unsigned int sizes[], void *alloc_ctxs[])
{
struct em28xx *dev = vb2_get_drv_priv(vq);
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
unsigned long size;
if (fmt)
size = fmt->fmt.pix.sizeimage;
else
- size = dev->vbi_width * dev->vbi_height * 2;
+ size = v4l2->vbi_width * v4l2->vbi_height * 2;
if (0 == *nbuffers)
*nbuffers = 32;
@@ -68,11 +70,12 @@ static int vbi_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
static int vbi_buffer_prepare(struct vb2_buffer *vb)
{
- struct em28xx *dev = vb2_get_drv_priv(vb->vb2_queue);
- struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb);
+ struct em28xx *dev = vb2_get_drv_priv(vb->vb2_queue);
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
+ struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb);
unsigned long size;
- size = dev->vbi_width * dev->vbi_height * 2;
+ size = v4l2->vbi_width * v4l2->vbi_height * 2;
if (vb2_plane_size(vb, 0) < size) {
printk(KERN_INFO "%s data will not fit into plane (%lu < %lu)\n",
diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
index 9d103344f34..f6b49c98e2c 100644
--- a/drivers/media/usb/em28xx/em28xx-video.c
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -38,9 +38,11 @@
#include <linux/slab.h>
#include "em28xx.h"
+#include "em28xx-v4l.h"
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-event.h>
+#include <media/v4l2-clk.h>
#include <media/msp3400.h>
#include <media/tuner.h>
@@ -49,19 +51,23 @@
"Mauro Carvalho Chehab <mchehab@infradead.org>, " \
"Sascha Sommer <saschasommer@freenet.de>"
-#define DRIVER_DESC "Empia em28xx based USB video device driver"
+static unsigned int isoc_debug;
+module_param(isoc_debug, int, 0644);
+MODULE_PARM_DESC(isoc_debug, "enable debug messages [isoc transfers]");
+
+static unsigned int disable_vbi;
+module_param(disable_vbi, int, 0644);
+MODULE_PARM_DESC(disable_vbi, "disable vbi support");
-#define EM28XX_VERSION "0.2.0"
+static int alt;
+module_param(alt, int, 0644);
+MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint");
#define em28xx_videodbg(fmt, arg...) do {\
if (video_debug) \
printk(KERN_INFO "%s %s :"fmt, \
dev->name, __func__ , ##arg); } while (0)
-static unsigned int isoc_debug;
-module_param(isoc_debug, int, 0644);
-MODULE_PARM_DESC(isoc_debug, "enable debug messages [isoc transfers]");
-
#define em28xx_isocdbg(fmt, arg...) \
do {\
if (isoc_debug) { \
@@ -71,7 +77,7 @@ do {\
} while (0)
MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_DESCRIPTION(DRIVER_DESC " - v4l2 interface");
MODULE_LICENSE("GPL");
MODULE_VERSION(EM28XX_VERSION);
@@ -135,6 +141,287 @@ static struct em28xx_fmt format[] = {
},
};
+/*FIXME: maxw should be dependent of alt mode */
+static inline unsigned int norm_maxw(struct em28xx *dev)
+{
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
+
+ if (dev->board.is_webcam)
+ return v4l2->sensor_xres;
+
+ if (dev->board.max_range_640_480)
+ return 640;
+
+ return 720;
+}
+
+static inline unsigned int norm_maxh(struct em28xx *dev)
+{
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
+
+ if (dev->board.is_webcam)
+ return v4l2->sensor_yres;
+
+ if (dev->board.max_range_640_480)
+ return 480;
+
+ return (v4l2->norm & V4L2_STD_625_50) ? 576 : 480;
+}
+
+static int em28xx_vbi_supported(struct em28xx *dev)
+{
+ /* Modprobe option to manually disable */
+ if (disable_vbi == 1)
+ return 0;
+
+ if (dev->board.is_webcam)
+ return 0;
+
+ /* FIXME: check subdevices for VBI support */
+
+ if (dev->chip_id == CHIP_ID_EM2860 ||
+ dev->chip_id == CHIP_ID_EM2883)
+ return 1;
+
+ /* Version of em28xx that does not support VBI */
+ return 0;
+}
+
+/*
+ * em28xx_wake_i2c()
+ * configure i2c attached devices
+ */
+static void em28xx_wake_i2c(struct em28xx *dev)
+{
+ struct v4l2_device *v4l2_dev = &dev->v4l2->v4l2_dev;
+ v4l2_device_call_all(v4l2_dev, 0, core, reset, 0);
+ v4l2_device_call_all(v4l2_dev, 0, video, s_routing,
+ INPUT(dev->ctl_input)->vmux, 0, 0);
+ v4l2_device_call_all(v4l2_dev, 0, video, s_stream, 0);
+}
+
+static int em28xx_colorlevels_set_default(struct em28xx *dev)
+{
+ em28xx_write_reg(dev, EM28XX_R20_YGAIN, CONTRAST_DEFAULT);
+ em28xx_write_reg(dev, EM28XX_R21_YOFFSET, BRIGHTNESS_DEFAULT);
+ em28xx_write_reg(dev, EM28XX_R22_UVGAIN, SATURATION_DEFAULT);
+ em28xx_write_reg(dev, EM28XX_R23_UOFFSET, BLUE_BALANCE_DEFAULT);
+ em28xx_write_reg(dev, EM28XX_R24_VOFFSET, RED_BALANCE_DEFAULT);
+ em28xx_write_reg(dev, EM28XX_R25_SHARPNESS, SHARPNESS_DEFAULT);
+
+ em28xx_write_reg(dev, EM28XX_R14_GAMMA, 0x20);
+ em28xx_write_reg(dev, EM28XX_R15_RGAIN, 0x20);
+ em28xx_write_reg(dev, EM28XX_R16_GGAIN, 0x20);
+ em28xx_write_reg(dev, EM28XX_R17_BGAIN, 0x20);
+ em28xx_write_reg(dev, EM28XX_R18_ROFFSET, 0x00);
+ em28xx_write_reg(dev, EM28XX_R19_GOFFSET, 0x00);
+ return em28xx_write_reg(dev, EM28XX_R1A_BOFFSET, 0x00);
+}
+
+static int em28xx_set_outfmt(struct em28xx *dev)
+{
+ int ret;
+ u8 fmt, vinctrl;
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
+
+ fmt = v4l2->format->reg;
+ if (!dev->is_em25xx)
+ fmt |= 0x20;
+ /*
+ * NOTE: it's not clear if this is really needed !
+ * The datasheets say bit 5 is a reserved bit and devices seem to work
+ * fine without it. But the Windows driver sets it for em2710/50+em28xx
+ * devices and we've always been setting it, too.
+ *
+ * em2765 (em25xx, em276x/7x/8x) devices do NOT work with this bit set,
+ * it's likely used for an additional (compressed ?) format there.
+ */
+ ret = em28xx_write_reg(dev, EM28XX_R27_OUTFMT, fmt);
+ if (ret < 0)
+ return ret;
+
+ ret = em28xx_write_reg(dev, EM28XX_R10_VINMODE, v4l2->vinmode);
+ if (ret < 0)
+ return ret;
+
+ vinctrl = v4l2->vinctl;
+ if (em28xx_vbi_supported(dev) == 1) {
+ vinctrl |= EM28XX_VINCTRL_VBI_RAW;
+ em28xx_write_reg(dev, EM28XX_R34_VBI_START_H, 0x00);
+ em28xx_write_reg(dev, EM28XX_R36_VBI_WIDTH, v4l2->vbi_width/4);
+ em28xx_write_reg(dev, EM28XX_R37_VBI_HEIGHT, v4l2->vbi_height);
+ if (v4l2->norm & V4L2_STD_525_60) {
+ /* NTSC */
+ em28xx_write_reg(dev, EM28XX_R35_VBI_START_V, 0x09);
+ } else if (v4l2->norm & V4L2_STD_625_50) {
+ /* PAL */
+ em28xx_write_reg(dev, EM28XX_R35_VBI_START_V, 0x07);
+ }
+ }
+
+ return em28xx_write_reg(dev, EM28XX_R11_VINCTRL, vinctrl);
+}
+
+static int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax,
+ u8 ymin, u8 ymax)
+{
+ em28xx_videodbg("em28xx Scale: (%d,%d)-(%d,%d)\n",
+ xmin, ymin, xmax, ymax);
+
+ em28xx_write_regs(dev, EM28XX_R28_XMIN, &xmin, 1);
+ em28xx_write_regs(dev, EM28XX_R29_XMAX, &xmax, 1);
+ em28xx_write_regs(dev, EM28XX_R2A_YMIN, &ymin, 1);
+ return em28xx_write_regs(dev, EM28XX_R2B_YMAX, &ymax, 1);
+}
+
+static void em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart,
+ u16 width, u16 height)
+{
+ u8 cwidth = width >> 2;
+ u8 cheight = height >> 2;
+ u8 overflow = (height >> 9 & 0x02) | (width >> 10 & 0x01);
+ /* NOTE: size limit: 2047x1023 = 2MPix */
+
+ em28xx_videodbg("capture area set to (%d,%d): %dx%d\n",
+ hstart, vstart,
+ ((overflow & 2) << 9 | cwidth << 2),
+ ((overflow & 1) << 10 | cheight << 2));
+
+ em28xx_write_regs(dev, EM28XX_R1C_HSTART, &hstart, 1);
+ em28xx_write_regs(dev, EM28XX_R1D_VSTART, &vstart, 1);
+ em28xx_write_regs(dev, EM28XX_R1E_CWIDTH, &cwidth, 1);
+ em28xx_write_regs(dev, EM28XX_R1F_CHEIGHT, &cheight, 1);
+ em28xx_write_regs(dev, EM28XX_R1B_OFLOW, &overflow, 1);
+
+ /* FIXME: function/meaning of these registers ? */
+ /* FIXME: align width+height to multiples of 4 ?! */
+ if (dev->is_em25xx) {
+ em28xx_write_reg(dev, 0x34, width >> 4);
+ em28xx_write_reg(dev, 0x35, height >> 4);
+ }
+}
+
+static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v)
+{
+ u8 mode = 0x00;
+ /* the em2800 scaler only supports scaling down to 50% */
+
+ if (dev->board.is_em2800) {
+ mode = (v ? 0x20 : 0x00) | (h ? 0x10 : 0x00);
+ } else {
+ u8 buf[2];
+
+ buf[0] = h;
+ buf[1] = h >> 8;
+ em28xx_write_regs(dev, EM28XX_R30_HSCALELOW, (char *)buf, 2);
+
+ buf[0] = v;
+ buf[1] = v >> 8;
+ em28xx_write_regs(dev, EM28XX_R32_VSCALELOW, (char *)buf, 2);
+ /* it seems that both H and V scalers must be active
+ to work correctly */
+ mode = (h || v) ? 0x30 : 0x00;
+ }
+ return em28xx_write_reg(dev, EM28XX_R26_COMPR, mode);
+}
+
+/* FIXME: this only function read values from dev */
+static int em28xx_resolution_set(struct em28xx *dev)
+{
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
+ int width = norm_maxw(dev);
+ int height = norm_maxh(dev);
+
+ /* Properly setup VBI */
+ v4l2->vbi_width = 720;
+ if (v4l2->norm & V4L2_STD_525_60)
+ v4l2->vbi_height = 12;
+ else
+ v4l2->vbi_height = 18;
+
+ em28xx_set_outfmt(dev);
+
+ em28xx_accumulator_set(dev, 1, (width - 4) >> 2, 1, (height - 4) >> 2);
+
+ /* If we don't set the start position to 2 in VBI mode, we end up
+ with line 20/21 being YUYV encoded instead of being in 8-bit
+ greyscale. The core of the issue is that line 21 (and line 23 for
+ PAL WSS) are inside of active video region, and as a result they
+ get the pixelformatting associated with that area. So by cropping
+ it out, we end up with the same format as the rest of the VBI
+ region */
+ if (em28xx_vbi_supported(dev) == 1)
+ em28xx_capture_area_set(dev, 0, 2, width, height);
+ else
+ em28xx_capture_area_set(dev, 0, 0, width, height);
+
+ return em28xx_scaler_set(dev, v4l2->hscale, v4l2->vscale);
+}
+
+/* Set USB alternate setting for analog video */
+static int em28xx_set_alternate(struct em28xx *dev)
+{
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
+ int errCode;
+ int i;
+ unsigned int min_pkt_size = v4l2->width * 2 + 4;
+
+ /* NOTE: for isoc transfers, only alt settings > 0 are allowed
+ bulk transfers seem to work only with alt=0 ! */
+ dev->alt = 0;
+ if ((alt > 0) && (alt < dev->num_alt)) {
+ em28xx_videodbg("alternate forced to %d\n", dev->alt);
+ dev->alt = alt;
+ goto set_alt;
+ }
+ if (dev->analog_xfer_bulk)
+ goto set_alt;
+
+ /* When image size is bigger than a certain value,
+ the frame size should be increased, otherwise, only
+ green screen will be received.
+ */
+ if (v4l2->width * 2 * v4l2->height > 720 * 240 * 2)
+ min_pkt_size *= 2;
+
+ for (i = 0; i < dev->num_alt; i++) {
+ /* stop when the selected alt setting offers enough bandwidth */
+ if (dev->alt_max_pkt_size_isoc[i] >= min_pkt_size) {
+ dev->alt = i;
+ break;
+ /* otherwise make sure that we end up with the maximum bandwidth
+ because the min_pkt_size equation might be wrong...
+ */
+ } else if (dev->alt_max_pkt_size_isoc[i] >
+ dev->alt_max_pkt_size_isoc[dev->alt])
+ dev->alt = i;
+ }
+
+set_alt:
+ /* NOTE: for bulk transfers, we need to call usb_set_interface()
+ * even if the previous settings were the same. Otherwise streaming
+ * fails with all urbs having status = -EOVERFLOW ! */
+ if (dev->analog_xfer_bulk) {
+ dev->max_pkt_size = 512; /* USB 2.0 spec */
+ dev->packet_multiplier = EM28XX_BULK_PACKET_MULTIPLIER;
+ } else { /* isoc */
+ em28xx_videodbg("minimum isoc packet size: %u (alt=%d)\n",
+ min_pkt_size, dev->alt);
+ dev->max_pkt_size =
+ dev->alt_max_pkt_size_isoc[dev->alt];
+ dev->packet_multiplier = EM28XX_NUM_ISOC_PACKETS;
+ }
+ em28xx_videodbg("setting alternate %d with wMaxPacketSize=%u\n",
+ dev->alt, dev->max_pkt_size);
+ errCode = usb_set_interface(dev->udev, dev->ifnum, dev->alt);
+ if (errCode < 0) {
+ em28xx_errdev("cannot change alternate number to %d (error=%i)\n",
+ dev->alt, errCode);
+ return errCode;
+ }
+ return 0;
+}
+
/* ------------------------------------------------------------------
DMA and thread functions
------------------------------------------------------------------*/
@@ -147,7 +434,7 @@ static inline void finish_buffer(struct em28xx *dev,
{
em28xx_isocdbg("[%p/%d] wakeup\n", buf, buf->top_field);
- buf->vb.v4l2_buf.sequence = dev->field_count++;
+ buf->vb.v4l2_buf.sequence = dev->v4l2->field_count++;
buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED;
v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
@@ -162,9 +449,10 @@ static void em28xx_copy_video(struct em28xx *dev,
unsigned char *usb_buf,
unsigned long len)
{
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
void *fieldstart, *startwrite, *startread;
int linesdone, currlinedone, offset, lencopy, remain;
- int bytesperline = dev->width << 1;
+ int bytesperline = v4l2->width << 1;
if (buf->pos + len > buf->length)
len = buf->length - buf->pos;
@@ -172,7 +460,7 @@ static void em28xx_copy_video(struct em28xx *dev,
startread = usb_buf;
remain = len;
- if (dev->progressive || buf->top_field)
+ if (v4l2->progressive || buf->top_field)
fieldstart = buf->vb_buf;
else /* interlaced mode, even nr. of lines */
fieldstart = buf->vb_buf + bytesperline;
@@ -180,7 +468,7 @@ static void em28xx_copy_video(struct em28xx *dev,
linesdone = buf->pos / bytesperline;
currlinedone = buf->pos % bytesperline;
- if (dev->progressive)
+ if (v4l2->progressive)
offset = linesdone * bytesperline + currlinedone;
else
offset = linesdone * bytesperline * 2 + currlinedone;
@@ -204,7 +492,7 @@ static void em28xx_copy_video(struct em28xx *dev,
remain -= lencopy;
while (remain > 0) {
- if (dev->progressive)
+ if (v4l2->progressive)
startwrite += lencopy;
else
startwrite += lencopy + bytesperline;
@@ -250,7 +538,7 @@ static void em28xx_copy_vbi(struct em28xx *dev,
offset = buf->pos;
/* Make sure the bottom field populates the second half of the frame */
if (buf->top_field == 0)
- offset += dev->vbi_width * dev->vbi_height;
+ offset += dev->v4l2->vbi_width * dev->v4l2->vbi_height;
memcpy(buf->vb_buf + offset, usb_buf, len);
buf->pos += len;
@@ -326,13 +614,15 @@ finish_field_prepare_next(struct em28xx *dev,
struct em28xx_buffer *buf,
struct em28xx_dmaqueue *dma_q)
{
- if (dev->progressive || dev->top_field) { /* Brand new frame */
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
+
+ if (v4l2->progressive || v4l2->top_field) { /* Brand new frame */
if (buf != NULL)
finish_buffer(dev, buf);
buf = get_next_buf(dev, dma_q);
}
if (buf != NULL) {
- buf->top_field = dev->top_field;
+ buf->top_field = v4l2->top_field;
buf->pos = 0;
}
@@ -346,6 +636,7 @@ static inline void process_frame_data_em28xx(struct em28xx *dev,
unsigned char *data_pkt,
unsigned int data_len)
{
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
struct em28xx_buffer *buf = dev->usb_ctl.vid_buf;
struct em28xx_buffer *vbi_buf = dev->usb_ctl.vbi_buf;
struct em28xx_dmaqueue *dma_q = &dev->vidq;
@@ -365,17 +656,17 @@ static inline void process_frame_data_em28xx(struct em28xx *dev,
data_len -= 4;
} else if (data_pkt[0] == 0x33 && data_pkt[1] == 0x95) {
/* Field start (VBI mode) */
- dev->capture_type = 0;
- dev->vbi_read = 0;
+ v4l2->capture_type = 0;
+ v4l2->vbi_read = 0;
em28xx_isocdbg("VBI START HEADER !!!\n");
- dev->top_field = !(data_pkt[2] & 1);
+ v4l2->top_field = !(data_pkt[2] & 1);
data_pkt += 4;
data_len -= 4;
} else if (data_pkt[0] == 0x22 && data_pkt[1] == 0x5a) {
/* Field start (VBI disabled) */
- dev->capture_type = 2;
+ v4l2->capture_type = 2;
em28xx_isocdbg("VIDEO START HEADER !!!\n");
- dev->top_field = !(data_pkt[2] & 1);
+ v4l2->top_field = !(data_pkt[2] & 1);
data_pkt += 4;
data_len -= 4;
}
@@ -383,37 +674,37 @@ static inline void process_frame_data_em28xx(struct em28xx *dev,
/* NOTE: With bulk transfers, intermediate data packets
* have no continuation header */
- if (dev->capture_type == 0) {
+ if (v4l2->capture_type == 0) {
vbi_buf = finish_field_prepare_next(dev, vbi_buf, vbi_dma_q);
dev->usb_ctl.vbi_buf = vbi_buf;
- dev->capture_type = 1;
+ v4l2->capture_type = 1;
}
- if (dev->capture_type == 1) {
- int vbi_size = dev->vbi_width * dev->vbi_height;
- int vbi_data_len = ((dev->vbi_read + data_len) > vbi_size) ?
- (vbi_size - dev->vbi_read) : data_len;
+ if (v4l2->capture_type == 1) {
+ int vbi_size = v4l2->vbi_width * v4l2->vbi_height;
+ int vbi_data_len = ((v4l2->vbi_read + data_len) > vbi_size) ?
+ (vbi_size - v4l2->vbi_read) : data_len;
/* Copy VBI data */
if (vbi_buf != NULL)
em28xx_copy_vbi(dev, vbi_buf, data_pkt, vbi_data_len);
- dev->vbi_read += vbi_data_len;
+ v4l2->vbi_read += vbi_data_len;
if (vbi_data_len < data_len) {
/* Continue with copying video data */
- dev->capture_type = 2;
+ v4l2->capture_type = 2;
data_pkt += vbi_data_len;
data_len -= vbi_data_len;
}
}
- if (dev->capture_type == 2) {
+ if (v4l2->capture_type == 2) {
buf = finish_field_prepare_next(dev, buf, dma_q);
dev->usb_ctl.vid_buf = buf;
- dev->capture_type = 3;
+ v4l2->capture_type = 3;
}
- if (dev->capture_type == 3 && buf != NULL && data_len > 0)
+ if (v4l2->capture_type == 3 && buf != NULL && data_len > 0)
em28xx_copy_video(dev, buf, data_pkt, data_len);
}
@@ -426,6 +717,7 @@ static inline void process_frame_data_em25xx(struct em28xx *dev,
{
struct em28xx_buffer *buf = dev->usb_ctl.vid_buf;
struct em28xx_dmaqueue *dmaq = &dev->vidq;
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
bool frame_end = 0;
/* Check for header */
@@ -434,7 +726,7 @@ static inline void process_frame_data_em25xx(struct em28xx *dev,
if (data_len >= 2) { /* em25xx header is only 2 bytes long */
if ((data_pkt[0] == EM25XX_FRMDATAHDR_BYTE1) &&
((data_pkt[1] & ~EM25XX_FRMDATAHDR_BYTE2_MASK) == 0x00)) {
- dev->top_field = !(data_pkt[1] &
+ v4l2->top_field = !(data_pkt[1] &
EM25XX_FRMDATAHDR_BYTE2_FRAME_ID);
frame_end = data_pkt[1] &
EM25XX_FRMDATAHDR_BYTE2_FRAME_END;
@@ -584,12 +876,14 @@ static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
unsigned int sizes[], void *alloc_ctxs[])
{
struct em28xx *dev = vb2_get_drv_priv(vq);
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
unsigned long size;
if (fmt)
size = fmt->fmt.pix.sizeimage;
else
- size = (dev->width * dev->height * dev->format->depth + 7) >> 3;
+ size =
+ (v4l2->width * v4l2->height * v4l2->format->depth + 7) >> 3;
if (size == 0)
return -EINVAL;
@@ -607,12 +901,13 @@ static int
buffer_prepare(struct vb2_buffer *vb)
{
struct em28xx *dev = vb2_get_drv_priv(vb->vb2_queue);
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb);
unsigned long size;
em28xx_videodbg("%s, field=%d\n", __func__, vb->v4l2_buf.field);
- size = (dev->width * dev->height * dev->format->depth + 7) >> 3;
+ size = (v4l2->width * v4l2->height * v4l2->format->depth + 7) >> 3;
if (vb2_plane_size(vb, 0) < size) {
em28xx_videodbg("%s data will not fit into plane (%lu < %lu)\n",
@@ -627,6 +922,7 @@ buffer_prepare(struct vb2_buffer *vb)
int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count)
{
struct em28xx *dev = vb2_get_drv_priv(vq);
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
struct v4l2_frequency f;
int rc = 0;
@@ -638,7 +934,7 @@ int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count)
if (rc)
return rc;
- if (dev->streaming_users++ == 0) {
+ if (v4l2->streaming_users == 0) {
/* First active streaming user, so allocate all the URBs */
/* Allocate the USB bandwidth */
@@ -649,7 +945,7 @@ int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count)
*/
em28xx_wake_i2c(dev);
- dev->capture_type = -1;
+ v4l2->capture_type = -1;
rc = em28xx_init_usb_xfer(dev, EM28XX_ANALOG_MODE,
dev->analog_xfer_bulk,
EM28XX_NUM_BUFS,
@@ -657,7 +953,7 @@ int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count)
dev->packet_multiplier,
em28xx_urb_data_copy);
if (rc < 0)
- goto fail;
+ return rc;
/*
* djh: it's not clear whether this code is still needed. I'm
@@ -667,21 +963,24 @@ int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count)
/* Ask tuner to go to analog or radio mode */
memset(&f, 0, sizeof(f));
- f.frequency = dev->ctl_freq;
+ f.frequency = v4l2->frequency;
if (vq->owner && vq->owner->vdev->vfl_type == VFL_TYPE_RADIO)
f.type = V4L2_TUNER_RADIO;
else
f.type = V4L2_TUNER_ANALOG_TV;
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
+ v4l2_device_call_all(&v4l2->v4l2_dev,
+ 0, tuner, s_frequency, &f);
}
-fail:
+ v4l2->streaming_users++;
+
return rc;
}
-static int em28xx_stop_streaming(struct vb2_queue *vq)
+static void em28xx_stop_streaming(struct vb2_queue *vq)
{
struct em28xx *dev = vb2_get_drv_priv(vq);
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
struct em28xx_dmaqueue *vidq = &dev->vidq;
unsigned long flags = 0;
@@ -689,7 +988,7 @@ static int em28xx_stop_streaming(struct vb2_queue *vq)
res_free(dev, vq->type);
- if (dev->streaming_users-- == 1) {
+ if (v4l2->streaming_users-- == 1) {
/* Last active user, so shutdown all the URBS */
em28xx_uninit_usb_xfer(dev, EM28XX_ANALOG_MODE);
}
@@ -703,13 +1002,12 @@ static int em28xx_stop_streaming(struct vb2_queue *vq)
}
dev->usb_ctl.vid_buf = NULL;
spin_unlock_irqrestore(&dev->slock, flags);
-
- return 0;
}
-int em28xx_stop_vbi_streaming(struct vb2_queue *vq)
+void em28xx_stop_vbi_streaming(struct vb2_queue *vq)
{
struct em28xx *dev = vb2_get_drv_priv(vq);
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
struct em28xx_dmaqueue *vbiq = &dev->vbiq;
unsigned long flags = 0;
@@ -717,7 +1015,7 @@ int em28xx_stop_vbi_streaming(struct vb2_queue *vq)
res_free(dev, vq->type);
- if (dev->streaming_users-- == 1) {
+ if (v4l2->streaming_users-- == 1) {
/* Last active user, so shutdown all the URBS */
em28xx_uninit_usb_xfer(dev, EM28XX_ANALOG_MODE);
}
@@ -731,8 +1029,6 @@ int em28xx_stop_vbi_streaming(struct vb2_queue *vq)
}
dev->usb_ctl.vbi_buf = NULL;
spin_unlock_irqrestore(&dev->slock, flags);
-
- return 0;
}
static void
@@ -762,16 +1058,17 @@ static struct vb2_ops em28xx_video_qops = {
.wait_finish = vb2_ops_wait_finish,
};
-int em28xx_vb2_setup(struct em28xx *dev)
+static int em28xx_vb2_setup(struct em28xx *dev)
{
int rc;
struct vb2_queue *q;
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
/* Setup Videobuf2 for Video capture */
- q = &dev->vb_vidq;
+ q = &v4l2->vb_vidq;
q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
q->io_modes = VB2_READ | VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
- q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
q->drv_priv = dev;
q->buf_struct_size = sizeof(struct em28xx_buffer);
q->ops = &em28xx_video_qops;
@@ -782,10 +1079,10 @@ int em28xx_vb2_setup(struct em28xx *dev)
return rc;
/* Setup Videobuf2 for VBI capture */
- q = &dev->vb_vbiq;
+ q = &v4l2->vb_vbiq;
q->type = V4L2_BUF_TYPE_VBI_CAPTURE;
q->io_modes = VB2_READ | VB2_MMAP | VB2_USERPTR;
- q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
q->drv_priv = dev;
q->buf_struct_size = sizeof(struct em28xx_buffer);
q->ops = &em28xx_vbi_qops;
@@ -802,6 +1099,7 @@ int em28xx_vb2_setup(struct em28xx *dev)
static void video_mux(struct em28xx *dev, int index)
{
+ struct v4l2_device *v4l2_dev = &dev->v4l2->v4l2_dev;
dev->ctl_input = index;
dev->ctl_ainput = INPUT(index)->amux;
dev->ctl_aoutput = INPUT(index)->aout;
@@ -809,28 +1107,28 @@ static void video_mux(struct em28xx *dev, int index)
if (!dev->ctl_aoutput)
dev->ctl_aoutput = EM28XX_AOUT_MASTER;
- v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing,
+ v4l2_device_call_all(v4l2_dev, 0, video, s_routing,
INPUT(index)->vmux, 0, 0);
if (dev->board.has_msp34xx) {
if (dev->i2s_speed) {
- v4l2_device_call_all(&dev->v4l2_dev, 0, audio,
+ v4l2_device_call_all(v4l2_dev, 0, audio,
s_i2s_clock_freq, dev->i2s_speed);
}
/* Note: this is msp3400 specific */
- v4l2_device_call_all(&dev->v4l2_dev, 0, audio, s_routing,
+ v4l2_device_call_all(v4l2_dev, 0, audio, s_routing,
dev->ctl_ainput, MSP_OUTPUT(MSP_SC_IN_DSP_SCART1), 0);
}
if (dev->board.adecoder != EM28XX_NOADECODER) {
- v4l2_device_call_all(&dev->v4l2_dev, 0, audio, s_routing,
+ v4l2_device_call_all(v4l2_dev, 0, audio, s_routing,
dev->ctl_ainput, dev->ctl_aoutput, 0);
}
em28xx_audio_analog_set(dev);
}
-void em28xx_ctrl_notify(struct v4l2_ctrl *ctrl, void *priv)
+static void em28xx_ctrl_notify(struct v4l2_ctrl *ctrl, void *priv)
{
struct em28xx *dev = priv;
@@ -854,7 +1152,9 @@ void em28xx_ctrl_notify(struct v4l2_ctrl *ctrl, void *priv)
static int em28xx_s_ctrl(struct v4l2_ctrl *ctrl)
{
- struct em28xx *dev = container_of(ctrl->handler, struct em28xx, ctrl_handler);
+ struct em28xx_v4l2 *v4l2 =
+ container_of(ctrl->handler, struct em28xx_v4l2, ctrl_handler);
+ struct em28xx *dev = v4l2->dev;
int ret = -EINVAL;
switch (ctrl->id) {
@@ -889,7 +1189,7 @@ static int em28xx_s_ctrl(struct v4l2_ctrl *ctrl)
return (ret < 0) ? ret : 0;
}
-const struct v4l2_ctrl_ops em28xx_ctrl_ops = {
+static const struct v4l2_ctrl_ops em28xx_ctrl_ops = {
.s_ctrl = em28xx_s_ctrl,
};
@@ -929,19 +1229,20 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
{
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
- f->fmt.pix.width = dev->width;
- f->fmt.pix.height = dev->height;
- f->fmt.pix.pixelformat = dev->format->fourcc;
- f->fmt.pix.bytesperline = (dev->width * dev->format->depth + 7) >> 3;
- f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * dev->height;
+ f->fmt.pix.width = v4l2->width;
+ f->fmt.pix.height = v4l2->height;
+ f->fmt.pix.pixelformat = v4l2->format->fourcc;
+ f->fmt.pix.bytesperline = (v4l2->width * v4l2->format->depth + 7) >> 3;
+ f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * v4l2->height;
f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
/* FIXME: TOP? NONE? BOTTOM? ALTENATE? */
- if (dev->progressive)
+ if (v4l2->progressive)
f->fmt.pix.field = V4L2_FIELD_NONE;
else
- f->fmt.pix.field = dev->interlaced ?
+ f->fmt.pix.field = v4l2->interlaced_fieldmode ?
V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP;
return 0;
}
@@ -962,6 +1263,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
{
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
unsigned int width = f->fmt.pix.width;
unsigned int height = f->fmt.pix.height;
unsigned int maxw = norm_maxw(dev);
@@ -1003,10 +1305,10 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
f->fmt.pix.bytesperline = (width * fmt->depth + 7) >> 3;
f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * height;
f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
- if (dev->progressive)
+ if (v4l2->progressive)
f->fmt.pix.field = V4L2_FIELD_NONE;
else
- f->fmt.pix.field = dev->interlaced ?
+ f->fmt.pix.field = v4l2->interlaced_fieldmode ?
V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP;
f->fmt.pix.priv = 0;
@@ -1017,17 +1319,19 @@ static int em28xx_set_video_format(struct em28xx *dev, unsigned int fourcc,
unsigned width, unsigned height)
{
struct em28xx_fmt *fmt;
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
fmt = format_by_fourcc(fourcc);
if (!fmt)
return -EINVAL;
- dev->format = fmt;
- dev->width = width;
- dev->height = height;
+ v4l2->format = fmt;
+ v4l2->width = width;
+ v4l2->height = height;
/* set new image size */
- size_to_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
+ size_to_scale(dev, v4l2->width, v4l2->height,
+ &v4l2->hscale, &v4l2->vscale);
em28xx_resolution_set(dev);
@@ -1038,8 +1342,9 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct em28xx *dev = video_drvdata(file);
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
- if (dev->streaming_users > 0)
+ if (v4l2->streaming_users > 0)
return -EBUSY;
vidioc_try_fmt_vid_cap(file, priv, f);
@@ -1053,7 +1358,7 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *norm)
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
- *norm = dev->norm;
+ *norm = dev->v4l2->norm;
return 0;
}
@@ -1063,24 +1368,25 @@ static int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *norm)
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
- v4l2_device_call_all(&dev->v4l2_dev, 0, video, querystd, norm);
+ v4l2_device_call_all(&dev->v4l2->v4l2_dev, 0, video, querystd, norm);
return 0;
}
static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm)
{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
+ struct em28xx_fh *fh = priv;
+ struct em28xx *dev = fh->dev;
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
struct v4l2_format f;
- if (norm == dev->norm)
+ if (norm == v4l2->norm)
return 0;
- if (dev->streaming_users > 0)
+ if (v4l2->streaming_users > 0)
return -EBUSY;
- dev->norm = norm;
+ v4l2->norm = norm;
/* Adjusts width/height, if needed */
f.fmt.pix.width = 720;
@@ -1088,12 +1394,13 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm)
vidioc_try_fmt_vid_cap(file, priv, &f);
/* set new image size */
- dev->width = f.fmt.pix.width;
- dev->height = f.fmt.pix.height;
- size_to_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
+ v4l2->width = f.fmt.pix.width;
+ v4l2->height = f.fmt.pix.height;
+ size_to_scale(dev, v4l2->width, v4l2->height,
+ &v4l2->hscale, &v4l2->vscale);
em28xx_resolution_set(dev);
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm);
+ v4l2_device_call_all(&v4l2->v4l2_dev, 0, video, s_std, v4l2->norm);
return 0;
}
@@ -1101,16 +1408,17 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm)
static int vidioc_g_parm(struct file *file, void *priv,
struct v4l2_streamparm *p)
{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
+ struct em28xx_fh *fh = priv;
+ struct em28xx *dev = fh->dev;
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
int rc = 0;
p->parm.capture.readbuffers = EM28XX_MIN_BUF;
if (dev->board.is_webcam)
- rc = v4l2_device_call_until_err(&dev->v4l2_dev, 0,
+ rc = v4l2_device_call_until_err(&v4l2->v4l2_dev, 0,
video, g_parm, p);
else
- v4l2_video_std_frame_period(dev->norm,
+ v4l2_video_std_frame_period(v4l2->norm,
&p->parm.capture.timeperframe);
return rc;
@@ -1123,7 +1431,8 @@ static int vidioc_s_parm(struct file *file, void *priv,
struct em28xx *dev = fh->dev;
p->parm.capture.readbuffers = EM28XX_MIN_BUF;
- return v4l2_device_call_until_err(&dev->v4l2_dev, 0, video, s_parm, p);
+ return v4l2_device_call_until_err(&dev->v4l2->v4l2_dev,
+ 0, video, s_parm, p);
}
static const char *iname[] = {
@@ -1160,7 +1469,7 @@ static int vidioc_enum_input(struct file *file, void *priv,
(EM28XX_VMUX_CABLE == INPUT(n)->type))
i->type = V4L2_INPUT_TYPE_TUNER;
- i->std = dev->vdev->tvnorms;
+ i->std = dev->v4l2->vdev->tvnorms;
/* webcams do not have the STD API */
if (dev->board.is_webcam)
i->capabilities = 0;
@@ -1262,7 +1571,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
strcpy(t->name, "Tuner");
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t);
+ v4l2_device_call_all(&dev->v4l2->v4l2_dev, 0, tuner, g_tuner, t);
return 0;
}
@@ -1275,7 +1584,7 @@ static int vidioc_s_tuner(struct file *file, void *priv,
if (0 != t->index)
return -EINVAL;
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t);
+ v4l2_device_call_all(&dev->v4l2->v4l2_dev, 0, tuner, s_tuner, t);
return 0;
}
@@ -1284,27 +1593,29 @@ static int vidioc_g_frequency(struct file *file, void *priv,
{
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
if (0 != f->tuner)
return -EINVAL;
- f->frequency = dev->ctl_freq;
+ f->frequency = v4l2->frequency;
return 0;
}
static int vidioc_s_frequency(struct file *file, void *priv,
const struct v4l2_frequency *f)
{
- struct v4l2_frequency new_freq = *f;
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
+ struct v4l2_frequency new_freq = *f;
+ struct em28xx_fh *fh = priv;
+ struct em28xx *dev = fh->dev;
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
if (0 != f->tuner)
return -EINVAL;
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, f);
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_frequency, &new_freq);
- dev->ctl_freq = new_freq.frequency;
+ v4l2_device_call_all(&v4l2->v4l2_dev, 0, tuner, s_frequency, f);
+ v4l2_device_call_all(&v4l2->v4l2_dev, 0, tuner, g_frequency, &new_freq);
+ v4l2->frequency = new_freq.frequency;
return 0;
}
@@ -1321,7 +1632,8 @@ static int vidioc_g_chip_info(struct file *file, void *priv,
if (chip->match.addr == 1)
strlcpy(chip->name, "ac97", sizeof(chip->name));
else
- strlcpy(chip->name, dev->v4l2_dev.name, sizeof(chip->name));
+ strlcpy(chip->name,
+ dev->v4l2->v4l2_dev.name, sizeof(chip->name));
return 0;
}
@@ -1367,7 +1679,7 @@ static int vidioc_g_register(struct file *file, void *priv,
reg->val = ret;
} else {
__le16 val = 0;
- ret = em28xx_read_reg_req_len(dev, USB_REQ_GET_STATUS,
+ ret = dev->em28xx_read_reg_req_len(dev, USB_REQ_GET_STATUS,
reg->reg, (char *)&val, 2);
if (ret < 0)
return ret;
@@ -1402,9 +1714,10 @@ static int vidioc_s_register(struct file *file, void *priv,
static int vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
- struct video_device *vdev = video_devdata(file);
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
+ struct video_device *vdev = video_devdata(file);
+ struct em28xx_fh *fh = priv;
+ struct em28xx *dev = fh->dev;
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
strlcpy(cap->driver, "em28xx", sizeof(cap->driver));
strlcpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card));
@@ -1426,9 +1739,9 @@ static int vidioc_querycap(struct file *file, void *priv,
cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS |
V4L2_CAP_READWRITE | V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
- if (dev->vbi_dev)
+ if (v4l2->vbi_dev)
cap->capabilities |= V4L2_CAP_VBI_CAPTURE;
- if (dev->radio_dev)
+ if (v4l2->radio_dev)
cap->capabilities |= V4L2_CAP_RADIO;
return 0;
}
@@ -1493,24 +1806,25 @@ static int vidioc_enum_framesizes(struct file *file, void *priv,
static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
struct v4l2_format *format)
{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
+ struct em28xx_fh *fh = priv;
+ struct em28xx *dev = fh->dev;
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
- format->fmt.vbi.samples_per_line = dev->vbi_width;
+ format->fmt.vbi.samples_per_line = v4l2->vbi_width;
format->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
format->fmt.vbi.offset = 0;
format->fmt.vbi.flags = 0;
format->fmt.vbi.sampling_rate = 6750000 * 4 / 2;
- format->fmt.vbi.count[0] = dev->vbi_height;
- format->fmt.vbi.count[1] = dev->vbi_height;
+ format->fmt.vbi.count[0] = v4l2->vbi_height;
+ format->fmt.vbi.count[1] = v4l2->vbi_height;
memset(format->fmt.vbi.reserved, 0, sizeof(format->fmt.vbi.reserved));
/* Varies by video standard (NTSC, PAL, etc.) */
- if (dev->norm & V4L2_STD_525_60) {
+ if (v4l2->norm & V4L2_STD_525_60) {
/* NTSC */
format->fmt.vbi.start[0] = 10;
format->fmt.vbi.start[1] = 273;
- } else if (dev->norm & V4L2_STD_625_50) {
+ } else if (v4l2->norm & V4L2_STD_625_50) {
/* PAL */
format->fmt.vbi.start[0] = 6;
format->fmt.vbi.start[1] = 318;
@@ -1533,7 +1847,7 @@ static int radio_g_tuner(struct file *file, void *priv,
strcpy(t->name, "Radio");
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t);
+ v4l2_device_call_all(&dev->v4l2->v4l2_dev, 0, tuner, g_tuner, t);
return 0;
}
@@ -1546,12 +1860,27 @@ static int radio_s_tuner(struct file *file, void *priv,
if (0 != t->index)
return -EINVAL;
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t);
+ v4l2_device_call_all(&dev->v4l2->v4l2_dev, 0, tuner, s_tuner, t);
return 0;
}
/*
+ * em28xx_free_v4l2() - Free struct em28xx_v4l2
+ *
+ * @ref: struct kref for struct em28xx_v4l2
+ *
+ * Called when all users of struct em28xx_v4l2 are gone
+ */
+static void em28xx_free_v4l2(struct kref *ref)
+{
+ struct em28xx_v4l2 *v4l2 = container_of(ref, struct em28xx_v4l2, ref);
+
+ v4l2->dev->v4l2 = NULL;
+ kfree(v4l2);
+}
+
+/*
* em28xx_v4l2_open()
* inits the device and starts isoc transfer
*/
@@ -1559,6 +1888,7 @@ static int em28xx_v4l2_open(struct file *filp)
{
struct video_device *vdev = video_devdata(filp);
struct em28xx *dev = video_drvdata(filp);
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
enum v4l2_buf_type fh_type = 0;
struct em28xx_fh *fh;
@@ -1569,12 +1899,15 @@ static int em28xx_v4l2_open(struct file *filp)
case VFL_TYPE_VBI:
fh_type = V4L2_BUF_TYPE_VBI_CAPTURE;
break;
+ case VFL_TYPE_RADIO:
+ break;
+ default:
+ return -EINVAL;
}
em28xx_videodbg("open dev=%s type=%s users=%d\n",
video_device_node_name(vdev), v4l2_type_names[fh_type],
- dev->users);
-
+ v4l2->users);
if (mutex_lock_interruptible(&dev->lock))
return -ERESTARTSYS;
@@ -1589,23 +1922,27 @@ static int em28xx_v4l2_open(struct file *filp)
fh->type = fh_type;
filp->private_data = fh;
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) {
+ if (v4l2->users == 0) {
em28xx_set_mode(dev, EM28XX_ANALOG_MODE);
- em28xx_resolution_set(dev);
- /* Needed, since GPIO might have disabled power of
- some i2c device
+ if (vdev->vfl_type != VFL_TYPE_RADIO)
+ em28xx_resolution_set(dev);
+
+ /*
+ * Needed, since GPIO might have disabled power
+ * of some i2c devices
*/
em28xx_wake_i2c(dev);
-
}
if (vdev->vfl_type == VFL_TYPE_RADIO) {
em28xx_videodbg("video_open: setting radio device\n");
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_radio);
+ v4l2_device_call_all(&v4l2->v4l2_dev, 0, tuner, s_radio);
}
- dev->users++;
+ kref_get(&dev->ref);
+ kref_get(&v4l2->ref);
+ v4l2->users++;
mutex_unlock(&dev->lock);
v4l2_fh_add(&fh->fh);
@@ -1614,40 +1951,92 @@ static int em28xx_v4l2_open(struct file *filp)
}
/*
- * em28xx_realease_resources()
+ * em28xx_v4l2_fini()
* unregisters the v4l2,i2c and usb devices
* called when the device gets disconected or at module unload
*/
-void em28xx_release_analog_resources(struct em28xx *dev)
+static int em28xx_v4l2_fini(struct em28xx *dev)
{
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
- /*FIXME: I2C IR should be disconnected */
+ if (dev->is_audio_only) {
+ /* Shouldn't initialize IR for this interface */
+ return 0;
+ }
- if (dev->radio_dev) {
- if (video_is_registered(dev->radio_dev))
- video_unregister_device(dev->radio_dev);
- else
- video_device_release(dev->radio_dev);
- dev->radio_dev = NULL;
+ if (!dev->has_video) {
+ /* This device does not support the v4l2 extension */
+ return 0;
+ }
+
+ if (v4l2 == NULL)
+ return 0;
+
+ em28xx_info("Closing video extension");
+
+ mutex_lock(&dev->lock);
+
+ v4l2_device_disconnect(&v4l2->v4l2_dev);
+
+ em28xx_uninit_usb_xfer(dev, EM28XX_ANALOG_MODE);
+
+ if (v4l2->radio_dev) {
+ em28xx_info("V4L2 device %s deregistered\n",
+ video_device_node_name(v4l2->radio_dev));
+ video_unregister_device(v4l2->radio_dev);
}
- if (dev->vbi_dev) {
+ if (v4l2->vbi_dev) {
em28xx_info("V4L2 device %s deregistered\n",
- video_device_node_name(dev->vbi_dev));
- if (video_is_registered(dev->vbi_dev))
- video_unregister_device(dev->vbi_dev);
- else
- video_device_release(dev->vbi_dev);
- dev->vbi_dev = NULL;
+ video_device_node_name(v4l2->vbi_dev));
+ video_unregister_device(v4l2->vbi_dev);
}
- if (dev->vdev) {
+ if (v4l2->vdev) {
em28xx_info("V4L2 device %s deregistered\n",
- video_device_node_name(dev->vdev));
- if (video_is_registered(dev->vdev))
- video_unregister_device(dev->vdev);
- else
- video_device_release(dev->vdev);
- dev->vdev = NULL;
+ video_device_node_name(v4l2->vdev));
+ video_unregister_device(v4l2->vdev);
+ }
+
+ v4l2_ctrl_handler_free(&v4l2->ctrl_handler);
+ v4l2_device_unregister(&v4l2->v4l2_dev);
+
+ if (v4l2->clk) {
+ v4l2_clk_unregister_fixed(v4l2->clk);
+ v4l2->clk = NULL;
}
+
+ kref_put(&v4l2->ref, em28xx_free_v4l2);
+
+ mutex_unlock(&dev->lock);
+
+ kref_put(&dev->ref, em28xx_free_device);
+
+ return 0;
+}
+
+static int em28xx_v4l2_suspend(struct em28xx *dev)
+{
+ if (dev->is_audio_only)
+ return 0;
+
+ if (!dev->has_video)
+ return 0;
+
+ em28xx_info("Suspending video extension");
+ em28xx_stop_urbs(dev);
+ return 0;
+}
+
+static int em28xx_v4l2_resume(struct em28xx *dev)
+{
+ if (dev->is_audio_only)
+ return 0;
+
+ if (!dev->has_video)
+ return 0;
+
+ em28xx_info("Resuming video extension");
+ /* what do we do here */
+ return 0;
}
/*
@@ -1657,28 +2046,23 @@ void em28xx_release_analog_resources(struct em28xx *dev)
*/
static int em28xx_v4l2_close(struct file *filp)
{
- struct em28xx_fh *fh = filp->private_data;
- struct em28xx *dev = fh->dev;
+ struct em28xx_fh *fh = filp->private_data;
+ struct em28xx *dev = fh->dev;
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
int errCode;
- em28xx_videodbg("users=%d\n", dev->users);
+ em28xx_videodbg("users=%d\n", v4l2->users);
- mutex_lock(&dev->lock);
vb2_fop_release(filp);
+ mutex_lock(&dev->lock);
- if (dev->users == 1) {
- /* the device is already disconnect,
- free the remaining resources */
- if (dev->disconnected) {
- em28xx_release_resources(dev);
- kfree(dev->alt_max_pkt_size_isoc);
- mutex_unlock(&dev->lock);
- kfree(dev);
- return 0;
- }
+ if (v4l2->users == 1) {
+ /* No sense to try to write to the device */
+ if (dev->disconnected)
+ goto exit;
/* Save some power by putting tuner to sleep */
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0);
+ v4l2_device_call_all(&v4l2->v4l2_dev, 0, core, s_power, 0);
/* do this before setting alternate! */
em28xx_set_mode(dev, EM28XX_SUSPEND);
@@ -1693,8 +2077,12 @@ static int em28xx_v4l2_close(struct file *filp)
}
}
- dev->users--;
+exit:
+ v4l2->users--;
+ kref_put(&v4l2->ref, em28xx_free_v4l2);
mutex_unlock(&dev->lock);
+ kref_put(&dev->ref, em28xx_free_device);
+
return 0;
}
@@ -1752,11 +2140,10 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
};
static const struct video_device em28xx_video_template = {
- .fops = &em28xx_v4l_fops,
- .release = video_device_release_empty,
- .ioctl_ops = &video_ioctl_ops,
-
- .tvnorms = V4L2_STD_ALL,
+ .fops = &em28xx_v4l_fops,
+ .ioctl_ops = &video_ioctl_ops,
+ .release = video_device_release,
+ .tvnorms = V4L2_STD_ALL,
};
static const struct v4l2_file_operations radio_fops = {
@@ -1782,14 +2169,30 @@ static const struct v4l2_ioctl_ops radio_ioctl_ops = {
};
static struct video_device em28xx_radio_template = {
- .name = "em28xx-radio",
- .fops = &radio_fops,
- .ioctl_ops = &radio_ioctl_ops,
+ .fops = &radio_fops,
+ .ioctl_ops = &radio_ioctl_ops,
+ .release = video_device_release,
};
-/******************************** usb interface ******************************/
+/* I2C possible address to saa7115, tvp5150, msp3400, tvaudio */
+static unsigned short saa711x_addrs[] = {
+ 0x4a >> 1, 0x48 >> 1, /* SAA7111, SAA7111A and SAA7113 */
+ 0x42 >> 1, 0x40 >> 1, /* SAA7114, SAA7115 and SAA7118 */
+ I2C_CLIENT_END };
+
+static unsigned short tvp5150_addrs[] = {
+ 0xb8 >> 1,
+ 0xba >> 1,
+ I2C_CLIENT_END
+};
+static unsigned short msp3400_addrs[] = {
+ 0x80 >> 1,
+ 0x88 >> 1,
+ I2C_CLIENT_END
+};
+/******************************** usb interface ******************************/
static struct video_device *em28xx_vdev_init(struct em28xx *dev,
const struct video_device *template,
@@ -1802,7 +2205,7 @@ static struct video_device *em28xx_vdev_init(struct em28xx *dev,
return NULL;
*vfd = *template;
- vfd->v4l2_dev = &dev->v4l2_dev;
+ vfd->v4l2_dev = &dev->v4l2->v4l2_dev;
vfd->debug = video_debug;
vfd->lock = &dev->lock;
set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
@@ -1816,22 +2219,232 @@ static struct video_device *em28xx_vdev_init(struct em28xx *dev,
return vfd;
}
-int em28xx_register_analog_devices(struct em28xx *dev)
+static void em28xx_tuner_setup(struct em28xx *dev, unsigned short tuner_addr)
+{
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
+ struct v4l2_device *v4l2_dev = &v4l2->v4l2_dev;
+ struct tuner_setup tun_setup;
+ struct v4l2_frequency f;
+
+ memset(&tun_setup, 0, sizeof(tun_setup));
+
+ tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
+ tun_setup.tuner_callback = em28xx_tuner_callback;
+
+ if (dev->board.radio.type) {
+ tun_setup.type = dev->board.radio.type;
+ tun_setup.addr = dev->board.radio_addr;
+
+ v4l2_device_call_all(v4l2_dev,
+ 0, tuner, s_type_addr, &tun_setup);
+ }
+
+ if ((dev->tuner_type != TUNER_ABSENT) && (dev->tuner_type)) {
+ tun_setup.type = dev->tuner_type;
+ tun_setup.addr = tuner_addr;
+
+ v4l2_device_call_all(v4l2_dev,
+ 0, tuner, s_type_addr, &tun_setup);
+ }
+
+ if (dev->board.tda9887_conf) {
+ struct v4l2_priv_tun_config tda9887_cfg;
+
+ tda9887_cfg.tuner = TUNER_TDA9887;
+ tda9887_cfg.priv = &dev->board.tda9887_conf;
+
+ v4l2_device_call_all(v4l2_dev,
+ 0, tuner, s_config, &tda9887_cfg);
+ }
+
+ if (dev->tuner_type == TUNER_XC2028) {
+ struct v4l2_priv_tun_config xc2028_cfg;
+ struct xc2028_ctrl ctl;
+
+ memset(&xc2028_cfg, 0, sizeof(xc2028_cfg));
+ memset(&ctl, 0, sizeof(ctl));
+
+ em28xx_setup_xc3028(dev, &ctl);
+
+ xc2028_cfg.tuner = TUNER_XC2028;
+ xc2028_cfg.priv = &ctl;
+
+ v4l2_device_call_all(v4l2_dev, 0, tuner, s_config, &xc2028_cfg);
+ }
+
+ /* configure tuner */
+ f.tuner = 0;
+ f.type = V4L2_TUNER_ANALOG_TV;
+ f.frequency = 9076; /* just a magic number */
+ v4l2->frequency = f.frequency;
+ v4l2_device_call_all(v4l2_dev, 0, tuner, s_frequency, &f);
+}
+
+static int em28xx_v4l2_init(struct em28xx *dev)
{
u8 val;
int ret;
unsigned int maxw;
+ struct v4l2_ctrl_handler *hdl;
+ struct em28xx_v4l2 *v4l2;
+
+ if (dev->is_audio_only) {
+ /* Shouldn't initialize IR for this interface */
+ return 0;
+ }
+
+ if (!dev->has_video) {
+ /* This device does not support the v4l2 extension */
+ return 0;
+ }
+
+ em28xx_info("Registering V4L2 extension\n");
+
+ mutex_lock(&dev->lock);
- printk(KERN_INFO "%s: v4l2 driver version %s\n",
- dev->name, EM28XX_VERSION);
+ v4l2 = kzalloc(sizeof(struct em28xx_v4l2), GFP_KERNEL);
+ if (v4l2 == NULL) {
+ em28xx_info("em28xx_v4l: memory allocation failed\n");
+ mutex_unlock(&dev->lock);
+ return -ENOMEM;
+ }
+ kref_init(&v4l2->ref);
+ v4l2->dev = dev;
+ dev->v4l2 = v4l2;
+
+ ret = v4l2_device_register(&dev->udev->dev, &v4l2->v4l2_dev);
+ if (ret < 0) {
+ em28xx_errdev("Call to v4l2_device_register() failed!\n");
+ goto err;
+ }
+
+ hdl = &v4l2->ctrl_handler;
+ v4l2_ctrl_handler_init(hdl, 8);
+ v4l2->v4l2_dev.ctrl_handler = hdl;
+
+ if (dev->board.is_webcam)
+ v4l2->progressive = 1;
+
+ /*
+ * Default format, used for tvp5150 or saa711x output formats
+ */
+ v4l2->vinmode = 0x10;
+ v4l2->vinctl = EM28XX_VINCTRL_INTERLACED |
+ EM28XX_VINCTRL_CCIR656_ENABLE;
+
+ /* request some modules */
+
+ if (dev->board.has_msp34xx)
+ v4l2_i2c_new_subdev(&v4l2->v4l2_dev,
+ &dev->i2c_adap[dev->def_i2c_bus],
+ "msp3400", 0, msp3400_addrs);
+
+ if (dev->board.decoder == EM28XX_SAA711X)
+ v4l2_i2c_new_subdev(&v4l2->v4l2_dev,
+ &dev->i2c_adap[dev->def_i2c_bus],
+ "saa7115_auto", 0, saa711x_addrs);
+
+ if (dev->board.decoder == EM28XX_TVP5150)
+ v4l2_i2c_new_subdev(&v4l2->v4l2_dev,
+ &dev->i2c_adap[dev->def_i2c_bus],
+ "tvp5150", 0, tvp5150_addrs);
+
+ if (dev->board.adecoder == EM28XX_TVAUDIO)
+ v4l2_i2c_new_subdev(&v4l2->v4l2_dev,
+ &dev->i2c_adap[dev->def_i2c_bus],
+ "tvaudio", dev->board.tvaudio_addr, NULL);
+
+ /* Initialize tuner and camera */
+
+ if (dev->board.tuner_type != TUNER_ABSENT) {
+ unsigned short tuner_addr = dev->board.tuner_addr;
+ int has_demod = (dev->board.tda9887_conf & TDA9887_PRESENT);
+
+ if (dev->board.radio.type)
+ v4l2_i2c_new_subdev(&v4l2->v4l2_dev,
+ &dev->i2c_adap[dev->def_i2c_bus],
+ "tuner", dev->board.radio_addr, NULL);
+
+ if (has_demod)
+ v4l2_i2c_new_subdev(&v4l2->v4l2_dev,
+ &dev->i2c_adap[dev->def_i2c_bus], "tuner",
+ 0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
+ if (tuner_addr == 0) {
+ enum v4l2_i2c_tuner_type type =
+ has_demod ? ADDRS_TV_WITH_DEMOD : ADDRS_TV;
+ struct v4l2_subdev *sd;
+
+ sd = v4l2_i2c_new_subdev(&v4l2->v4l2_dev,
+ &dev->i2c_adap[dev->def_i2c_bus], "tuner",
+ 0, v4l2_i2c_tuner_addrs(type));
+
+ if (sd)
+ tuner_addr = v4l2_i2c_subdev_addr(sd);
+ } else {
+ v4l2_i2c_new_subdev(&v4l2->v4l2_dev,
+ &dev->i2c_adap[dev->def_i2c_bus],
+ "tuner", tuner_addr, NULL);
+ }
+
+ em28xx_tuner_setup(dev, tuner_addr);
+ }
+
+ if (dev->em28xx_sensor != EM28XX_NOSENSOR)
+ em28xx_init_camera(dev);
+
+ /* Configure audio */
+ ret = em28xx_audio_setup(dev);
+ if (ret < 0) {
+ em28xx_errdev("%s: Error while setting audio - error [%d]!\n",
+ __func__, ret);
+ goto unregister_dev;
+ }
+ if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
+ v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
+ V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
+ v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
+ V4L2_CID_AUDIO_VOLUME, 0, 0x1f, 1, 0x1f);
+ } else {
+ /* install the em28xx notify callback */
+ v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_MUTE),
+ em28xx_ctrl_notify, dev);
+ v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_VOLUME),
+ em28xx_ctrl_notify, dev);
+ }
+
+ /* wake i2c devices */
+ em28xx_wake_i2c(dev);
+
+ /* init video dma queues */
+ INIT_LIST_HEAD(&dev->vidq.active);
+ INIT_LIST_HEAD(&dev->vbiq.active);
+
+ if (dev->board.has_msp34xx) {
+ /* Send a reset to other chips via gpio */
+ ret = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xf7);
+ if (ret < 0) {
+ em28xx_errdev("%s: em28xx_write_reg - msp34xx(1) failed! error [%d]\n",
+ __func__, ret);
+ goto unregister_dev;
+ }
+ msleep(3);
+
+ ret = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xff);
+ if (ret < 0) {
+ em28xx_errdev("%s: em28xx_write_reg - msp34xx(2) failed! error [%d]\n",
+ __func__, ret);
+ goto unregister_dev;
+ }
+ msleep(3);
+ }
/* set default norm */
- dev->norm = V4L2_STD_PAL;
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm);
- dev->interlaced = EM28XX_INTERLACED_DEFAULT;
+ v4l2->norm = V4L2_STD_PAL;
+ v4l2_device_call_all(&v4l2->v4l2_dev, 0, video, s_std, v4l2->norm);
+ v4l2->interlaced_fieldmode = EM28XX_INTERLACED_DEFAULT;
/* Analog specific initialization */
- dev->format = &format[0];
+ v4l2->format = &format[0];
maxw = norm_maxw(dev);
/* MaxPacketSize for em2800 is too small to capture at full resolution
@@ -1854,132 +2467,178 @@ int em28xx_register_analog_devices(struct em28xx *dev)
(EM28XX_XCLK_AUDIO_UNMUTE | val));
em28xx_set_outfmt(dev);
- em28xx_compression_disable(dev);
/* Add image controls */
/* NOTE: at this point, the subdevices are already registered, so bridge
* controls are only added/enabled when no subdevice provides them */
- if (NULL == v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_CONTRAST))
- v4l2_ctrl_new_std(&dev->ctrl_handler, &em28xx_ctrl_ops,
+ if (NULL == v4l2_ctrl_find(hdl, V4L2_CID_CONTRAST))
+ v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
V4L2_CID_CONTRAST,
0, 0x1f, 1, CONTRAST_DEFAULT);
- if (NULL == v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_BRIGHTNESS))
- v4l2_ctrl_new_std(&dev->ctrl_handler, &em28xx_ctrl_ops,
+ if (NULL == v4l2_ctrl_find(hdl, V4L2_CID_BRIGHTNESS))
+ v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
V4L2_CID_BRIGHTNESS,
-0x80, 0x7f, 1, BRIGHTNESS_DEFAULT);
- if (NULL == v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_SATURATION))
- v4l2_ctrl_new_std(&dev->ctrl_handler, &em28xx_ctrl_ops,
+ if (NULL == v4l2_ctrl_find(hdl, V4L2_CID_SATURATION))
+ v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
V4L2_CID_SATURATION,
0, 0x1f, 1, SATURATION_DEFAULT);
- if (NULL == v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_BLUE_BALANCE))
- v4l2_ctrl_new_std(&dev->ctrl_handler, &em28xx_ctrl_ops,
+ if (NULL == v4l2_ctrl_find(hdl, V4L2_CID_BLUE_BALANCE))
+ v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
V4L2_CID_BLUE_BALANCE,
-0x30, 0x30, 1, BLUE_BALANCE_DEFAULT);
- if (NULL == v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_RED_BALANCE))
- v4l2_ctrl_new_std(&dev->ctrl_handler, &em28xx_ctrl_ops,
+ if (NULL == v4l2_ctrl_find(hdl, V4L2_CID_RED_BALANCE))
+ v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
V4L2_CID_RED_BALANCE,
-0x30, 0x30, 1, RED_BALANCE_DEFAULT);
- if (NULL == v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_SHARPNESS))
- v4l2_ctrl_new_std(&dev->ctrl_handler, &em28xx_ctrl_ops,
+ if (NULL == v4l2_ctrl_find(hdl, V4L2_CID_SHARPNESS))
+ v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
V4L2_CID_SHARPNESS,
0, 0x0f, 1, SHARPNESS_DEFAULT);
/* Reset image controls */
em28xx_colorlevels_set_default(dev);
- v4l2_ctrl_handler_setup(&dev->ctrl_handler);
- if (dev->ctrl_handler.error)
- return dev->ctrl_handler.error;
+ v4l2_ctrl_handler_setup(hdl);
+ ret = hdl->error;
+ if (ret)
+ goto unregister_dev;
/* allocate and fill video video_device struct */
- dev->vdev = em28xx_vdev_init(dev, &em28xx_video_template, "video");
- if (!dev->vdev) {
+ v4l2->vdev = em28xx_vdev_init(dev, &em28xx_video_template, "video");
+ if (!v4l2->vdev) {
em28xx_errdev("cannot allocate video_device.\n");
- return -ENODEV;
+ ret = -ENODEV;
+ goto unregister_dev;
}
- dev->vdev->queue = &dev->vb_vidq;
- dev->vdev->queue->lock = &dev->vb_queue_lock;
+ mutex_init(&v4l2->vb_queue_lock);
+ mutex_init(&v4l2->vb_vbi_queue_lock);
+ v4l2->vdev->queue = &v4l2->vb_vidq;
+ v4l2->vdev->queue->lock = &v4l2->vb_queue_lock;
/* disable inapplicable ioctls */
if (dev->board.is_webcam) {
- v4l2_disable_ioctl(dev->vdev, VIDIOC_QUERYSTD);
- v4l2_disable_ioctl(dev->vdev, VIDIOC_G_STD);
- v4l2_disable_ioctl(dev->vdev, VIDIOC_S_STD);
+ v4l2_disable_ioctl(v4l2->vdev, VIDIOC_QUERYSTD);
+ v4l2_disable_ioctl(v4l2->vdev, VIDIOC_G_STD);
+ v4l2_disable_ioctl(v4l2->vdev, VIDIOC_S_STD);
} else {
- v4l2_disable_ioctl(dev->vdev, VIDIOC_S_PARM);
+ v4l2_disable_ioctl(v4l2->vdev, VIDIOC_S_PARM);
}
if (dev->tuner_type == TUNER_ABSENT) {
- v4l2_disable_ioctl(dev->vdev, VIDIOC_G_TUNER);
- v4l2_disable_ioctl(dev->vdev, VIDIOC_S_TUNER);
- v4l2_disable_ioctl(dev->vdev, VIDIOC_G_FREQUENCY);
- v4l2_disable_ioctl(dev->vdev, VIDIOC_S_FREQUENCY);
+ v4l2_disable_ioctl(v4l2->vdev, VIDIOC_G_TUNER);
+ v4l2_disable_ioctl(v4l2->vdev, VIDIOC_S_TUNER);
+ v4l2_disable_ioctl(v4l2->vdev, VIDIOC_G_FREQUENCY);
+ v4l2_disable_ioctl(v4l2->vdev, VIDIOC_S_FREQUENCY);
}
if (!dev->audio_mode.has_audio) {
- v4l2_disable_ioctl(dev->vdev, VIDIOC_G_AUDIO);
- v4l2_disable_ioctl(dev->vdev, VIDIOC_S_AUDIO);
+ v4l2_disable_ioctl(v4l2->vdev, VIDIOC_G_AUDIO);
+ v4l2_disable_ioctl(v4l2->vdev, VIDIOC_S_AUDIO);
}
/* register v4l2 video video_device */
- ret = video_register_device(dev->vdev, VFL_TYPE_GRABBER,
+ ret = video_register_device(v4l2->vdev, VFL_TYPE_GRABBER,
video_nr[dev->devno]);
if (ret) {
em28xx_errdev("unable to register video device (error=%i).\n",
ret);
- return ret;
+ goto unregister_dev;
}
/* Allocate and fill vbi video_device struct */
if (em28xx_vbi_supported(dev) == 1) {
- dev->vbi_dev = em28xx_vdev_init(dev, &em28xx_video_template,
+ v4l2->vbi_dev = em28xx_vdev_init(dev, &em28xx_video_template,
"vbi");
- dev->vbi_dev->queue = &dev->vb_vbiq;
- dev->vbi_dev->queue->lock = &dev->vb_vbi_queue_lock;
+ v4l2->vbi_dev->queue = &v4l2->vb_vbiq;
+ v4l2->vbi_dev->queue->lock = &v4l2->vb_vbi_queue_lock;
/* disable inapplicable ioctls */
- v4l2_disable_ioctl(dev->vdev, VIDIOC_S_PARM);
+ v4l2_disable_ioctl(v4l2->vdev, VIDIOC_S_PARM);
if (dev->tuner_type == TUNER_ABSENT) {
- v4l2_disable_ioctl(dev->vbi_dev, VIDIOC_G_TUNER);
- v4l2_disable_ioctl(dev->vbi_dev, VIDIOC_S_TUNER);
- v4l2_disable_ioctl(dev->vbi_dev, VIDIOC_G_FREQUENCY);
- v4l2_disable_ioctl(dev->vbi_dev, VIDIOC_S_FREQUENCY);
+ v4l2_disable_ioctl(v4l2->vbi_dev, VIDIOC_G_TUNER);
+ v4l2_disable_ioctl(v4l2->vbi_dev, VIDIOC_S_TUNER);
+ v4l2_disable_ioctl(v4l2->vbi_dev, VIDIOC_G_FREQUENCY);
+ v4l2_disable_ioctl(v4l2->vbi_dev, VIDIOC_S_FREQUENCY);
}
if (!dev->audio_mode.has_audio) {
- v4l2_disable_ioctl(dev->vbi_dev, VIDIOC_G_AUDIO);
- v4l2_disable_ioctl(dev->vbi_dev, VIDIOC_S_AUDIO);
+ v4l2_disable_ioctl(v4l2->vbi_dev, VIDIOC_G_AUDIO);
+ v4l2_disable_ioctl(v4l2->vbi_dev, VIDIOC_S_AUDIO);
}
/* register v4l2 vbi video_device */
- ret = video_register_device(dev->vbi_dev, VFL_TYPE_VBI,
+ ret = video_register_device(v4l2->vbi_dev, VFL_TYPE_VBI,
vbi_nr[dev->devno]);
if (ret < 0) {
em28xx_errdev("unable to register vbi device\n");
- return ret;
+ goto unregister_dev;
}
}
if (em28xx_boards[dev->model].radio.type == EM28XX_RADIO) {
- dev->radio_dev = em28xx_vdev_init(dev, &em28xx_radio_template,
- "radio");
- if (!dev->radio_dev) {
+ v4l2->radio_dev = em28xx_vdev_init(dev, &em28xx_radio_template,
+ "radio");
+ if (!v4l2->radio_dev) {
em28xx_errdev("cannot allocate video_device.\n");
- return -ENODEV;
+ ret = -ENODEV;
+ goto unregister_dev;
}
- ret = video_register_device(dev->radio_dev, VFL_TYPE_RADIO,
+ ret = video_register_device(v4l2->radio_dev, VFL_TYPE_RADIO,
radio_nr[dev->devno]);
if (ret < 0) {
em28xx_errdev("can't register radio device\n");
- return ret;
+ goto unregister_dev;
}
em28xx_info("Registered radio device as %s\n",
- video_device_node_name(dev->radio_dev));
+ video_device_node_name(v4l2->radio_dev));
}
em28xx_info("V4L2 video device registered as %s\n",
- video_device_node_name(dev->vdev));
+ video_device_node_name(v4l2->vdev));
- if (dev->vbi_dev)
+ if (v4l2->vbi_dev)
em28xx_info("V4L2 VBI device registered as %s\n",
- video_device_node_name(dev->vbi_dev));
+ video_device_node_name(v4l2->vbi_dev));
+
+ /* Save some power by putting tuner to sleep */
+ v4l2_device_call_all(&v4l2->v4l2_dev, 0, core, s_power, 0);
+ /* initialize videobuf2 stuff */
+ em28xx_vb2_setup(dev);
+
+ em28xx_info("V4L2 extension successfully initialized\n");
+
+ kref_get(&dev->ref);
+
+ mutex_unlock(&dev->lock);
return 0;
+
+unregister_dev:
+ v4l2_ctrl_handler_free(&v4l2->ctrl_handler);
+ v4l2_device_unregister(&v4l2->v4l2_dev);
+err:
+ dev->v4l2 = NULL;
+ kref_put(&v4l2->ref, em28xx_free_v4l2);
+ mutex_unlock(&dev->lock);
+ return ret;
}
+
+static struct em28xx_ops v4l2_ops = {
+ .id = EM28XX_V4L2,
+ .name = "Em28xx v4l2 Extension",
+ .init = em28xx_v4l2_init,
+ .fini = em28xx_v4l2_fini,
+ .suspend = em28xx_v4l2_suspend,
+ .resume = em28xx_v4l2_resume,
+};
+
+static int __init em28xx_video_register(void)
+{
+ return em28xx_register_extension(&v4l2_ops);
+}
+
+static void __exit em28xx_video_unregister(void)
+{
+ em28xx_unregister_extension(&v4l2_ops);
+}
+
+module_init(em28xx_video_register);
+module_exit(em28xx_video_unregister);
diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
index 205e9038b1c..b4c837d77e5 100644
--- a/drivers/media/usb/em28xx/em28xx.h
+++ b/drivers/media/usb/em28xx/em28xx.h
@@ -26,9 +26,13 @@
#ifndef _EM28XX_H
#define _EM28XX_H
+#define EM28XX_VERSION "0.2.1"
+#define DRIVER_DESC "Empia em28xx device driver"
+
#include <linux/workqueue.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
+#include <linux/kref.h>
#include <linux/videodev2.h>
#include <media/videobuf2-vmalloc.h>
@@ -101,6 +105,7 @@
#define EM2882_BOARD_PINNACLE_HYBRID_PRO_330E 56
#define EM2883_BOARD_KWORLD_HYBRID_330U 57
#define EM2820_BOARD_COMPRO_VIDEOMATE_FORYOU 58
+#define EM2874_BOARD_PCTV_HD_MINI_80E 59
#define EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850 60
#define EM2820_BOARD_PROLINK_PLAYTV_BOX4_USB2 61
#define EM2820_BOARD_GADMEI_TVR200 62
@@ -131,6 +136,11 @@
#define EM2884_BOARD_TERRATEC_HTC_USB_XS 87
#define EM2884_BOARD_C3TECH_DIGITAL_DUO 88
#define EM2874_BOARD_DELOCK_61959 89
+#define EM2874_BOARD_KWORLD_UB435Q_V2 90
+#define EM2765_BOARD_SPEEDLINK_VAD_LAPLACE 91
+#define EM28178_BOARD_PCTV_461E 92
+#define EM2874_BOARD_KWORLD_UB435Q_V3 93
+#define EM28178_BOARD_PCTV_292E 94
/* Limits minimum and default number of buffers */
#define EM28XX_MIN_BUF 4
@@ -177,8 +187,27 @@
#define EM28XX_INTERLACED_DEFAULT 1
-/* time in msecs to wait for i2c writes to finish */
-#define EM2800_I2C_XFER_TIMEOUT 20
+/*
+ * Time in msecs to wait for i2c xfers to finish.
+ * 35ms is the maximum time a SMBUS device could wait when
+ * clock stretching is used. As the transfer itself will take
+ * some time to happen, set it to 35 ms.
+ *
+ * Ok, I2C doesn't specify any limit. So, eventually, we may need
+ * to increase this timeout.
+ *
+ * FIXME: this assumes that an I2C message is not longer than 1ms.
+ * This is actually dependent on the I2C bus speed, although most
+ * devices use a 100kHz clock. So, this assumtion is true most of
+ * the time.
+ */
+#define EM28XX_I2C_XFER_TIMEOUT 36
+
+/* time in msecs to wait for AC97 xfers to finish */
+#define EM28XX_AC97_XFER_TIMEOUT 100
+
+/* max. number of button state polling addresses */
+#define EM28XX_NUM_BUTTON_ADDRESSES_MAX 5
enum em28xx_mode {
EM28XX_SUSPEND,
@@ -286,8 +315,7 @@ struct em28xx_audio_mode {
unsigned int has_audio:1;
- unsigned int i2s_3rates:1;
- unsigned int i2s_5rates:1;
+ u8 i2s_samplerates;
};
/* em28xx has two audio inputs: tuner and line in.
@@ -373,6 +401,34 @@ enum em28xx_adecoder {
EM28XX_TVAUDIO,
};
+enum em28xx_led_role {
+ EM28XX_LED_ANALOG_CAPTURING = 0,
+ EM28XX_LED_DIGITAL_CAPTURING,
+ EM28XX_LED_ILLUMINATION,
+ EM28XX_NUM_LED_ROLES, /* must be the last */
+};
+
+struct em28xx_led {
+ enum em28xx_led_role role;
+ u8 gpio_reg;
+ u8 gpio_mask;
+ bool inverted;
+};
+
+enum em28xx_button_role {
+ EM28XX_BUTTON_SNAPSHOT = 0,
+ EM28XX_BUTTON_ILLUMINATION,
+ EM28XX_NUM_BUTTON_ROLES, /* must be the last */
+};
+
+struct em28xx_button {
+ enum em28xx_button_role role;
+ u8 reg_r;
+ u8 reg_clearing;
+ u8 mask;
+ bool inverted;
+};
+
struct em28xx_board {
char *name;
int vchannels;
@@ -394,7 +450,6 @@ struct em28xx_board {
unsigned int mts_firmware:1;
unsigned int max_range_640_480:1;
unsigned int has_dvb:1;
- unsigned int has_snapshot_button:1;
unsigned int is_webcam:1;
unsigned int valid:1;
unsigned int has_ir_i2c:1;
@@ -409,6 +464,12 @@ struct em28xx_board {
struct em28xx_input input[MAX_EM28XX_INPUT];
struct em28xx_input radio;
char *ir_codes;
+
+ /* LEDs that need to be controlled explicitly */
+ struct em28xx_led *leds;
+
+ /* Buttons */
+ struct em28xx_button *buttons;
};
struct em28xx_eeprom {
@@ -425,24 +486,77 @@ struct em28xx_eeprom {
u8 string_idx_table;
};
-#define EM28XX_AUDIO_BUFS 5
-#define EM28XX_NUM_AUDIO_PACKETS 64
-#define EM28XX_AUDIO_MAX_PACKET_SIZE 196 /* static value */
#define EM28XX_CAPTURE_STREAM_EN 1
/* em28xx extensions */
#define EM28XX_AUDIO 0x10
#define EM28XX_DVB 0x20
#define EM28XX_RC 0x30
+#define EM28XX_V4L2 0x40
/* em28xx resource types (used for res_get/res_lock etc */
#define EM28XX_RESOURCE_VIDEO 0x01
#define EM28XX_RESOURCE_VBI 0x02
+struct em28xx_v4l2 {
+ struct kref ref;
+ struct em28xx *dev;
+
+ struct v4l2_device v4l2_dev;
+ struct v4l2_ctrl_handler ctrl_handler;
+ struct v4l2_clk *clk;
+
+ struct video_device *vdev;
+ struct video_device *vbi_dev;
+ struct video_device *radio_dev;
+
+ /* Videobuf2 */
+ struct vb2_queue vb_vidq;
+ struct vb2_queue vb_vbiq;
+ struct mutex vb_queue_lock;
+ struct mutex vb_vbi_queue_lock;
+
+ u8 vinmode;
+ u8 vinctl;
+
+ /* Camera specific fields */
+ int sensor_xres;
+ int sensor_yres;
+ int sensor_xtal;
+
+ int users; /* user count for exclusive use */
+ int streaming_users; /* number of actively streaming users */
+
+ u32 frequency; /* selected tuner frequency */
+
+ struct em28xx_fmt *format;
+ v4l2_std_id norm; /* selected tv norm */
+
+ /* Progressive/interlaced mode */
+ bool progressive;
+ int interlaced_fieldmode; /* 1=interlaced fields, 0=just top fields */
+ /* FIXME: everything else than interlaced_fieldmode=1 doesn't work */
+
+ /* Frame properties */
+ int width; /* current frame width */
+ int height; /* current frame height */
+ unsigned hscale; /* horizontal scale factor (see datasheet) */
+ unsigned vscale; /* vertical scale factor (see datasheet) */
+ unsigned int vbi_width;
+ unsigned int vbi_height; /* lines per field */
+
+ /* Capture state tracking */
+ int capture_type;
+ bool top_field;
+ int vbi_read;
+ unsigned int field_count;
+};
+
struct em28xx_audio {
char name[50];
- char *transfer_buffer[EM28XX_AUDIO_BUFS];
- struct urb *urb[EM28XX_AUDIO_BUFS];
+ unsigned num_urb;
+ char **transfer_buffer;
+ struct urb **urb;
struct usb_device *udev;
unsigned int capture_transfer_done;
struct snd_pcm_substream *capture_pcm_substream;
@@ -450,8 +564,14 @@ struct em28xx_audio {
unsigned int hwptr_done_capture;
struct snd_card *sndcard;
+ size_t period;
+
int users;
spinlock_t slock;
+
+ /* Controls streaming */
+ struct work_struct wq_trigger; /* trigger to start/stop audio */
+ atomic_t stream_started; /* stream should be running if true */
};
struct em28xx;
@@ -476,46 +596,32 @@ struct em28xx_i2c_bus {
enum em28xx_i2c_algo_type algo_type;
};
-
/* main device struct */
struct em28xx {
+ struct kref ref;
+
+ /* Sub-module data */
+ struct em28xx_v4l2 *v4l2;
+ struct em28xx_dvb *dvb;
+ struct em28xx_audio adev;
+ struct em28xx_IR *ir;
+
/* generic device properties */
char name[30]; /* name (including minor) of the device */
int model; /* index in the device_data struct */
int devno; /* marks the number of this device */
enum em28xx_chip_id chip_id;
- unsigned int is_em25xx:1; /* em25xx/em276x/7x/8x family bridge */
+ unsigned int is_em25xx:1; /* em25xx/em276x/7x/8x family bridge */
unsigned char disconnected:1; /* device has been diconnected */
-
- int audio_ifnum;
-
- struct v4l2_device v4l2_dev;
- struct v4l2_ctrl_handler ctrl_handler;
- struct em28xx_board board;
-
- /* Webcam specific fields */
- enum em28xx_sensor em28xx_sensor;
- int sensor_xres, sensor_yres;
- int sensor_xtal;
-
- /* Progressive (non-interlaced) mode */
- int progressive;
-
- /* Vinmode/Vinctl used at the driver */
- int vinmode, vinctl;
-
+ unsigned int has_video:1;
unsigned int has_audio_class:1;
unsigned int has_alsa_audio:1;
unsigned int is_audio_only:1;
- /* Controls audio streaming */
- struct work_struct wq_trigger; /* Trigger to start/stop audio for alsa module */
- atomic_t stream_started; /* stream should be running if true */
-
- struct em28xx_fmt *format;
+ struct em28xx_board board;
- struct em28xx_IR *ir;
+ enum em28xx_sensor em28xx_sensor; /* camera specific */
/* Some older em28xx chips needs a waiting time after writing */
unsigned int wait_after_write;
@@ -527,8 +633,6 @@ struct em28xx {
struct em28xx_audio_mode audio_mode;
int tuner_type; /* type of the tuner */
- int tuner_addr; /* tuner address */
- int tda9887_conf;
/* i2c i/o */
struct i2c_adapter i2c_adap[NUM_I2C_BUSES];
@@ -541,52 +645,21 @@ struct em28xx {
struct rt_mutex i2c_bus_lock;
/* video for linux */
- int users; /* user count for exclusive use */
- int streaming_users; /* Number of actively streaming users */
- struct video_device *vdev; /* video for linux device struct */
- v4l2_std_id norm; /* selected tv norm */
- int ctl_freq; /* selected frequency */
unsigned int ctl_input; /* selected input */
unsigned int ctl_ainput;/* selected audio input */
unsigned int ctl_aoutput;/* selected audio output */
int mute;
int volume;
- /* frame properties */
- int width; /* current frame width */
- int height; /* current frame height */
- unsigned hscale; /* horizontal scale factor (see datasheet) */
- unsigned vscale; /* vertical scale factor (see datasheet) */
- int interlaced; /* 1=interlace fileds, 0=just top fileds */
- unsigned int video_bytesread; /* Number of bytes read */
unsigned long hash; /* eeprom hash - for boards with generic ID */
unsigned long i2c_hash; /* i2c devicelist hash -
for boards with generic ID */
- struct em28xx_audio adev;
-
- /* capture state tracking */
- int capture_type;
- unsigned char top_field:1;
- int vbi_read;
- unsigned int vbi_width;
- unsigned int vbi_height; /* lines per field */
-
struct work_struct request_module_wk;
/* locks */
struct mutex lock;
struct mutex ctrl_urb_lock; /* protects urb_buf */
- /* spinlock_t queue_lock; */
- struct list_head inqueue, outqueue;
- struct video_device *vbi_dev;
- struct video_device *radio_dev;
-
- /* Videobuf2 */
- struct vb2_queue vb_vidq;
- struct vb2_queue vb_vbiq;
- struct mutex vb_queue_lock;
- struct mutex vb_vbi_queue_lock;
/* resources in use */
unsigned int resources;
@@ -601,11 +674,9 @@ struct em28xx {
struct em28xx_usb_ctl usb_ctl;
spinlock_t slock;
- unsigned int field_count;
- unsigned int vbi_field_count;
-
/* usb transfer */
struct usb_device *udev; /* the usb device */
+ u8 ifnum; /* number of the assigned usb interface */
u8 analog_ep_isoc; /* address of isoc endpoint for analog */
u8 analog_ep_bulk; /* address of bulk endpoint for analog */
u8 dvb_ep_isoc; /* address of isoc endpoint for DVB */
@@ -637,20 +708,27 @@ struct em28xx {
enum em28xx_mode mode;
- /* Snapshot button */
+ /* Button state polling */
+ struct delayed_work buttons_query_work;
+ u8 button_polling_addresses[EM28XX_NUM_BUTTON_ADDRESSES_MAX];
+ u8 button_polling_last_values[EM28XX_NUM_BUTTON_ADDRESSES_MAX];
+ u8 num_button_polling_addresses;
+ u16 button_polling_interval; /* [ms] */
+ /* Snapshot button input device */
char snapshot_button_path[30]; /* path of the input dev */
struct input_dev *sbutton_input_dev;
- struct delayed_work sbutton_query_work;
-
- struct em28xx_dvb *dvb;
};
+#define kref_to_dev(d) container_of(d, struct em28xx, ref)
+
struct em28xx_ops {
struct list_head next;
char *name;
int id;
int (*init)(struct em28xx *);
int (*fini)(struct em28xx *);
+ int (*suspend)(struct em28xx *);
+ int (*resume)(struct em28xx *);
};
/* Provided by em28xx-i2c.c */
@@ -670,6 +748,7 @@ int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len);
int em28xx_write_reg(struct em28xx *dev, u16 reg, u8 val);
int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val,
u8 bitmask);
+int em28xx_toggle_reg_bits(struct em28xx *dev, u16 reg, u8 bitmask);
int em28xx_read_ac97(struct em28xx *dev, u8 reg);
int em28xx_write_ac97(struct em28xx *dev, u8 reg, u16 val);
@@ -677,12 +756,9 @@ int em28xx_write_ac97(struct em28xx *dev, u8 reg, u16 val);
int em28xx_audio_analog_set(struct em28xx *dev);
int em28xx_audio_setup(struct em28xx *dev);
-int em28xx_colorlevels_set_default(struct em28xx *dev);
+const struct em28xx_led *em28xx_find_led(struct em28xx *dev,
+ enum em28xx_led_role role);
int em28xx_capture_start(struct em28xx *dev, int start);
-int em28xx_vbi_supported(struct em28xx *dev);
-int em28xx_set_outfmt(struct em28xx *dev);
-int em28xx_resolution_set(struct em28xx *dev);
-int em28xx_set_alternate(struct em28xx *dev);
int em28xx_alloc_urbs(struct em28xx *dev, enum em28xx_mode mode, int xfer_bulk,
int num_bufs, int max_pkt_size, int packet_multiplier);
int em28xx_init_usb_xfer(struct em28xx *dev, enum em28xx_mode mode,
@@ -694,29 +770,19 @@ void em28xx_uninit_usb_xfer(struct em28xx *dev, enum em28xx_mode mode);
void em28xx_stop_urbs(struct em28xx *dev);
int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode);
int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio);
-void em28xx_wake_i2c(struct em28xx *dev);
int em28xx_register_extension(struct em28xx_ops *dev);
void em28xx_unregister_extension(struct em28xx_ops *dev);
void em28xx_init_extension(struct em28xx *dev);
void em28xx_close_extension(struct em28xx *dev);
-
-/* Provided by em28xx-video.c */
-int em28xx_vb2_setup(struct em28xx *dev);
-int em28xx_register_analog_devices(struct em28xx *dev);
-void em28xx_release_analog_resources(struct em28xx *dev);
-void em28xx_ctrl_notify(struct v4l2_ctrl *ctrl, void *priv);
-int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count);
-int em28xx_stop_vbi_streaming(struct vb2_queue *vq);
-extern const struct v4l2_ctrl_ops em28xx_ctrl_ops;
+int em28xx_suspend_extension(struct em28xx *dev);
+int em28xx_resume_extension(struct em28xx *dev);
/* Provided by em28xx-cards.c */
extern struct em28xx_board em28xx_boards[];
extern struct usb_device_id em28xx_id_table[];
int em28xx_tuner_callback(void *ptr, int component, int command, int arg);
-void em28xx_release_resources(struct em28xx *dev);
-
-/* Provided by em28xx-vbi.c */
-extern struct vb2_ops em28xx_vbi_qops;
+void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl);
+void em28xx_free_device(struct kref *ref);
/* Provided by em28xx-camera.c */
int em28xx_detect_sensor(struct em28xx *dev);
@@ -738,32 +804,4 @@ int em28xx_init_camera(struct em28xx *dev);
printk(KERN_WARNING "%s: "fmt,\
dev->name , ##arg); } while (0)
-static inline int em28xx_compression_disable(struct em28xx *dev)
-{
- /* side effect of disabling scaler and mixer */
- return em28xx_write_reg(dev, EM28XX_R26_COMPR, 0x00);
-}
-
-/*FIXME: maxw should be dependent of alt mode */
-static inline unsigned int norm_maxw(struct em28xx *dev)
-{
- if (dev->board.is_webcam)
- return dev->sensor_xres;
-
- if (dev->board.max_range_640_480)
- return 640;
-
- return 720;
-}
-
-static inline unsigned int norm_maxh(struct em28xx *dev)
-{
- if (dev->board.is_webcam)
- return dev->sensor_yres;
-
- if (dev->board.max_range_640_480)
- return 480;
-
- return (dev->norm & V4L2_STD_625_50) ? 576 : 480;
-}
#endif
diff --git a/drivers/media/usb/gspca/Kconfig b/drivers/media/usb/gspca/Kconfig
index 4f0c6d566c8..eed10d78253 100644
--- a/drivers/media/usb/gspca/Kconfig
+++ b/drivers/media/usb/gspca/Kconfig
@@ -50,6 +50,16 @@ config USB_GSPCA_CPIA1
To compile this driver as a module, choose M here: the
module will be called gspca_cpia1.
+config USB_GSPCA_DTCS033
+ tristate "DTCS033 (Scopium) USB Astro-Camera Driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for the Scopium camera
+ for planetary astrophotography.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_dtcs033.
+
config USB_GSPCA_ETOMS
tristate "Etoms USB Camera Driver"
depends on VIDEO_V4L2 && USB_GSPCA
diff --git a/drivers/media/usb/gspca/Makefile b/drivers/media/usb/gspca/Makefile
index 5855131ab8b..f46975e4c82 100644
--- a/drivers/media/usb/gspca/Makefile
+++ b/drivers/media/usb/gspca/Makefile
@@ -2,6 +2,7 @@ obj-$(CONFIG_USB_GSPCA) += gspca_main.o
obj-$(CONFIG_USB_GSPCA_BENQ) += gspca_benq.o
obj-$(CONFIG_USB_GSPCA_CONEX) += gspca_conex.o
obj-$(CONFIG_USB_GSPCA_CPIA1) += gspca_cpia1.o
+obj-$(CONFIG_USB_GSPCA_DTCS033) += gspca_dtcs033.o
obj-$(CONFIG_USB_GSPCA_ETOMS) += gspca_etoms.o
obj-$(CONFIG_USB_GSPCA_FINEPIX) += gspca_finepix.o
obj-$(CONFIG_USB_GSPCA_JEILINJ) += gspca_jeilinj.o
@@ -48,6 +49,7 @@ gspca_main-objs := gspca.o autogain_functions.o
gspca_benq-objs := benq.o
gspca_conex-objs := conex.o
gspca_cpia1-objs := cpia1.o
+gspca_dtcs033-objs := dtcs033.o
gspca_etoms-objs := etoms.o
gspca_finepix-objs := finepix.o
gspca_jeilinj-objs := jeilinj.o
diff --git a/drivers/media/usb/gspca/conex.c b/drivers/media/usb/gspca/conex.c
index 38714df31ac..2e15c80d6e3 100644
--- a/drivers/media/usb/gspca/conex.c
+++ b/drivers/media/usb/gspca/conex.c
@@ -783,7 +783,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev;
/* create the JPEG header */
- jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
+ jpeg_define(sd->jpeg_hdr, gspca_dev->pixfmt.height,
+ gspca_dev->pixfmt.width,
0x22); /* JPEG 411 */
jpeg_set_qual(sd->jpeg_hdr, QUALITY);
diff --git a/drivers/media/usb/gspca/cpia1.c b/drivers/media/usb/gspca/cpia1.c
index 064b53043b1..f23df4a9d8c 100644
--- a/drivers/media/usb/gspca/cpia1.c
+++ b/drivers/media/usb/gspca/cpia1.c
@@ -1553,9 +1553,9 @@ static int sd_start(struct gspca_dev *gspca_dev)
sd->params.format.videoSize = VIDEOSIZE_CIF;
sd->params.roi.colEnd = sd->params.roi.colStart +
- (gspca_dev->width >> 3);
+ (gspca_dev->pixfmt.width >> 3);
sd->params.roi.rowEnd = sd->params.roi.rowStart +
- (gspca_dev->height >> 2);
+ (gspca_dev->pixfmt.height >> 2);
/* And now set the camera to a known state */
ret = do_command(gspca_dev, CPIA_COMMAND_SetGrabMode,
diff --git a/drivers/media/usb/gspca/dtcs033.c b/drivers/media/usb/gspca/dtcs033.c
new file mode 100644
index 00000000000..96bfd4e0f0e
--- /dev/null
+++ b/drivers/media/usb/gspca/dtcs033.c
@@ -0,0 +1,441 @@
+/*
+ * Subdriver for Scopium astro-camera (DTCS033, 0547:7303)
+ *
+ * Copyright (C) 2014 Robert Butora (robert.butora.fi@gmail.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#define MODULE_NAME "dtcs033"
+#include "gspca.h"
+
+MODULE_AUTHOR("Robert Butora <robert.butora.fi@gmail.com>");
+MODULE_DESCRIPTION("Scopium DTCS033 astro-cam USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+struct dtcs033_usb_requests {
+ u8 bRequestType;
+ u8 bRequest;
+ u16 wValue;
+ u16 wIndex;
+ u16 wLength;
+};
+
+/* send a usb request */
+static void reg_rw(struct gspca_dev *gspca_dev,
+ u8 bRequestType, u8 bRequest,
+ u16 wValue, u16 wIndex, u16 wLength)
+{
+ struct usb_device *udev = gspca_dev->dev;
+ int ret;
+
+ if (gspca_dev->usb_err < 0)
+ return;
+
+ ret = usb_control_msg(udev,
+ usb_rcvctrlpipe(udev, 0),
+ bRequest,
+ bRequestType,
+ wValue, wIndex,
+ gspca_dev->usb_buf, wLength, 500);
+
+ if (ret < 0) {
+ gspca_dev->usb_err = ret;
+ pr_err("usb_control_msg error %d\n", ret);
+ }
+
+ return;
+}
+/* send several usb in/out requests */
+static int reg_reqs(struct gspca_dev *gspca_dev,
+ const struct dtcs033_usb_requests *preqs, int n_reqs)
+{
+ int i = 0;
+ const struct dtcs033_usb_requests *preq;
+
+ while ((i < n_reqs) && (gspca_dev->usb_err >= 0)) {
+
+ preq = &preqs[i];
+
+ reg_rw(gspca_dev, preq->bRequestType, preq->bRequest,
+ preq->wValue, preq->wIndex, preq->wLength);
+
+ if (gspca_dev->usb_err < 0) {
+
+ PERR("usb error request no: %d / %d\n",
+ i, n_reqs);
+ } else if (preq->bRequestType & USB_DIR_IN) {
+
+ PDEBUG(D_STREAM,
+ "USB IN (%d) returned[%d] %02X %02X %02X %s",
+ i,
+ preq->wLength,
+ gspca_dev->usb_buf[0],
+ gspca_dev->usb_buf[1],
+ gspca_dev->usb_buf[2],
+ preq->wLength > 3 ? "...\n" : "\n");
+ }
+
+ i++;
+ }
+ return gspca_dev->usb_err;
+}
+
+/* -- subdriver interface implementation -- */
+
+#define DT_COLS (640)
+static const struct v4l2_pix_format dtcs033_mode[] = {
+ /* raw Bayer patterned output */
+ {DT_COLS, 480, V4L2_PIX_FMT_GREY, V4L2_FIELD_NONE,
+ .bytesperline = DT_COLS,
+ .sizeimage = DT_COLS*480,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ },
+ /* this mode will demosaic the Bayer pattern */
+ {DT_COLS, 480, V4L2_PIX_FMT_SRGGB8, V4L2_FIELD_NONE,
+ .bytesperline = DT_COLS,
+ .sizeimage = DT_COLS*480,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ }
+};
+
+/* config called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+ const struct usb_device_id *id)
+{
+ gspca_dev->cam.cam_mode = dtcs033_mode;
+ gspca_dev->cam.nmodes = ARRAY_SIZE(dtcs033_mode);
+
+ gspca_dev->cam.bulk = 1;
+ gspca_dev->cam.bulk_nurbs = 1;
+ gspca_dev->cam.bulk_size = DT_COLS*512;
+
+ return 0;
+}
+
+/* init called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+ return 0;
+}
+
+/* start stop the camera */
+static int dtcs033_start(struct gspca_dev *gspca_dev);
+static void dtcs033_stopN(struct gspca_dev *gspca_dev);
+
+/* intercept camera image data */
+static void dtcs033_pkt_scan(struct gspca_dev *gspca_dev,
+ u8 *data, /* packet data */
+ int len) /* packet data length */
+{
+ /* drop incomplete frames */
+ if (len != DT_COLS*512) {
+ gspca_dev->last_packet_type = DISCARD_PACKET;
+ /* gspca.c: discard invalidates the whole frame. */
+ return;
+ }
+
+ /* forward complete frames */
+ gspca_frame_add(gspca_dev, FIRST_PACKET, NULL, 0);
+ gspca_frame_add(gspca_dev, INTER_PACKET,
+ data + 16*DT_COLS,
+ len - 32*DT_COLS); /* skip first & last 16 lines */
+ gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
+
+ return;
+}
+
+/* -- controls: exposure and gain -- */
+
+static void dtcs033_setexposure(struct gspca_dev *gspca_dev,
+ s32 expo, s32 gain)
+{
+ /* gain [dB] encoding */
+ u16 sGain = (u16)gain;
+ u16 gainVal = 224+(sGain-14)*(768-224)/(33-14);
+ u16 wIndex = 0x0100|(0x00FF&gainVal);
+ u16 wValue = (0xFF00&gainVal)>>8;
+
+ /* exposure time [msec] encoding */
+ u16 sXTime = (u16)expo;
+ u16 xtimeVal = (524*(150-(sXTime-1)))/150;
+
+ const u8 bRequestType =
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE;
+ const u8 bRequest = 0x18;
+
+ reg_rw(gspca_dev,
+ bRequestType, bRequest, wValue, wIndex, 0);
+ if (gspca_dev->usb_err < 0)
+ PERR("usb error in setexposure(gain) sequence.\n");
+
+ reg_rw(gspca_dev,
+ bRequestType, bRequest, (xtimeVal<<4), 0x6300, 0);
+ if (gspca_dev->usb_err < 0)
+ PERR("usb error in setexposure(time) sequence.\n");
+}
+
+/* specific webcam descriptor */
+struct sd {
+ struct gspca_dev gspca_dev;/* !! must be the first item */
+
+ /* exposure & gain controls */
+ struct {
+ struct v4l2_ctrl *exposure;
+ struct v4l2_ctrl *gain;
+ };
+};
+
+static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct gspca_dev *gspca_dev =
+ container_of(ctrl->handler,
+ struct gspca_dev, ctrl_handler);
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ gspca_dev->usb_err = 0;
+
+ if (!gspca_dev->streaming)
+ return 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_EXPOSURE:
+ dtcs033_setexposure(gspca_dev,
+ ctrl->val, sd->gain->val);
+ break;
+ case V4L2_CID_GAIN:
+ dtcs033_setexposure(gspca_dev,
+ sd->exposure->val, ctrl->val);
+ break;
+ }
+ return gspca_dev->usb_err;
+}
+
+static const struct v4l2_ctrl_ops sd_ctrl_ops = {
+ .s_ctrl = sd_s_ctrl,
+};
+
+static int dtcs033_init_controls(struct gspca_dev *gspca_dev)
+{
+ struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ gspca_dev->vdev.ctrl_handler = hdl;
+ v4l2_ctrl_handler_init(hdl, 2);
+ /* min max step default */
+ sd->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_EXPOSURE,
+ 1, 150, 1, 75);/* [msec] */
+ sd->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_GAIN,
+ 14, 33, 1, 24);/* [dB] */
+ if (hdl->error) {
+ PERR("Could not initialize controls: %d\n",
+ hdl->error);
+ return hdl->error;
+ }
+
+ v4l2_ctrl_cluster(2, &sd->exposure);
+ return 0;
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .config = sd_config,
+ .init = sd_init,
+ .start = dtcs033_start,
+ .stopN = dtcs033_stopN,
+ .pkt_scan = dtcs033_pkt_scan,
+ .init_controls = dtcs033_init_controls,
+};
+
+/* -- module initialisation -- */
+
+static const struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x0547, 0x7303)},
+ {}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* device connect */
+static int sd_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ return gspca_dev_probe(intf, id,
+ &sd_desc, sizeof(struct sd),
+ THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+ .name = MODULE_NAME,
+ .id_table = device_table,
+ .probe = sd_probe,
+ .disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+ .suspend = gspca_suspend,
+ .resume = gspca_resume,
+ .reset_resume = gspca_resume,
+#endif
+};
+module_usb_driver(sd_driver);
+
+
+/* ---------------------------------------------------------
+ USB requests to start/stop the camera [USB 2.0 spec Ch.9].
+
+ bRequestType :
+ 0x40 = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0xC0 = USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+*/
+static const struct dtcs033_usb_requests dtcs033_start_reqs[] = {
+/* -- bRequest,wValue,wIndex,wLength */
+{ 0x40, 0x01, 0x0001, 0x000F, 0x0000 },
+{ 0x40, 0x01, 0x0000, 0x000F, 0x0000 },
+{ 0x40, 0x01, 0x0001, 0x000F, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x7F00, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x1001, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x0004, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x7F01, 0x0000 },
+{ 0x40, 0x18, 0x30E0, 0x0009, 0x0000 },
+{ 0x40, 0x18, 0x0500, 0x012C, 0x0000 },
+{ 0x40, 0x18, 0x0380, 0x0200, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x035C, 0x0000 },
+{ 0x40, 0x18, 0x05C0, 0x0438, 0x0000 },
+{ 0x40, 0x18, 0x0440, 0x0500, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x0668, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x0700, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x0800, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x0900, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x0A00, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x0B00, 0x0000 },
+{ 0x40, 0x18, 0x30E0, 0x6009, 0x0000 },
+{ 0x40, 0x18, 0x0500, 0x612C, 0x0000 },
+{ 0x40, 0x18, 0x2090, 0x6274, 0x0000 },
+{ 0x40, 0x18, 0x05C0, 0x6338, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x6400, 0x0000 },
+{ 0x40, 0x18, 0x05C0, 0x6538, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x6600, 0x0000 },
+{ 0x40, 0x18, 0x0680, 0x6744, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x6800, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x6900, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x6A00, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x6B00, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x6C00, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x6D00, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x6E00, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x808C, 0x0000 },
+{ 0x40, 0x18, 0x0010, 0x8101, 0x0000 },
+{ 0x40, 0x18, 0x30E0, 0x8200, 0x0000 },
+{ 0x40, 0x18, 0x0810, 0x832C, 0x0000 },
+{ 0x40, 0x18, 0x0680, 0x842B, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x8500, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x8600, 0x0000 },
+{ 0x40, 0x18, 0x0280, 0x8715, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x880C, 0x0000 },
+{ 0x40, 0x18, 0x0010, 0x8901, 0x0000 },
+{ 0x40, 0x18, 0x30E0, 0x8A00, 0x0000 },
+{ 0x40, 0x18, 0x0810, 0x8B2C, 0x0000 },
+{ 0x40, 0x18, 0x0680, 0x8C2B, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x8D00, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x8E00, 0x0000 },
+{ 0x40, 0x18, 0x0280, 0x8F15, 0x0000 },
+{ 0x40, 0x18, 0x0010, 0xD040, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0xD100, 0x0000 },
+{ 0x40, 0x18, 0x00B0, 0xD20A, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0xD300, 0x0000 },
+{ 0x40, 0x18, 0x30E2, 0xD40D, 0x0000 },
+{ 0x40, 0x18, 0x0001, 0xD5C0, 0x0000 },
+{ 0x40, 0x18, 0x00A0, 0xD60A, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0xD700, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x7F00, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x1501, 0x0000 },
+{ 0x40, 0x18, 0x0001, 0x01FF, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x0200, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x0304, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x1101, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x1201, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x1300, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x1400, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x1601, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x1800, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x1900, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x1A00, 0x0000 },
+{ 0x40, 0x18, 0x2000, 0x1B00, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x1C00, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x2100, 0x0000 },
+{ 0x40, 0x18, 0x00C0, 0x228E, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x3001, 0x0000 },
+{ 0x40, 0x18, 0x0010, 0x3101, 0x0000 },
+{ 0x40, 0x18, 0x0008, 0x3301, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x3400, 0x0000 },
+{ 0x40, 0x18, 0x0012, 0x3549, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x3620, 0x0000 },
+{ 0x40, 0x18, 0x0001, 0x3700, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x4000, 0x0000 },
+{ 0x40, 0x18, 0xFFFF, 0x41FF, 0x0000 },
+{ 0x40, 0x18, 0xFFFF, 0x42FF, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x500F, 0x0000 },
+{ 0x40, 0x18, 0x2272, 0x5108, 0x0000 },
+{ 0x40, 0x18, 0x2272, 0x5208, 0x0000 },
+{ 0x40, 0x18, 0xFFFF, 0x53FF, 0x0000 },
+{ 0x40, 0x18, 0xFFFF, 0x54FF, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x6000, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x6102, 0x0000 },
+{ 0x40, 0x18, 0x0010, 0x6214, 0x0000 },
+{ 0x40, 0x18, 0x0C80, 0x6300, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x6401, 0x0000 },
+{ 0x40, 0x18, 0x0680, 0x6551, 0x0000 },
+{ 0x40, 0x18, 0xFFFF, 0x66FF, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x6702, 0x0000 },
+{ 0x40, 0x18, 0x0010, 0x6800, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x6900, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x6A00, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x6B00, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x6C00, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x6D01, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x6E00, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x6F00, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x7000, 0x0000 },
+{ 0x40, 0x18, 0x0001, 0x7118, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x2001, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x1101, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x1301, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x1300, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x1501, 0x0000 },
+{ 0xC0, 0x11, 0x0000, 0x24C0, 0x0003 },
+{ 0x40, 0x18, 0x0000, 0x3000, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x3620, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x1501, 0x0000 },
+{ 0x40, 0x18, 0x0010, 0x6300, 0x0000 },
+{ 0x40, 0x18, 0x0002, 0x01F0, 0x0000 },
+{ 0x40, 0x01, 0x0003, 0x000F, 0x0000 }
+};
+
+static const struct dtcs033_usb_requests dtcs033_stop_reqs[] = {
+/* -- bRequest,wValue,wIndex,wLength */
+{ 0x40, 0x01, 0x0001, 0x000F, 0x0000 },
+{ 0x40, 0x01, 0x0000, 0x000F, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x0003, 0x0000 }
+};
+static int dtcs033_start(struct gspca_dev *gspca_dev)
+{
+ return reg_reqs(gspca_dev, dtcs033_start_reqs,
+ ARRAY_SIZE(dtcs033_start_reqs));
+}
+
+static void dtcs033_stopN(struct gspca_dev *gspca_dev)
+{
+ reg_reqs(gspca_dev, dtcs033_stop_reqs,
+ ARRAY_SIZE(dtcs033_stop_reqs));
+ return;
+}
diff --git a/drivers/media/usb/gspca/gl860/gl860-mi2020.c b/drivers/media/usb/gspca/gl860/gl860-mi2020.c
index 2edda6b7d65..a785828d4b9 100644
--- a/drivers/media/usb/gspca/gl860/gl860-mi2020.c
+++ b/drivers/media/usb/gspca/gl860/gl860-mi2020.c
@@ -35,32 +35,34 @@ static u8 dat_hvflip5[] = {0x8c, 0xa1, 0x03};
static u8 dat_hvflip6[] = {0x90, 0x00, 0x06};
static struct idxdata tbl_middle_hvflip_low[] = {
- {0x33, "\x90\x00\x06"},
- {6, "\xff\xff\xff"},
- {0x33, "\x90\x00\x06"},
- {6, "\xff\xff\xff"},
- {0x33, "\x90\x00\x06"},
- {6, "\xff\xff\xff"},
- {0x33, "\x90\x00\x06"},
- {6, "\xff\xff\xff"},
+ {0x33, {0x90, 0x00, 0x06}},
+ {6, {0xff, 0xff, 0xff}},
+ {0x33, {0x90, 0x00, 0x06}},
+ {6, {0xff, 0xff, 0xff}},
+ {0x33, {0x90, 0x00, 0x06}},
+ {6, {0xff, 0xff, 0xff}},
+ {0x33, {0x90, 0x00, 0x06}},
+ {6, {0xff, 0xff, 0xff}},
};
static struct idxdata tbl_middle_hvflip_big[] = {
- {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x01"}, {0x33, "\x8c\xa1\x20"},
- {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x00"},
- {102, "\xff\xff\xff"},
- {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x02"}, {0x33, "\x8c\xa1\x20"},
- {0x33, "\x90\x00\x72"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x01"},
+ {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x01}},
+ {0x33, {0x8c, 0xa1, 0x20}}, {0x33, {0x90, 0x00, 0x00}},
+ {0x33, {0x8c, 0xa7, 0x02}}, {0x33, {0x90, 0x00, 0x00}},
+ {102, {0xff, 0xff, 0xff}},
+ {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x02}},
+ {0x33, {0x8c, 0xa1, 0x20}}, {0x33, {0x90, 0x00, 0x72}},
+ {0x33, {0x8c, 0xa7, 0x02}}, {0x33, {0x90, 0x00, 0x01}},
};
static struct idxdata tbl_end_hvflip[] = {
- {0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"},
- {6, "\xff\xff\xff"},
- {0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"},
- {6, "\xff\xff\xff"},
- {0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"},
- {6, "\xff\xff\xff"},
- {0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"},
+ {0x33, {0x8c, 0xa1, 0x02}}, {0x33, {0x90, 0x00, 0x1f}},
+ {6, {0xff, 0xff, 0xff}},
+ {0x33, {0x8c, 0xa1, 0x02}}, {0x33, {0x90, 0x00, 0x1f}},
+ {6, {0xff, 0xff, 0xff}},
+ {0x33, {0x8c, 0xa1, 0x02}}, {0x33, {0x90, 0x00, 0x1f}},
+ {6, {0xff, 0xff, 0xff}},
+ {0x33, {0x8c, 0xa1, 0x02}}, {0x33, {0x90, 0x00, 0x1f}},
};
static u8 dat_freq1[] = { 0x8c, 0xa4, 0x04 };
@@ -82,197 +84,267 @@ static struct validx tbl_common_0B[] = {
};
static struct idxdata tbl_common_3B[] = {
- {0x33, "\x86\x25\x01"}, {0x33, "\x86\x25\x00"},
- {2, "\xff\xff\xff"},
- {0x30, "\x1a\x0a\xcc"}, {0x32, "\x02\x00\x08"}, {0x33, "\xf4\x03\x1d"},
- {6, "\xff\xff\xff"}, /* 12 */
- {0x34, "\x1e\x8f\x09"}, {0x34, "\x1c\x01\x28"}, {0x34, "\x1e\x8f\x09"},
- {2, "\xff\xff\xff"}, /* - */
- {0x34, "\x1e\x8f\x09"}, {0x32, "\x14\x06\xe6"}, {0x33, "\x8c\x22\x23"},
- {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa2\x0f"}, {0x33, "\x90\x00\x0d"},
- {0x33, "\x8c\xa2\x10"}, {0x33, "\x90\x00\x0b"}, {0x33, "\x8c\xa2\x11"},
- {0x33, "\x90\x00\x07"}, {0x33, "\xf4\x03\x1d"}, {0x35, "\xa2\x00\xe2"},
- {0x33, "\x8c\xab\x05"}, {0x33, "\x90\x00\x01"}, {0x32, "\x6e\x00\x86"},
- {0x32, "\x70\x0f\xaa"}, {0x32, "\x72\x0f\xe4"}, {0x33, "\x8c\xa3\x4a"},
- {0x33, "\x90\x00\x5a"}, {0x33, "\x8c\xa3\x4b"}, {0x33, "\x90\x00\xa6"},
- {0x33, "\x8c\xa3\x61"}, {0x33, "\x90\x00\xc8"}, {0x33, "\x8c\xa3\x62"},
- {0x33, "\x90\x00\xe1"}, {0x34, "\xce\x01\xa8"}, {0x34, "\xd0\x66\x33"},
- {0x34, "\xd2\x31\x9a"}, {0x34, "\xd4\x94\x63"}, {0x34, "\xd6\x4b\x25"},
- {0x34, "\xd8\x26\x70"}, {0x34, "\xda\x72\x4c"}, {0x34, "\xdc\xff\x04"},
- {0x34, "\xde\x01\x5b"}, {0x34, "\xe6\x01\x13"}, {0x34, "\xee\x0b\xf0"},
- {0x34, "\xf6\x0b\xa4"}, {0x35, "\x00\xf6\xe7"}, {0x35, "\x08\x0d\xfd"},
- {0x35, "\x10\x25\x63"}, {0x35, "\x18\x35\x6c"}, {0x35, "\x20\x42\x7e"},
- {0x35, "\x28\x19\x44"}, {0x35, "\x30\x39\xd4"}, {0x35, "\x38\xf5\xa8"},
- {0x35, "\x4c\x07\x90"}, {0x35, "\x44\x07\xb8"}, {0x35, "\x5c\x06\x88"},
- {0x35, "\x54\x07\xff"}, {0x34, "\xe0\x01\x52"}, {0x34, "\xe8\x00\xcc"},
- {0x34, "\xf0\x0d\x83"}, {0x34, "\xf8\x0c\xb3"}, {0x35, "\x02\xfe\xba"},
- {0x35, "\x0a\x04\xe0"}, {0x35, "\x12\x1c\x63"}, {0x35, "\x1a\x2b\x5a"},
- {0x35, "\x22\x32\x5e"}, {0x35, "\x2a\x0d\x28"}, {0x35, "\x32\x2c\x02"},
- {0x35, "\x3a\xf4\xfa"}, {0x35, "\x4e\x07\xef"}, {0x35, "\x46\x07\x88"},
- {0x35, "\x5e\x07\xc1"}, {0x35, "\x56\x04\x64"}, {0x34, "\xe4\x01\x15"},
- {0x34, "\xec\x00\x82"}, {0x34, "\xf4\x0c\xce"}, {0x34, "\xfc\x0c\xba"},
- {0x35, "\x06\x1f\x02"}, {0x35, "\x0e\x02\xe3"}, {0x35, "\x16\x1a\x50"},
- {0x35, "\x1e\x24\x39"}, {0x35, "\x26\x23\x4c"}, {0x35, "\x2e\xf9\x1b"},
- {0x35, "\x36\x23\x19"}, {0x35, "\x3e\x12\x08"}, {0x35, "\x52\x07\x22"},
- {0x35, "\x4a\x03\xd3"}, {0x35, "\x62\x06\x54"}, {0x35, "\x5a\x04\x5d"},
- {0x34, "\xe2\x01\x04"}, {0x34, "\xea\x00\xa0"}, {0x34, "\xf2\x0c\xbc"},
- {0x34, "\xfa\x0c\x5b"}, {0x35, "\x04\x17\xf2"}, {0x35, "\x0c\x02\x08"},
- {0x35, "\x14\x28\x43"}, {0x35, "\x1c\x28\x62"}, {0x35, "\x24\x2b\x60"},
- {0x35, "\x2c\x07\x33"}, {0x35, "\x34\x1f\xb0"}, {0x35, "\x3c\xed\xcd"},
- {0x35, "\x50\x00\x06"}, {0x35, "\x48\x07\xff"}, {0x35, "\x60\x05\x89"},
- {0x35, "\x58\x07\xff"}, {0x35, "\x40\x00\xa0"}, {0x35, "\x42\x00\x00"},
- {0x32, "\x10\x01\xfc"}, {0x33, "\x8c\xa1\x18"}, {0x33, "\x90\x00\x3c"},
- {0x33, "\x78\x00\x00"},
- {2, "\xff\xff\xff"},
- {0x35, "\xb8\x1f\x20"}, {0x33, "\x8c\xa2\x06"}, {0x33, "\x90\x00\x10"},
- {0x33, "\x8c\xa2\x07"}, {0x33, "\x90\x00\x08"}, {0x33, "\x8c\xa2\x42"},
- {0x33, "\x90\x00\x0b"}, {0x33, "\x8c\xa2\x4a"}, {0x33, "\x90\x00\x8c"},
- {0x35, "\xba\xfa\x08"}, {0x33, "\x8c\xa2\x02"}, {0x33, "\x90\x00\x22"},
- {0x33, "\x8c\xa2\x03"}, {0x33, "\x90\x00\xbb"}, {0x33, "\x8c\xa4\x04"},
- {0x33, "\x90\x00\x80"}, {0x33, "\x8c\xa7\x9d"}, {0x33, "\x90\x00\x00"},
- {0x33, "\x8c\xa7\x9e"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa2\x0c"},
- {0x33, "\x90\x00\x17"}, {0x33, "\x8c\xa2\x15"}, {0x33, "\x90\x00\x04"},
- {0x33, "\x8c\xa2\x14"}, {0x33, "\x90\x00\x20"}, {0x33, "\x8c\xa1\x03"},
- {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x17"}, {0x33, "\x90\x21\x11"},
- {0x33, "\x8c\x27\x1b"}, {0x33, "\x90\x02\x4f"}, {0x33, "\x8c\x27\x25"},
- {0x33, "\x90\x06\x0f"}, {0x33, "\x8c\x27\x39"}, {0x33, "\x90\x21\x11"},
- {0x33, "\x8c\x27\x3d"}, {0x33, "\x90\x01\x20"}, {0x33, "\x8c\x27\x47"},
- {0x33, "\x90\x09\x4c"}, {0x33, "\x8c\x27\x03"}, {0x33, "\x90\x02\x84"},
- {0x33, "\x8c\x27\x05"}, {0x33, "\x90\x01\xe2"}, {0x33, "\x8c\x27\x07"},
- {0x33, "\x90\x06\x40"}, {0x33, "\x8c\x27\x09"}, {0x33, "\x90\x04\xb0"},
- {0x33, "\x8c\x27\x0d"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x0f"},
- {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x11"}, {0x33, "\x90\x04\xbd"},
- {0x33, "\x8c\x27\x13"}, {0x33, "\x90\x06\x4d"}, {0x33, "\x8c\x27\x15"},
- {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x17"}, {0x33, "\x90\x21\x11"},
- {0x33, "\x8c\x27\x19"}, {0x33, "\x90\x04\x6c"}, {0x33, "\x8c\x27\x1b"},
- {0x33, "\x90\x02\x4f"}, {0x33, "\x8c\x27\x1d"}, {0x33, "\x90\x01\x02"},
- {0x33, "\x8c\x27\x1f"}, {0x33, "\x90\x02\x79"}, {0x33, "\x8c\x27\x21"},
- {0x33, "\x90\x01\x55"}, {0x33, "\x8c\x27\x23"}, {0x33, "\x90\x02\x85"},
- {0x33, "\x8c\x27\x25"}, {0x33, "\x90\x06\x0f"}, {0x33, "\x8c\x27\x27"},
- {0x33, "\x90\x20\x20"}, {0x33, "\x8c\x27\x29"}, {0x33, "\x90\x20\x20"},
- {0x33, "\x8c\x27\x2b"}, {0x33, "\x90\x10\x20"}, {0x33, "\x8c\x27\x2d"},
- {0x33, "\x90\x20\x07"}, {0x33, "\x8c\x27\x2f"}, {0x33, "\x90\x00\x04"},
- {0x33, "\x8c\x27\x31"}, {0x33, "\x90\x00\x04"}, {0x33, "\x8c\x27\x33"},
- {0x33, "\x90\x04\xbb"}, {0x33, "\x8c\x27\x35"}, {0x33, "\x90\x06\x4b"},
- {0x33, "\x8c\x27\x37"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x39"},
- {0x33, "\x90\x21\x11"}, {0x33, "\x8c\x27\x3b"}, {0x33, "\x90\x00\x24"},
- {0x33, "\x8c\x27\x3d"}, {0x33, "\x90\x01\x20"}, {0x33, "\x8c\x27\x41"},
- {0x33, "\x90\x01\x69"}, {0x33, "\x8c\x27\x45"}, {0x33, "\x90\x04\xed"},
- {0x33, "\x8c\x27\x47"}, {0x33, "\x90\x09\x4c"}, {0x33, "\x8c\x27\x51"},
- {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x53"}, {0x33, "\x90\x03\x20"},
- {0x33, "\x8c\x27\x55"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x57"},
- {0x33, "\x90\x02\x58"}, {0x33, "\x8c\x27\x5f"}, {0x33, "\x90\x00\x00"},
- {0x33, "\x8c\x27\x61"}, {0x33, "\x90\x06\x40"}, {0x33, "\x8c\x27\x63"},
- {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x65"}, {0x33, "\x90\x04\xb0"},
- {0x33, "\x8c\x22\x2e"}, {0x33, "\x90\x00\xa1"}, {0x33, "\x8c\xa4\x08"},
- {0x33, "\x90\x00\x1f"}, {0x33, "\x8c\xa4\x09"}, {0x33, "\x90\x00\x21"},
- {0x33, "\x8c\xa4\x0a"}, {0x33, "\x90\x00\x25"}, {0x33, "\x8c\xa4\x0b"},
- {0x33, "\x90\x00\x27"}, {0x33, "\x8c\x24\x11"}, {0x33, "\x90\x00\xa1"},
- {0x33, "\x8c\x24\x13"}, {0x33, "\x90\x00\xc1"}, {0x33, "\x8c\x24\x15"},
- {0x33, "\x90\x00\x6a"}, {0x33, "\x8c\x24\x17"}, {0x33, "\x90\x00\x80"},
- {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"},
- {2, "\xff\xff\xff"},
- {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"},
- {3, "\xff\xff\xff"},
+ {0x33, {0x86, 0x25, 0x01}}, {0x33, {0x86, 0x25, 0x00}},
+ {2, {0xff, 0xff, 0xff}},
+ {0x30, {0x1a, 0x0a, 0xcc}}, {0x32, {0x02, 0x00, 0x08}},
+ {0x33, {0xf4, 0x03, 0x1d}},
+ {6, {0xff, 0xff, 0xff}}, /* 12 */
+ {0x34, {0x1e, 0x8f, 0x09}}, {0x34, {0x1c, 0x01, 0x28}},
+ {0x34, {0x1e, 0x8f, 0x09}},
+ {2, {0xff, 0xff, 0xff}}, /* - */
+ {0x34, {0x1e, 0x8f, 0x09}}, {0x32, {0x14, 0x06, 0xe6}},
+ {0x33, {0x8c, 0x22, 0x23}}, {0x33, {0x90, 0x00, 0x00}},
+ {0x33, {0x8c, 0xa2, 0x0f}}, {0x33, {0x90, 0x00, 0x0d}},
+ {0x33, {0x8c, 0xa2, 0x10}}, {0x33, {0x90, 0x00, 0x0b}},
+ {0x33, {0x8c, 0xa2, 0x11}}, {0x33, {0x90, 0x00, 0x07}},
+ {0x33, {0xf4, 0x03, 0x1d}}, {0x35, {0xa2, 0x00, 0xe2}},
+ {0x33, {0x8c, 0xab, 0x05}}, {0x33, {0x90, 0x00, 0x01}},
+ {0x32, {0x6e, 0x00, 0x86}}, {0x32, {0x70, 0x0f, 0xaa}},
+ {0x32, {0x72, 0x0f, 0xe4}}, {0x33, {0x8c, 0xa3, 0x4a}},
+ {0x33, {0x90, 0x00, 0x5a}}, {0x33, {0x8c, 0xa3, 0x4b}},
+ {0x33, {0x90, 0x00, 0xa6}}, {0x33, {0x8c, 0xa3, 0x61}},
+ {0x33, {0x90, 0x00, 0xc8}}, {0x33, {0x8c, 0xa3, 0x62}},
+ {0x33, {0x90, 0x00, 0xe1}}, {0x34, {0xce, 0x01, 0xa8}},
+ {0x34, {0xd0, 0x66, 0x33}}, {0x34, {0xd2, 0x31, 0x9a}},
+ {0x34, {0xd4, 0x94, 0x63}}, {0x34, {0xd6, 0x4b, 0x25}},
+ {0x34, {0xd8, 0x26, 0x70}}, {0x34, {0xda, 0x72, 0x4c}},
+ {0x34, {0xdc, 0xff, 0x04}}, {0x34, {0xde, 0x01, 0x5b}},
+ {0x34, {0xe6, 0x01, 0x13}}, {0x34, {0xee, 0x0b, 0xf0}},
+ {0x34, {0xf6, 0x0b, 0xa4}}, {0x35, {0x00, 0xf6, 0xe7}},
+ {0x35, {0x08, 0x0d, 0xfd}}, {0x35, {0x10, 0x25, 0x63}},
+ {0x35, {0x18, 0x35, 0x6c}}, {0x35, {0x20, 0x42, 0x7e}},
+ {0x35, {0x28, 0x19, 0x44}}, {0x35, {0x30, 0x39, 0xd4}},
+ {0x35, {0x38, 0xf5, 0xa8}}, {0x35, {0x4c, 0x07, 0x90}},
+ {0x35, {0x44, 0x07, 0xb8}}, {0x35, {0x5c, 0x06, 0x88}},
+ {0x35, {0x54, 0x07, 0xff}}, {0x34, {0xe0, 0x01, 0x52}},
+ {0x34, {0xe8, 0x00, 0xcc}}, {0x34, {0xf0, 0x0d, 0x83}},
+ {0x34, {0xf8, 0x0c, 0xb3}}, {0x35, {0x02, 0xfe, 0xba}},
+ {0x35, {0x0a, 0x04, 0xe0}}, {0x35, {0x12, 0x1c, 0x63}},
+ {0x35, {0x1a, 0x2b, 0x5a}}, {0x35, {0x22, 0x32, 0x5e}},
+ {0x35, {0x2a, 0x0d, 0x28}}, {0x35, {0x32, 0x2c, 0x02}},
+ {0x35, {0x3a, 0xf4, 0xfa}}, {0x35, {0x4e, 0x07, 0xef}},
+ {0x35, {0x46, 0x07, 0x88}}, {0x35, {0x5e, 0x07, 0xc1}},
+ {0x35, {0x56, 0x04, 0x64}}, {0x34, {0xe4, 0x01, 0x15}},
+ {0x34, {0xec, 0x00, 0x82}}, {0x34, {0xf4, 0x0c, 0xce}},
+ {0x34, {0xfc, 0x0c, 0xba}}, {0x35, {0x06, 0x1f, 0x02}},
+ {0x35, {0x0e, 0x02, 0xe3}}, {0x35, {0x16, 0x1a, 0x50}},
+ {0x35, {0x1e, 0x24, 0x39}}, {0x35, {0x26, 0x23, 0x4c}},
+ {0x35, {0x2e, 0xf9, 0x1b}}, {0x35, {0x36, 0x23, 0x19}},
+ {0x35, {0x3e, 0x12, 0x08}}, {0x35, {0x52, 0x07, 0x22}},
+ {0x35, {0x4a, 0x03, 0xd3}}, {0x35, {0x62, 0x06, 0x54}},
+ {0x35, {0x5a, 0x04, 0x5d}}, {0x34, {0xe2, 0x01, 0x04}},
+ {0x34, {0xea, 0x00, 0xa0}}, {0x34, {0xf2, 0x0c, 0xbc}},
+ {0x34, {0xfa, 0x0c, 0x5b}}, {0x35, {0x04, 0x17, 0xf2}},
+ {0x35, {0x0c, 0x02, 0x08}}, {0x35, {0x14, 0x28, 0x43}},
+ {0x35, {0x1c, 0x28, 0x62}}, {0x35, {0x24, 0x2b, 0x60}},
+ {0x35, {0x2c, 0x07, 0x33}}, {0x35, {0x34, 0x1f, 0xb0}},
+ {0x35, {0x3c, 0xed, 0xcd}}, {0x35, {0x50, 0x00, 0x06}},
+ {0x35, {0x48, 0x07, 0xff}}, {0x35, {0x60, 0x05, 0x89}},
+ {0x35, {0x58, 0x07, 0xff}}, {0x35, {0x40, 0x00, 0xa0}},
+ {0x35, {0x42, 0x00, 0x00}}, {0x32, {0x10, 0x01, 0xfc}},
+ {0x33, {0x8c, 0xa1, 0x18}}, {0x33, {0x90, 0x00, 0x3c}},
+ {0x33, {0x78, 0x00, 0x00}},
+ {2, {0xff, 0xff, 0xff}},
+ {0x35, {0xb8, 0x1f, 0x20}}, {0x33, {0x8c, 0xa2, 0x06}},
+ {0x33, {0x90, 0x00, 0x10}}, {0x33, {0x8c, 0xa2, 0x07}},
+ {0x33, {0x90, 0x00, 0x08}}, {0x33, {0x8c, 0xa2, 0x42}},
+ {0x33, {0x90, 0x00, 0x0b}}, {0x33, {0x8c, 0xa2, 0x4a}},
+ {0x33, {0x90, 0x00, 0x8c}}, {0x35, {0xba, 0xfa, 0x08}},
+ {0x33, {0x8c, 0xa2, 0x02}}, {0x33, {0x90, 0x00, 0x22}},
+ {0x33, {0x8c, 0xa2, 0x03}}, {0x33, {0x90, 0x00, 0xbb}},
+ {0x33, {0x8c, 0xa4, 0x04}}, {0x33, {0x90, 0x00, 0x80}},
+ {0x33, {0x8c, 0xa7, 0x9d}}, {0x33, {0x90, 0x00, 0x00}},
+ {0x33, {0x8c, 0xa7, 0x9e}}, {0x33, {0x90, 0x00, 0x00}},
+ {0x33, {0x8c, 0xa2, 0x0c}}, {0x33, {0x90, 0x00, 0x17}},
+ {0x33, {0x8c, 0xa2, 0x15}}, {0x33, {0x90, 0x00, 0x04}},
+ {0x33, {0x8c, 0xa2, 0x14}}, {0x33, {0x90, 0x00, 0x20}},
+ {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x00}},
+ {0x33, {0x8c, 0x27, 0x17}}, {0x33, {0x90, 0x21, 0x11}},
+ {0x33, {0x8c, 0x27, 0x1b}}, {0x33, {0x90, 0x02, 0x4f}},
+ {0x33, {0x8c, 0x27, 0x25}}, {0x33, {0x90, 0x06, 0x0f}},
+ {0x33, {0x8c, 0x27, 0x39}}, {0x33, {0x90, 0x21, 0x11}},
+ {0x33, {0x8c, 0x27, 0x3d}}, {0x33, {0x90, 0x01, 0x20}},
+ {0x33, {0x8c, 0x27, 0x47}}, {0x33, {0x90, 0x09, 0x4c}},
+ {0x33, {0x8c, 0x27, 0x03}}, {0x33, {0x90, 0x02, 0x84}},
+ {0x33, {0x8c, 0x27, 0x05}}, {0x33, {0x90, 0x01, 0xe2}},
+ {0x33, {0x8c, 0x27, 0x07}}, {0x33, {0x90, 0x06, 0x40}},
+ {0x33, {0x8c, 0x27, 0x09}}, {0x33, {0x90, 0x04, 0xb0}},
+ {0x33, {0x8c, 0x27, 0x0d}}, {0x33, {0x90, 0x00, 0x00}},
+ {0x33, {0x8c, 0x27, 0x0f}}, {0x33, {0x90, 0x00, 0x00}},
+ {0x33, {0x8c, 0x27, 0x11}}, {0x33, {0x90, 0x04, 0xbd}},
+ {0x33, {0x8c, 0x27, 0x13}}, {0x33, {0x90, 0x06, 0x4d}},
+ {0x33, {0x8c, 0x27, 0x15}}, {0x33, {0x90, 0x00, 0x00}},
+ {0x33, {0x8c, 0x27, 0x17}}, {0x33, {0x90, 0x21, 0x11}},
+ {0x33, {0x8c, 0x27, 0x19}}, {0x33, {0x90, 0x04, 0x6c}},
+ {0x33, {0x8c, 0x27, 0x1b}}, {0x33, {0x90, 0x02, 0x4f}},
+ {0x33, {0x8c, 0x27, 0x1d}}, {0x33, {0x90, 0x01, 0x02}},
+ {0x33, {0x8c, 0x27, 0x1f}}, {0x33, {0x90, 0x02, 0x79}},
+ {0x33, {0x8c, 0x27, 0x21}}, {0x33, {0x90, 0x01, 0x55}},
+ {0x33, {0x8c, 0x27, 0x23}}, {0x33, {0x90, 0x02, 0x85}},
+ {0x33, {0x8c, 0x27, 0x25}}, {0x33, {0x90, 0x06, 0x0f}},
+ {0x33, {0x8c, 0x27, 0x27}}, {0x33, {0x90, 0x20, 0x20}},
+ {0x33, {0x8c, 0x27, 0x29}}, {0x33, {0x90, 0x20, 0x20}},
+ {0x33, {0x8c, 0x27, 0x2b}}, {0x33, {0x90, 0x10, 0x20}},
+ {0x33, {0x8c, 0x27, 0x2d}}, {0x33, {0x90, 0x20, 0x07}},
+ {0x33, {0x8c, 0x27, 0x2f}}, {0x33, {0x90, 0x00, 0x04}},
+ {0x33, {0x8c, 0x27, 0x31}}, {0x33, {0x90, 0x00, 0x04}},
+ {0x33, {0x8c, 0x27, 0x33}}, {0x33, {0x90, 0x04, 0xbb}},
+ {0x33, {0x8c, 0x27, 0x35}}, {0x33, {0x90, 0x06, 0x4b}},
+ {0x33, {0x8c, 0x27, 0x37}}, {0x33, {0x90, 0x00, 0x00}},
+ {0x33, {0x8c, 0x27, 0x39}}, {0x33, {0x90, 0x21, 0x11}},
+ {0x33, {0x8c, 0x27, 0x3b}}, {0x33, {0x90, 0x00, 0x24}},
+ {0x33, {0x8c, 0x27, 0x3d}}, {0x33, {0x90, 0x01, 0x20}},
+ {0x33, {0x8c, 0x27, 0x41}}, {0x33, {0x90, 0x01, 0x69}},
+ {0x33, {0x8c, 0x27, 0x45}}, {0x33, {0x90, 0x04, 0xed}},
+ {0x33, {0x8c, 0x27, 0x47}}, {0x33, {0x90, 0x09, 0x4c}},
+ {0x33, {0x8c, 0x27, 0x51}}, {0x33, {0x90, 0x00, 0x00}},
+ {0x33, {0x8c, 0x27, 0x53}}, {0x33, {0x90, 0x03, 0x20}},
+ {0x33, {0x8c, 0x27, 0x55}}, {0x33, {0x90, 0x00, 0x00}},
+ {0x33, {0x8c, 0x27, 0x57}}, {0x33, {0x90, 0x02, 0x58}},
+ {0x33, {0x8c, 0x27, 0x5f}}, {0x33, {0x90, 0x00, 0x00}},
+ {0x33, {0x8c, 0x27, 0x61}}, {0x33, {0x90, 0x06, 0x40}},
+ {0x33, {0x8c, 0x27, 0x63}}, {0x33, {0x90, 0x00, 0x00}},
+ {0x33, {0x8c, 0x27, 0x65}}, {0x33, {0x90, 0x04, 0xb0}},
+ {0x33, {0x8c, 0x22, 0x2e}}, {0x33, {0x90, 0x00, 0xa1}},
+ {0x33, {0x8c, 0xa4, 0x08}}, {0x33, {0x90, 0x00, 0x1f}},
+ {0x33, {0x8c, 0xa4, 0x09}}, {0x33, {0x90, 0x00, 0x21}},
+ {0x33, {0x8c, 0xa4, 0x0a}}, {0x33, {0x90, 0x00, 0x25}},
+ {0x33, {0x8c, 0xa4, 0x0b}}, {0x33, {0x90, 0x00, 0x27}},
+ {0x33, {0x8c, 0x24, 0x11}}, {0x33, {0x90, 0x00, 0xa1}},
+ {0x33, {0x8c, 0x24, 0x13}}, {0x33, {0x90, 0x00, 0xc1}},
+ {0x33, {0x8c, 0x24, 0x15}}, {0x33, {0x90, 0x00, 0x6a}},
+ {0x33, {0x8c, 0x24, 0x17}}, {0x33, {0x90, 0x00, 0x80}},
+ {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x05}},
+ {2, {0xff, 0xff, 0xff}},
+ {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x06}},
+ {3, {0xff, 0xff, 0xff}},
};
static struct idxdata tbl_init_post_alt_low1[] = {
- {0x33, "\x8c\x27\x15"}, {0x33, "\x90\x00\x25"}, {0x33, "\x8c\x22\x2e"},
- {0x33, "\x90\x00\x81"}, {0x33, "\x8c\xa4\x08"}, {0x33, "\x90\x00\x17"},
- {0x33, "\x8c\xa4\x09"}, {0x33, "\x90\x00\x1a"}, {0x33, "\x8c\xa4\x0a"},
- {0x33, "\x90\x00\x1d"}, {0x33, "\x8c\xa4\x0b"}, {0x33, "\x90\x00\x20"},
- {0x33, "\x8c\x24\x11"}, {0x33, "\x90\x00\x81"}, {0x33, "\x8c\x24\x13"},
- {0x33, "\x90\x00\x9b"},
+ {0x33, {0x8c, 0x27, 0x15}}, {0x33, {0x90, 0x00, 0x25}},
+ {0x33, {0x8c, 0x22, 0x2e}}, {0x33, {0x90, 0x00, 0x81}},
+ {0x33, {0x8c, 0xa4, 0x08}}, {0x33, {0x90, 0x00, 0x17}},
+ {0x33, {0x8c, 0xa4, 0x09}}, {0x33, {0x90, 0x00, 0x1a}},
+ {0x33, {0x8c, 0xa4, 0x0a}}, {0x33, {0x90, 0x00, 0x1d}},
+ {0x33, {0x8c, 0xa4, 0x0b}}, {0x33, {0x90, 0x00, 0x20}},
+ {0x33, {0x8c, 0x24, 0x11}}, {0x33, {0x90, 0x00, 0x81}},
+ {0x33, {0x8c, 0x24, 0x13}}, {0x33, {0x90, 0x00, 0x9b}},
};
static struct idxdata tbl_init_post_alt_low2[] = {
- {0x33, "\x8c\x27\x03"}, {0x33, "\x90\x03\x24"}, {0x33, "\x8c\x27\x05"},
- {0x33, "\x90\x02\x58"}, {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"},
- {2, "\xff\xff\xff"},
- {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"},
- {2, "\xff\xff\xff"},
+ {0x33, {0x8c, 0x27, 0x03}}, {0x33, {0x90, 0x03, 0x24}},
+ {0x33, {0x8c, 0x27, 0x05}}, {0x33, {0x90, 0x02, 0x58}},
+ {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x05}},
+ {2, {0xff, 0xff, 0xff}},
+ {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x06}},
+ {2, {0xff, 0xff, 0xff}},
};
static struct idxdata tbl_init_post_alt_low3[] = {
- {0x34, "\x1e\x8f\x09"}, {0x34, "\x1c\x01\x28"}, {0x34, "\x1e\x8f\x09"},
- {2, "\xff\xff\xff"},
- {0x34, "\x1e\x8f\x09"}, {0x32, "\x14\x06\xe6"}, {0x33, "\x8c\xa1\x20"},
- {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x01"},
- {0x33, "\x2e\x01\x00"}, {0x34, "\x04\x00\x2a"}, {0x33, "\x8c\xa7\x02"},
- {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x95"}, {0x33, "\x90\x01\x00"},
- {2, "\xff\xff\xff"},
- {0x33, "\x8c\xa1\x20"}, {0x33, "\x90\x00\x72"}, {0x33, "\x8c\xa1\x03"},
- {0x33, "\x90\x00\x02"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x01"},
- {2, "\xff\xff\xff"},
- {0x33, "\x8c\xa1\x20"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa1\x03"},
- {0x33, "\x90\x00\x01"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x00"},
- {2, "\xff\xff\xff"},
- {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"},
- {2, "\xff\xff\xff"},
- {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"},
- {2, "\xff\xff\xff"},
- {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"},
- {2, "\xff\xff\xff"},
- {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"},
+ {0x34, {0x1e, 0x8f, 0x09}}, {0x34, {0x1c, 0x01, 0x28}},
+ {0x34, {0x1e, 0x8f, 0x09}},
+ {2, {0xff, 0xff, 0xff}},
+ {0x34, {0x1e, 0x8f, 0x09}}, {0x32, {0x14, 0x06, 0xe6}},
+ {0x33, {0x8c, 0xa1, 0x20}}, {0x33, {0x90, 0x00, 0x00}},
+ {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x01}},
+ {0x33, {0x2e, 0x01, 0x00}}, {0x34, {0x04, 0x00, 0x2a}},
+ {0x33, {0x8c, 0xa7, 0x02}}, {0x33, {0x90, 0x00, 0x00}},
+ {0x33, {0x8c, 0x27, 0x95}}, {0x33, {0x90, 0x01, 0x00}},
+ {2, {0xff, 0xff, 0xff}},
+ {0x33, {0x8c, 0xa1, 0x20}}, {0x33, {0x90, 0x00, 0x72}},
+ {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x02}},
+ {0x33, {0x8c, 0xa7, 0x02}}, {0x33, {0x90, 0x00, 0x01}},
+ {2, {0xff, 0xff, 0xff}},
+ {0x33, {0x8c, 0xa1, 0x20}}, {0x33, {0x90, 0x00, 0x00}},
+ {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x01}},
+ {0x33, {0x8c, 0xa7, 0x02}}, {0x33, {0x90, 0x00, 0x00}},
+ {2, {0xff, 0xff, 0xff}},
+ {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x05}},
+ {2, {0xff, 0xff, 0xff}},
+ {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x06}},
+ {2, {0xff, 0xff, 0xff}},
+ {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x05}},
+ {2, {0xff, 0xff, 0xff}},
+ {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x06}},
};
static struct idxdata tbl_init_post_alt_big[] = {
- {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"},
- {2, "\xff\xff\xff"},
- {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"},
- {2, "\xff\xff\xff"},
- {0x34, "\x1e\x8f\x09"}, {0x34, "\x1c\x01\x28"}, {0x34, "\x1e\x8f\x09"},
- {2, "\xff\xff\xff"},
- {0x34, "\x1e\x8f\x09"}, {0x32, "\x14\x06\xe6"}, {0x33, "\x8c\xa1\x03"},
- {0x33, "\x90\x00\x05"},
- {2, "\xff\xff\xff"},
- {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"},
- {2, "\xff\xff\xff"},
- {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"},
- {2, "\xff\xff\xff"},
- {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"}, {0x33, "\x8c\xa1\x20"},
- {0x33, "\x90\x00\x72"}, {0x33, "\x8c\xa1\x30"}, {0x33, "\x90\x00\x03"},
- {0x33, "\x8c\xa1\x31"}, {0x33, "\x90\x00\x02"}, {0x33, "\x8c\xa1\x32"},
- {0x33, "\x90\x00\x03"}, {0x33, "\x8c\xa1\x34"}, {0x33, "\x90\x00\x03"},
- {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x02"}, {0x33, "\x2e\x01\x00"},
- {0x34, "\x04\x00\x2a"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x01"},
- {0x33, "\x8c\x27\x97"}, {0x33, "\x90\x01\x00"},
- {51, "\xff\xff\xff"},
- {0x33, "\x8c\xa1\x20"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa1\x03"},
- {0x33, "\x90\x00\x01"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x00"},
- {51, "\xff\xff\xff"},
- {0x33, "\x8c\xa1\x20"}, {0x33, "\x90\x00\x72"}, {0x33, "\x8c\xa1\x03"},
- {0x33, "\x90\x00\x02"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x01"},
- {51, "\xff\xff\xff"},
+ {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x05}},
+ {2, {0xff, 0xff, 0xff}},
+ {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x06}},
+ {2, {0xff, 0xff, 0xff}},
+ {0x34, {0x1e, 0x8f, 0x09}}, {0x34, {0x1c, 0x01, 0x28}},
+ {0x34, {0x1e, 0x8f, 0x09}},
+ {2, {0xff, 0xff, 0xff}},
+ {0x34, {0x1e, 0x8f, 0x09}}, {0x32, {0x14, 0x06, 0xe6}},
+ {0x33, {0x8c, 0xa1, 0x03}},
+ {0x33, {0x90, 0x00, 0x05}},
+ {2, {0xff, 0xff, 0xff}},
+ {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x06}},
+ {2, {0xff, 0xff, 0xff}},
+ {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x05}},
+ {2, {0xff, 0xff, 0xff}},
+ {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x06}},
+ {0x33, {0x8c, 0xa1, 0x20}}, {0x33, {0x90, 0x00, 0x72}},
+ {0x33, {0x8c, 0xa1, 0x30}}, {0x33, {0x90, 0x00, 0x03}},
+ {0x33, {0x8c, 0xa1, 0x31}}, {0x33, {0x90, 0x00, 0x02}},
+ {0x33, {0x8c, 0xa1, 0x32}}, {0x33, {0x90, 0x00, 0x03}},
+ {0x33, {0x8c, 0xa1, 0x34}}, {0x33, {0x90, 0x00, 0x03}},
+ {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x02}},
+ {0x33, {0x2e, 0x01, 0x00}}, {0x34, {0x04, 0x00, 0x2a}},
+ {0x33, {0x8c, 0xa7, 0x02}}, {0x33, {0x90, 0x00, 0x01}},
+ {0x33, {0x8c, 0x27, 0x97}}, {0x33, {0x90, 0x01, 0x00}},
+ {51, {0xff, 0xff, 0xff}},
+ {0x33, {0x8c, 0xa1, 0x20}}, {0x33, {0x90, 0x00, 0x00}},
+ {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x01}},
+ {0x33, {0x8c, 0xa7, 0x02}}, {0x33, {0x90, 0x00, 0x00}},
+ {51, {0xff, 0xff, 0xff}},
+ {0x33, {0x8c, 0xa1, 0x20}}, {0x33, {0x90, 0x00, 0x72}},
+ {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x02}},
+ {0x33, {0x8c, 0xa7, 0x02}}, {0x33, {0x90, 0x00, 0x01}},
+ {51, {0xff, 0xff, 0xff}},
};
static struct idxdata tbl_init_post_alt_3B[] = {
- {0x32, "\x10\x01\xf8"}, {0x34, "\xce\x01\xa8"}, {0x34, "\xd0\x66\x33"},
- {0x34, "\xd2\x31\x9a"}, {0x34, "\xd4\x94\x63"}, {0x34, "\xd6\x4b\x25"},
- {0x34, "\xd8\x26\x70"}, {0x34, "\xda\x72\x4c"}, {0x34, "\xdc\xff\x04"},
- {0x34, "\xde\x01\x5b"}, {0x34, "\xe6\x01\x13"}, {0x34, "\xee\x0b\xf0"},
- {0x34, "\xf6\x0b\xa4"}, {0x35, "\x00\xf6\xe7"}, {0x35, "\x08\x0d\xfd"},
- {0x35, "\x10\x25\x63"}, {0x35, "\x18\x35\x6c"}, {0x35, "\x20\x42\x7e"},
- {0x35, "\x28\x19\x44"}, {0x35, "\x30\x39\xd4"}, {0x35, "\x38\xf5\xa8"},
- {0x35, "\x4c\x07\x90"}, {0x35, "\x44\x07\xb8"}, {0x35, "\x5c\x06\x88"},
- {0x35, "\x54\x07\xff"}, {0x34, "\xe0\x01\x52"}, {0x34, "\xe8\x00\xcc"},
- {0x34, "\xf0\x0d\x83"}, {0x34, "\xf8\x0c\xb3"}, {0x35, "\x02\xfe\xba"},
- {0x35, "\x0a\x04\xe0"}, {0x35, "\x12\x1c\x63"}, {0x35, "\x1a\x2b\x5a"},
- {0x35, "\x22\x32\x5e"}, {0x35, "\x2a\x0d\x28"}, {0x35, "\x32\x2c\x02"},
- {0x35, "\x3a\xf4\xfa"}, {0x35, "\x4e\x07\xef"}, {0x35, "\x46\x07\x88"},
- {0x35, "\x5e\x07\xc1"}, {0x35, "\x56\x04\x64"}, {0x34, "\xe4\x01\x15"},
- {0x34, "\xec\x00\x82"}, {0x34, "\xf4\x0c\xce"}, {0x34, "\xfc\x0c\xba"},
- {0x35, "\x06\x1f\x02"}, {0x35, "\x0e\x02\xe3"}, {0x35, "\x16\x1a\x50"},
- {0x35, "\x1e\x24\x39"}, {0x35, "\x26\x23\x4c"}, {0x35, "\x2e\xf9\x1b"},
- {0x35, "\x36\x23\x19"}, {0x35, "\x3e\x12\x08"}, {0x35, "\x52\x07\x22"},
- {0x35, "\x4a\x03\xd3"}, {0x35, "\x62\x06\x54"}, {0x35, "\x5a\x04\x5d"},
- {0x34, "\xe2\x01\x04"}, {0x34, "\xea\x00\xa0"}, {0x34, "\xf2\x0c\xbc"},
- {0x34, "\xfa\x0c\x5b"}, {0x35, "\x04\x17\xf2"}, {0x35, "\x0c\x02\x08"},
- {0x35, "\x14\x28\x43"}, {0x35, "\x1c\x28\x62"}, {0x35, "\x24\x2b\x60"},
- {0x35, "\x2c\x07\x33"}, {0x35, "\x34\x1f\xb0"}, {0x35, "\x3c\xed\xcd"},
- {0x35, "\x50\x00\x06"}, {0x35, "\x48\x07\xff"}, {0x35, "\x60\x05\x89"},
- {0x35, "\x58\x07\xff"}, {0x35, "\x40\x00\xa0"}, {0x35, "\x42\x00\x00"},
- {0x32, "\x10\x01\xfc"}, {0x33, "\x8c\xa1\x18"}, {0x33, "\x90\x00\x3c"},
+ {0x32, {0x10, 0x01, 0xf8}}, {0x34, {0xce, 0x01, 0xa8}},
+ {0x34, {0xd0, 0x66, 0x33}}, {0x34, {0xd2, 0x31, 0x9a}},
+ {0x34, {0xd4, 0x94, 0x63}}, {0x34, {0xd6, 0x4b, 0x25}},
+ {0x34, {0xd8, 0x26, 0x70}}, {0x34, {0xda, 0x72, 0x4c}},
+ {0x34, {0xdc, 0xff, 0x04}}, {0x34, {0xde, 0x01, 0x5b}},
+ {0x34, {0xe6, 0x01, 0x13}}, {0x34, {0xee, 0x0b, 0xf0}},
+ {0x34, {0xf6, 0x0b, 0xa4}}, {0x35, {0x00, 0xf6, 0xe7}},
+ {0x35, {0x08, 0x0d, 0xfd}}, {0x35, {0x10, 0x25, 0x63}},
+ {0x35, {0x18, 0x35, 0x6c}}, {0x35, {0x20, 0x42, 0x7e}},
+ {0x35, {0x28, 0x19, 0x44}}, {0x35, {0x30, 0x39, 0xd4}},
+ {0x35, {0x38, 0xf5, 0xa8}}, {0x35, {0x4c, 0x07, 0x90}},
+ {0x35, {0x44, 0x07, 0xb8}}, {0x35, {0x5c, 0x06, 0x88}},
+ {0x35, {0x54, 0x07, 0xff}}, {0x34, {0xe0, 0x01, 0x52}},
+ {0x34, {0xe8, 0x00, 0xcc}}, {0x34, {0xf0, 0x0d, 0x83}},
+ {0x34, {0xf8, 0x0c, 0xb3}}, {0x35, {0x02, 0xfe, 0xba}},
+ {0x35, {0x0a, 0x04, 0xe0}}, {0x35, {0x12, 0x1c, 0x63}},
+ {0x35, {0x1a, 0x2b, 0x5a}}, {0x35, {0x22, 0x32, 0x5e}},
+ {0x35, {0x2a, 0x0d, 0x28}}, {0x35, {0x32, 0x2c, 0x02}},
+ {0x35, {0x3a, 0xf4, 0xfa}}, {0x35, {0x4e, 0x07, 0xef}},
+ {0x35, {0x46, 0x07, 0x88}}, {0x35, {0x5e, 0x07, 0xc1}},
+ {0x35, {0x56, 0x04, 0x64}}, {0x34, {0xe4, 0x01, 0x15}},
+ {0x34, {0xec, 0x00, 0x82}}, {0x34, {0xf4, 0x0c, 0xce}},
+ {0x34, {0xfc, 0x0c, 0xba}}, {0x35, {0x06, 0x1f, 0x02}},
+ {0x35, {0x0e, 0x02, 0xe3}}, {0x35, {0x16, 0x1a, 0x50}},
+ {0x35, {0x1e, 0x24, 0x39}}, {0x35, {0x26, 0x23, 0x4c}},
+ {0x35, {0x2e, 0xf9, 0x1b}}, {0x35, {0x36, 0x23, 0x19}},
+ {0x35, {0x3e, 0x12, 0x08}}, {0x35, {0x52, 0x07, 0x22}},
+ {0x35, {0x4a, 0x03, 0xd3}}, {0x35, {0x62, 0x06, 0x54}},
+ {0x35, {0x5a, 0x04, 0x5d}}, {0x34, {0xe2, 0x01, 0x04}},
+ {0x34, {0xea, 0x00, 0xa0}}, {0x34, {0xf2, 0x0c, 0xbc}},
+ {0x34, {0xfa, 0x0c, 0x5b}}, {0x35, {0x04, 0x17, 0xf2}},
+ {0x35, {0x0c, 0x02, 0x08}}, {0x35, {0x14, 0x28, 0x43}},
+ {0x35, {0x1c, 0x28, 0x62}}, {0x35, {0x24, 0x2b, 0x60}},
+ {0x35, {0x2c, 0x07, 0x33}}, {0x35, {0x34, 0x1f, 0xb0}},
+ {0x35, {0x3c, 0xed, 0xcd}}, {0x35, {0x50, 0x00, 0x06}},
+ {0x35, {0x48, 0x07, 0xff}}, {0x35, {0x60, 0x05, 0x89}},
+ {0x35, {0x58, 0x07, 0xff}}, {0x35, {0x40, 0x00, 0xa0}},
+ {0x35, {0x42, 0x00, 0x00}}, {0x32, {0x10, 0x01, 0xfc}},
+ {0x33, {0x8c, 0xa1, 0x18}}, {0x33, {0x90, 0x00, 0x3c}},
};
static u8 *dat_640 = "\xd0\x02\xd1\x08\xd2\xe1\xd3\x02\xd4\x10\xd5\x81";
diff --git a/drivers/media/usb/gspca/gl860/gl860.c b/drivers/media/usb/gspca/gl860/gl860.c
index cb1e64ca59c..cea8d7f51c3 100644
--- a/drivers/media/usb/gspca/gl860/gl860.c
+++ b/drivers/media/usb/gspca/gl860/gl860.c
@@ -438,7 +438,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
s32 nToSkip =
sd->swapRB * (gspca_dev->cam.cam_mode[mode].bytesperline + 1);
- /* Test only against 0202h, so endianess does not matter */
+ /* Test only against 0202h, so endianness does not matter */
switch (*(s16 *) data) {
case 0x0202: /* End of frame, start a new one */
gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
diff --git a/drivers/media/usb/gspca/gspca.c b/drivers/media/usb/gspca/gspca.c
index 048507b27bb..f3a7ace0fac 100644
--- a/drivers/media/usb/gspca/gspca.c
+++ b/drivers/media/usb/gspca/gspca.c
@@ -504,8 +504,7 @@ static int frame_alloc(struct gspca_dev *gspca_dev, struct file *file,
unsigned int frsz;
int i;
- i = gspca_dev->curr_mode;
- frsz = gspca_dev->cam.cam_mode[i].sizeimage;
+ frsz = gspca_dev->pixfmt.sizeimage;
PDEBUG(D_STREAM, "frame alloc frsz: %d", frsz);
frsz = PAGE_ALIGN(frsz);
if (count >= GSPCA_MAX_FRAMES)
@@ -627,16 +626,14 @@ static struct usb_host_endpoint *alt_xfer(struct usb_host_interface *alt,
static u32 which_bandwidth(struct gspca_dev *gspca_dev)
{
u32 bandwidth;
- int i;
/* get the (max) image size */
- i = gspca_dev->curr_mode;
- bandwidth = gspca_dev->cam.cam_mode[i].sizeimage;
+ bandwidth = gspca_dev->pixfmt.sizeimage;
/* if the image is compressed, estimate its mean size */
if (!gspca_dev->cam.needs_full_bandwidth &&
- bandwidth < gspca_dev->cam.cam_mode[i].width *
- gspca_dev->cam.cam_mode[i].height)
+ bandwidth < gspca_dev->pixfmt.width *
+ gspca_dev->pixfmt.height)
bandwidth = bandwidth * 3 / 8; /* 0.375 */
/* estimate the frame rate */
@@ -650,7 +647,7 @@ static u32 which_bandwidth(struct gspca_dev *gspca_dev)
/* don't hope more than 15 fps with USB 1.1 and
* image resolution >= 640x480 */
- if (gspca_dev->width >= 640
+ if (gspca_dev->pixfmt.width >= 640
&& gspca_dev->dev->speed == USB_SPEED_FULL)
bandwidth *= 15; /* 15 fps */
else
@@ -982,9 +979,7 @@ static void gspca_set_default_mode(struct gspca_dev *gspca_dev)
i = gspca_dev->cam.nmodes - 1; /* take the highest mode */
gspca_dev->curr_mode = i;
- gspca_dev->width = gspca_dev->cam.cam_mode[i].width;
- gspca_dev->height = gspca_dev->cam.cam_mode[i].height;
- gspca_dev->pixfmt = gspca_dev->cam.cam_mode[i].pixelformat;
+ gspca_dev->pixfmt = gspca_dev->cam.cam_mode[i];
/* does nothing if ctrl_handler == NULL */
v4l2_ctrl_handler_setup(gspca_dev->vdev.ctrl_handler);
@@ -1105,10 +1100,8 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *fmt)
{
struct gspca_dev *gspca_dev = video_drvdata(file);
- int mode;
- mode = gspca_dev->curr_mode;
- fmt->fmt.pix = gspca_dev->cam.cam_mode[mode];
+ fmt->fmt.pix = gspca_dev->pixfmt;
/* some drivers use priv internally, zero it before giving it to
userspace */
fmt->fmt.pix.priv = 0;
@@ -1140,6 +1133,12 @@ static int try_fmt_vid_cap(struct gspca_dev *gspca_dev,
mode = mode2;
}
fmt->fmt.pix = gspca_dev->cam.cam_mode[mode];
+ if (gspca_dev->sd_desc->try_fmt) {
+ /* pass original resolution to subdriver try_fmt */
+ fmt->fmt.pix.width = w;
+ fmt->fmt.pix.height = h;
+ gspca_dev->sd_desc->try_fmt(gspca_dev, fmt);
+ }
/* some drivers use priv internally, zero it before giving it to
userspace */
fmt->fmt.pix.priv = 0;
@@ -1178,19 +1177,16 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
goto out;
}
- if (ret == gspca_dev->curr_mode) {
- ret = 0;
- goto out; /* same mode */
- }
-
if (gspca_dev->streaming) {
ret = -EBUSY;
goto out;
}
- gspca_dev->width = fmt->fmt.pix.width;
- gspca_dev->height = fmt->fmt.pix.height;
- gspca_dev->pixfmt = fmt->fmt.pix.pixelformat;
gspca_dev->curr_mode = ret;
+ if (gspca_dev->sd_desc->try_fmt)
+ /* subdriver try_fmt can modify format parameters */
+ gspca_dev->pixfmt = fmt->fmt.pix;
+ else
+ gspca_dev->pixfmt = gspca_dev->cam.cam_mode[ret];
ret = 0;
out:
@@ -1205,6 +1201,9 @@ static int vidioc_enum_framesizes(struct file *file, void *priv,
int i;
__u32 index = 0;
+ if (gspca_dev->sd_desc->enum_framesizes)
+ return gspca_dev->sd_desc->enum_framesizes(gspca_dev, fsize);
+
for (i = 0; i < gspca_dev->cam.nmodes; i++) {
if (fsize->pixel_format !=
gspca_dev->cam.cam_mode[i].pixelformat)
@@ -1471,8 +1470,9 @@ static int vidioc_streamon(struct file *file, void *priv,
if (ret < 0)
goto out;
}
- PDEBUG_MODE(gspca_dev, D_STREAM, "stream on OK", gspca_dev->pixfmt,
- gspca_dev->width, gspca_dev->height);
+ PDEBUG_MODE(gspca_dev, D_STREAM, "stream on OK",
+ gspca_dev->pixfmt.pixelformat,
+ gspca_dev->pixfmt.width, gspca_dev->pixfmt.height);
ret = 0;
out:
mutex_unlock(&gspca_dev->queue_lock);
diff --git a/drivers/media/usb/gspca/gspca.h b/drivers/media/usb/gspca/gspca.h
index ac0b11f46f5..300642dc1a1 100644
--- a/drivers/media/usb/gspca/gspca.h
+++ b/drivers/media/usb/gspca/gspca.h
@@ -88,6 +88,10 @@ typedef void (*cam_pkt_op) (struct gspca_dev *gspca_dev,
typedef int (*cam_int_pkt_op) (struct gspca_dev *gspca_dev,
u8 *data,
int len);
+typedef void (*cam_format_op) (struct gspca_dev *gspca_dev,
+ struct v4l2_format *fmt);
+typedef int (*cam_frmsize_op) (struct gspca_dev *gspca_dev,
+ struct v4l2_frmsizeenum *fsize);
/* subdriver description */
struct sd_desc {
@@ -109,6 +113,8 @@ struct sd_desc {
cam_set_jpg_op set_jcomp;
cam_streamparm_op get_streamparm;
cam_streamparm_op set_streamparm;
+ cam_format_op try_fmt;
+ cam_frmsize_op enum_framesizes;
#ifdef CONFIG_VIDEO_ADV_DEBUG
cam_set_reg_op set_register;
cam_get_reg_op get_register;
@@ -183,9 +189,7 @@ struct gspca_dev {
__u8 streaming; /* protected by both mutexes (*) */
__u8 curr_mode; /* current camera mode */
- __u32 pixfmt; /* current mode parameters */
- __u16 width;
- __u16 height;
+ struct v4l2_pix_format pixfmt; /* current mode parameters */
__u32 sequence; /* frame sequence number */
wait_queue_head_t wq; /* wait queue */
diff --git a/drivers/media/usb/gspca/jeilinj.c b/drivers/media/usb/gspca/jeilinj.c
index 8da3dde3838..19736e237b3 100644
--- a/drivers/media/usb/gspca/jeilinj.c
+++ b/drivers/media/usb/gspca/jeilinj.c
@@ -378,11 +378,12 @@ static int sd_start(struct gspca_dev *gspca_dev)
struct sd *dev = (struct sd *) gspca_dev;
/* create the JPEG header */
- jpeg_define(dev->jpeg_hdr, gspca_dev->height, gspca_dev->width,
+ jpeg_define(dev->jpeg_hdr, gspca_dev->pixfmt.height,
+ gspca_dev->pixfmt.width,
0x21); /* JPEG 422 */
jpeg_set_qual(dev->jpeg_hdr, dev->quality);
PDEBUG(D_STREAM, "Start streaming at %dx%d",
- gspca_dev->height, gspca_dev->width);
+ gspca_dev->pixfmt.height, gspca_dev->pixfmt.width);
jlj_start(gspca_dev);
return gspca_dev->usb_err;
}
diff --git a/drivers/media/usb/gspca/jl2005bcd.c b/drivers/media/usb/gspca/jl2005bcd.c
index fdaeeb14453..5b481fa4309 100644
--- a/drivers/media/usb/gspca/jl2005bcd.c
+++ b/drivers/media/usb/gspca/jl2005bcd.c
@@ -455,7 +455,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev;
sd->cap_mode = gspca_dev->cam.cam_mode;
- switch (gspca_dev->width) {
+ switch (gspca_dev->pixfmt.width) {
case 640:
PDEBUG(D_STREAM, "Start streaming at vga resolution");
jl2005c_stream_start_vga_lg(gspca_dev);
diff --git a/drivers/media/usb/gspca/jpeg.h b/drivers/media/usb/gspca/jpeg.h
index ab54910418b..0aa2b671faa 100644
--- a/drivers/media/usb/gspca/jpeg.h
+++ b/drivers/media/usb/gspca/jpeg.h
@@ -154,7 +154,9 @@ static void jpeg_set_qual(u8 *jpeg_hdr,
{
int i, sc;
- if (quality < 50)
+ if (quality <= 0)
+ sc = 5000;
+ else if (quality < 50)
sc = 5000 / quality;
else
sc = 200 - quality * 2;
diff --git a/drivers/media/usb/gspca/kinect.c b/drivers/media/usb/gspca/kinect.c
index 3773a8a745d..081f0516280 100644
--- a/drivers/media/usb/gspca/kinect.c
+++ b/drivers/media/usb/gspca/kinect.c
@@ -155,10 +155,11 @@ static int send_cmd(struct gspca_dev *gspca_dev, uint16_t cmd, void *cmdbuf,
do {
actual_len = kinect_read(udev, ibuf, 0x200);
} while (actual_len == 0);
- PDEBUG(D_USBO, "Control reply: %d", res);
+ PDEBUG(D_USBO, "Control reply: %d", actual_len);
if (actual_len < sizeof(*rhdr)) {
- pr_err("send_cmd: Input control transfer failed (%d)\n", res);
- return res;
+ pr_err("send_cmd: Input control transfer failed (%d)\n",
+ actual_len);
+ return actual_len < 0 ? actual_len : -EREMOTEIO;
}
actual_len -= sizeof(*rhdr);
diff --git a/drivers/media/usb/gspca/m5602/m5602_mt9m111.c b/drivers/media/usb/gspca/m5602/m5602_mt9m111.c
index cfa4663f893..27fcef11aef 100644
--- a/drivers/media/usb/gspca/m5602/m5602_mt9m111.c
+++ b/drivers/media/usb/gspca/m5602/m5602_mt9m111.c
@@ -266,7 +266,7 @@ static int mt9m111_set_hvflip(struct gspca_dev *gspca_dev)
return err;
data[0] = MT9M111_RMB_OVER_SIZED;
- if (gspca_dev->width == 640) {
+ if (gspca_dev->pixfmt.width == 640) {
data[1] = MT9M111_RMB_ROW_SKIP_2X |
MT9M111_RMB_COLUMN_SKIP_2X |
(hflip << 1) | vflip;
diff --git a/drivers/media/usb/gspca/mars.c b/drivers/media/usb/gspca/mars.c
index ff2c5abf115..779a8785f42 100644
--- a/drivers/media/usb/gspca/mars.c
+++ b/drivers/media/usb/gspca/mars.c
@@ -254,7 +254,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
int i;
/* create the JPEG header */
- jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
+ jpeg_define(sd->jpeg_hdr, gspca_dev->pixfmt.height,
+ gspca_dev->pixfmt.width,
0x21); /* JPEG 422 */
jpeg_set_qual(sd->jpeg_hdr, QUALITY);
@@ -270,8 +271,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
data[0] = 0x00; /* address */
data[1] = 0x0c | 0x01; /* reg 0 */
data[2] = 0x01; /* reg 1 */
- data[3] = gspca_dev->width / 8; /* h_size , reg 2 */
- data[4] = gspca_dev->height / 8; /* v_size , reg 3 */
+ data[3] = gspca_dev->pixfmt.width / 8; /* h_size , reg 2 */
+ data[4] = gspca_dev->pixfmt.height / 8; /* v_size , reg 3 */
data[5] = 0x30; /* reg 4, MI, PAS5101 :
* 0x30 for 24mhz , 0x28 for 12mhz */
data[6] = 0x02; /* reg 5, H start - was 0x04 */
diff --git a/drivers/media/usb/gspca/mr97310a.c b/drivers/media/usb/gspca/mr97310a.c
index 68bb2f35966..f006e29ca01 100644
--- a/drivers/media/usb/gspca/mr97310a.c
+++ b/drivers/media/usb/gspca/mr97310a.c
@@ -521,7 +521,7 @@ static int start_cif_cam(struct gspca_dev *gspca_dev)
if (sd->sensor_type)
data[5] = 0xbb;
- switch (gspca_dev->width) {
+ switch (gspca_dev->pixfmt.width) {
case 160:
data[9] |= 0x04; /* reg 8, 2:1 scale down from 320 */
/* fall thru */
@@ -618,7 +618,7 @@ static int start_vga_cam(struct gspca_dev *gspca_dev)
data[10] = 0x18;
}
- switch (gspca_dev->width) {
+ switch (gspca_dev->pixfmt.width) {
case 160:
data[9] |= 0x0c; /* reg 8, 4:1 scale down */
/* fall thru */
@@ -847,7 +847,7 @@ static void setexposure(struct gspca_dev *gspca_dev, s32 expo, s32 min_clockdiv)
u8 clockdiv = (60 * expo + 7999) / 8000;
/* Limit framerate to not exceed usb bandwidth */
- if (clockdiv < min_clockdiv && gspca_dev->width >= 320)
+ if (clockdiv < min_clockdiv && gspca_dev->pixfmt.width >= 320)
clockdiv = min_clockdiv;
else if (clockdiv < 2)
clockdiv = 2;
diff --git a/drivers/media/usb/gspca/nw80x.c b/drivers/media/usb/gspca/nw80x.c
index 44c9964b1b3..599f755e75b 100644
--- a/drivers/media/usb/gspca/nw80x.c
+++ b/drivers/media/usb/gspca/nw80x.c
@@ -1708,7 +1708,7 @@ static void setautogain(struct gspca_dev *gspca_dev, s32 val)
reg_r(gspca_dev, 0x1004, 1);
if (gspca_dev->usb_buf[0] & 0x04) { /* if AE_FULL_FRM */
- sd->ae_res = gspca_dev->width * gspca_dev->height;
+ sd->ae_res = gspca_dev->pixfmt.width * gspca_dev->pixfmt.height;
} else { /* get the AE window size */
reg_r(gspca_dev, 0x1011, 8);
w = (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0]
@@ -1717,7 +1717,8 @@ static void setautogain(struct gspca_dev *gspca_dev, s32 val)
- (gspca_dev->usb_buf[7] << 8) - gspca_dev->usb_buf[6];
sd->ae_res = h * w;
if (sd->ae_res == 0)
- sd->ae_res = gspca_dev->width * gspca_dev->height;
+ sd->ae_res = gspca_dev->pixfmt.width *
+ gspca_dev->pixfmt.height;
}
}
@@ -1856,21 +1857,21 @@ static int sd_start(struct gspca_dev *gspca_dev)
reg_w_buf(gspca_dev, cmd);
switch (sd->webcam) {
case P35u:
- if (gspca_dev->width == 320)
+ if (gspca_dev->pixfmt.width == 320)
reg_w_buf(gspca_dev, nw801_start_qvga);
else
reg_w_buf(gspca_dev, nw801_start_vga);
reg_w_buf(gspca_dev, nw801_start_2);
break;
case Kr651us:
- if (gspca_dev->width == 320)
+ if (gspca_dev->pixfmt.width == 320)
reg_w_buf(gspca_dev, kr651_start_qvga);
else
reg_w_buf(gspca_dev, kr651_start_vga);
reg_w_buf(gspca_dev, kr651_start_2);
break;
case Proscope:
- if (gspca_dev->width == 320)
+ if (gspca_dev->pixfmt.width == 320)
reg_w_buf(gspca_dev, proscope_start_qvga);
else
reg_w_buf(gspca_dev, proscope_start_vga);
diff --git a/drivers/media/usb/gspca/ov519.c b/drivers/media/usb/gspca/ov519.c
index 8937d79fd17..c95f32a0c02 100644
--- a/drivers/media/usb/gspca/ov519.c
+++ b/drivers/media/usb/gspca/ov519.c
@@ -3468,7 +3468,7 @@ static int sd_isoc_init(struct gspca_dev *gspca_dev)
switch (sd->bridge) {
case BRIDGE_OVFX2:
- if (gspca_dev->width != 800)
+ if (gspca_dev->pixfmt.width != 800)
gspca_dev->cam.bulk_size = OVFX2_BULK_SIZE;
else
gspca_dev->cam.bulk_size = 7 * 4096;
@@ -3507,8 +3507,8 @@ static void ov511_mode_init_regs(struct sd *sd)
/* Here I'm assuming that snapshot size == image size.
* I hope that's always true. --claudio
*/
- hsegs = (sd->gspca_dev.width >> 3) - 1;
- vsegs = (sd->gspca_dev.height >> 3) - 1;
+ hsegs = (sd->gspca_dev.pixfmt.width >> 3) - 1;
+ vsegs = (sd->gspca_dev.pixfmt.height >> 3) - 1;
reg_w(sd, R511_CAM_PXCNT, hsegs);
reg_w(sd, R511_CAM_LNCNT, vsegs);
@@ -3541,7 +3541,7 @@ static void ov511_mode_init_regs(struct sd *sd)
case SEN_OV7640:
case SEN_OV7648:
case SEN_OV76BE:
- if (sd->gspca_dev.width == 320)
+ if (sd->gspca_dev.pixfmt.width == 320)
interlaced = 1;
/* Fall through */
case SEN_OV6630:
@@ -3551,7 +3551,7 @@ static void ov511_mode_init_regs(struct sd *sd)
case 30:
case 25:
/* Not enough bandwidth to do 640x480 @ 30 fps */
- if (sd->gspca_dev.width != 640) {
+ if (sd->gspca_dev.pixfmt.width != 640) {
sd->clockdiv = 0;
break;
}
@@ -3584,7 +3584,8 @@ static void ov511_mode_init_regs(struct sd *sd)
/* Check if we have enough bandwidth to disable compression */
fps = (interlaced ? 60 : 30) / (sd->clockdiv + 1) + 1;
- needed = fps * sd->gspca_dev.width * sd->gspca_dev.height * 3 / 2;
+ needed = fps * sd->gspca_dev.pixfmt.width *
+ sd->gspca_dev.pixfmt.height * 3 / 2;
/* 1000 isoc packets/sec */
if (needed > 1000 * packet_size) {
/* Enable Y and UV quantization and compression */
@@ -3646,8 +3647,8 @@ static void ov518_mode_init_regs(struct sd *sd)
reg_w(sd, 0x38, 0x80);
}
- hsegs = sd->gspca_dev.width / 16;
- vsegs = sd->gspca_dev.height / 4;
+ hsegs = sd->gspca_dev.pixfmt.width / 16;
+ vsegs = sd->gspca_dev.pixfmt.height / 4;
reg_w(sd, 0x29, hsegs);
reg_w(sd, 0x2a, vsegs);
@@ -3686,7 +3687,8 @@ static void ov518_mode_init_regs(struct sd *sd)
* happened to be with revision < 2 cams using an
* OV7620 and revision 2 cams using an OV7620AE.
*/
- if (sd->revision > 0 && sd->gspca_dev.width == 640) {
+ if (sd->revision > 0 &&
+ sd->gspca_dev.pixfmt.width == 640) {
reg_w(sd, 0x20, 0x60);
reg_w(sd, 0x21, 0x1f);
} else {
@@ -3812,8 +3814,8 @@ static void ov519_mode_init_regs(struct sd *sd)
break;
}
- reg_w(sd, OV519_R10_H_SIZE, sd->gspca_dev.width >> 4);
- reg_w(sd, OV519_R11_V_SIZE, sd->gspca_dev.height >> 3);
+ reg_w(sd, OV519_R10_H_SIZE, sd->gspca_dev.pixfmt.width >> 4);
+ reg_w(sd, OV519_R11_V_SIZE, sd->gspca_dev.pixfmt.height >> 3);
if (sd->sensor == SEN_OV7670 &&
sd->gspca_dev.cam.cam_mode[sd->gspca_dev.curr_mode].priv)
reg_w(sd, OV519_R12_X_OFFSETL, 0x04);
@@ -3947,14 +3949,16 @@ static void mode_init_ov_sensor_regs(struct sd *sd)
}
case SEN_OV3610:
if (qvga) {
- xstart = (1040 - gspca_dev->width) / 2 + (0x1f << 4);
- ystart = (776 - gspca_dev->height) / 2;
+ xstart = (1040 - gspca_dev->pixfmt.width) / 2 +
+ (0x1f << 4);
+ ystart = (776 - gspca_dev->pixfmt.height) / 2;
} else {
- xstart = (2076 - gspca_dev->width) / 2 + (0x10 << 4);
- ystart = (1544 - gspca_dev->height) / 2;
+ xstart = (2076 - gspca_dev->pixfmt.width) / 2 +
+ (0x10 << 4);
+ ystart = (1544 - gspca_dev->pixfmt.height) / 2;
}
- xend = xstart + gspca_dev->width;
- yend = ystart + gspca_dev->height;
+ xend = xstart + gspca_dev->pixfmt.width;
+ yend = ystart + gspca_dev->pixfmt.height;
/* Writing to the COMH register resets the other windowing regs
to their default values, so we must do this first. */
i2c_w_mask(sd, 0x12, qvga ? 0x40 : 0x00, 0xf0);
@@ -4229,8 +4233,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev;
/* Default for most bridges, allow bridge_mode_init_regs to override */
- sd->sensor_width = sd->gspca_dev.width;
- sd->sensor_height = sd->gspca_dev.height;
+ sd->sensor_width = sd->gspca_dev.pixfmt.width;
+ sd->sensor_height = sd->gspca_dev.pixfmt.height;
switch (sd->bridge) {
case BRIDGE_OV511:
@@ -4345,12 +4349,13 @@ static void ov511_pkt_scan(struct gspca_dev *gspca_dev,
ov51x_handle_button(gspca_dev, (in[8] >> 2) & 1);
if (in[8] & 0x80) {
/* Frame end */
- if ((in[9] + 1) * 8 != gspca_dev->width ||
- (in[10] + 1) * 8 != gspca_dev->height) {
+ if ((in[9] + 1) * 8 != gspca_dev->pixfmt.width ||
+ (in[10] + 1) * 8 != gspca_dev->pixfmt.height) {
PERR("Invalid frame size, got: %dx%d,"
" requested: %dx%d\n",
(in[9] + 1) * 8, (in[10] + 1) * 8,
- gspca_dev->width, gspca_dev->height);
+ gspca_dev->pixfmt.width,
+ gspca_dev->pixfmt.height);
gspca_dev->last_packet_type = DISCARD_PACKET;
return;
}
@@ -4470,7 +4475,8 @@ static void ovfx2_pkt_scan(struct gspca_dev *gspca_dev,
if (sd->first_frame) {
sd->first_frame--;
if (gspca_dev->image_len <
- sd->gspca_dev.width * sd->gspca_dev.height)
+ sd->gspca_dev.pixfmt.width *
+ sd->gspca_dev.pixfmt.height)
gspca_dev->last_packet_type = DISCARD_PACKET;
}
gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
diff --git a/drivers/media/usb/gspca/ov534.c b/drivers/media/usb/gspca/ov534.c
index 03a33c46ca2..90f0d637cd9 100644
--- a/drivers/media/usb/gspca/ov534.c
+++ b/drivers/media/usb/gspca/ov534.c
@@ -1440,9 +1440,10 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
/* If this packet is marked as EOF, end the frame */
} else if (data[1] & UVC_STREAM_EOF) {
sd->last_pts = 0;
- if (gspca_dev->pixfmt == V4L2_PIX_FMT_YUYV
+ if (gspca_dev->pixfmt.pixelformat == V4L2_PIX_FMT_YUYV
&& gspca_dev->image_len + len - 12 !=
- gspca_dev->width * gspca_dev->height * 2) {
+ gspca_dev->pixfmt.width *
+ gspca_dev->pixfmt.height * 2) {
PDEBUG(D_PACK, "wrong sized frame");
goto discard;
}
diff --git a/drivers/media/usb/gspca/ov534_9.c b/drivers/media/usb/gspca/ov534_9.c
index c4cd028fe0b..47085cf2d72 100644
--- a/drivers/media/usb/gspca/ov534_9.c
+++ b/drivers/media/usb/gspca/ov534_9.c
@@ -59,6 +59,7 @@ enum sensors {
SENSOR_OV965x, /* ov9657 */
SENSOR_OV971x, /* ov9712 */
SENSOR_OV562x, /* ov5621 */
+ SENSOR_OV361x, /* ov3610 */
NSENSORS
};
@@ -106,6 +107,274 @@ static const struct v4l2_pix_format ov562x_mode[] = {
}
};
+enum ov361x {
+ ov361x_2048 = 0,
+ ov361x_1600,
+ ov361x_1024,
+ ov361x_640,
+ ov361x_320,
+ ov361x_160,
+ ov361x_last
+};
+
+static const struct v4l2_pix_format ov361x_mode[] = {
+ {0x800, 0x600, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+ .bytesperline = 0x800,
+ .sizeimage = 0x800 * 0x600,
+ .colorspace = V4L2_COLORSPACE_SRGB},
+ {1600, 1200, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+ .bytesperline = 1600,
+ .sizeimage = 1600 * 1200,
+ .colorspace = V4L2_COLORSPACE_SRGB},
+ {1024, 768, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+ .bytesperline = 768,
+ .sizeimage = 1024 * 768,
+ .colorspace = V4L2_COLORSPACE_SRGB},
+ {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480,
+ .colorspace = V4L2_COLORSPACE_SRGB},
+ {320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240,
+ .colorspace = V4L2_COLORSPACE_SRGB},
+ {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+ .bytesperline = 160,
+ .sizeimage = 160 * 120,
+ .colorspace = V4L2_COLORSPACE_SRGB}
+};
+
+static const u8 ov361x_start_2048[][2] = {
+ {0x12, 0x80},
+ {0x13, 0xcf},
+ {0x14, 0x40},
+ {0x15, 0x00},
+ {0x01, 0x80},
+ {0x02, 0x80},
+ {0x04, 0x70},
+ {0x0d, 0x40},
+ {0x0f, 0x47},
+ {0x11, 0x81},
+ {0x32, 0x36},
+ {0x33, 0x0c},
+ {0x34, 0x00},
+ {0x35, 0x90},
+ {0x12, 0x00},
+ {0x17, 0x10},
+ {0x18, 0x90},
+ {0x19, 0x00},
+ {0x1a, 0xc0},
+};
+static const u8 ov361x_bridge_start_2048[][2] = {
+ {0xf1, 0x60},
+ {0x88, 0x00},
+ {0x89, 0x08},
+ {0x8a, 0x00},
+ {0x8b, 0x06},
+ {0x8c, 0x01},
+ {0x8d, 0x10},
+ {0x1c, 0x00},
+ {0x1d, 0x48},
+ {0x1d, 0x00},
+ {0x1d, 0xff},
+ {0x1c, 0x0a},
+ {0x1d, 0x2e},
+ {0x1d, 0x1e},
+};
+
+static const u8 ov361x_start_1600[][2] = {
+ {0x12, 0x80},
+ {0x13, 0xcf},
+ {0x14, 0x40},
+ {0x15, 0x00},
+ {0x01, 0x80},
+ {0x02, 0x80},
+ {0x04, 0x70},
+ {0x0d, 0x40},
+ {0x0f, 0x47},
+ {0x11, 0x81},
+ {0x32, 0x36},
+ {0x33, 0x0C},
+ {0x34, 0x00},
+ {0x35, 0x90},
+ {0x12, 0x00},
+ {0x17, 0x10},
+ {0x18, 0x90},
+ {0x19, 0x00},
+ {0x1a, 0xc0},
+};
+static const u8 ov361x_bridge_start_1600[][2] = {
+ {0xf1, 0x60}, /* Hsize[7:0] */
+ {0x88, 0x00}, /* Hsize[15:8] Write Only, can't read */
+ {0x89, 0x08}, /* Vsize[7:0] */
+ {0x8a, 0x00}, /* Vsize[15:8] Write Only, can't read */
+ {0x8b, 0x06}, /* for Iso */
+ {0x8c, 0x01}, /* RAW input */
+ {0x8d, 0x10},
+ {0x1c, 0x00}, /* RAW output, Iso transfer */
+ {0x1d, 0x48},
+ {0x1d, 0x00},
+ {0x1d, 0xff},
+ {0x1c, 0x0a}, /* turn off JPEG, Iso mode */
+ {0x1d, 0x2e}, /* for Iso */
+ {0x1d, 0x1e},
+};
+
+static const u8 ov361x_start_1024[][2] = {
+ {0x12, 0x80},
+ {0x13, 0xcf},
+ {0x14, 0x40},
+ {0x15, 0x00},
+ {0x01, 0x80},
+ {0x02, 0x80},
+ {0x04, 0x70},
+ {0x0d, 0x40},
+ {0x0f, 0x47},
+ {0x11, 0x81},
+ {0x32, 0x36},
+ {0x33, 0x0C},
+ {0x34, 0x00},
+ {0x35, 0x90},
+ {0x12, 0x40},
+ {0x17, 0x1f},
+ {0x18, 0x5f},
+ {0x19, 0x00},
+ {0x1a, 0x68},
+};
+static const u8 ov361x_bridge_start_1024[][2] = {
+ {0xf1, 0x60}, /* Hsize[7:0] */
+ {0x88, 0x00}, /* Hsize[15:8] Write Only, can't read */
+ {0x89, 0x04}, /* Vsize[7:0] */
+ {0x8a, 0x00}, /* Vsize[15:8] Write Only, can't read */
+ {0x8b, 0x03}, /* for Iso */
+ {0x8c, 0x01}, /* RAW input */
+ {0x8d, 0x10},
+ {0x1c, 0x00}, /* RAW output, Iso transfer */
+ {0x1d, 0x48},
+ {0x1d, 0x00},
+ {0x1d, 0xff},
+ {0x1c, 0x0a}, /* turn off JPEG, Iso mode */
+ {0x1d, 0x2e}, /* for Iso */
+ {0x1d, 0x1e},
+};
+
+static const u8 ov361x_start_640[][2] = {
+ {0x12, 0x80},
+ {0x13, 0xcf},
+ {0x14, 0x40},
+ {0x15, 0x00},
+ {0x01, 0x80},
+ {0x02, 0x80},
+ {0x04, 0x70},
+ {0x0d, 0x40},
+ {0x0f, 0x47},
+ {0x11, 0x81},
+ {0x32, 0x36},
+ {0x33, 0x0C},
+ {0x34, 0x00},
+ {0x35, 0x90},
+ {0x12, 0x40},
+ {0x17, 0x1f},
+ {0x18, 0x5f},
+ {0x19, 0x00},
+ {0x1a, 0x68},
+};
+
+static const u8 ov361x_bridge_start_640[][2] = {
+ {0xf1, 0x60}, /* Hsize[7:0]*/
+ {0x88, 0x00}, /* Hsize[15:8] Write Only, can't read */
+ {0x89, 0x04}, /* Vsize[7:0] */
+ {0x8a, 0x00}, /* Vsize[15:8] Write Only, can't read */
+ {0x8b, 0x03}, /* for Iso */
+ {0x8c, 0x01}, /* RAW input */
+ {0x8d, 0x10},
+ {0x1c, 0x00}, /* RAW output, Iso transfer */
+ {0x1d, 0x48},
+ {0x1d, 0x00},
+ {0x1d, 0xff},
+ {0x1c, 0x0a}, /* turn off JPEG, Iso mode */
+ {0x1d, 0x2e}, /* for Iso */
+ {0x1d, 0x1e},
+};
+
+static const u8 ov361x_start_320[][2] = {
+ {0x12, 0x80},
+ {0x13, 0xcf},
+ {0x14, 0x40},
+ {0x15, 0x00},
+ {0x01, 0x80},
+ {0x02, 0x80},
+ {0x04, 0x70},
+ {0x0d, 0x40},
+ {0x0f, 0x47},
+ {0x11, 0x81},
+ {0x32, 0x36},
+ {0x33, 0x0C},
+ {0x34, 0x00},
+ {0x35, 0x90},
+ {0x12, 0x40},
+ {0x17, 0x1f},
+ {0x18, 0x5f},
+ {0x19, 0x00},
+ {0x1a, 0x68},
+};
+
+static const u8 ov361x_bridge_start_320[][2] = {
+ {0xf1, 0x60}, /* Hsize[7:0] */
+ {0x88, 0x00}, /* Hsize[15:8] Write Only, can't read */
+ {0x89, 0x04}, /* Vsize[7:0] */
+ {0x8a, 0x00}, /* Vsize[15:8] Write Only, can't read */
+ {0x8b, 0x03}, /* for Iso */
+ {0x8c, 0x01}, /* RAW input */
+ {0x8d, 0x10},
+ {0x1c, 0x00}, /* RAW output, Iso transfer; */
+ {0x1d, 0x48},
+ {0x1d, 0x00},
+ {0x1d, 0xff},
+ {0x1c, 0x0a}, /* turn off JPEG, Iso mode */
+ {0x1d, 0x2e}, /* for Iso */
+ {0x1d, 0x1e},
+};
+
+static const u8 ov361x_start_160[][2] = {
+ {0x12, 0x80},
+ {0x13, 0xcf},
+ {0x14, 0x40},
+ {0x15, 0x00},
+ {0x01, 0x80},
+ {0x02, 0x80},
+ {0x04, 0x70},
+ {0x0d, 0x40},
+ {0x0f, 0x47},
+ {0x11, 0x81},
+ {0x32, 0x36},
+ {0x33, 0x0C},
+ {0x34, 0x00},
+ {0x35, 0x90},
+ {0x12, 0x40},
+ {0x17, 0x1f},
+ {0x18, 0x5f},
+ {0x19, 0x00},
+ {0x1a, 0x68},
+};
+
+static const u8 ov361x_bridge_start_160[][2] = {
+ {0xf1, 0x60}, /* Hsize[7:0] */
+ {0x88, 0x00}, /* Hsize[15:8] Write Only, can't read */
+ {0x89, 0x04}, /* Vsize[7:0] */
+ {0x8a, 0x00}, /* Vsize[15:8] Write Only, can't read */
+ {0x8b, 0x03}, /* for Iso */
+ {0x8c, 0x01}, /* RAW input */
+ {0x8d, 0x10},
+ {0x1c, 0x00}, /* RAW output, Iso transfer */
+ {0x1d, 0x48},
+ {0x1d, 0x00},
+ {0x1d, 0xff},
+ {0x1c, 0x0a}, /* turn off JPEG, Iso mode */
+ {0x1d, 0x2e}, /* for Iso */
+ {0x1d, 0x1e},
+};
+
static const u8 bridge_init[][2] = {
{0x88, 0xf8},
{0x89, 0xff},
@@ -898,7 +1167,7 @@ static int sccb_check_status(struct gspca_dev *gspca_dev)
int i;
for (i = 0; i < 5; i++) {
- msleep(10);
+ msleep(20);
data = reg_r(gspca_dev, OV534_REG_STATUS);
switch (data) {
@@ -1221,6 +1490,13 @@ static int sd_init(struct gspca_dev *gspca_dev)
sccb_w_array(gspca_dev, ov562x_init_2,
ARRAY_SIZE(ov562x_init_2));
reg_w(gspca_dev, 0xe0, 0x00);
+ } else if ((sensor_id & 0xfff0) == 0x3610) {
+ sd->sensor = SENSOR_OV361x;
+ gspca_dev->cam.cam_mode = ov361x_mode;
+ gspca_dev->cam.nmodes = ARRAY_SIZE(ov361x_mode);
+ reg_w(gspca_dev, 0xe7, 0x3a);
+ reg_w(gspca_dev, 0xf1, 0x60);
+ sccb_write(gspca_dev, 0x12, 0x80);
} else {
pr_err("Unknown sensor %04x", sensor_id);
return -EINVAL;
@@ -1229,6 +1505,53 @@ static int sd_init(struct gspca_dev *gspca_dev)
return gspca_dev->usb_err;
}
+static int sd_start_ov361x(struct gspca_dev *gspca_dev)
+{
+ sccb_write(gspca_dev, 0x12, 0x80);
+ msleep(20);
+ switch (gspca_dev->curr_mode % (ov361x_last)) {
+ case ov361x_2048:
+ reg_w_array(gspca_dev, ov361x_bridge_start_2048,
+ ARRAY_SIZE(ov361x_bridge_start_2048));
+ sccb_w_array(gspca_dev, ov361x_start_2048,
+ ARRAY_SIZE(ov361x_start_2048));
+ break;
+ case ov361x_1600:
+ reg_w_array(gspca_dev, ov361x_bridge_start_1600,
+ ARRAY_SIZE(ov361x_bridge_start_1600));
+ sccb_w_array(gspca_dev, ov361x_start_1600,
+ ARRAY_SIZE(ov361x_start_1600));
+ break;
+ case ov361x_1024:
+ reg_w_array(gspca_dev, ov361x_bridge_start_1024,
+ ARRAY_SIZE(ov361x_bridge_start_1024));
+ sccb_w_array(gspca_dev, ov361x_start_1024,
+ ARRAY_SIZE(ov361x_start_1024));
+ break;
+ case ov361x_640:
+ reg_w_array(gspca_dev, ov361x_bridge_start_640,
+ ARRAY_SIZE(ov361x_bridge_start_640));
+ sccb_w_array(gspca_dev, ov361x_start_640,
+ ARRAY_SIZE(ov361x_start_640));
+ break;
+ case ov361x_320:
+ reg_w_array(gspca_dev, ov361x_bridge_start_320,
+ ARRAY_SIZE(ov361x_bridge_start_320));
+ sccb_w_array(gspca_dev, ov361x_start_320,
+ ARRAY_SIZE(ov361x_start_320));
+ break;
+ case ov361x_160:
+ reg_w_array(gspca_dev, ov361x_bridge_start_160,
+ ARRAY_SIZE(ov361x_bridge_start_160));
+ sccb_w_array(gspca_dev, ov361x_start_160,
+ ARRAY_SIZE(ov361x_start_160));
+ break;
+ }
+ reg_w(gspca_dev, 0xe0, 0x00); /* start transfer */
+
+ return gspca_dev->usb_err;
+}
+
static int sd_start(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -1237,6 +1560,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
return gspca_dev->usb_err;
if (sd->sensor == SENSOR_OV562x)
return gspca_dev->usb_err;
+ if (sd->sensor == SENSOR_OV361x)
+ return sd_start_ov361x(gspca_dev);
switch (gspca_dev->curr_mode) {
case QVGA_MODE: /* 320x240 */
@@ -1290,6 +1615,11 @@ static int sd_start(struct gspca_dev *gspca_dev)
static void sd_stopN(struct gspca_dev *gspca_dev)
{
+ if (((struct sd *)gspca_dev)->sensor == SENSOR_OV361x) {
+ reg_w(gspca_dev, 0xe0, 0x01); /* stop transfer */
+ /* reg_w(gspca_dev, 0x31, 0x09); */
+ return;
+ }
reg_w(gspca_dev, 0xe0, 0x01);
set_led(gspca_dev, 0);
reg_w(gspca_dev, 0xe0, 0x00);
@@ -1425,6 +1755,8 @@ static int sd_init_controls(struct gspca_dev *gspca_dev)
if (sd->sensor == SENSOR_OV971x)
return 0;
+ if (sd->sensor == SENSOR_OV361x)
+ return 0;
gspca_dev->vdev.ctrl_handler = hdl;
v4l2_ctrl_handler_init(hdl, 7);
if (sd->sensor == SENSOR_OV562x) {
diff --git a/drivers/media/usb/gspca/pac207.c b/drivers/media/usb/gspca/pac207.c
index 83519be94e5..07529e5a0c5 100644
--- a/drivers/media/usb/gspca/pac207.c
+++ b/drivers/media/usb/gspca/pac207.c
@@ -299,7 +299,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
pac207_write_regs(gspca_dev, 0x0042, pac207_sensor_init[3], 8);
/* Compression Balance */
- if (gspca_dev->width == 176)
+ if (gspca_dev->pixfmt.width == 176)
pac207_write_reg(gspca_dev, 0x4a, 0xff);
else
pac207_write_reg(gspca_dev, 0x4a, 0x30);
@@ -317,7 +317,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
mode = 0x00;
else
mode = 0x02;
- if (gspca_dev->width == 176) { /* 176x144 */
+ if (gspca_dev->pixfmt.width == 176) { /* 176x144 */
mode |= 0x01;
PDEBUG(D_STREAM, "pac207_start mode 176x144");
} else { /* 352x288 */
@@ -416,7 +416,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
#if IS_ENABLED(CONFIG_INPUT)
static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
u8 *data, /* interrupt packet data */
- int len) /* interrput packet length */
+ int len) /* interrupt packet length */
{
int ret = -EINVAL;
diff --git a/drivers/media/usb/gspca/pac7302.c b/drivers/media/usb/gspca/pac7302.c
index a9150964356..339adce7c7a 100644
--- a/drivers/media/usb/gspca/pac7302.c
+++ b/drivers/media/usb/gspca/pac7302.c
@@ -874,7 +874,7 @@ static int sd_dbg_s_register(struct gspca_dev *gspca_dev,
#if IS_ENABLED(CONFIG_INPUT)
static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
u8 *data, /* interrupt packet data */
- int len) /* interrput packet length */
+ int len) /* interrupt packet length */
{
int ret = -EINVAL;
u8 data0, data1;
@@ -928,6 +928,7 @@ static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x093a, 0x2620)},
{USB_DEVICE(0x093a, 0x2621)},
{USB_DEVICE(0x093a, 0x2622), .driver_info = FL_VFLIP},
+ {USB_DEVICE(0x093a, 0x2623), .driver_info = FL_VFLIP},
{USB_DEVICE(0x093a, 0x2624), .driver_info = FL_VFLIP},
{USB_DEVICE(0x093a, 0x2625)},
{USB_DEVICE(0x093a, 0x2626)},
diff --git a/drivers/media/usb/gspca/pac7311.c b/drivers/media/usb/gspca/pac7311.c
index 1a5bdc853a8..25f86b1e74a 100644
--- a/drivers/media/usb/gspca/pac7311.c
+++ b/drivers/media/usb/gspca/pac7311.c
@@ -326,7 +326,7 @@ static void setexposure(struct gspca_dev *gspca_dev, s32 val)
* 640x480 mode and page 4 reg 2 <= 3 then it must be 9
*/
reg_w(gspca_dev, 0xff, 0x01);
- if (gspca_dev->width != 640 && val <= 3)
+ if (gspca_dev->pixfmt.width != 640 && val <= 3)
reg_w(gspca_dev, 0x08, 0x09);
else
reg_w(gspca_dev, 0x08, 0x08);
@@ -337,7 +337,7 @@ static void setexposure(struct gspca_dev *gspca_dev, s32 val)
* camera to use higher compression or we may run out of
* bandwidth.
*/
- if (gspca_dev->width == 640 && val == 2)
+ if (gspca_dev->pixfmt.width == 640 && val == 2)
reg_w(gspca_dev, 0x80, 0x01);
else
reg_w(gspca_dev, 0x80, 0x1c);
@@ -615,7 +615,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
/* Start the new frame with the jpeg header */
pac_start_frame(gspca_dev,
- gspca_dev->height, gspca_dev->width);
+ gspca_dev->pixfmt.height, gspca_dev->pixfmt.width);
}
gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
}
diff --git a/drivers/media/usb/gspca/se401.c b/drivers/media/usb/gspca/se401.c
index 5f729b8aa2b..5102cea5047 100644
--- a/drivers/media/usb/gspca/se401.c
+++ b/drivers/media/usb/gspca/se401.c
@@ -354,9 +354,9 @@ static int sd_start(struct gspca_dev *gspca_dev)
/* set size + mode */
se401_write_req(gspca_dev, SE401_REQ_SET_WIDTH,
- gspca_dev->width * mult, 0);
+ gspca_dev->pixfmt.width * mult, 0);
se401_write_req(gspca_dev, SE401_REQ_SET_HEIGHT,
- gspca_dev->height * mult, 0);
+ gspca_dev->pixfmt.height * mult, 0);
/*
* HDG: disabled this as it does not seem to do anything
* se401_write_req(gspca_dev, SE401_REQ_SET_OUTPUT_MODE,
@@ -480,7 +480,7 @@ static void sd_complete_frame(struct gspca_dev *gspca_dev, u8 *data, int len)
static void sd_pkt_scan_janggu(struct gspca_dev *gspca_dev, u8 *data, int len)
{
struct sd *sd = (struct sd *)gspca_dev;
- int imagesize = gspca_dev->width * gspca_dev->height;
+ int imagesize = gspca_dev->pixfmt.width * gspca_dev->pixfmt.height;
int i, plen, bits, pixels, info, count;
if (sd->restart_stream)
diff --git a/drivers/media/usb/gspca/sn9c20x.c b/drivers/media/usb/gspca/sn9c20x.c
index f4453d52801..41a9a892f79 100644
--- a/drivers/media/usb/gspca/sn9c20x.c
+++ b/drivers/media/usb/gspca/sn9c20x.c
@@ -1955,7 +1955,7 @@ static int sd_isoc_init(struct gspca_dev *gspca_dev)
return 0;
}
- switch (gspca_dev->width) {
+ switch (gspca_dev->pixfmt.width) {
case 160: /* 160x120 */
gspca_dev->alt = 2;
break;
@@ -1985,8 +1985,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
int mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
- int width = gspca_dev->width;
- int height = gspca_dev->height;
+ int width = gspca_dev->pixfmt.width;
+ int height = gspca_dev->pixfmt.height;
u8 fmt, scale = 0;
jpeg_define(sd->jpeg_hdr, height, width,
@@ -2359,6 +2359,7 @@ static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x045e, 0x00f4), SN9C20X(OV9650, 0x30, 0)},
{USB_DEVICE(0x145f, 0x013d), SN9C20X(OV7660, 0x21, 0)},
{USB_DEVICE(0x0458, 0x7029), SN9C20X(HV7131R, 0x11, 0)},
+ {USB_DEVICE(0x0458, 0x7045), SN9C20X(MT9M112, 0x5d, LED_REVERSE)},
{USB_DEVICE(0x0458, 0x704a), SN9C20X(MT9M112, 0x5d, 0)},
{USB_DEVICE(0x0458, 0x704c), SN9C20X(MT9M112, 0x5d, 0)},
{USB_DEVICE(0xa168, 0x0610), SN9C20X(HV7131R, 0x11, 0)},
diff --git a/drivers/media/usb/gspca/sonixb.c b/drivers/media/usb/gspca/sonixb.c
index d7ff3b9687c..ecbcb39feb7 100644
--- a/drivers/media/usb/gspca/sonixb.c
+++ b/drivers/media/usb/gspca/sonixb.c
@@ -513,10 +513,7 @@ static void i2c_w(struct gspca_dev *gspca_dev, const u8 *buf)
if (gspca_dev->usb_buf[0] & 0x04) {
if (gspca_dev->usb_buf[0] & 0x08) {
dev_err(gspca_dev->v4l2_dev.dev,
- "i2c error writing %02x %02x %02x %02x"
- " %02x %02x %02x %02x\n",
- buf[0], buf[1], buf[2], buf[3],
- buf[4], buf[5], buf[6], buf[7]);
+ "i2c error writing %8ph\n", buf);
gspca_dev->usb_err = -EIO;
}
return;
@@ -753,7 +750,7 @@ static void setexposure(struct gspca_dev *gspca_dev)
/* In 640x480, if the reg11 has less than 4, the image is
unstable (the bridge goes into a higher compression mode
which we have not reverse engineered yet). */
- if (gspca_dev->width == 640 && reg11 < 4)
+ if (gspca_dev->pixfmt.width == 640 && reg11 < 4)
reg11 = 4;
/* frame exposure time in ms = 1000 * reg11 / 30 ->
@@ -1433,10 +1430,8 @@ static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x0c45, 0x600d), SB(PAS106, 101)},
{USB_DEVICE(0x0c45, 0x6011), SB(OV6650, 101)},
{USB_DEVICE(0x0c45, 0x6019), SB(OV7630, 101)},
-#if !IS_ENABLED(CONFIG_USB_SN9C102)
{USB_DEVICE(0x0c45, 0x6024), SB(TAS5130CXX, 102)},
{USB_DEVICE(0x0c45, 0x6025), SB(TAS5130CXX, 102)},
-#endif
{USB_DEVICE(0x0c45, 0x6027), SB(OV7630, 101)}, /* Genius Eye 310 */
{USB_DEVICE(0x0c45, 0x6028), SB(PAS202, 102)},
{USB_DEVICE(0x0c45, 0x6029), SB(PAS106, 102)},
diff --git a/drivers/media/usb/gspca/sonixj.c b/drivers/media/usb/gspca/sonixj.c
index 3b5ccb1c4cd..c69b45d7cfb 100644
--- a/drivers/media/usb/gspca/sonixj.c
+++ b/drivers/media/usb/gspca/sonixj.c
@@ -2204,7 +2204,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
{ 0x14, 0xe7, 0x1e, 0xdd };
/* create the JPEG header */
- jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
+ jpeg_define(sd->jpeg_hdr, gspca_dev->pixfmt.height,
+ gspca_dev->pixfmt.width,
0x21); /* JPEG 422 */
/* initialize the bridge */
diff --git a/drivers/media/usb/gspca/spca1528.c b/drivers/media/usb/gspca/spca1528.c
index 688592b289e..f38fd894960 100644
--- a/drivers/media/usb/gspca/spca1528.c
+++ b/drivers/media/usb/gspca/spca1528.c
@@ -255,7 +255,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev;
/* initialize the JPEG header */
- jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
+ jpeg_define(sd->jpeg_hdr, gspca_dev->pixfmt.height,
+ gspca_dev->pixfmt.width,
0x22); /* JPEG 411 */
/* the JPEG quality shall be 85% */
diff --git a/drivers/media/usb/gspca/spca500.c b/drivers/media/usb/gspca/spca500.c
index 9f8bf51fd64..f011a309dd6 100644
--- a/drivers/media/usb/gspca/spca500.c
+++ b/drivers/media/usb/gspca/spca500.c
@@ -608,7 +608,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
__u8 xmult, ymult;
/* create the JPEG header */
- jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
+ jpeg_define(sd->jpeg_hdr, gspca_dev->pixfmt.height,
+ gspca_dev->pixfmt.width,
0x22); /* JPEG 411 */
jpeg_set_qual(sd->jpeg_hdr, QUALITY);
diff --git a/drivers/media/usb/gspca/sq905c.c b/drivers/media/usb/gspca/sq905c.c
index acb19fb9a3d..aa21edc9502 100644
--- a/drivers/media/usb/gspca/sq905c.c
+++ b/drivers/media/usb/gspca/sq905c.c
@@ -272,7 +272,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
dev->cap_mode = gspca_dev->cam.cam_mode;
/* "Open the shutter" and set size, to start capture */
- switch (gspca_dev->width) {
+ switch (gspca_dev->pixfmt.width) {
case 640:
PDEBUG(D_STREAM, "Start streaming at high resolution");
dev->cap_mode++;
diff --git a/drivers/media/usb/gspca/sq930x.c b/drivers/media/usb/gspca/sq930x.c
index b10d0821111..e274cf19a3e 100644
--- a/drivers/media/usb/gspca/sq930x.c
+++ b/drivers/media/usb/gspca/sq930x.c
@@ -906,7 +906,8 @@ static int sd_isoc_init(struct gspca_dev *gspca_dev)
gspca_dev->cam.bulk_nurbs = 1; /* there must be one URB only */
sd->do_ctrl = 0;
- gspca_dev->cam.bulk_size = gspca_dev->width * gspca_dev->height + 8;
+ gspca_dev->cam.bulk_size = gspca_dev->pixfmt.width *
+ gspca_dev->pixfmt.height + 8;
return 0;
}
diff --git a/drivers/media/usb/gspca/stk014.c b/drivers/media/usb/gspca/stk014.c
index 8c0982607f2..b0c70fea760 100644
--- a/drivers/media/usb/gspca/stk014.c
+++ b/drivers/media/usb/gspca/stk014.c
@@ -250,7 +250,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
int ret, value;
/* create the JPEG header */
- jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
+ jpeg_define(sd->jpeg_hdr, gspca_dev->pixfmt.height,
+ gspca_dev->pixfmt.width,
0x22); /* JPEG 411 */
jpeg_set_qual(sd->jpeg_hdr, QUALITY);
@@ -261,7 +262,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
set_par(gspca_dev, 0x00000000);
set_par(gspca_dev, 0x8002e001);
set_par(gspca_dev, 0x14000000);
- if (gspca_dev->width > 320)
+ if (gspca_dev->pixfmt.width > 320)
value = 0x8002e001; /* 640x480 */
else
value = 0x4001f000; /* 320x240 */
diff --git a/drivers/media/usb/gspca/stk1135.c b/drivers/media/usb/gspca/stk1135.c
index 585868835ac..48234c9a8b6 100644
--- a/drivers/media/usb/gspca/stk1135.c
+++ b/drivers/media/usb/gspca/stk1135.c
@@ -48,42 +48,11 @@ struct sd {
};
static const struct v4l2_pix_format stk1135_modes[] = {
- {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
- .bytesperline = 160,
- .sizeimage = 160 * 120,
- .colorspace = V4L2_COLORSPACE_SRGB},
- {176, 144, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
- .bytesperline = 176,
- .sizeimage = 176 * 144,
- .colorspace = V4L2_COLORSPACE_SRGB},
- {320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
- .bytesperline = 320,
- .sizeimage = 320 * 240,
- .colorspace = V4L2_COLORSPACE_SRGB},
- {352, 288, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
- .bytesperline = 352,
- .sizeimage = 352 * 288,
- .colorspace = V4L2_COLORSPACE_SRGB},
+ /* default mode (this driver supports variable resolution) */
{640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
.bytesperline = 640,
.sizeimage = 640 * 480,
.colorspace = V4L2_COLORSPACE_SRGB},
- {720, 576, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
- .bytesperline = 720,
- .sizeimage = 720 * 576,
- .colorspace = V4L2_COLORSPACE_SRGB},
- {800, 600, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
- .bytesperline = 800,
- .sizeimage = 800 * 600,
- .colorspace = V4L2_COLORSPACE_SRGB},
- {1024, 768, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
- .bytesperline = 1024,
- .sizeimage = 1024 * 768,
- .colorspace = V4L2_COLORSPACE_SRGB},
- {1280, 1024, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
- .bytesperline = 1280,
- .sizeimage = 1280 * 1024,
- .colorspace = V4L2_COLORSPACE_SRGB},
};
/* -- read a register -- */
@@ -347,16 +316,16 @@ static void stk1135_configure_mt9m112(struct gspca_dev *gspca_dev)
sensor_write(gspca_dev, cfg[i].reg, cfg[i].val);
/* set output size */
- width = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].width;
- height = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].height;
- if (width <= 640) { /* use context A (half readout speed by default) */
+ width = gspca_dev->pixfmt.width;
+ height = gspca_dev->pixfmt.height;
+ if (width <= 640 && height <= 512) { /* context A (half readout speed)*/
sensor_write(gspca_dev, 0x1a7, width);
sensor_write(gspca_dev, 0x1aa, height);
/* set read mode context A */
sensor_write(gspca_dev, 0x0c8, 0x0000);
/* set resize, read mode, vblank, hblank context A */
sensor_write(gspca_dev, 0x2c8, 0x0000);
- } else { /* use context B (full readout speed by default) */
+ } else { /* context B (full readout speed) */
sensor_write(gspca_dev, 0x1a1, width);
sensor_write(gspca_dev, 0x1a4, height);
/* set read mode context B */
@@ -392,6 +361,9 @@ static void stk1135_configure_clock(struct gspca_dev *gspca_dev)
/* set serial interface clock divider (30MHz/0x1f*16+2) = 60240 kHz) */
reg_w(gspca_dev, STK1135_REG_SICTL + 2, 0x1f);
+
+ /* wait a while for sensor to catch up */
+ udelay(1000);
}
static void stk1135_camera_disable(struct gspca_dev *gspca_dev)
@@ -484,8 +456,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
reg_w(gspca_dev, STK1135_REG_CISPO + 3, 0x00);
/* set capture end position */
- width = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].width;
- height = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].height;
+ width = gspca_dev->pixfmt.width;
+ height = gspca_dev->pixfmt.height;
reg_w(gspca_dev, STK1135_REG_CIEPO + 0, width & 0xff);
reg_w(gspca_dev, STK1135_REG_CIEPO + 1, width >> 8);
reg_w(gspca_dev, STK1135_REG_CIEPO + 2, height & 0xff);
@@ -643,6 +615,35 @@ static int sd_init_controls(struct gspca_dev *gspca_dev)
return 0;
}
+static void stk1135_try_fmt(struct gspca_dev *gspca_dev, struct v4l2_format *fmt)
+{
+ fmt->fmt.pix.width = clamp(fmt->fmt.pix.width, 32U, 1280U);
+ fmt->fmt.pix.height = clamp(fmt->fmt.pix.height, 32U, 1024U);
+ /* round up to even numbers */
+ fmt->fmt.pix.width += (fmt->fmt.pix.width & 1);
+ fmt->fmt.pix.height += (fmt->fmt.pix.height & 1);
+
+ fmt->fmt.pix.bytesperline = fmt->fmt.pix.width;
+ fmt->fmt.pix.sizeimage = fmt->fmt.pix.width * fmt->fmt.pix.height;
+}
+
+static int stk1135_enum_framesizes(struct gspca_dev *gspca_dev,
+ struct v4l2_frmsizeenum *fsize)
+{
+ if (fsize->index != 0 || fsize->pixel_format != V4L2_PIX_FMT_SBGGR8)
+ return -EINVAL;
+
+ fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
+ fsize->stepwise.min_width = 32;
+ fsize->stepwise.min_height = 32;
+ fsize->stepwise.max_width = 1280;
+ fsize->stepwise.max_height = 1024;
+ fsize->stepwise.step_width = 2;
+ fsize->stepwise.step_height = 2;
+
+ return 0;
+}
+
/* sub-driver description */
static const struct sd_desc sd_desc = {
.name = MODULE_NAME,
@@ -653,6 +654,8 @@ static const struct sd_desc sd_desc = {
.stopN = sd_stopN,
.pkt_scan = sd_pkt_scan,
.dq_callback = stk1135_dq_callback,
+ .try_fmt = stk1135_try_fmt,
+ .enum_framesizes = stk1135_enum_framesizes,
};
/* -- module initialisation -- */
diff --git a/drivers/media/usb/gspca/stv0680.c b/drivers/media/usb/gspca/stv0680.c
index 9c0827631b9..7f94ec74282 100644
--- a/drivers/media/usb/gspca/stv0680.c
+++ b/drivers/media/usb/gspca/stv0680.c
@@ -139,7 +139,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
struct sd *sd = (struct sd *) gspca_dev;
struct cam *cam = &gspca_dev->cam;
- /* Give the camera some time to settle, otherwise initalization will
+ /* Give the camera some time to settle, otherwise initialization will
fail on hotplug, and yes it really needs a full second. */
msleep(1000);
diff --git a/drivers/media/usb/gspca/stv06xx/stv06xx.c b/drivers/media/usb/gspca/stv06xx/stv06xx.c
index 55ee7a61c67..49d209bbf9e 100644
--- a/drivers/media/usb/gspca/stv06xx/stv06xx.c
+++ b/drivers/media/usb/gspca/stv06xx/stv06xx.c
@@ -452,7 +452,7 @@ frame_data:
NULL, 0);
if (sd->bridge == BRIDGE_ST6422)
- sd->to_skip = gspca_dev->width * 4;
+ sd->to_skip = gspca_dev->pixfmt.width * 4;
if (chunk_len)
PERR("Chunk length is "
diff --git a/drivers/media/usb/gspca/stv06xx/stv06xx_pb0100.c b/drivers/media/usb/gspca/stv06xx/stv06xx_pb0100.c
index 8206b774330..8d785edcccf 100644
--- a/drivers/media/usb/gspca/stv06xx/stv06xx_pb0100.c
+++ b/drivers/media/usb/gspca/stv06xx/stv06xx_pb0100.c
@@ -421,7 +421,7 @@ static int pb0100_set_autogain_target(struct gspca_dev *gspca_dev, __s32 val)
/* Number of pixels counted by the sensor when subsampling the pixels.
* Slightly larger than the real value to avoid oscillation */
- totalpixels = gspca_dev->width * gspca_dev->height;
+ totalpixels = gspca_dev->pixfmt.width * gspca_dev->pixfmt.height;
totalpixels = totalpixels/(8*8) + totalpixels/(64*64);
brightpixels = (totalpixels * val) >> 8;
diff --git a/drivers/media/usb/gspca/stv06xx/stv06xx_vv6410.c b/drivers/media/usb/gspca/stv06xx/stv06xx_vv6410.c
index bf3e5c317a2..e60cbb3aa60 100644
--- a/drivers/media/usb/gspca/stv06xx/stv06xx_vv6410.c
+++ b/drivers/media/usb/gspca/stv06xx/stv06xx_vv6410.c
@@ -178,7 +178,7 @@ static int vv6410_stop(struct sd *sd)
PDEBUG(D_STREAM, "Halting stream");
- return (err < 0) ? err : 0;
+ return 0;
}
static int vv6410_dump(struct sd *sd)
diff --git a/drivers/media/usb/gspca/sunplus.c b/drivers/media/usb/gspca/sunplus.c
index af8767a9bd4..46c9f2229a1 100644
--- a/drivers/media/usb/gspca/sunplus.c
+++ b/drivers/media/usb/gspca/sunplus.c
@@ -715,7 +715,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
int enable;
/* create the JPEG header */
- jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
+ jpeg_define(sd->jpeg_hdr, gspca_dev->pixfmt.height,
+ gspca_dev->pixfmt.width,
0x22); /* JPEG 411 */
jpeg_set_qual(sd->jpeg_hdr, QUALITY);
@@ -1026,6 +1027,7 @@ static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x055f, 0xc650), BS(SPCA533, 0)},
{USB_DEVICE(0x05da, 0x1018), BS(SPCA504B, 0)},
{USB_DEVICE(0x06d6, 0x0031), BS(SPCA533, 0)},
+ {USB_DEVICE(0x06d6, 0x0041), BS(SPCA504B, 0)},
{USB_DEVICE(0x0733, 0x1311), BS(SPCA533, 0)},
{USB_DEVICE(0x0733, 0x1314), BS(SPCA533, 0)},
{USB_DEVICE(0x0733, 0x2211), BS(SPCA533, 0)},
diff --git a/drivers/media/usb/gspca/topro.c b/drivers/media/usb/gspca/topro.c
index 4cb511ccc5f..5fcd1eec200 100644
--- a/drivers/media/usb/gspca/topro.c
+++ b/drivers/media/usb/gspca/topro.c
@@ -3856,7 +3856,7 @@ static void setsharpness(struct gspca_dev *gspca_dev, s32 val)
if (sd->bridge == BRIDGE_TP6800) {
val |= 0x08; /* grid compensation enable */
- if (gspca_dev->width == 640)
+ if (gspca_dev->pixfmt.width == 640)
reg_w(gspca_dev, TP6800_R78_FORMAT, 0x00); /* vga */
else
val |= 0x04; /* scaling down enable */
@@ -3880,7 +3880,7 @@ static void set_resolution(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev;
reg_w(gspca_dev, TP6800_R21_ENDP_1_CTL, 0x00);
- if (gspca_dev->width == 320) {
+ if (gspca_dev->pixfmt.width == 320) {
reg_w(gspca_dev, TP6800_R3F_FRAME_RATE, 0x06);
msleep(100);
i2c_w(gspca_dev, CX0342_AUTO_ADC_CALIB, 0x01);
@@ -3924,7 +3924,7 @@ static int get_fr_idx(struct gspca_dev *gspca_dev)
/* 640x480 * 30 fps does not work */
if (i == 6 /* if 30 fps */
- && gspca_dev->width == 640)
+ && gspca_dev->pixfmt.width == 640)
i = 0x05; /* 15 fps */
} else {
for (i = 0; i < ARRAY_SIZE(rates_6810) - 1; i++) {
@@ -3935,7 +3935,7 @@ static int get_fr_idx(struct gspca_dev *gspca_dev)
/* 640x480 * 30 fps does not work */
if (i == 7 /* if 30 fps */
- && gspca_dev->width == 640)
+ && gspca_dev->pixfmt.width == 640)
i = 6; /* 15 fps */
i |= 0x80; /* clock * 1 */
}
@@ -4554,7 +4554,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width);
+ jpeg_define(sd->jpeg_hdr, gspca_dev->pixfmt.height,
+ gspca_dev->pixfmt.width);
set_dqt(gspca_dev, sd->quality);
if (sd->bridge == BRIDGE_TP6800) {
if (sd->sensor == SENSOR_CX0342)
@@ -4630,8 +4631,16 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
}
data++;
len--;
+ if (len < 2) {
+ gspca_dev->last_packet_type = DISCARD_PACKET;
+ return;
+ }
if (*data == 0xff && data[1] == 0xd8) {
/*fixme: there may be information in the 4 high bits*/
+ if (len < 7) {
+ gspca_dev->last_packet_type = DISCARD_PACKET;
+ return;
+ }
if ((data[6] & 0x0f) != sd->quality)
set_dqt(gspca_dev, data[6] & 0x0f);
gspca_frame_add(gspca_dev, FIRST_PACKET,
@@ -4671,7 +4680,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
gspca_dev->last_packet_type = DISCARD_PACKET;
break;
case 0xcc:
- if (data[1] != 0xff || data[2] != 0xd8)
+ if (len >= 3 && (data[1] != 0xff || data[2] != 0xd8))
gspca_frame_add(gspca_dev, INTER_PACKET,
data + 1, len - 1);
else
@@ -4737,7 +4746,7 @@ static void sd_dq_callback(struct gspca_dev *gspca_dev)
(gspca_dev->usb_buf[26] << 8) + gspca_dev->usb_buf[25] +
(gspca_dev->usb_buf[29] << 8) + gspca_dev->usb_buf[28])
/ 8;
- if (gspca_dev->width == 640)
+ if (gspca_dev->pixfmt.width == 640)
luma /= 4;
reg_w(gspca_dev, 0x7d, 0x00);
diff --git a/drivers/media/usb/gspca/tv8532.c b/drivers/media/usb/gspca/tv8532.c
index 8591324a53e..d497ba38af0 100644
--- a/drivers/media/usb/gspca/tv8532.c
+++ b/drivers/media/usb/gspca/tv8532.c
@@ -268,7 +268,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
packet_type0 = packet_type1 = INTER_PACKET;
if (gspca_dev->empty_packet) {
gspca_dev->empty_packet = 0;
- sd->packet = gspca_dev->height / 2;
+ sd->packet = gspca_dev->pixfmt.height / 2;
packet_type0 = FIRST_PACKET;
} else if (sd->packet == 0)
return; /* 2 more lines in 352x288 ! */
@@ -284,9 +284,10 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
* - 4 bytes
*/
gspca_frame_add(gspca_dev, packet_type0,
- data + 2, gspca_dev->width);
+ data + 2, gspca_dev->pixfmt.width);
gspca_frame_add(gspca_dev, packet_type1,
- data + gspca_dev->width + 5, gspca_dev->width);
+ data + gspca_dev->pixfmt.width + 5,
+ gspca_dev->pixfmt.width);
}
static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
diff --git a/drivers/media/usb/gspca/vicam.c b/drivers/media/usb/gspca/vicam.c
index a2275cfe0b8..103f6c4236b 100644
--- a/drivers/media/usb/gspca/vicam.c
+++ b/drivers/media/usb/gspca/vicam.c
@@ -121,13 +121,13 @@ static int vicam_read_frame(struct gspca_dev *gspca_dev, u8 *data, int size)
memset(req_data, 0, 16);
req_data[0] = gain;
- if (gspca_dev->width == 256)
+ if (gspca_dev->pixfmt.width == 256)
req_data[1] |= 0x01; /* low nibble x-scale */
- if (gspca_dev->height <= 122) {
+ if (gspca_dev->pixfmt.height <= 122) {
req_data[1] |= 0x10; /* high nibble y-scale */
- unscaled_height = gspca_dev->height * 2;
+ unscaled_height = gspca_dev->pixfmt.height * 2;
} else
- unscaled_height = gspca_dev->height;
+ unscaled_height = gspca_dev->pixfmt.height;
req_data[2] = 0x90; /* unknown, does not seem to do anything */
if (unscaled_height <= 200)
req_data[3] = 0x06; /* vend? */
diff --git a/drivers/media/usb/gspca/w996Xcf.c b/drivers/media/usb/gspca/w996Xcf.c
index 2165da0c7ce..fb9fe2ef3a6 100644
--- a/drivers/media/usb/gspca/w996Xcf.c
+++ b/drivers/media/usb/gspca/w996Xcf.c
@@ -430,11 +430,11 @@ static void w9968cf_set_crop_window(struct sd *sd)
#define SC(x) ((x) << 10)
/* Scaling factors */
- fw = SC(sd->gspca_dev.width) / max_width;
- fh = SC(sd->gspca_dev.height) / max_height;
+ fw = SC(sd->gspca_dev.pixfmt.width) / max_width;
+ fh = SC(sd->gspca_dev.pixfmt.height) / max_height;
- cw = (fw >= fh) ? max_width : SC(sd->gspca_dev.width) / fh;
- ch = (fw >= fh) ? SC(sd->gspca_dev.height) / fw : max_height;
+ cw = (fw >= fh) ? max_width : SC(sd->gspca_dev.pixfmt.width) / fh;
+ ch = (fw >= fh) ? SC(sd->gspca_dev.pixfmt.height) / fw : max_height;
sd->sensor_width = max_width;
sd->sensor_height = max_height;
@@ -454,34 +454,34 @@ static void w9968cf_mode_init_regs(struct sd *sd)
w9968cf_set_crop_window(sd);
- reg_w(sd, 0x14, sd->gspca_dev.width);
- reg_w(sd, 0x15, sd->gspca_dev.height);
+ reg_w(sd, 0x14, sd->gspca_dev.pixfmt.width);
+ reg_w(sd, 0x15, sd->gspca_dev.pixfmt.height);
/* JPEG width & height */
- reg_w(sd, 0x30, sd->gspca_dev.width);
- reg_w(sd, 0x31, sd->gspca_dev.height);
+ reg_w(sd, 0x30, sd->gspca_dev.pixfmt.width);
+ reg_w(sd, 0x31, sd->gspca_dev.pixfmt.height);
/* Y & UV frame buffer strides (in WORD) */
if (w9968cf_vga_mode[sd->gspca_dev.curr_mode].pixelformat ==
V4L2_PIX_FMT_JPEG) {
- reg_w(sd, 0x2c, sd->gspca_dev.width / 2);
- reg_w(sd, 0x2d, sd->gspca_dev.width / 4);
+ reg_w(sd, 0x2c, sd->gspca_dev.pixfmt.width / 2);
+ reg_w(sd, 0x2d, sd->gspca_dev.pixfmt.width / 4);
} else
- reg_w(sd, 0x2c, sd->gspca_dev.width);
+ reg_w(sd, 0x2c, sd->gspca_dev.pixfmt.width);
reg_w(sd, 0x00, 0xbf17); /* reset everything */
reg_w(sd, 0x00, 0xbf10); /* normal operation */
/* Transfer size in WORDS (for UYVY format only) */
- val = sd->gspca_dev.width * sd->gspca_dev.height;
+ val = sd->gspca_dev.pixfmt.width * sd->gspca_dev.pixfmt.height;
reg_w(sd, 0x3d, val & 0xffff); /* low bits */
reg_w(sd, 0x3e, val >> 16); /* high bits */
if (w9968cf_vga_mode[sd->gspca_dev.curr_mode].pixelformat ==
V4L2_PIX_FMT_JPEG) {
/* We may get called multiple times (usb isoc bw negotiat.) */
- jpeg_define(sd->jpeg_hdr, sd->gspca_dev.height,
- sd->gspca_dev.width, 0x22); /* JPEG 420 */
+ jpeg_define(sd->jpeg_hdr, sd->gspca_dev.pixfmt.height,
+ sd->gspca_dev.pixfmt.width, 0x22); /* JPEG 420 */
jpeg_set_qual(sd->jpeg_hdr, v4l2_ctrl_g_ctrl(sd->jpegqual));
w9968cf_upload_quantizationtables(sd);
v4l2_ctrl_grab(sd->jpegqual, true);
diff --git a/drivers/media/usb/gspca/xirlink_cit.c b/drivers/media/usb/gspca/xirlink_cit.c
index 7eaf64eb867..a41aa7817c5 100644
--- a/drivers/media/usb/gspca/xirlink_cit.c
+++ b/drivers/media/usb/gspca/xirlink_cit.c
@@ -1471,14 +1471,14 @@ static int cit_get_clock_div(struct gspca_dev *gspca_dev)
while (clock_div > 3 &&
1000 * packet_size >
- gspca_dev->width * gspca_dev->height *
+ gspca_dev->pixfmt.width * gspca_dev->pixfmt.height *
fps[clock_div - 1] * 3 / 2)
clock_div--;
PDEBUG(D_PROBE,
"PacketSize: %d, res: %dx%d -> using clockdiv: %d (%d fps)",
- packet_size, gspca_dev->width, gspca_dev->height, clock_div,
- fps[clock_div]);
+ packet_size, gspca_dev->pixfmt.width, gspca_dev->pixfmt.height,
+ clock_div, fps[clock_div]);
return clock_div;
}
@@ -1502,7 +1502,7 @@ static int cit_start_model0(struct gspca_dev *gspca_dev)
cit_write_reg(gspca_dev, 0x0002, 0x0426);
cit_write_reg(gspca_dev, 0x0014, 0x0427);
- switch (gspca_dev->width) {
+ switch (gspca_dev->pixfmt.width) {
case 160: /* 160x120 */
cit_write_reg(gspca_dev, 0x0004, 0x010b);
cit_write_reg(gspca_dev, 0x0001, 0x010a);
@@ -1643,7 +1643,7 @@ static int cit_start_model1(struct gspca_dev *gspca_dev)
cit_write_reg(gspca_dev, 0x00, 0x0101);
cit_write_reg(gspca_dev, 0x00, 0x010a);
- switch (gspca_dev->width) {
+ switch (gspca_dev->pixfmt.width) {
case 128: /* 128x96 */
cit_write_reg(gspca_dev, 0x80, 0x0103);
cit_write_reg(gspca_dev, 0x60, 0x0105);
@@ -1700,7 +1700,7 @@ static int cit_start_model1(struct gspca_dev *gspca_dev)
}
/* Assorted init */
- switch (gspca_dev->width) {
+ switch (gspca_dev->pixfmt.width) {
case 128: /* 128x96 */
cit_Packet_Format1(gspca_dev, 0x2b, 0x1e);
cit_write_reg(gspca_dev, 0xc9, 0x0119); /* Same everywhere */
@@ -1753,7 +1753,7 @@ static int cit_start_model2(struct gspca_dev *gspca_dev)
cit_write_reg(gspca_dev, 0x0000, 0x0108);
cit_write_reg(gspca_dev, 0x0001, 0x0133);
cit_write_reg(gspca_dev, 0x0001, 0x0102);
- switch (gspca_dev->width) {
+ switch (gspca_dev->pixfmt.width) {
case 176: /* 176x144 */
cit_write_reg(gspca_dev, 0x002c, 0x0103); /* All except 320x240 */
cit_write_reg(gspca_dev, 0x0000, 0x0104); /* Same */
@@ -1792,7 +1792,7 @@ static int cit_start_model2(struct gspca_dev *gspca_dev)
cit_write_reg(gspca_dev, 0x0000, 0x0100); /* LED on */
- switch (gspca_dev->width) {
+ switch (gspca_dev->pixfmt.width) {
case 176: /* 176x144 */
cit_write_reg(gspca_dev, 0x0050, 0x0111);
cit_write_reg(gspca_dev, 0x00d0, 0x0111);
@@ -1840,7 +1840,7 @@ static int cit_start_model2(struct gspca_dev *gspca_dev)
* Magic control of CMOS sensor. Only lower values like
* 0-3 work, and picture shifts left or right. Don't change.
*/
- switch (gspca_dev->width) {
+ switch (gspca_dev->pixfmt.width) {
case 176: /* 176x144 */
cit_model2_Packet1(gspca_dev, 0x0014, 0x0002);
cit_model2_Packet1(gspca_dev, 0x0016, 0x0002); /* Horizontal shift */
@@ -1899,7 +1899,7 @@ static int cit_start_model2(struct gspca_dev *gspca_dev)
* does not allow arbitrary values and apparently is a bit mask, to
* be activated only at appropriate time. Don't change it randomly!
*/
- switch (gspca_dev->width) {
+ switch (gspca_dev->pixfmt.width) {
case 176: /* 176x144 */
cit_model2_Packet1(gspca_dev, 0x0026, 0x00c2);
break;
@@ -2023,7 +2023,7 @@ static int cit_start_model3(struct gspca_dev *gspca_dev)
cit_model3_Packet1(gspca_dev, 0x009e, 0x0096);
cit_model3_Packet1(gspca_dev, 0x009f, 0x000a);
- switch (gspca_dev->width) {
+ switch (gspca_dev->pixfmt.width) {
case 160:
cit_write_reg(gspca_dev, 0x0000, 0x0101); /* Same on 160x120, 320x240 */
cit_write_reg(gspca_dev, 0x00a0, 0x0103); /* Same on 160x120, 320x240 */
@@ -2134,7 +2134,7 @@ static int cit_start_model3(struct gspca_dev *gspca_dev)
like with the IBM netcam pro). */
cit_write_reg(gspca_dev, clock_div, 0x0111); /* Clock Divider */
- switch (gspca_dev->width) {
+ switch (gspca_dev->pixfmt.width) {
case 160:
cit_model3_Packet1(gspca_dev, 0x001f, 0x0000); /* Same */
cit_model3_Packet1(gspca_dev, 0x0039, 0x001f); /* Same */
@@ -2211,7 +2211,7 @@ static int cit_start_model4(struct gspca_dev *gspca_dev)
cit_write_reg(gspca_dev, 0xfffa, 0x0124);
cit_model4_Packet1(gspca_dev, 0x0034, 0x0000);
- switch (gspca_dev->width) {
+ switch (gspca_dev->pixfmt.width) {
case 128: /* 128x96 */
cit_write_reg(gspca_dev, 0x0070, 0x0119);
cit_write_reg(gspca_dev, 0x00d0, 0x0111);
@@ -2531,7 +2531,7 @@ static int cit_start_ibm_netcam_pro(struct gspca_dev *gspca_dev)
cit_write_reg(gspca_dev, 0x00fc, 0x012b); /* Same */
cit_write_reg(gspca_dev, 0x0022, 0x012a); /* Same */
- switch (gspca_dev->width) {
+ switch (gspca_dev->pixfmt.width) {
case 160: /* 160x120 */
cit_write_reg(gspca_dev, 0x0024, 0x010b);
cit_write_reg(gspca_dev, 0x0089, 0x0119);
@@ -2635,7 +2635,7 @@ static int sd_isoc_init(struct gspca_dev *gspca_dev)
struct usb_host_interface *alt;
int max_packet_size;
- switch (gspca_dev->width) {
+ switch (gspca_dev->pixfmt.width) {
case 160:
max_packet_size = 450;
break;
@@ -2659,7 +2659,7 @@ static int sd_isoc_nego(struct gspca_dev *gspca_dev)
int ret, packet_size, min_packet_size;
struct usb_host_interface *alt;
- switch (gspca_dev->width) {
+ switch (gspca_dev->pixfmt.width) {
case 160:
min_packet_size = 200;
break;
@@ -2780,7 +2780,7 @@ static u8 *cit_find_sof(struct gspca_dev *gspca_dev, u8 *data, int len)
case CIT_MODEL1:
case CIT_MODEL3:
case CIT_IBM_NETCAM_PRO:
- switch (gspca_dev->width) {
+ switch (gspca_dev->pixfmt.width) {
case 160: /* 160x120 */
byte3 = 0x02;
byte4 = 0x0a;
@@ -2864,20 +2864,16 @@ static u8 *cit_find_sof(struct gspca_dev *gspca_dev, u8 *data, int len)
if (data[i] == 0xff) {
if (i >= 4)
PDEBUG(D_FRAM,
- "header found at offset: %d: %02x %02x 00 %02x %02x %02x\n",
+ "header found at offset: %d: %02x %02x 00 %3ph\n",
i - 1,
data[i - 4],
data[i - 3],
- data[i],
- data[i + 1],
- data[i + 2]);
+ &data[i]);
else
PDEBUG(D_FRAM,
- "header found at offset: %d: 00 %02x %02x %02x\n",
+ "header found at offset: %d: 00 %3ph\n",
i - 1,
- data[i],
- data[i + 1],
- data[i + 2]);
+ &data[i]);
return data + i + (sd->sof_len - 1);
}
break;
diff --git a/drivers/media/usb/gspca/zc3xx.c b/drivers/media/usb/gspca/zc3xx.c
index cbfc2f92142..d3e1b6d8bf4 100644
--- a/drivers/media/usb/gspca/zc3xx.c
+++ b/drivers/media/usb/gspca/zc3xx.c
@@ -6700,7 +6700,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
};
/* create the JPEG header */
- jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
+ jpeg_define(sd->jpeg_hdr, gspca_dev->pixfmt.height,
+ gspca_dev->pixfmt.width,
0x21); /* JPEG 422 */
mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
@@ -6904,7 +6905,7 @@ static int sd_get_jcomp(struct gspca_dev *gspca_dev,
#if IS_ENABLED(CONFIG_INPUT)
static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
u8 *data, /* interrupt packet data */
- int len) /* interrput packet length */
+ int len) /* interrupt packet length */
{
if (len == 8 && data[4] == 1) {
input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
diff --git a/drivers/media/usb/hdpvr/hdpvr-core.c b/drivers/media/usb/hdpvr/hdpvr-core.c
index 6e5070774dc..c5638964c3f 100644
--- a/drivers/media/usb/hdpvr/hdpvr-core.c
+++ b/drivers/media/usb/hdpvr/hdpvr-core.c
@@ -78,7 +78,8 @@ void hdpvr_delete(struct hdpvr_device *dev)
static void challenge(u8 *bytes)
{
- u64 *i64P, tmp64;
+ __le64 *i64P;
+ u64 tmp64;
uint i, idx;
for (idx = 0; idx < 32; ++idx) {
@@ -106,10 +107,10 @@ static void challenge(u8 *bytes)
for (i = 0; i < 3; i++)
bytes[1] *= bytes[6] + 1;
for (i = 0; i < 3; i++) {
- i64P = (u64 *)bytes;
+ i64P = (__le64 *)bytes;
tmp64 = le64_to_cpup(i64P);
- tmp64 <<= bytes[7] & 0x0f;
- *i64P += cpu_to_le64(tmp64);
+ tmp64 = tmp64 + (tmp64 << (bytes[7] & 0x0f));
+ *i64P = cpu_to_le64(tmp64);
}
break;
}
@@ -197,7 +198,6 @@ static int device_authorization(struct hdpvr_device *dev)
hex_dump_to_buffer(response, 8, 16, 1, print_buf, 5*buf_size+1, 0);
v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, " response: %s\n",
print_buf);
- kfree(print_buf);
#endif
msleep(100);
@@ -213,6 +213,9 @@ static int device_authorization(struct hdpvr_device *dev)
retval = ret != 8;
unlock:
mutex_unlock(&dev->usbc_mutex);
+#ifdef HDPVR_DEBUG
+ kfree(print_buf);
+#endif
return retval;
}
@@ -301,8 +304,6 @@ static int hdpvr_probe(struct usb_interface *interface,
goto error;
}
- dev->workqueue = 0;
-
/* init video transfer queues first of all */
/* to prevent oops in hdpvr_delete() on error paths */
INIT_LIST_HEAD(&dev->free_buff_list);
diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c
index 0500c4175d5..6bce01a674f 100644
--- a/drivers/media/usb/hdpvr/hdpvr-video.c
+++ b/drivers/media/usb/hdpvr/hdpvr-video.c
@@ -82,7 +82,7 @@ static void hdpvr_read_bulk_callback(struct urb *urb)
}
/*=========================================================================*/
-/* bufffer bits */
+/* buffer bits */
/* function expects dev->io_mutex to be hold by caller */
int hdpvr_cancel_queue(struct hdpvr_device *dev)
@@ -926,7 +926,7 @@ static int hdpvr_s_ctrl(struct v4l2_ctrl *ctrl)
case V4L2_CID_MPEG_AUDIO_ENCODING:
if (dev->flags & HDPVR_FLAG_AC3_CAP) {
opt->audio_codec = ctrl->val;
- return hdpvr_set_audio(dev, opt->audio_input,
+ return hdpvr_set_audio(dev, opt->audio_input + 1,
opt->audio_codec);
}
return 0;
@@ -1198,7 +1198,7 @@ int hdpvr_register_videodev(struct hdpvr_device *dev, struct device *parent,
v4l2_ctrl_new_std_menu(hdl, &hdpvr_ctrl_ops,
V4L2_CID_MPEG_AUDIO_ENCODING,
ac3 ? V4L2_MPEG_AUDIO_ENCODING_AC3 : V4L2_MPEG_AUDIO_ENCODING_AAC,
- 0x7, V4L2_MPEG_AUDIO_ENCODING_AAC);
+ 0x7, ac3 ? dev->options.audio_codec : V4L2_MPEG_AUDIO_ENCODING_AAC);
v4l2_ctrl_new_std_menu(hdl, &hdpvr_ctrl_ops,
V4L2_CID_MPEG_VIDEO_ENCODING,
V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC, 0x3,
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c
index c4d51d78f83..9623b621821 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c
@@ -2868,7 +2868,7 @@ static void pvr2_subdev_set_control(struct pvr2_hdw *hdw, int id,
pvr2_subdev_set_control(hdw, id, #lab, (hdw)->lab##_val); \
}
-v4l2_std_id pvr2_hdw_get_detected_std(struct pvr2_hdw *hdw)
+static v4l2_std_id pvr2_hdw_get_detected_std(struct pvr2_hdw *hdw)
{
v4l2_std_id std;
std = (v4l2_std_id)hdw->std_mask_avail;
@@ -2910,7 +2910,7 @@ static void pvr2_subdev_update(struct pvr2_hdw *hdw)
v4l2_std_id vs;
vs = hdw->std_mask_cur;
v4l2_device_call_all(&hdw->v4l2_dev, 0,
- core, s_std, vs);
+ video, s_std, vs);
pvr2_hdw_cx25840_vbi_hack(hdw);
}
hdw->tuner_signal_stale = !0;
diff --git a/drivers/media/usb/pwc/pwc-if.c b/drivers/media/usb/pwc/pwc-if.c
index 77bbf788965..a73b0bced96 100644
--- a/drivers/media/usb/pwc/pwc-if.c
+++ b/drivers/media/usb/pwc/pwc-if.c
@@ -614,17 +614,20 @@ static int buffer_prepare(struct vb2_buffer *vb)
return 0;
}
-static int buffer_finish(struct vb2_buffer *vb)
+static void buffer_finish(struct vb2_buffer *vb)
{
struct pwc_device *pdev = vb2_get_drv_priv(vb->vb2_queue);
struct pwc_frame_buf *buf = container_of(vb, struct pwc_frame_buf, vb);
- /*
- * Application has called dqbuf and is getting back a buffer we've
- * filled, take the pwc data we've stored in buf->data and decompress
- * it into a usable format, storing the result in the vb2_buffer
- */
- return pwc_decompress(pdev, buf);
+ if (vb->state == VB2_BUF_STATE_DONE) {
+ /*
+ * Application has called dqbuf and is getting back a buffer
+ * we've filled, take the pwc data we've stored in buf->data
+ * and decompress it into a usable format, storing the result
+ * in the vb2_buffer.
+ */
+ pwc_decompress(pdev, buf);
+ }
}
static void buffer_cleanup(struct vb2_buffer *vb)
@@ -678,12 +681,11 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count)
return r;
}
-static int stop_streaming(struct vb2_queue *vq)
+static void stop_streaming(struct vb2_queue *vq)
{
struct pwc_device *pdev = vb2_get_drv_priv(vq);
- if (mutex_lock_interruptible(&pdev->v4l2_lock))
- return -ERESTARTSYS;
+ mutex_lock(&pdev->v4l2_lock);
if (pdev->udev) {
pwc_set_leds(pdev, 0, 0);
pwc_camera_power(pdev, 0);
@@ -692,8 +694,6 @@ static int stop_streaming(struct vb2_queue *vq)
pwc_cleanup_queued_bufs(pdev);
mutex_unlock(&pdev->v4l2_lock);
-
- return 0;
}
static struct vb2_ops pwc_vb_queue_ops = {
@@ -1001,7 +1001,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
pdev->vb_queue.buf_struct_size = sizeof(struct pwc_frame_buf);
pdev->vb_queue.ops = &pwc_vb_queue_ops;
pdev->vb_queue.mem_ops = &vb2_vmalloc_memops;
- pdev->vb_queue.timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ pdev->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
rc = vb2_queue_init(&pdev->vb_queue);
if (rc < 0) {
PWC_ERROR("Oops, could not initialize vb2 queue.\n");
@@ -1039,7 +1039,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
/* Set the leds off */
pwc_set_leds(pdev, 0, 0);
- /* Setup intial videomode */
+ /* Setup initial videomode */
rc = pwc_set_video_mode(pdev, MAX_WIDTH, MAX_HEIGHT,
V4L2_PIX_FMT_YUV420, 30, &compression, 1);
if (rc)
@@ -1078,7 +1078,6 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
/* register webcam snapshot button input device */
pdev->button_dev = input_allocate_device();
if (!pdev->button_dev) {
- PWC_ERROR("Err, insufficient memory for webcam snapshot button device.");
rc = -ENOMEM;
goto err_video_unreg;
}
diff --git a/drivers/media/usb/s2255/Kconfig b/drivers/media/usb/s2255/Kconfig
index 7e8ee1f864a..8c3fceef9a0 100644
--- a/drivers/media/usb/s2255/Kconfig
+++ b/drivers/media/usb/s2255/Kconfig
@@ -1,7 +1,7 @@
config USB_S2255
tristate "USB Sensoray 2255 video capture device"
depends on VIDEO_V4L2
- select VIDEOBUF_VMALLOC
+ select VIDEOBUF2_VMALLOC
default n
help
Say Y here if you want support for the Sensoray 2255 USB device.
diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c
index 6bc9b8e19e2..a44466bc7b8 100644
--- a/drivers/media/usb/s2255/s2255drv.c
+++ b/drivers/media/usb/s2255/s2255drv.c
@@ -1,7 +1,7 @@
/*
* s2255drv.c - a driver for the Sensoray 2255 USB video capture device
*
- * Copyright (C) 2007-2013 by Sensoray Company Inc.
+ * Copyright (C) 2007-2014 by Sensoray Company Inc.
* Dean Anderson
*
* Some video buffer code based on vivi driver:
@@ -45,14 +45,14 @@
#include <linux/mm.h>
#include <linux/vmalloc.h>
#include <linux/usb.h>
-#include <media/videobuf-vmalloc.h>
+#include <media/videobuf2-vmalloc.h>
#include <media/v4l2-common.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-event.h>
-#define S2255_VERSION "1.23.1"
+#define S2255_VERSION "1.25.1"
#define FIRMWARE_FILE_NAME "f2255usb.bin"
/* default JPEG quality */
@@ -69,7 +69,7 @@
#define S2255_DSP_BOOTTIME 800
/* maximum time to wait for firmware to load (ms) */
#define S2255_LOAD_TIMEOUT (5000 + S2255_DSP_BOOTTIME)
-#define S2255_DEF_BUFS 16
+#define S2255_MIN_BUFS 2
#define S2255_SETMODE_TIMEOUT 500
#define S2255_VIDSTATUS_TIMEOUT 350
#define S2255_MARKER_FRAME cpu_to_le32(0x2255DA4AL)
@@ -178,11 +178,6 @@ struct s2255_bufferi {
DEF_FDEC, DEF_BRIGHT, DEF_CONTRAST, DEF_SATURATION, \
DEF_HUE, 0, DEF_USB_BLOCK, 0}
-struct s2255_dmaqueue {
- struct list_head active;
- struct s2255_dev *dev;
-};
-
/* for firmware loading, fw_state */
#define S2255_FW_NOTLOADED 0
#define S2255_FW_LOADED_DSPWAIT 1
@@ -217,12 +212,14 @@ struct s2255_pipeinfo {
struct s2255_fmt; /*forward declaration */
struct s2255_dev;
-struct s2255_channel {
+/* 2255 video channel */
+struct s2255_vc {
+ struct s2255_dev *dev;
struct video_device vdev;
struct v4l2_ctrl_handler hdl;
struct v4l2_ctrl *jpegqual_ctrl;
int resources;
- struct s2255_dmaqueue vidq;
+ struct list_head buf_list;
struct s2255_bufferi buffer;
struct s2255_mode mode;
v4l2_std_id std;
@@ -232,8 +229,6 @@ struct s2255_channel {
struct v4l2_captureparm cap_parm;
int cur_frame;
int last_frame;
-
- int b_acquire;
/* allocated image size */
unsigned long req_image_size;
/* received packet size */
@@ -252,17 +247,22 @@ struct s2255_channel {
int vidstatus_ready;
unsigned int width;
unsigned int height;
+ enum v4l2_field field;
const struct s2255_fmt *fmt;
int idx; /* channel number on device, 0-3 */
+ struct vb2_queue vb_vidq;
+ struct mutex vb_lock; /* streaming lock */
+ spinlock_t qlock;
};
struct s2255_dev {
- struct s2255_channel channel[MAX_CHANNELS];
- struct v4l2_device v4l2_dev;
+ struct s2255_vc vc[MAX_CHANNELS];
+ struct v4l2_device v4l2_dev;
atomic_t num_channels;
int frames;
struct mutex lock; /* channels[].vdev.lock */
+ struct mutex cmdlock; /* protects cmdbuf */
struct usb_device *udev;
struct usb_interface *interface;
u8 read_endpoint;
@@ -272,10 +272,11 @@ struct s2255_dev {
u32 cc; /* current channel */
int frame_ready;
int chn_ready;
- spinlock_t slock;
/* dsp firmware version (f2255usb.bin) */
int dsp_fw_ver;
u16 pid; /* product id */
+#define S2255_CMDBUF_SIZE 512
+ __le32 *cmdbuf;
};
static inline struct s2255_dev *to_s2255_dev(struct v4l2_device *v4l2_dev)
@@ -292,19 +293,10 @@ struct s2255_fmt {
/* buffer for one video frame */
struct s2255_buffer {
/* common v4l buffer stuff -- must be first */
- struct videobuf_buffer vb;
- const struct s2255_fmt *fmt;
+ struct vb2_buffer vb;
+ struct list_head list;
};
-struct s2255_fh {
- /* this must be the first field in this struct */
- struct v4l2_fh fh;
- struct s2255_dev *dev;
- struct videobuf_queue vb_vidq;
- enum v4l2_buf_type type;
- struct s2255_channel *channel;
- int resources;
-};
/* current cypress EEPROM firmware version */
#define S2255_CUR_USB_FWVER ((3 << 8) | 12)
@@ -352,15 +344,14 @@ struct s2255_fh {
static unsigned long G_chnmap[MAX_CHANNELS] = {3, 2, 1, 0};
static int debug;
-static int *s2255_debug = &debug;
static int s2255_start_readpipe(struct s2255_dev *dev);
static void s2255_stop_readpipe(struct s2255_dev *dev);
-static int s2255_start_acquire(struct s2255_channel *channel);
-static int s2255_stop_acquire(struct s2255_channel *channel);
-static void s2255_fillbuff(struct s2255_channel *chn, struct s2255_buffer *buf,
+static int s2255_start_acquire(struct s2255_vc *vc);
+static int s2255_stop_acquire(struct s2255_vc *vc);
+static void s2255_fillbuff(struct s2255_vc *vc, struct s2255_buffer *buf,
int jpgsize);
-static int s2255_set_mode(struct s2255_channel *chan, struct s2255_mode *mode);
+static int s2255_set_mode(struct s2255_vc *vc, struct s2255_mode *mode);
static int s2255_board_shutdown(struct s2255_dev *dev);
static void s2255_fwload_start(struct s2255_dev *dev, int reset);
static void s2255_destroy(struct s2255_dev *dev);
@@ -373,19 +364,11 @@ static long s2255_vendor_req(struct s2255_dev *dev, unsigned char req,
#define s2255_dev_err(dev, fmt, arg...) \
dev_err(dev, S2255_DRIVER_NAME " - " fmt, ##arg)
-#define dprintk(level, fmt, arg...) \
- do { \
- if (*s2255_debug >= (level)) { \
- printk(KERN_DEBUG S2255_DRIVER_NAME \
- ": " fmt, ##arg); \
- } \
- } while (0)
+#define dprintk(dev, level, fmt, arg...) \
+ v4l2_dbg(level, debug, &dev->v4l2_dev, fmt, ## arg)
static struct usb_driver s2255_driver;
-/* Declare static vars that will be used as parameters */
-static unsigned int vid_limit = 16; /* Video memory limit, in Mb */
-
/* start video number */
static int video_nr = -1; /* /dev/videoN, -1 for autodetect */
@@ -394,8 +377,6 @@ static int jpeg_enable = 1;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Debug level(0-100) default 0");
-module_param(vid_limit, int, 0644);
-MODULE_PARM_DESC(vid_limit, "video memory limit(Mb)");
module_param(video_nr, int, 0644);
MODULE_PARM_DESC(video_nr, "start video minor(-1 default autodetect)");
module_param(jpeg_enable, int, 0644);
@@ -444,27 +425,27 @@ static const struct s2255_fmt formats[] = {
}
};
-static int norm_maxw(struct s2255_channel *channel)
+static int norm_maxw(struct s2255_vc *vc)
{
- return (channel->std & V4L2_STD_525_60) ?
+ return (vc->std & V4L2_STD_525_60) ?
LINE_SZ_4CIFS_NTSC : LINE_SZ_4CIFS_PAL;
}
-static int norm_maxh(struct s2255_channel *channel)
+static int norm_maxh(struct s2255_vc *vc)
{
- return (channel->std & V4L2_STD_525_60) ?
+ return (vc->std & V4L2_STD_525_60) ?
(NUM_LINES_1CIFS_NTSC * 2) : (NUM_LINES_1CIFS_PAL * 2);
}
-static int norm_minw(struct s2255_channel *channel)
+static int norm_minw(struct s2255_vc *vc)
{
- return (channel->std & V4L2_STD_525_60) ?
+ return (vc->std & V4L2_STD_525_60) ?
LINE_SZ_1CIFS_NTSC : LINE_SZ_1CIFS_PAL;
}
-static int norm_minh(struct s2255_channel *channel)
+static int norm_minh(struct s2255_vc *vc)
{
- return (channel->std & V4L2_STD_525_60) ?
+ return (vc->std & V4L2_STD_525_60) ?
(NUM_LINES_1CIFS_NTSC) : (NUM_LINES_1CIFS_PAL);
}
@@ -498,7 +479,7 @@ static void planar422p_to_yuv_packed(const unsigned char *in,
static void s2255_reset_dsppower(struct s2255_dev *dev)
{
s2255_vendor_req(dev, 0x40, 0x0000, 0x0001, NULL, 0, 1);
- msleep(10);
+ msleep(20);
s2255_vendor_req(dev, 0x50, 0x0000, 0x0000, NULL, 0, 1);
msleep(600);
s2255_vendor_req(dev, 0x10, 0x0000, 0x0000, NULL, 0, 1);
@@ -510,9 +491,8 @@ static void s2255_reset_dsppower(struct s2255_dev *dev)
static void s2255_timer(unsigned long user_data)
{
struct s2255_fw *data = (struct s2255_fw *)user_data;
- dprintk(100, "%s\n", __func__);
if (usb_submit_urb(data->fw_urb, GFP_ATOMIC) < 0) {
- printk(KERN_ERR "s2255: can't submit urb\n");
+ pr_err("s2255: can't submit urb\n");
atomic_set(&data->fw_state, S2255_FW_FAILED);
/* wake up anything waiting for the firmware */
wake_up(&data->wait_fw);
@@ -532,7 +512,6 @@ static void s2255_fwchunk_complete(struct urb *urb)
struct s2255_fw *data = urb->context;
struct usb_device *udev = urb->dev;
int len;
- dprintk(100, "%s: udev %p urb %p", __func__, udev, urb);
if (urb->status) {
dev_err(&udev->dev, "URB failed with status %d\n", urb->status);
atomic_set(&data->fw_state, S2255_FW_FAILED);
@@ -559,9 +538,6 @@ static void s2255_fwchunk_complete(struct urb *urb)
if (len < CHUNK_SIZE)
memset(data->pfw_data, 0, CHUNK_SIZE);
- dprintk(100, "completed len %d, loaded %d \n", len,
- data->fw_loaded);
-
memcpy(data->pfw_data,
(char *) data->fw->data + data->fw_loaded, len);
@@ -576,36 +552,32 @@ static void s2255_fwchunk_complete(struct urb *urb)
return;
}
data->fw_loaded += len;
- } else {
+ } else
atomic_set(&data->fw_state, S2255_FW_LOADED_DSPWAIT);
- dprintk(100, "%s: firmware upload complete\n", __func__);
- }
return;
}
-static int s2255_got_frame(struct s2255_channel *channel, int jpgsize)
+static int s2255_got_frame(struct s2255_vc *vc, int jpgsize)
{
- struct s2255_dmaqueue *dma_q = &channel->vidq;
struct s2255_buffer *buf;
- struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
+ struct s2255_dev *dev = to_s2255_dev(vc->vdev.v4l2_dev);
unsigned long flags = 0;
int rc = 0;
- spin_lock_irqsave(&dev->slock, flags);
- if (list_empty(&dma_q->active)) {
- dprintk(1, "No active queue to serve\n");
+ spin_lock_irqsave(&vc->qlock, flags);
+ if (list_empty(&vc->buf_list)) {
+ dprintk(dev, 1, "No active queue to serve\n");
rc = -1;
goto unlock;
}
- buf = list_entry(dma_q->active.next,
- struct s2255_buffer, vb.queue);
- list_del(&buf->vb.queue);
- v4l2_get_timestamp(&buf->vb.ts);
- s2255_fillbuff(channel, buf, jpgsize);
- wake_up(&buf->vb.done);
- dprintk(2, "%s: [buf/i] [%p/%d]\n", __func__, buf, buf->vb.i);
+ buf = list_entry(vc->buf_list.next,
+ struct s2255_buffer, list);
+ list_del(&buf->list);
+ v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
+ s2255_fillbuff(vc, buf, jpgsize);
+ dprintk(dev, 2, "%s: [buf] [%p]\n", __func__, buf);
unlock:
- spin_unlock_irqrestore(&dev->slock, flags);
+ spin_unlock_irqrestore(&vc->qlock, flags);
return rc;
}
@@ -615,9 +587,9 @@ static const struct s2255_fmt *format_by_fourcc(int fourcc)
for (i = 0; i < ARRAY_SIZE(formats); i++) {
if (-1 == formats[i].fourcc)
continue;
- if (!jpeg_enable && ((formats[i].fourcc == V4L2_PIX_FMT_JPEG) ||
- (formats[i].fourcc == V4L2_PIX_FMT_MJPEG)))
- continue;
+ if (!jpeg_enable && ((formats[i].fourcc == V4L2_PIX_FMT_JPEG) ||
+ (formats[i].fourcc == V4L2_PIX_FMT_MJPEG)))
+ continue;
if (formats[i].fourcc == fourcc)
return formats + i;
}
@@ -632,56 +604,56 @@ static const struct s2255_fmt *format_by_fourcc(int fourcc)
* http://v4l.videotechnology.com/
*
*/
-static void s2255_fillbuff(struct s2255_channel *channel,
+static void s2255_fillbuff(struct s2255_vc *vc,
struct s2255_buffer *buf, int jpgsize)
{
int pos = 0;
const char *tmpbuf;
- char *vbuf = videobuf_to_vmalloc(&buf->vb);
+ char *vbuf = vb2_plane_vaddr(&buf->vb, 0);
unsigned long last_frame;
+ struct s2255_dev *dev = vc->dev;
if (!vbuf)
return;
- last_frame = channel->last_frame;
+ last_frame = vc->last_frame;
if (last_frame != -1) {
tmpbuf =
- (const char *)channel->buffer.frame[last_frame].lpvbits;
- switch (buf->fmt->fourcc) {
+ (const char *)vc->buffer.frame[last_frame].lpvbits;
+ switch (vc->fmt->fourcc) {
case V4L2_PIX_FMT_YUYV:
case V4L2_PIX_FMT_UYVY:
planar422p_to_yuv_packed((const unsigned char *)tmpbuf,
- vbuf, buf->vb.width,
- buf->vb.height,
- buf->fmt->fourcc);
+ vbuf, vc->width,
+ vc->height,
+ vc->fmt->fourcc);
break;
case V4L2_PIX_FMT_GREY:
- memcpy(vbuf, tmpbuf, buf->vb.width * buf->vb.height);
+ memcpy(vbuf, tmpbuf, vc->width * vc->height);
break;
case V4L2_PIX_FMT_JPEG:
case V4L2_PIX_FMT_MJPEG:
- buf->vb.size = jpgsize;
- memcpy(vbuf, tmpbuf, buf->vb.size);
+ buf->vb.v4l2_buf.length = jpgsize;
+ memcpy(vbuf, tmpbuf, jpgsize);
break;
case V4L2_PIX_FMT_YUV422P:
memcpy(vbuf, tmpbuf,
- buf->vb.width * buf->vb.height * 2);
+ vc->width * vc->height * 2);
break;
default:
- printk(KERN_DEBUG "s2255: unknown format?\n");
+ pr_info("s2255: unknown format?\n");
}
- channel->last_frame = -1;
+ vc->last_frame = -1;
} else {
- printk(KERN_ERR "s2255: =======no frame\n");
+ pr_err("s2255: =======no frame\n");
return;
-
}
- dprintk(2, "s2255fill at : Buffer 0x%08lx size= %d\n",
+ dprintk(dev, 2, "s2255fill at : Buffer 0x%08lx size= %d\n",
(unsigned long)vbuf, pos);
/* tell v4l buffer was filled */
-
- buf->vb.field_count = channel->frame_count * 2;
- v4l2_get_timestamp(&buf->vb.ts);
- buf->vb.state = VIDEOBUF_DONE;
+ buf->vb.v4l2_buf.field = vc->field;
+ buf->vb.v4l2_buf.sequence = vc->frame_count;
+ v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
}
@@ -689,144 +661,82 @@ static void s2255_fillbuff(struct s2255_channel *channel,
Videobuf operations
------------------------------------------------------------------*/
-static int buffer_setup(struct videobuf_queue *vq, unsigned int *count,
- unsigned int *size)
+static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
+ unsigned int *nbuffers, unsigned int *nplanes,
+ unsigned int sizes[], void *alloc_ctxs[])
{
- struct s2255_fh *fh = vq->priv_data;
- struct s2255_channel *channel = fh->channel;
- *size = channel->width * channel->height * (channel->fmt->depth >> 3);
-
- if (0 == *count)
- *count = S2255_DEF_BUFS;
-
- if (*size * *count > vid_limit * 1024 * 1024)
- *count = (vid_limit * 1024 * 1024) / *size;
-
+ struct s2255_vc *vc = vb2_get_drv_priv(vq);
+ if (*nbuffers < S2255_MIN_BUFS)
+ *nbuffers = S2255_MIN_BUFS;
+ *nplanes = 1;
+ sizes[0] = vc->width * vc->height * (vc->fmt->depth >> 3);
return 0;
}
-static void free_buffer(struct videobuf_queue *vq, struct s2255_buffer *buf)
-{
- dprintk(4, "%s\n", __func__);
-
- videobuf_vmalloc_free(&buf->vb);
- buf->vb.state = VIDEOBUF_NEEDS_INIT;
-}
-
-static int buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
- enum v4l2_field field)
+static int buffer_prepare(struct vb2_buffer *vb)
{
- struct s2255_fh *fh = vq->priv_data;
- struct s2255_channel *channel = fh->channel;
+ struct s2255_vc *vc = vb2_get_drv_priv(vb->vb2_queue);
struct s2255_buffer *buf = container_of(vb, struct s2255_buffer, vb);
- int rc;
- int w = channel->width;
- int h = channel->height;
- dprintk(4, "%s, field=%d\n", __func__, field);
- if (channel->fmt == NULL)
+ int w = vc->width;
+ int h = vc->height;
+ unsigned long size;
+
+ dprintk(vc->dev, 4, "%s\n", __func__);
+ if (vc->fmt == NULL)
return -EINVAL;
- if ((w < norm_minw(channel)) ||
- (w > norm_maxw(channel)) ||
- (h < norm_minh(channel)) ||
- (h > norm_maxh(channel))) {
- dprintk(4, "invalid buffer prepare\n");
+ if ((w < norm_minw(vc)) ||
+ (w > norm_maxw(vc)) ||
+ (h < norm_minh(vc)) ||
+ (h > norm_maxh(vc))) {
+ dprintk(vc->dev, 4, "invalid buffer prepare\n");
return -EINVAL;
}
- buf->vb.size = w * h * (channel->fmt->depth >> 3);
- if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) {
- dprintk(4, "invalid buffer prepare\n");
+ size = w * h * (vc->fmt->depth >> 3);
+ if (vb2_plane_size(vb, 0) < size) {
+ dprintk(vc->dev, 4, "invalid buffer prepare\n");
return -EINVAL;
}
- buf->fmt = channel->fmt;
- buf->vb.width = w;
- buf->vb.height = h;
- buf->vb.field = field;
-
- if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
- rc = videobuf_iolock(vq, &buf->vb, NULL);
- if (rc < 0)
- goto fail;
- }
-
- buf->vb.state = VIDEOBUF_PREPARED;
+ vb2_set_plane_payload(&buf->vb, 0, size);
return 0;
-fail:
- free_buffer(vq, buf);
- return rc;
}
-static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+static void buffer_queue(struct vb2_buffer *vb)
{
struct s2255_buffer *buf = container_of(vb, struct s2255_buffer, vb);
- struct s2255_fh *fh = vq->priv_data;
- struct s2255_channel *channel = fh->channel;
- struct s2255_dmaqueue *vidq = &channel->vidq;
- dprintk(1, "%s\n", __func__);
- buf->vb.state = VIDEOBUF_QUEUED;
- list_add_tail(&buf->vb.queue, &vidq->active);
+ struct s2255_vc *vc = vb2_get_drv_priv(vb->vb2_queue);
+ unsigned long flags = 0;
+ dprintk(vc->dev, 1, "%s\n", __func__);
+ spin_lock_irqsave(&vc->qlock, flags);
+ list_add_tail(&buf->list, &vc->buf_list);
+ spin_unlock_irqrestore(&vc->qlock, flags);
}
-static void buffer_release(struct videobuf_queue *vq,
- struct videobuf_buffer *vb)
-{
- struct s2255_buffer *buf = container_of(vb, struct s2255_buffer, vb);
- struct s2255_fh *fh = vq->priv_data;
- dprintk(4, "%s %d\n", __func__, fh->channel->idx);
- free_buffer(vq, buf);
-}
+static int start_streaming(struct vb2_queue *vq, unsigned int count);
+static void stop_streaming(struct vb2_queue *vq);
-static struct videobuf_queue_ops s2255_video_qops = {
- .buf_setup = buffer_setup,
+static struct vb2_ops s2255_video_qops = {
+ .queue_setup = queue_setup,
.buf_prepare = buffer_prepare,
.buf_queue = buffer_queue,
- .buf_release = buffer_release,
+ .start_streaming = start_streaming,
+ .stop_streaming = stop_streaming,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
};
-
-static int res_get(struct s2255_fh *fh)
-{
- struct s2255_channel *channel = fh->channel;
- /* is it free? */
- if (channel->resources)
- return 0; /* no, someone else uses it */
- /* it's free, grab it */
- channel->resources = 1;
- fh->resources = 1;
- dprintk(1, "s2255: res: get\n");
- return 1;
-}
-
-static int res_locked(struct s2255_fh *fh)
-{
- return fh->channel->resources;
-}
-
-static int res_check(struct s2255_fh *fh)
-{
- return fh->resources;
-}
-
-
-static void res_free(struct s2255_fh *fh)
-{
- struct s2255_channel *channel = fh->channel;
- channel->resources = 0;
- fh->resources = 0;
- dprintk(1, "res: put\n");
-}
-
static int vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
- struct s2255_fh *fh = file->private_data;
- struct s2255_dev *dev = fh->dev;
+ struct s2255_vc *vc = video_drvdata(file);
+ struct s2255_dev *dev = vc->dev;
strlcpy(cap->driver, "s2255", sizeof(cap->driver));
strlcpy(cap->card, "s2255", sizeof(cap->card));
usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
- cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+ cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
+ V4L2_CAP_READWRITE;
cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -841,7 +751,6 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
if (!jpeg_enable && ((formats[index].fourcc == V4L2_PIX_FMT_JPEG) ||
(formats[index].fourcc == V4L2_PIX_FMT_MJPEG)))
return -EINVAL;
- dprintk(4, "name %s\n", formats[index].name);
strlcpy(f->description, formats[index].name, sizeof(f->description));
f->pixelformat = formats[index].fourcc;
return 0;
@@ -850,19 +759,18 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct s2255_fh *fh = priv;
- struct s2255_channel *channel = fh->channel;
- int is_ntsc = channel->std & V4L2_STD_525_60;
+ struct s2255_vc *vc = video_drvdata(file);
+ int is_ntsc = vc->std & V4L2_STD_525_60;
- f->fmt.pix.width = channel->width;
- f->fmt.pix.height = channel->height;
+ f->fmt.pix.width = vc->width;
+ f->fmt.pix.height = vc->height;
if (f->fmt.pix.height >=
(is_ntsc ? NUM_LINES_1CIFS_NTSC : NUM_LINES_1CIFS_PAL) * 2)
f->fmt.pix.field = V4L2_FIELD_INTERLACED;
else
f->fmt.pix.field = V4L2_FIELD_TOP;
- f->fmt.pix.pixelformat = channel->fmt->fourcc;
- f->fmt.pix.bytesperline = f->fmt.pix.width * (channel->fmt->depth >> 3);
+ f->fmt.pix.pixelformat = vc->fmt->fourcc;
+ f->fmt.pix.bytesperline = f->fmt.pix.width * (vc->fmt->depth >> 3);
f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
f->fmt.pix.priv = 0;
@@ -874,9 +782,8 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
{
const struct s2255_fmt *fmt;
enum v4l2_field field;
- struct s2255_fh *fh = priv;
- struct s2255_channel *channel = fh->channel;
- int is_ntsc = channel->std & V4L2_STD_525_60;
+ struct s2255_vc *vc = video_drvdata(file);
+ int is_ntsc = vc->std & V4L2_STD_525_60;
fmt = format_by_fourcc(f->fmt.pix.pixelformat);
@@ -885,7 +792,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
field = f->fmt.pix.field;
- dprintk(50, "%s NTSC: %d suggested width: %d, height: %d\n",
+ dprintk(vc->dev, 50, "%s NTSC: %d suggested width: %d, height: %d\n",
__func__, is_ntsc, f->fmt.pix.width, f->fmt.pix.height);
if (is_ntsc) {
/* NTSC */
@@ -927,7 +834,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
f->fmt.pix.priv = 0;
- dprintk(50, "%s: set width %d height %d field %d\n", __func__,
+ dprintk(vc->dev, 50, "%s: set width %d height %d field %d\n", __func__,
f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field);
return 0;
}
@@ -935,14 +842,13 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct s2255_fh *fh = priv;
- struct s2255_channel *channel = fh->channel;
+ struct s2255_vc *vc = video_drvdata(file);
const struct s2255_fmt *fmt;
- struct videobuf_queue *q = &fh->vb_vidq;
+ struct vb2_queue *q = &vc->vb_vidq;
struct s2255_mode mode;
int ret;
- ret = vidioc_try_fmt_vid_cap(file, fh, f);
+ ret = vidioc_try_fmt_vid_cap(file, vc, f);
if (ret < 0)
return ret;
@@ -952,28 +858,19 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
if (fmt == NULL)
return -EINVAL;
- mutex_lock(&q->vb_lock);
-
- if (videobuf_queue_is_busy(&fh->vb_vidq)) {
- dprintk(1, "queue busy\n");
- ret = -EBUSY;
- goto out_s_fmt;
+ if (vb2_is_busy(q)) {
+ dprintk(vc->dev, 1, "queue busy\n");
+ return -EBUSY;
}
- if (res_locked(fh)) {
- dprintk(1, "%s: channel busy\n", __func__);
- ret = -EBUSY;
- goto out_s_fmt;
- }
- mode = channel->mode;
- channel->fmt = fmt;
- channel->width = f->fmt.pix.width;
- channel->height = f->fmt.pix.height;
- fh->vb_vidq.field = f->fmt.pix.field;
- fh->type = f->type;
- if (channel->width > norm_minw(channel)) {
- if (channel->height > norm_minh(channel)) {
- if (channel->cap_parm.capturemode &
+ mode = vc->mode;
+ vc->fmt = fmt;
+ vc->width = f->fmt.pix.width;
+ vc->height = f->fmt.pix.height;
+ vc->field = f->fmt.pix.field;
+ if (vc->width > norm_minw(vc)) {
+ if (vc->height > norm_minh(vc)) {
+ if (vc->cap_parm.capturemode &
V4L2_MODE_HIGHQUALITY)
mode.scale = SCALE_4CIFSI;
else
@@ -985,7 +882,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
mode.scale = SCALE_1CIFS;
}
/* color mode */
- switch (channel->fmt->fourcc) {
+ switch (vc->fmt->fourcc) {
case V4L2_PIX_FMT_GREY:
mode.color &= ~MASK_COLOR;
mode.color |= COLOR_Y8;
@@ -994,7 +891,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
case V4L2_PIX_FMT_MJPEG:
mode.color &= ~MASK_COLOR;
mode.color |= COLOR_JPG;
- mode.color |= (channel->jpegqual << 8);
+ mode.color |= (vc->jpegqual << 8);
break;
case V4L2_PIX_FMT_YUV422P:
mode.color &= ~MASK_COLOR;
@@ -1007,52 +904,17 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
mode.color |= COLOR_YUVPK;
break;
}
- if ((mode.color & MASK_COLOR) != (channel->mode.color & MASK_COLOR))
+ if ((mode.color & MASK_COLOR) != (vc->mode.color & MASK_COLOR))
mode.restart = 1;
- else if (mode.scale != channel->mode.scale)
+ else if (mode.scale != vc->mode.scale)
mode.restart = 1;
- else if (mode.format != channel->mode.format)
+ else if (mode.format != vc->mode.format)
mode.restart = 1;
- channel->mode = mode;
- (void) s2255_set_mode(channel, &mode);
- ret = 0;
-out_s_fmt:
- mutex_unlock(&q->vb_lock);
- return ret;
-}
-
-static int vidioc_reqbufs(struct file *file, void *priv,
- struct v4l2_requestbuffers *p)
-{
- int rc;
- struct s2255_fh *fh = priv;
- rc = videobuf_reqbufs(&fh->vb_vidq, p);
- return rc;
-}
-
-static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
- int rc;
- struct s2255_fh *fh = priv;
- rc = videobuf_querybuf(&fh->vb_vidq, p);
- return rc;
-}
-
-static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
- int rc;
- struct s2255_fh *fh = priv;
- rc = videobuf_qbuf(&fh->vb_vidq, p);
- return rc;
+ vc->mode = mode;
+ (void) s2255_set_mode(vc, &mode);
+ return 0;
}
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
- int rc;
- struct s2255_fh *fh = priv;
- rc = videobuf_dqbuf(&fh->vb_vidq, p, file->f_flags & O_NONBLOCK);
- return rc;
-}
/* write to the configuration pipe, synchronously */
static int s2255_write_config(struct usb_device *udev, unsigned char *pbuf,
@@ -1150,201 +1012,165 @@ static void s2255_print_cfg(struct s2255_dev *sdev, struct s2255_mode *mode)
* When the restart parameter is set, we sleep for ONE frame to allow the
* DSP time to get the new frame
*/
-static int s2255_set_mode(struct s2255_channel *channel,
+static int s2255_set_mode(struct s2255_vc *vc,
struct s2255_mode *mode)
{
int res;
- __le32 *buffer;
unsigned long chn_rev;
- struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
+ struct s2255_dev *dev = to_s2255_dev(vc->vdev.v4l2_dev);
int i;
+ __le32 *buffer = dev->cmdbuf;
- chn_rev = G_chnmap[channel->idx];
- dprintk(3, "%s channel: %d\n", __func__, channel->idx);
+ mutex_lock(&dev->cmdlock);
+ chn_rev = G_chnmap[vc->idx];
+ dprintk(dev, 3, "%s channel: %d\n", __func__, vc->idx);
/* if JPEG, set the quality */
if ((mode->color & MASK_COLOR) == COLOR_JPG) {
mode->color &= ~MASK_COLOR;
mode->color |= COLOR_JPG;
mode->color &= ~MASK_JPG_QUALITY;
- mode->color |= (channel->jpegqual << 8);
+ mode->color |= (vc->jpegqual << 8);
}
/* save the mode */
- channel->mode = *mode;
- channel->req_image_size = get_transfer_size(mode);
- dprintk(1, "%s: reqsize %ld\n", __func__, channel->req_image_size);
- buffer = kzalloc(512, GFP_KERNEL);
- if (buffer == NULL) {
- dev_err(&dev->udev->dev, "out of mem\n");
- return -ENOMEM;
- }
+ vc->mode = *mode;
+ vc->req_image_size = get_transfer_size(mode);
+ dprintk(dev, 1, "%s: reqsize %ld\n", __func__, vc->req_image_size);
/* set the mode */
buffer[0] = IN_DATA_TOKEN;
buffer[1] = (__le32) cpu_to_le32(chn_rev);
buffer[2] = CMD_SET_MODE;
for (i = 0; i < sizeof(struct s2255_mode) / sizeof(u32); i++)
- buffer[3 + i] = cpu_to_le32(((u32 *)&channel->mode)[i]);
- channel->setmode_ready = 0;
+ buffer[3 + i] = cpu_to_le32(((u32 *)&vc->mode)[i]);
+ vc->setmode_ready = 0;
res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512);
if (debug)
s2255_print_cfg(dev, mode);
- kfree(buffer);
/* wait at least 3 frames before continuing */
if (mode->restart) {
- wait_event_timeout(channel->wait_setmode,
- (channel->setmode_ready != 0),
+ wait_event_timeout(vc->wait_setmode,
+ (vc->setmode_ready != 0),
msecs_to_jiffies(S2255_SETMODE_TIMEOUT));
- if (channel->setmode_ready != 1) {
- printk(KERN_DEBUG "s2255: no set mode response\n");
+ if (vc->setmode_ready != 1) {
+ dprintk(dev, 0, "s2255: no set mode response\n");
res = -EFAULT;
}
}
/* clear the restart flag */
- channel->mode.restart = 0;
- dprintk(1, "%s chn %d, result: %d\n", __func__, channel->idx, res);
+ vc->mode.restart = 0;
+ dprintk(dev, 1, "%s chn %d, result: %d\n", __func__, vc->idx, res);
+ mutex_unlock(&dev->cmdlock);
return res;
}
-static int s2255_cmd_status(struct s2255_channel *channel, u32 *pstatus)
+static int s2255_cmd_status(struct s2255_vc *vc, u32 *pstatus)
{
int res;
- __le32 *buffer;
u32 chn_rev;
- struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
- chn_rev = G_chnmap[channel->idx];
- dprintk(4, "%s chan %d\n", __func__, channel->idx);
- buffer = kzalloc(512, GFP_KERNEL);
- if (buffer == NULL) {
- dev_err(&dev->udev->dev, "out of mem\n");
- return -ENOMEM;
- }
+ struct s2255_dev *dev = to_s2255_dev(vc->vdev.v4l2_dev);
+ __le32 *buffer = dev->cmdbuf;
+
+ mutex_lock(&dev->cmdlock);
+ chn_rev = G_chnmap[vc->idx];
+ dprintk(dev, 4, "%s chan %d\n", __func__, vc->idx);
/* form the get vid status command */
buffer[0] = IN_DATA_TOKEN;
buffer[1] = (__le32) cpu_to_le32(chn_rev);
buffer[2] = CMD_STATUS;
*pstatus = 0;
- channel->vidstatus_ready = 0;
+ vc->vidstatus_ready = 0;
res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512);
- kfree(buffer);
- wait_event_timeout(channel->wait_vidstatus,
- (channel->vidstatus_ready != 0),
+ wait_event_timeout(vc->wait_vidstatus,
+ (vc->vidstatus_ready != 0),
msecs_to_jiffies(S2255_VIDSTATUS_TIMEOUT));
- if (channel->vidstatus_ready != 1) {
- printk(KERN_DEBUG "s2255: no vidstatus response\n");
+ if (vc->vidstatus_ready != 1) {
+ dprintk(dev, 0, "s2255: no vidstatus response\n");
res = -EFAULT;
}
- *pstatus = channel->vidstatus;
- dprintk(4, "%s, vid status %d\n", __func__, *pstatus);
+ *pstatus = vc->vidstatus;
+ dprintk(dev, 4, "%s, vid status %d\n", __func__, *pstatus);
+ mutex_unlock(&dev->cmdlock);
return res;
}
-static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+static int start_streaming(struct vb2_queue *vq, unsigned int count)
{
- int res;
- struct s2255_fh *fh = priv;
- struct s2255_dev *dev = fh->dev;
- struct s2255_channel *channel = fh->channel;
+ struct s2255_vc *vc = vb2_get_drv_priv(vq);
int j;
- dprintk(4, "%s\n", __func__);
- if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- dev_err(&dev->udev->dev, "invalid fh type0\n");
- return -EINVAL;
- }
- if (i != fh->type) {
- dev_err(&dev->udev->dev, "invalid fh type1\n");
- return -EINVAL;
- }
- if (!res_get(fh)) {
- s2255_dev_err(&dev->udev->dev, "stream busy\n");
- return -EBUSY;
- }
- channel->last_frame = -1;
- channel->bad_payload = 0;
- channel->cur_frame = 0;
- channel->frame_count = 0;
+ vc->last_frame = -1;
+ vc->bad_payload = 0;
+ vc->cur_frame = 0;
+ vc->frame_count = 0;
for (j = 0; j < SYS_FRAMES; j++) {
- channel->buffer.frame[j].ulState = S2255_READ_IDLE;
- channel->buffer.frame[j].cur_size = 0;
+ vc->buffer.frame[j].ulState = S2255_READ_IDLE;
+ vc->buffer.frame[j].cur_size = 0;
}
- res = videobuf_streamon(&fh->vb_vidq);
- if (res == 0) {
- s2255_start_acquire(channel);
- channel->b_acquire = 1;
- } else
- res_free(fh);
-
- return res;
+ return s2255_start_acquire(vc);
}
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+/* abort streaming and wait for last buffer */
+static void stop_streaming(struct vb2_queue *vq)
{
- struct s2255_fh *fh = priv;
- dprintk(4, "%s\n, channel: %d", __func__, fh->channel->idx);
- if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- printk(KERN_ERR "invalid fh type0\n");
- return -EINVAL;
+ struct s2255_vc *vc = vb2_get_drv_priv(vq);
+ struct s2255_buffer *buf, *node;
+ unsigned long flags;
+ (void) s2255_stop_acquire(vc);
+ spin_lock_irqsave(&vc->qlock, flags);
+ list_for_each_entry_safe(buf, node, &vc->buf_list, list) {
+ list_del(&buf->list);
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+ dprintk(vc->dev, 2, "[%p/%d] done\n",
+ buf, buf->vb.v4l2_buf.index);
}
- if (i != fh->type) {
- printk(KERN_ERR "invalid type i\n");
- return -EINVAL;
- }
- s2255_stop_acquire(fh->channel);
- videobuf_streamoff(&fh->vb_vidq);
- res_free(fh);
- return 0;
+ spin_unlock_irqrestore(&vc->qlock, flags);
}
static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id i)
{
- struct s2255_fh *fh = priv;
+ struct s2255_vc *vc = video_drvdata(file);
struct s2255_mode mode;
- struct videobuf_queue *q = &fh->vb_vidq;
- struct s2255_channel *channel = fh->channel;
- int ret = 0;
+ struct vb2_queue *q = &vc->vb_vidq;
- mutex_lock(&q->vb_lock);
- if (res_locked(fh)) {
- dprintk(1, "can't change standard after started\n");
- ret = -EBUSY;
- goto out_s_std;
- }
- mode = fh->channel->mode;
+ /*
+ * Changing the standard implies a format change, which is not allowed
+ * while buffers for use with streaming have already been allocated.
+ */
+ if (vb2_is_busy(q))
+ return -EBUSY;
+
+ mode = vc->mode;
if (i & V4L2_STD_525_60) {
- dprintk(4, "%s 60 Hz\n", __func__);
+ dprintk(vc->dev, 4, "%s 60 Hz\n", __func__);
/* if changing format, reset frame decimation/intervals */
if (mode.format != FORMAT_NTSC) {
mode.restart = 1;
mode.format = FORMAT_NTSC;
mode.fdec = FDEC_1;
- channel->width = LINE_SZ_4CIFS_NTSC;
- channel->height = NUM_LINES_4CIFS_NTSC * 2;
+ vc->width = LINE_SZ_4CIFS_NTSC;
+ vc->height = NUM_LINES_4CIFS_NTSC * 2;
}
} else if (i & V4L2_STD_625_50) {
- dprintk(4, "%s 50 Hz\n", __func__);
+ dprintk(vc->dev, 4, "%s 50 Hz\n", __func__);
if (mode.format != FORMAT_PAL) {
mode.restart = 1;
mode.format = FORMAT_PAL;
mode.fdec = FDEC_1;
- channel->width = LINE_SZ_4CIFS_PAL;
- channel->height = NUM_LINES_4CIFS_PAL * 2;
+ vc->width = LINE_SZ_4CIFS_PAL;
+ vc->height = NUM_LINES_4CIFS_PAL * 2;
}
- } else {
- ret = -EINVAL;
- goto out_s_std;
- }
- fh->channel->std = i;
+ } else
+ return -EINVAL;
+ vc->std = i;
if (mode.restart)
- s2255_set_mode(fh->channel, &mode);
-out_s_std:
- mutex_unlock(&q->vb_lock);
- return ret;
+ s2255_set_mode(vc, &mode);
+ return 0;
}
static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *i)
{
- struct s2255_fh *fh = priv;
+ struct s2255_vc *vc = video_drvdata(file);
- *i = fh->channel->std;
+ *i = vc->std;
return 0;
}
@@ -1358,10 +1184,10 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *i)
static int vidioc_enum_input(struct file *file, void *priv,
struct v4l2_input *inp)
{
- struct s2255_fh *fh = priv;
- struct s2255_dev *dev = fh->dev;
- struct s2255_channel *channel = fh->channel;
+ struct s2255_vc *vc = video_drvdata(file);
+ struct s2255_dev *dev = vc->dev;
u32 status = 0;
+
if (inp->index != 0)
return -EINVAL;
inp->type = V4L2_INPUT_TYPE_CAMERA;
@@ -1369,8 +1195,9 @@ static int vidioc_enum_input(struct file *file, void *priv,
inp->status = 0;
if (dev->dsp_fw_ver >= S2255_MIN_DSP_STATUS) {
int rc;
- rc = s2255_cmd_status(fh->channel, &status);
- dprintk(4, "s2255_cmd_status rc: %d status %x\n", rc, status);
+ rc = s2255_cmd_status(vc, &status);
+ dprintk(dev, 4, "s2255_cmd_status rc: %d status %x\n",
+ rc, status);
if (rc == 0)
inp->status = (status & 0x01) ? 0
: V4L2_IN_ST_NO_SIGNAL;
@@ -1381,7 +1208,7 @@ static int vidioc_enum_input(struct file *file, void *priv,
strlcpy(inp->name, "Composite", sizeof(inp->name));
break;
case 0x2257:
- strlcpy(inp->name, (channel->idx < 2) ? "Composite" : "S-Video",
+ strlcpy(inp->name, (vc->idx < 2) ? "Composite" : "S-Video",
sizeof(inp->name));
break;
}
@@ -1402,13 +1229,10 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
static int s2255_s_ctrl(struct v4l2_ctrl *ctrl)
{
- struct s2255_channel *channel =
- container_of(ctrl->handler, struct s2255_channel, hdl);
+ struct s2255_vc *vc =
+ container_of(ctrl->handler, struct s2255_vc, hdl);
struct s2255_mode mode;
-
- mode = channel->mode;
- dprintk(4, "%s\n", __func__);
-
+ mode = vc->mode;
/* update the mode to the corresponding value */
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
@@ -1428,7 +1252,7 @@ static int s2255_s_ctrl(struct v4l2_ctrl *ctrl)
mode.color |= !ctrl->val << 16;
break;
case V4L2_CID_JPEG_COMPRESSION_QUALITY:
- channel->jpegqual = ctrl->val;
+ vc->jpegqual = ctrl->val;
return 0;
default:
return -EINVAL;
@@ -1438,48 +1262,48 @@ static int s2255_s_ctrl(struct v4l2_ctrl *ctrl)
some V4L programs restart stream unnecessarily
after a s_crtl.
*/
- s2255_set_mode(channel, &mode);
+ s2255_set_mode(vc, &mode);
return 0;
}
static int vidioc_g_jpegcomp(struct file *file, void *priv,
struct v4l2_jpegcompression *jc)
{
- struct s2255_fh *fh = priv;
- struct s2255_channel *channel = fh->channel;
+ struct s2255_vc *vc = video_drvdata(file);
memset(jc, 0, sizeof(*jc));
- jc->quality = channel->jpegqual;
- dprintk(2, "%s: quality %d\n", __func__, jc->quality);
+ jc->quality = vc->jpegqual;
+ dprintk(vc->dev, 2, "%s: quality %d\n", __func__, jc->quality);
return 0;
}
static int vidioc_s_jpegcomp(struct file *file, void *priv,
const struct v4l2_jpegcompression *jc)
{
- struct s2255_fh *fh = priv;
- struct s2255_channel *channel = fh->channel;
+ struct s2255_vc *vc = video_drvdata(file);
+
if (jc->quality < 0 || jc->quality > 100)
return -EINVAL;
- v4l2_ctrl_s_ctrl(channel->jpegqual_ctrl, jc->quality);
- dprintk(2, "%s: quality %d\n", __func__, jc->quality);
+ v4l2_ctrl_s_ctrl(vc->jpegqual_ctrl, jc->quality);
+ dprintk(vc->dev, 2, "%s: quality %d\n", __func__, jc->quality);
return 0;
}
static int vidioc_g_parm(struct file *file, void *priv,
struct v4l2_streamparm *sp)
{
- struct s2255_fh *fh = priv;
__u32 def_num, def_dem;
- struct s2255_channel *channel = fh->channel;
+ struct s2255_vc *vc = video_drvdata(file);
+
if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
sp->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
- sp->parm.capture.capturemode = channel->cap_parm.capturemode;
- def_num = (channel->mode.format == FORMAT_NTSC) ? 1001 : 1000;
- def_dem = (channel->mode.format == FORMAT_NTSC) ? 30000 : 25000;
+ sp->parm.capture.capturemode = vc->cap_parm.capturemode;
+ sp->parm.capture.readbuffers = S2255_MIN_BUFS;
+ def_num = (vc->mode.format == FORMAT_NTSC) ? 1001 : 1000;
+ def_dem = (vc->mode.format == FORMAT_NTSC) ? 30000 : 25000;
sp->parm.capture.timeperframe.denominator = def_dem;
- switch (channel->mode.fdec) {
+ switch (vc->mode.fdec) {
default:
case FDEC_1:
sp->parm.capture.timeperframe.numerator = def_num;
@@ -1494,7 +1318,8 @@ static int vidioc_g_parm(struct file *file, void *priv,
sp->parm.capture.timeperframe.numerator = def_num * 5;
break;
}
- dprintk(4, "%s capture mode, %d timeperframe %d/%d\n", __func__,
+ dprintk(vc->dev, 4, "%s capture mode, %d timeperframe %d/%d\n",
+ __func__,
sp->parm.capture.capturemode,
sp->parm.capture.timeperframe.numerator,
sp->parm.capture.timeperframe.denominator);
@@ -1504,17 +1329,16 @@ static int vidioc_g_parm(struct file *file, void *priv,
static int vidioc_s_parm(struct file *file, void *priv,
struct v4l2_streamparm *sp)
{
- struct s2255_fh *fh = priv;
- struct s2255_channel *channel = fh->channel;
+ struct s2255_vc *vc = video_drvdata(file);
struct s2255_mode mode;
int fdec = FDEC_1;
__u32 def_num, def_dem;
if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
- mode = channel->mode;
+ mode = vc->mode;
/* high quality capture mode requires a stream restart */
- if (channel->cap_parm.capturemode
- != sp->parm.capture.capturemode && res_locked(fh))
+ if ((vc->cap_parm.capturemode != sp->parm.capture.capturemode)
+ && vb2_is_streaming(&vc->vb_vidq))
return -EBUSY;
def_num = (mode.format == FORMAT_NTSC) ? 1001 : 1000;
def_dem = (mode.format == FORMAT_NTSC) ? 30000 : 25000;
@@ -1534,8 +1358,9 @@ static int vidioc_s_parm(struct file *file, void *priv,
}
mode.fdec = fdec;
sp->parm.capture.timeperframe.denominator = def_dem;
- s2255_set_mode(channel, &mode);
- dprintk(4, "%s capture mode, %d timeperframe %d/%d, fdec %d\n",
+ sp->parm.capture.readbuffers = S2255_MIN_BUFS;
+ s2255_set_mode(vc, &mode);
+ dprintk(vc->dev, 4, "%s capture mode, %d timeperframe %d/%d, fdec %d\n",
__func__,
sp->parm.capture.capturemode,
sp->parm.capture.timeperframe.numerator,
@@ -1558,9 +1383,8 @@ static const struct v4l2_frmsize_discrete pal_sizes[] = {
static int vidioc_enum_framesizes(struct file *file, void *priv,
struct v4l2_frmsizeenum *fe)
{
- struct s2255_fh *fh = priv;
- struct s2255_channel *channel = fh->channel;
- int is_ntsc = channel->std & V4L2_STD_525_60;
+ struct s2255_vc *vc = video_drvdata(file);
+ int is_ntsc = vc->std & V4L2_STD_525_60;
const struct s2255_fmt *fmt;
if (fe->index >= NUM_SIZE_ENUMS)
@@ -1577,11 +1401,10 @@ static int vidioc_enum_framesizes(struct file *file, void *priv,
static int vidioc_enum_frameintervals(struct file *file, void *priv,
struct v4l2_frmivalenum *fe)
{
- struct s2255_fh *fh = priv;
- struct s2255_channel *channel = fh->channel;
+ struct s2255_vc *vc = video_drvdata(file);
const struct s2255_fmt *fmt;
const struct v4l2_frmsize_discrete *sizes;
- int is_ntsc = channel->std & V4L2_STD_525_60;
+ int is_ntsc = vc->std & V4L2_STD_525_60;
#define NUM_FRAME_ENUMS 4
int frm_dec[NUM_FRAME_ENUMS] = {1, 2, 3, 5};
int i;
@@ -1604,21 +1427,24 @@ static int vidioc_enum_frameintervals(struct file *file, void *priv,
fe->type = V4L2_FRMIVAL_TYPE_DISCRETE;
fe->discrete.denominator = is_ntsc ? 30000 : 25000;
fe->discrete.numerator = (is_ntsc ? 1001 : 1000) * frm_dec[fe->index];
- dprintk(4, "%s discrete %d/%d\n", __func__, fe->discrete.numerator,
+ dprintk(vc->dev, 4, "%s discrete %d/%d\n", __func__,
+ fe->discrete.numerator,
fe->discrete.denominator);
return 0;
}
-static int __s2255_open(struct file *file)
+static int s2255_open(struct file *file)
{
- struct video_device *vdev = video_devdata(file);
- struct s2255_channel *channel = video_drvdata(file);
- struct s2255_dev *dev = to_s2255_dev(vdev->v4l2_dev);
- struct s2255_fh *fh;
- enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ struct s2255_vc *vc = video_drvdata(file);
+ struct s2255_dev *dev = vc->dev;
int state;
- dprintk(1, "s2255: open called (dev=%s)\n",
- video_device_node_name(vdev));
+ int rc = 0;
+
+ rc = v4l2_fh_open(file);
+ if (rc != 0)
+ return rc;
+
+ dprintk(dev, 1, "s2255: %s\n", __func__);
state = atomic_read(&dev->fw_data->fw_state);
switch (state) {
case S2255_FW_DISCONNECTING:
@@ -1640,7 +1466,7 @@ static int __s2255_open(struct file *file)
case S2255_FW_LOADED_DSPWAIT:
/* give S2255_LOAD_TIMEOUT time for firmware to load in case
driver loaded and then device immediately opened */
- printk(KERN_INFO "%s waiting for firmware load\n", __func__);
+ pr_info("%s waiting for firmware load\n", __func__);
wait_event_timeout(dev->fw_data->wait_fw,
((atomic_read(&dev->fw_data->fw_state)
== S2255_FW_SUCCESS) ||
@@ -1659,16 +1485,15 @@ static int __s2255_open(struct file *file)
case S2255_FW_SUCCESS:
break;
case S2255_FW_FAILED:
- printk(KERN_INFO "2255 firmware load failed.\n");
+ pr_info("2255 firmware load failed.\n");
return -ENODEV;
case S2255_FW_DISCONNECTING:
- printk(KERN_INFO "%s: disconnecting\n", __func__);
+ pr_info("%s: disconnecting\n", __func__);
return -ENODEV;
case S2255_FW_LOADED_DSPWAIT:
case S2255_FW_NOTLOADED:
- printk(KERN_INFO "%s: firmware not loaded yet"
- "please try again later\n",
- __func__);
+ pr_info("%s: firmware not loaded, please retry\n",
+ __func__);
/*
* Timeout on firmware load means device unusable.
* Set firmware failure state.
@@ -1678,75 +1503,25 @@ static int __s2255_open(struct file *file)
S2255_FW_FAILED);
return -EAGAIN;
default:
- printk(KERN_INFO "%s: unknown state\n", __func__);
+ pr_info("%s: unknown state\n", __func__);
return -EFAULT;
}
- /* allocate + initialize per filehandle data */
- fh = kzalloc(sizeof(*fh), GFP_KERNEL);
- if (NULL == fh)
- return -ENOMEM;
- v4l2_fh_init(&fh->fh, vdev);
- v4l2_fh_add(&fh->fh);
- file->private_data = &fh->fh;
- fh->dev = dev;
- fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- fh->channel = channel;
- if (!channel->configured) {
+ if (!vc->configured) {
/* configure channel to default state */
- channel->fmt = &formats[0];
- s2255_set_mode(channel, &channel->mode);
- channel->configured = 1;
- }
- dprintk(1, "%s: dev=%s type=%s\n", __func__,
- video_device_node_name(vdev), v4l2_type_names[type]);
- dprintk(2, "%s: fh=0x%08lx, dev=0x%08lx, vidq=0x%08lx\n", __func__,
- (unsigned long)fh, (unsigned long)dev,
- (unsigned long)&channel->vidq);
- dprintk(4, "%s: list_empty active=%d\n", __func__,
- list_empty(&channel->vidq.active));
- videobuf_queue_vmalloc_init(&fh->vb_vidq, &s2255_video_qops,
- NULL, &dev->slock,
- fh->type,
- V4L2_FIELD_INTERLACED,
- sizeof(struct s2255_buffer),
- fh, vdev->lock);
+ vc->fmt = &formats[0];
+ s2255_set_mode(vc, &vc->mode);
+ vc->configured = 1;
+ }
return 0;
}
-static int s2255_open(struct file *file)
-{
- struct video_device *vdev = video_devdata(file);
- int ret;
-
- if (mutex_lock_interruptible(vdev->lock))
- return -ERESTARTSYS;
- ret = __s2255_open(file);
- mutex_unlock(vdev->lock);
- return ret;
-}
-
-static unsigned int s2255_poll(struct file *file,
- struct poll_table_struct *wait)
-{
- struct s2255_fh *fh = file->private_data;
- struct s2255_dev *dev = fh->dev;
- int rc = v4l2_ctrl_poll(file, wait);
-
- dprintk(100, "%s\n", __func__);
- if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
- return POLLERR;
- mutex_lock(&dev->lock);
- rc |= videobuf_poll_stream(file, &fh->vb_vidq, wait);
- mutex_unlock(&dev->lock);
- return rc;
-}
-
static void s2255_destroy(struct s2255_dev *dev)
{
+ dprintk(dev, 1, "%s", __func__);
/* board shutdown stops the read pipe if it is running */
s2255_board_shutdown(dev);
/* make sure firmware still not trying to load */
- del_timer(&dev->timer); /* only started in .probe and .open */
+ del_timer_sync(&dev->timer); /* only started in .probe and .open */
if (dev->fw_data->fw_urb) {
usb_kill_urb(dev->fw_data->fw_urb);
usb_free_urb(dev->fw_data->fw_urb);
@@ -1760,62 +1535,18 @@ static void s2255_destroy(struct s2255_dev *dev)
mutex_destroy(&dev->lock);
usb_put_dev(dev->udev);
v4l2_device_unregister(&dev->v4l2_dev);
- dprintk(1, "%s", __func__);
+ kfree(dev->cmdbuf);
kfree(dev);
}
-static int s2255_release(struct file *file)
-{
- struct s2255_fh *fh = file->private_data;
- struct s2255_dev *dev = fh->dev;
- struct video_device *vdev = video_devdata(file);
- struct s2255_channel *channel = fh->channel;
- if (!dev)
- return -ENODEV;
- mutex_lock(&dev->lock);
- /* turn off stream */
- if (res_check(fh)) {
- if (channel->b_acquire)
- s2255_stop_acquire(fh->channel);
- videobuf_streamoff(&fh->vb_vidq);
- res_free(fh);
- }
- videobuf_mmap_free(&fh->vb_vidq);
- mutex_unlock(&dev->lock);
- dprintk(1, "%s (dev=%s)\n", __func__, video_device_node_name(vdev));
- v4l2_fh_del(&fh->fh);
- v4l2_fh_exit(&fh->fh);
- kfree(fh);
- return 0;
-}
-
-static int s2255_mmap_v4l(struct file *file, struct vm_area_struct *vma)
-{
- struct s2255_fh *fh = file->private_data;
- struct s2255_dev *dev;
- int ret;
-
- if (!fh)
- return -ENODEV;
- dev = fh->dev;
- dprintk(4, "%s, vma=0x%08lx\n", __func__, (unsigned long)vma);
- if (mutex_lock_interruptible(&dev->lock))
- return -ERESTARTSYS;
- ret = videobuf_mmap_mapper(&fh->vb_vidq, vma);
- mutex_unlock(&dev->lock);
- dprintk(4, "%s vma start=0x%08lx, size=%ld, ret=%d\n", __func__,
- (unsigned long)vma->vm_start,
- (unsigned long)vma->vm_end - (unsigned long)vma->vm_start, ret);
- return ret;
-}
-
static const struct v4l2_file_operations s2255_fops_v4l = {
.owner = THIS_MODULE,
.open = s2255_open,
- .release = s2255_release,
- .poll = s2255_poll,
+ .release = vb2_fop_release,
+ .poll = vb2_fop_poll,
.unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */
- .mmap = s2255_mmap_v4l,
+ .mmap = vb2_fop_mmap,
+ .read = vb2_fop_read,
};
static const struct v4l2_ioctl_ops s2255_ioctl_ops = {
@@ -1824,17 +1555,17 @@ static const struct v4l2_ioctl_ops s2255_ioctl_ops = {
.vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
.vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
- .vidioc_reqbufs = vidioc_reqbufs,
- .vidioc_querybuf = vidioc_querybuf,
- .vidioc_qbuf = vidioc_qbuf,
- .vidioc_dqbuf = vidioc_dqbuf,
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
.vidioc_s_std = vidioc_s_std,
.vidioc_g_std = vidioc_g_std,
.vidioc_enum_input = vidioc_enum_input,
.vidioc_g_input = vidioc_g_input,
.vidioc_s_input = vidioc_s_input,
- .vidioc_streamon = vidioc_streamon,
- .vidioc_streamoff = vidioc_streamoff,
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
.vidioc_s_jpegcomp = vidioc_s_jpegcomp,
.vidioc_g_jpegcomp = vidioc_g_jpegcomp,
.vidioc_s_parm = vidioc_s_parm,
@@ -1849,13 +1580,14 @@ static const struct v4l2_ioctl_ops s2255_ioctl_ops = {
static void s2255_video_device_release(struct video_device *vdev)
{
struct s2255_dev *dev = to_s2255_dev(vdev->v4l2_dev);
- struct s2255_channel *channel =
- container_of(vdev, struct s2255_channel, vdev);
+ struct s2255_vc *vc =
+ container_of(vdev, struct s2255_vc, vdev);
- v4l2_ctrl_handler_free(&channel->hdl);
- dprintk(4, "%s, chnls: %d\n", __func__,
+ dprintk(dev, 4, "%s, chnls: %d\n", __func__,
atomic_read(&dev->num_channels));
+ v4l2_ctrl_handler_free(&vc->hdl);
+
if (atomic_dec_and_test(&dev->num_channels))
s2255_destroy(dev);
return;
@@ -1888,52 +1620,70 @@ static int s2255_probe_v4l(struct s2255_dev *dev)
int ret;
int i;
int cur_nr = video_nr;
- struct s2255_channel *channel;
+ struct s2255_vc *vc;
+ struct vb2_queue *q;
+
ret = v4l2_device_register(&dev->interface->dev, &dev->v4l2_dev);
if (ret)
return ret;
/* initialize all video 4 linux */
/* register 4 video devices */
for (i = 0; i < MAX_CHANNELS; i++) {
- channel = &dev->channel[i];
- INIT_LIST_HEAD(&channel->vidq.active);
+ vc = &dev->vc[i];
+ INIT_LIST_HEAD(&vc->buf_list);
- v4l2_ctrl_handler_init(&channel->hdl, 6);
- v4l2_ctrl_new_std(&channel->hdl, &s2255_ctrl_ops,
+ v4l2_ctrl_handler_init(&vc->hdl, 6);
+ v4l2_ctrl_new_std(&vc->hdl, &s2255_ctrl_ops,
V4L2_CID_BRIGHTNESS, -127, 127, 1, DEF_BRIGHT);
- v4l2_ctrl_new_std(&channel->hdl, &s2255_ctrl_ops,
+ v4l2_ctrl_new_std(&vc->hdl, &s2255_ctrl_ops,
V4L2_CID_CONTRAST, 0, 255, 1, DEF_CONTRAST);
- v4l2_ctrl_new_std(&channel->hdl, &s2255_ctrl_ops,
+ v4l2_ctrl_new_std(&vc->hdl, &s2255_ctrl_ops,
V4L2_CID_SATURATION, 0, 255, 1, DEF_SATURATION);
- v4l2_ctrl_new_std(&channel->hdl, &s2255_ctrl_ops,
+ v4l2_ctrl_new_std(&vc->hdl, &s2255_ctrl_ops,
V4L2_CID_HUE, 0, 255, 1, DEF_HUE);
- channel->jpegqual_ctrl = v4l2_ctrl_new_std(&channel->hdl,
+ vc->jpegqual_ctrl = v4l2_ctrl_new_std(&vc->hdl,
&s2255_ctrl_ops,
V4L2_CID_JPEG_COMPRESSION_QUALITY,
0, 100, 1, S2255_DEF_JPEG_QUAL);
if (dev->dsp_fw_ver >= S2255_MIN_DSP_COLORFILTER &&
- (dev->pid != 0x2257 || channel->idx <= 1))
- v4l2_ctrl_new_custom(&channel->hdl, &color_filter_ctrl, NULL);
- if (channel->hdl.error) {
- ret = channel->hdl.error;
- v4l2_ctrl_handler_free(&channel->hdl);
+ (dev->pid != 0x2257 || vc->idx <= 1))
+ v4l2_ctrl_new_custom(&vc->hdl, &color_filter_ctrl,
+ NULL);
+ if (vc->hdl.error) {
+ ret = vc->hdl.error;
+ v4l2_ctrl_handler_free(&vc->hdl);
dev_err(&dev->udev->dev, "couldn't register control\n");
break;
}
- channel->vidq.dev = dev;
- /* register 4 video devices */
- channel->vdev = template;
- channel->vdev.ctrl_handler = &channel->hdl;
- channel->vdev.lock = &dev->lock;
- channel->vdev.v4l2_dev = &dev->v4l2_dev;
- set_bit(V4L2_FL_USE_FH_PRIO, &channel->vdev.flags);
- video_set_drvdata(&channel->vdev, channel);
+ q = &vc->vb_vidq;
+ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ q->io_modes = VB2_MMAP | VB2_READ | VB2_USERPTR;
+ q->drv_priv = vc;
+ q->lock = &vc->vb_lock;
+ q->buf_struct_size = sizeof(struct s2255_buffer);
+ q->mem_ops = &vb2_vmalloc_memops;
+ q->ops = &s2255_video_qops;
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ ret = vb2_queue_init(q);
+ if (ret != 0) {
+ dev_err(&dev->udev->dev,
+ "%s vb2_queue_init 0x%x\n", __func__, ret);
+ break;
+ }
+ /* register video devices */
+ vc->vdev = template;
+ vc->vdev.queue = q;
+ vc->vdev.ctrl_handler = &vc->hdl;
+ vc->vdev.lock = &dev->lock;
+ vc->vdev.v4l2_dev = &dev->v4l2_dev;
+ set_bit(V4L2_FL_USE_FH_PRIO, &vc->vdev.flags);
+ video_set_drvdata(&vc->vdev, vc);
if (video_nr == -1)
- ret = video_register_device(&channel->vdev,
+ ret = video_register_device(&vc->vdev,
VFL_TYPE_GRABBER,
video_nr);
else
- ret = video_register_device(&channel->vdev,
+ ret = video_register_device(&vc->vdev,
VFL_TYPE_GRABBER,
cur_nr + i);
@@ -1944,18 +1694,18 @@ static int s2255_probe_v4l(struct s2255_dev *dev)
}
atomic_inc(&dev->num_channels);
v4l2_info(&dev->v4l2_dev, "V4L2 device registered as %s\n",
- video_device_node_name(&channel->vdev));
+ video_device_node_name(&vc->vdev));
}
- printk(KERN_INFO "Sensoray 2255 V4L driver Revision: %s\n",
- S2255_VERSION);
+ 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) {
v4l2_device_unregister(&dev->v4l2_dev);
return ret;
}
if (atomic_read(&dev->num_channels) != MAX_CHANNELS)
- printk(KERN_WARNING "s2255: Not all channels available.\n");
+ pr_warn("s2255: Not all channels available.\n");
return 0;
}
@@ -1981,11 +1731,11 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
s32 idx = -1;
struct s2255_framei *frm;
unsigned char *pdata;
- struct s2255_channel *channel;
- dprintk(100, "buffer to user\n");
- channel = &dev->channel[dev->cc];
- idx = channel->cur_frame;
- frm = &channel->buffer.frame[idx];
+ struct s2255_vc *vc;
+ dprintk(dev, 100, "buffer to user\n");
+ vc = &dev->vc[dev->cc];
+ idx = vc->cur_frame;
+ frm = &vc->buffer.frame[idx];
if (frm->ulState == S2255_READ_IDLE) {
int jj;
unsigned int cc;
@@ -1997,28 +1747,27 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
for (jj = 0; jj < (pipe_info->cur_transfer_size - 12); jj++) {
switch (*pdword) {
case S2255_MARKER_FRAME:
- dprintk(4, "found frame marker at offset:"
- " %d [%x %x]\n", jj, pdata[0],
- pdata[1]);
+ dprintk(dev, 4, "marker @ offset: %d [%x %x]\n",
+ jj, pdata[0], pdata[1]);
offset = jj + PREFIX_SIZE;
bframe = 1;
cc = le32_to_cpu(pdword[1]);
if (cc >= MAX_CHANNELS) {
- printk(KERN_ERR
- "bad channel\n");
+ dprintk(dev, 0,
+ "bad channel\n");
return -EINVAL;
}
/* reverse it */
dev->cc = G_chnmap[cc];
- channel = &dev->channel[dev->cc];
+ vc = &dev->vc[dev->cc];
payload = le32_to_cpu(pdword[3]);
- if (payload > channel->req_image_size) {
- channel->bad_payload++;
+ if (payload > vc->req_image_size) {
+ vc->bad_payload++;
/* discard the bad frame */
return -EINVAL;
}
- channel->pkt_size = payload;
- channel->jpg_size = le32_to_cpu(pdword[4]);
+ vc->pkt_size = payload;
+ vc->jpg_size = le32_to_cpu(pdword[4]);
break;
case S2255_MARKER_RESPONSE:
@@ -2029,34 +1778,34 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
cc = G_chnmap[le32_to_cpu(pdword[1])];
if (cc >= MAX_CHANNELS)
break;
- channel = &dev->channel[cc];
+ vc = &dev->vc[cc];
switch (pdword[2]) {
case S2255_RESPONSE_SETMODE:
/* check if channel valid */
/* set mode ready */
- channel->setmode_ready = 1;
- wake_up(&channel->wait_setmode);
- dprintk(5, "setmode ready %d\n", cc);
+ vc->setmode_ready = 1;
+ wake_up(&vc->wait_setmode);
+ dprintk(dev, 5, "setmode rdy %d\n", cc);
break;
case S2255_RESPONSE_FW:
dev->chn_ready |= (1 << cc);
if ((dev->chn_ready & 0x0f) != 0x0f)
break;
/* all channels ready */
- printk(KERN_INFO "s2255: fw loaded\n");
+ pr_info("s2255: fw loaded\n");
atomic_set(&dev->fw_data->fw_state,
S2255_FW_SUCCESS);
wake_up(&dev->fw_data->wait_fw);
break;
case S2255_RESPONSE_STATUS:
- channel->vidstatus = le32_to_cpu(pdword[3]);
- channel->vidstatus_ready = 1;
- wake_up(&channel->wait_vidstatus);
- dprintk(5, "got vidstatus %x chan %d\n",
+ vc->vidstatus = le32_to_cpu(pdword[3]);
+ vc->vidstatus_ready = 1;
+ wake_up(&vc->wait_vidstatus);
+ dprintk(dev, 5, "vstat %x chan %d\n",
le32_to_cpu(pdword[3]), cc);
break;
default:
- printk(KERN_INFO "s2255 unknown resp\n");
+ pr_info("s2255 unknown resp\n");
}
default:
pdata++;
@@ -2068,11 +1817,11 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
if (!bframe)
return -EINVAL;
}
- channel = &dev->channel[dev->cc];
- idx = channel->cur_frame;
- frm = &channel->buffer.frame[idx];
+ vc = &dev->vc[dev->cc];
+ idx = vc->cur_frame;
+ frm = &vc->buffer.frame[idx];
/* search done. now find out if should be acquiring on this channel */
- if (!channel->b_acquire) {
+ if (!vb2_is_streaming(&vc->vb_vidq)) {
/* we found a frame, but this channel is turned off */
frm->ulState = S2255_READ_IDLE;
return -EINVAL;
@@ -2088,7 +1837,7 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
if (frm->lpvbits == NULL) {
- dprintk(1, "s2255 frame buffer == NULL.%p %p %d %d",
+ dprintk(dev, 1, "s2255 frame buffer == NULL.%p %p %d %d",
frm, dev, dev->cc, idx);
return -ENOMEM;
}
@@ -2097,28 +1846,28 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
copy_size = (pipe_info->cur_transfer_size - offset);
- size = channel->pkt_size - PREFIX_SIZE;
+ size = vc->pkt_size - PREFIX_SIZE;
/* sanity check on pdest */
- if ((copy_size + frm->cur_size) < channel->req_image_size)
+ if ((copy_size + frm->cur_size) < vc->req_image_size)
memcpy(pdest, psrc, copy_size);
frm->cur_size += copy_size;
- dprintk(4, "cur_size size %lu size %lu \n", frm->cur_size, size);
+ dprintk(dev, 4, "cur_size: %lu, size: %lu\n", frm->cur_size, size);
if (frm->cur_size >= size) {
- dprintk(2, "****************[%d]Buffer[%d]full*************\n",
+ dprintk(dev, 2, "******[%d]Buffer[%d]full*******\n",
dev->cc, idx);
- channel->last_frame = channel->cur_frame;
- channel->cur_frame++;
+ vc->last_frame = vc->cur_frame;
+ vc->cur_frame++;
/* end of system frame ring buffer, start at zero */
- if ((channel->cur_frame == SYS_FRAMES) ||
- (channel->cur_frame == channel->buffer.dwFrames))
- channel->cur_frame = 0;
+ if ((vc->cur_frame == SYS_FRAMES) ||
+ (vc->cur_frame == vc->buffer.dwFrames))
+ vc->cur_frame = 0;
/* frame ready */
- if (channel->b_acquire)
- s2255_got_frame(channel, channel->jpg_size);
- channel->frame_count++;
+ if (vb2_is_streaming(&vc->vb_vidq))
+ s2255_got_frame(vc, vc->jpg_size);
+ vc->frame_count++;
frm->ulState = S2255_READ_IDLE;
frm->cur_size = 0;
@@ -2131,7 +1880,7 @@ static void s2255_read_video_callback(struct s2255_dev *dev,
struct s2255_pipeinfo *pipe_info)
{
int res;
- dprintk(50, "callback read video \n");
+ dprintk(dev, 50, "callback read video\n");
if (dev->cc >= MAX_CHANNELS) {
dev->cc = 0;
@@ -2141,9 +1890,9 @@ static void s2255_read_video_callback(struct s2255_dev *dev,
/* otherwise copy to the system buffers */
res = save_frame(dev, pipe_info);
if (res != 0)
- dprintk(4, "s2255: read callback failed\n");
+ dprintk(dev, 4, "s2255: read callback failed\n");
- dprintk(50, "callback read video done\n");
+ dprintk(dev, 50, "callback read video done\n");
return;
}
@@ -2181,9 +1930,9 @@ static int s2255_get_fx2fw(struct s2255_dev *dev)
ret = s2255_vendor_req(dev, S2255_VR_FW, 0, 0, transBuffer, 2,
S2255_VR_IN);
if (ret < 0)
- dprintk(2, "get fw error: %x\n", ret);
+ dprintk(dev, 2, "get fw error: %x\n", ret);
fw = transBuffer[0] + (transBuffer[1] << 8);
- dprintk(2, "Get FW %x %x\n", transBuffer[0], transBuffer[1]);
+ dprintk(dev, 2, "Get FW %x %x\n", transBuffer[0], transBuffer[1]);
return fw;
}
@@ -2191,12 +1940,11 @@ static int s2255_get_fx2fw(struct s2255_dev *dev)
* Create the system ring buffer to copy frames into from the
* usb read pipe.
*/
-static int s2255_create_sys_buffers(struct s2255_channel *channel)
+static int s2255_create_sys_buffers(struct s2255_vc *vc)
{
unsigned long i;
unsigned long reqsize;
- dprintk(1, "create sys buffers\n");
- channel->buffer.dwFrames = SYS_FRAMES;
+ vc->buffer.dwFrames = SYS_FRAMES;
/* always allocate maximum size(PAL) for system buffers */
reqsize = SYS_FRAMES_MAXSIZE;
@@ -2205,40 +1953,33 @@ static int s2255_create_sys_buffers(struct s2255_channel *channel)
for (i = 0; i < SYS_FRAMES; i++) {
/* allocate the frames */
- channel->buffer.frame[i].lpvbits = vmalloc(reqsize);
- dprintk(1, "valloc %p chan %d, idx %lu, pdata %p\n",
- &channel->buffer.frame[i], channel->idx, i,
- channel->buffer.frame[i].lpvbits);
- channel->buffer.frame[i].size = reqsize;
- if (channel->buffer.frame[i].lpvbits == NULL) {
- printk(KERN_INFO "out of memory. using less frames\n");
- channel->buffer.dwFrames = i;
+ vc->buffer.frame[i].lpvbits = vmalloc(reqsize);
+ vc->buffer.frame[i].size = reqsize;
+ if (vc->buffer.frame[i].lpvbits == NULL) {
+ pr_info("out of memory. using less frames\n");
+ vc->buffer.dwFrames = i;
break;
}
}
/* make sure internal states are set */
for (i = 0; i < SYS_FRAMES; i++) {
- channel->buffer.frame[i].ulState = 0;
- channel->buffer.frame[i].cur_size = 0;
+ vc->buffer.frame[i].ulState = 0;
+ vc->buffer.frame[i].cur_size = 0;
}
- channel->cur_frame = 0;
- channel->last_frame = -1;
+ vc->cur_frame = 0;
+ vc->last_frame = -1;
return 0;
}
-static int s2255_release_sys_buffers(struct s2255_channel *channel)
+static int s2255_release_sys_buffers(struct s2255_vc *vc)
{
unsigned long i;
- dprintk(1, "release sys buffers\n");
for (i = 0; i < SYS_FRAMES; i++) {
- if (channel->buffer.frame[i].lpvbits) {
- dprintk(1, "vfree %p\n",
- channel->buffer.frame[i].lpvbits);
- vfree(channel->buffer.frame[i].lpvbits);
- }
- channel->buffer.frame[i].lpvbits = NULL;
+ if (vc->buffer.frame[i].lpvbits)
+ vfree(vc->buffer.frame[i].lpvbits);
+ vc->buffer.frame[i].lpvbits = NULL;
}
return 0;
}
@@ -2249,7 +1990,7 @@ static int s2255_board_init(struct s2255_dev *dev)
int fw_ver;
int j;
struct s2255_pipeinfo *pipe = &dev->pipe;
- dprintk(4, "board init: %p", dev);
+ dprintk(dev, 4, "board init: %p", dev);
memset(pipe, 0, sizeof(*pipe));
pipe->dev = dev;
pipe->cur_transfer_size = S2255_USB_XFER_SIZE;
@@ -2258,54 +1999,53 @@ static int s2255_board_init(struct s2255_dev *dev)
pipe->transfer_buffer = kzalloc(pipe->max_transfer_size,
GFP_KERNEL);
if (pipe->transfer_buffer == NULL) {
- dprintk(1, "out of memory!\n");
+ dprintk(dev, 1, "out of memory!\n");
return -ENOMEM;
}
/* query the firmware */
fw_ver = s2255_get_fx2fw(dev);
- printk(KERN_INFO "s2255: usb firmware version %d.%d\n",
- (fw_ver >> 8) & 0xff,
- fw_ver & 0xff);
+ pr_info("s2255: usb firmware version %d.%d\n",
+ (fw_ver >> 8) & 0xff,
+ fw_ver & 0xff);
if (fw_ver < S2255_CUR_USB_FWVER)
- printk(KERN_INFO "s2255: newer USB firmware available\n");
+ pr_info("s2255: newer USB firmware available\n");
for (j = 0; j < MAX_CHANNELS; j++) {
- struct s2255_channel *channel = &dev->channel[j];
- channel->b_acquire = 0;
- channel->mode = mode_def;
+ struct s2255_vc *vc = &dev->vc[j];
+ vc->mode = mode_def;
if (dev->pid == 0x2257 && j > 1)
- channel->mode.color |= (1 << 16);
- channel->jpegqual = S2255_DEF_JPEG_QUAL;
- channel->width = LINE_SZ_4CIFS_NTSC;
- channel->height = NUM_LINES_4CIFS_NTSC * 2;
- channel->std = V4L2_STD_NTSC_M;
- channel->fmt = &formats[0];
- channel->mode.restart = 1;
- channel->req_image_size = get_transfer_size(&mode_def);
- channel->frame_count = 0;
+ vc->mode.color |= (1 << 16);
+ vc->jpegqual = S2255_DEF_JPEG_QUAL;
+ vc->width = LINE_SZ_4CIFS_NTSC;
+ vc->height = NUM_LINES_4CIFS_NTSC * 2;
+ vc->std = V4L2_STD_NTSC_M;
+ vc->fmt = &formats[0];
+ vc->mode.restart = 1;
+ vc->req_image_size = get_transfer_size(&mode_def);
+ vc->frame_count = 0;
/* create the system buffers */
- s2255_create_sys_buffers(channel);
+ s2255_create_sys_buffers(vc);
}
/* start read pipe */
s2255_start_readpipe(dev);
- dprintk(1, "%s: success\n", __func__);
+ dprintk(dev, 1, "%s: success\n", __func__);
return 0;
}
static int s2255_board_shutdown(struct s2255_dev *dev)
{
u32 i;
- dprintk(1, "%s: dev: %p", __func__, dev);
+ dprintk(dev, 1, "%s: dev: %p", __func__, dev);
for (i = 0; i < MAX_CHANNELS; i++) {
- if (dev->channel[i].b_acquire)
- s2255_stop_acquire(&dev->channel[i]);
+ if (vb2_is_streaming(&dev->vc[i].vb_vidq))
+ s2255_stop_acquire(&dev->vc[i]);
}
s2255_stop_readpipe(dev);
for (i = 0; i < MAX_CHANNELS; i++)
- s2255_release_sys_buffers(&dev->channel[i]);
+ s2255_release_sys_buffers(&dev->vc[i]);
/* release transfer buffer */
kfree(dev->pipe.transfer_buffer);
return 0;
@@ -2318,13 +2058,10 @@ static void read_pipe_completion(struct urb *purb)
int status;
int pipe;
pipe_info = purb->context;
- dprintk(100, "%s: urb:%p, status %d\n", __func__, purb,
- purb->status);
if (pipe_info == NULL) {
dev_err(&purb->dev->dev, "no context!\n");
return;
}
-
dev = pipe_info->dev;
if (dev == NULL) {
dev_err(&purb->dev->dev, "no context!\n");
@@ -2333,13 +2070,13 @@ static void read_pipe_completion(struct urb *purb)
status = purb->status;
/* if shutting down, do not resubmit, exit immediately */
if (status == -ESHUTDOWN) {
- dprintk(2, "%s: err shutdown\n", __func__);
+ dprintk(dev, 2, "%s: err shutdown\n", __func__);
pipe_info->err_count++;
return;
}
if (pipe_info->state == 0) {
- dprintk(2, "%s: exiting USB pipe", __func__);
+ dprintk(dev, 2, "%s: exiting USB pipe", __func__);
return;
}
@@ -2347,7 +2084,7 @@ static void read_pipe_completion(struct urb *purb)
s2255_read_video_callback(dev, pipe_info);
else {
pipe_info->err_count++;
- dprintk(1, "%s: failed URB %d\n", __func__, status);
+ dprintk(dev, 1, "%s: failed URB %d\n", __func__, status);
}
pipe = usb_rcvbulkpipe(dev->udev, dev->read_endpoint);
@@ -2359,11 +2096,10 @@ static void read_pipe_completion(struct urb *purb)
read_pipe_completion, pipe_info);
if (pipe_info->state != 0) {
- if (usb_submit_urb(pipe_info->stream_urb, GFP_ATOMIC)) {
+ if (usb_submit_urb(pipe_info->stream_urb, GFP_ATOMIC))
dev_err(&dev->udev->dev, "error submitting urb\n");
- }
} else {
- dprintk(2, "%s :complete state 0\n", __func__);
+ dprintk(dev, 2, "%s :complete state 0\n", __func__);
}
return;
}
@@ -2374,7 +2110,7 @@ static int s2255_start_readpipe(struct s2255_dev *dev)
int retval;
struct s2255_pipeinfo *pipe_info = &dev->pipe;
pipe = usb_rcvbulkpipe(dev->udev, dev->read_endpoint);
- dprintk(2, "%s: IN %d\n", __func__, dev->read_endpoint);
+ dprintk(dev, 2, "%s: IN %d\n", __func__, dev->read_endpoint);
pipe_info->state = 1;
pipe_info->err_count = 0;
pipe_info->stream_urb = usb_alloc_urb(0, GFP_KERNEL);
@@ -2391,70 +2127,64 @@ static int s2255_start_readpipe(struct s2255_dev *dev)
read_pipe_completion, pipe_info);
retval = usb_submit_urb(pipe_info->stream_urb, GFP_KERNEL);
if (retval) {
- printk(KERN_ERR "s2255: start read pipe failed\n");
+ pr_err("s2255: start read pipe failed\n");
return retval;
}
return 0;
}
/* starts acquisition process */
-static int s2255_start_acquire(struct s2255_channel *channel)
+static int s2255_start_acquire(struct s2255_vc *vc)
{
- unsigned char *buffer;
int res;
unsigned long chn_rev;
int j;
- struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
- chn_rev = G_chnmap[channel->idx];
- buffer = kzalloc(512, GFP_KERNEL);
- if (buffer == NULL) {
- dev_err(&dev->udev->dev, "out of mem\n");
- return -ENOMEM;
- }
-
- channel->last_frame = -1;
- channel->bad_payload = 0;
- channel->cur_frame = 0;
+ struct s2255_dev *dev = to_s2255_dev(vc->vdev.v4l2_dev);
+ __le32 *buffer = dev->cmdbuf;
+
+ mutex_lock(&dev->cmdlock);
+ chn_rev = G_chnmap[vc->idx];
+ vc->last_frame = -1;
+ vc->bad_payload = 0;
+ vc->cur_frame = 0;
for (j = 0; j < SYS_FRAMES; j++) {
- channel->buffer.frame[j].ulState = 0;
- channel->buffer.frame[j].cur_size = 0;
+ vc->buffer.frame[j].ulState = 0;
+ vc->buffer.frame[j].cur_size = 0;
}
/* send the start command */
- *(__le32 *) buffer = IN_DATA_TOKEN;
- *((__le32 *) buffer + 1) = (__le32) cpu_to_le32(chn_rev);
- *((__le32 *) buffer + 2) = CMD_START;
+ buffer[0] = IN_DATA_TOKEN;
+ buffer[1] = (__le32) cpu_to_le32(chn_rev);
+ buffer[2] = CMD_START;
res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512);
if (res != 0)
dev_err(&dev->udev->dev, "CMD_START error\n");
- dprintk(2, "start acquire exit[%d] %d \n", channel->idx, res);
- kfree(buffer);
- return 0;
+ dprintk(dev, 2, "start acquire exit[%d] %d\n", vc->idx, res);
+ mutex_unlock(&dev->cmdlock);
+ return res;
}
-static int s2255_stop_acquire(struct s2255_channel *channel)
+static int s2255_stop_acquire(struct s2255_vc *vc)
{
- unsigned char *buffer;
int res;
unsigned long chn_rev;
- struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
- chn_rev = G_chnmap[channel->idx];
- buffer = kzalloc(512, GFP_KERNEL);
- if (buffer == NULL) {
- dev_err(&dev->udev->dev, "out of mem\n");
- return -ENOMEM;
- }
+ struct s2255_dev *dev = to_s2255_dev(vc->vdev.v4l2_dev);
+ __le32 *buffer = dev->cmdbuf;
+
+ mutex_lock(&dev->cmdlock);
+ chn_rev = G_chnmap[vc->idx];
/* send the stop command */
- *(__le32 *) buffer = IN_DATA_TOKEN;
- *((__le32 *) buffer + 1) = (__le32) cpu_to_le32(chn_rev);
- *((__le32 *) buffer + 2) = CMD_STOP;
+ buffer[0] = IN_DATA_TOKEN;
+ buffer[1] = (__le32) cpu_to_le32(chn_rev);
+ buffer[2] = CMD_STOP;
+
res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512);
if (res != 0)
dev_err(&dev->udev->dev, "CMD_STOP error\n");
- kfree(buffer);
- channel->b_acquire = 0;
- dprintk(4, "%s: chn %d, res %d\n", __func__, channel->idx, res);
+
+ dprintk(dev, 4, "%s: chn %d, res %d\n", __func__, vc->idx, res);
+ mutex_unlock(&dev->cmdlock);
return res;
}
@@ -2469,7 +2199,7 @@ static void s2255_stop_readpipe(struct s2255_dev *dev)
usb_free_urb(pipe->stream_urb);
pipe->stream_urb = NULL;
}
- dprintk(4, "%s", __func__);
+ dprintk(dev, 4, "%s", __func__);
return;
}
@@ -2501,19 +2231,27 @@ static int s2255_probe(struct usb_interface *interface,
int retval = -ENOMEM;
__le32 *pdata;
int fw_size;
- dprintk(2, "%s\n", __func__);
+
/* allocate memory for our device state and initialize it to zero */
dev = kzalloc(sizeof(struct s2255_dev), GFP_KERNEL);
if (dev == NULL) {
s2255_dev_err(&interface->dev, "out of memory\n");
return -ENOMEM;
}
+
+ dev->cmdbuf = kzalloc(S2255_CMDBUF_SIZE, GFP_KERNEL);
+ if (dev->cmdbuf == NULL) {
+ s2255_dev_err(&interface->dev, "out of memory\n");
+ goto errorFWDATA1;
+ }
+
atomic_set(&dev->num_channels, 0);
dev->pid = le16_to_cpu(id->idProduct);
dev->fw_data = kzalloc(sizeof(struct s2255_fw), GFP_KERNEL);
if (!dev->fw_data)
goto errorFWDATA1;
mutex_init(&dev->lock);
+ mutex_init(&dev->cmdlock);
/* grab usb_device and save it */
dev->udev = usb_get_dev(interface_to_usbdev(interface));
if (dev->udev == NULL) {
@@ -2521,12 +2259,13 @@ static int s2255_probe(struct usb_interface *interface,
retval = -ENODEV;
goto errorUDEV;
}
- dprintk(1, "dev: %p, udev %p interface %p\n", dev,
- dev->udev, interface);
+ dev_dbg(&interface->dev, "dev: %p, udev %p interface %p\n",
+ dev, dev->udev, interface);
dev->interface = interface;
/* set up the endpoint information */
iface_desc = interface->cur_altsetting;
- dprintk(1, "num endpoints %d\n", iface_desc->desc.bNumEndpoints);
+ dev_dbg(&interface->dev, "num EP: %d\n",
+ iface_desc->desc.bNumEndpoints);
for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
endpoint = &iface_desc->endpoint[i].desc;
if (!dev->read_endpoint && usb_endpoint_is_bulk_in(endpoint)) {
@@ -2544,10 +2283,13 @@ static int s2255_probe(struct usb_interface *interface,
dev->timer.data = (unsigned long)dev->fw_data;
init_waitqueue_head(&dev->fw_data->wait_fw);
for (i = 0; i < MAX_CHANNELS; i++) {
- struct s2255_channel *channel = &dev->channel[i];
- dev->channel[i].idx = i;
- init_waitqueue_head(&channel->wait_setmode);
- init_waitqueue_head(&channel->wait_vidstatus);
+ struct s2255_vc *vc = &dev->vc[i];
+ vc->idx = i;
+ vc->dev = dev;
+ init_waitqueue_head(&vc->wait_setmode);
+ init_waitqueue_head(&vc->wait_vidstatus);
+ spin_lock_init(&vc->qlock);
+ mutex_init(&vc->vb_lock);
}
dev->fw_data->fw_urb = usb_alloc_urb(0, GFP_KERNEL);
@@ -2564,7 +2306,7 @@ static int s2255_probe(struct usb_interface *interface,
/* load the first chunk */
if (request_firmware(&dev->fw_data->fw,
FIRMWARE_FILE_NAME, &dev->udev->dev)) {
- printk(KERN_ERR "sensoray 2255 failed to get firmware\n");
+ dev_err(&interface->dev, "sensoray 2255 failed to get firmware\n");
goto errorREQFW;
}
/* check the firmware is valid */
@@ -2572,28 +2314,27 @@ static int s2255_probe(struct usb_interface *interface,
pdata = (__le32 *) &dev->fw_data->fw->data[fw_size - 8];
if (*pdata != S2255_FW_MARKER) {
- printk(KERN_INFO "Firmware invalid.\n");
+ dev_err(&interface->dev, "Firmware invalid.\n");
retval = -ENODEV;
goto errorFWMARKER;
} else {
/* make sure firmware is the latest */
__le32 *pRel;
pRel = (__le32 *) &dev->fw_data->fw->data[fw_size - 4];
- printk(KERN_INFO "s2255 dsp fw version %x\n", le32_to_cpu(*pRel));
+ pr_info("s2255 dsp fw version %x\n", le32_to_cpu(*pRel));
dev->dsp_fw_ver = le32_to_cpu(*pRel);
if (dev->dsp_fw_ver < S2255_CUR_DSP_FWVER)
- printk(KERN_INFO "s2255: f2255usb.bin out of date.\n");
+ pr_info("s2255: f2255usb.bin out of date.\n");
if (dev->pid == 0x2257 &&
dev->dsp_fw_ver < S2255_MIN_DSP_COLORFILTER)
- printk(KERN_WARNING "s2255: 2257 requires firmware %d"
- " or above.\n", S2255_MIN_DSP_COLORFILTER);
+ pr_warn("2257 needs firmware %d or above.\n",
+ S2255_MIN_DSP_COLORFILTER);
}
usb_reset_device(dev->udev);
/* load 2255 board specific */
retval = s2255_board_init(dev);
if (retval)
goto errorBOARDINIT;
- spin_lock_init(&dev->slock);
s2255_fwload_start(dev, 0);
/* loads v4l specific */
retval = s2255_probe_v4l(dev);
@@ -2610,15 +2351,16 @@ errorREQFW:
errorFWDATA2:
usb_free_urb(dev->fw_data->fw_urb);
errorFWURB:
- del_timer(&dev->timer);
+ del_timer_sync(&dev->timer);
errorEP:
usb_put_dev(dev->udev);
errorUDEV:
kfree(dev->fw_data);
mutex_destroy(&dev->lock);
errorFWDATA1:
+ kfree(dev->cmdbuf);
kfree(dev);
- printk(KERN_WARNING "Sensoray 2255 driver load failed: 0x%x\n", retval);
+ pr_warn("Sensoray 2255 driver load failed: 0x%x\n", retval);
return retval;
}
@@ -2635,15 +2377,15 @@ static void s2255_disconnect(struct usb_interface *interface)
atomic_inc(&dev->num_channels);
/* unregister each video device. */
for (i = 0; i < channels; i++)
- video_unregister_device(&dev->channel[i].vdev);
+ video_unregister_device(&dev->vc[i].vdev);
/* wake up any of our timers */
atomic_set(&dev->fw_data->fw_state, S2255_FW_DISCONNECTING);
wake_up(&dev->fw_data->wait_fw);
for (i = 0; i < MAX_CHANNELS; i++) {
- dev->channel[i].setmode_ready = 1;
- wake_up(&dev->channel[i].wait_setmode);
- dev->channel[i].vidstatus_ready = 1;
- wake_up(&dev->channel[i].wait_vidstatus);
+ dev->vc[i].setmode_ready = 1;
+ wake_up(&dev->vc[i].wait_setmode);
+ dev->vc[i].vidstatus_ready = 1;
+ wake_up(&dev->vc[i].wait_vidstatus);
}
if (atomic_dec_and_test(&dev->num_channels))
s2255_destroy(dev);
diff --git a/drivers/media/usb/siano/smsusb.c b/drivers/media/usb/siano/smsusb.c
index 03761c6f472..1836a416d80 100644
--- a/drivers/media/usb/siano/smsusb.c
+++ b/drivers/media/usb/siano/smsusb.c
@@ -209,8 +209,10 @@ static int smsusb_sendrequest(void *context, void *buffer, size_t size)
struct sms_msg_hdr *phdr = (struct sms_msg_hdr *) buffer;
int dummy;
- if (dev->state != SMSUSB_ACTIVE)
+ if (dev->state != SMSUSB_ACTIVE) {
+ sms_debug("Device not active yet");
return -ENOENT;
+ }
sms_debug("sending %s(%d) size: %d",
smscore_translate_msg(phdr->msg_type), phdr->msg_type,
@@ -243,6 +245,9 @@ static int smsusb1_load_firmware(struct usb_device *udev, int id, int board_id)
int rc, dummy;
char *fw_filename;
+ if (id < 0)
+ id = sms_get_board(board_id)->default_mode;
+
if (id < DEVICE_MODE_DVBT || id > DEVICE_MODE_DVBT_BDA) {
sms_err("invalid firmware id specified %d", id);
return -EINVAL;
@@ -445,14 +450,15 @@ static int smsusb_probe(struct usb_interface *intf,
char devpath[32];
int i, rc;
- sms_info("interface number %d",
+ sms_info("board id=%lu, interface number %d",
+ id->driver_info,
intf->cur_altsetting->desc.bInterfaceNumber);
if (sms_get_board(id->driver_info)->intf_num !=
intf->cur_altsetting->desc.bInterfaceNumber) {
- sms_err("interface number is %d expecting %d",
- sms_get_board(id->driver_info)->intf_num,
- intf->cur_altsetting->desc.bInterfaceNumber);
+ sms_debug("interface %d won't be used. Expecting interface %d to popup",
+ intf->cur_altsetting->desc.bInterfaceNumber,
+ sms_get_board(id->driver_info)->intf_num);
return -ENODEV;
}
@@ -483,22 +489,32 @@ static int smsusb_probe(struct usb_interface *intf,
}
if ((udev->actconfig->desc.bNumInterfaces == 2) &&
(intf->cur_altsetting->desc.bInterfaceNumber == 0)) {
- sms_err("rom interface 0 is not used");
+ sms_debug("rom interface 0 is not used");
return -ENODEV;
}
if (id->driver_info == SMS1XXX_BOARD_SIANO_STELLAR_ROM) {
- sms_info("stellar device was found.");
+ /* Detected a Siano Stellar uninitialized */
+
snprintf(devpath, sizeof(devpath), "usb\\%d-%s",
udev->bus->busnum, udev->devpath);
- sms_info("stellar device was found.");
- return smsusb1_load_firmware(
+ sms_info("stellar device in cold state was found at %s.", devpath);
+ rc = smsusb1_load_firmware(
udev, smscore_registry_getmode(devpath),
id->driver_info);
+
+ /* This device will reset and gain another USB ID */
+ if (!rc)
+ sms_info("stellar device now in warm state");
+ else
+ sms_err("Failed to put stellar in warm state. Error: %d", rc);
+
+ return rc;
+ } else {
+ rc = smsusb_init_device(intf, id->driver_info);
}
- rc = smsusb_init_device(intf, id->driver_info);
- sms_info("rc %d", rc);
+ sms_info("Device initialized with return code %d", rc);
sms_board_load_modules(id->driver_info);
return rc;
}
@@ -550,10 +566,13 @@ static int smsusb_resume(struct usb_interface *intf)
}
static const struct usb_device_id smsusb_id_table[] = {
+ /* This device is only present before firmware load */
{ USB_DEVICE(0x187f, 0x0010),
- .driver_info = SMS1XXX_BOARD_SIANO_STELLAR },
+ .driver_info = SMS1XXX_BOARD_SIANO_STELLAR_ROM },
+ /* This device pops up after firmware load */
{ USB_DEVICE(0x187f, 0x0100),
.driver_info = SMS1XXX_BOARD_SIANO_STELLAR },
+
{ USB_DEVICE(0x187f, 0x0200),
.driver_info = SMS1XXX_BOARD_SIANO_NOVA_A },
{ USB_DEVICE(0x187f, 0x0201),
@@ -634,6 +653,8 @@ static const struct usb_device_id smsusb_id_table[] = {
.driver_info = SMS1XXX_BOARD_ZTE_DVB_DATA_CARD },
{ USB_DEVICE(0x19D2, 0x0078),
.driver_info = SMS1XXX_BOARD_ONDA_MDTV_DATA_CARD },
+ { USB_DEVICE(0x3275, 0x0080),
+ .driver_info = SMS1XXX_BOARD_SIANO_RIO },
{ } /* Terminating entry */
};
diff --git a/drivers/media/usb/sn9c102/Kconfig b/drivers/media/usb/sn9c102/Kconfig
deleted file mode 100644
index 6ebaf2940d0..00000000000
--- a/drivers/media/usb/sn9c102/Kconfig
+++ /dev/null
@@ -1,14 +0,0 @@
-config USB_SN9C102
- tristate "USB SN9C1xx PC Camera Controller support (DEPRECATED)"
- depends on VIDEO_V4L2
- ---help---
- This driver is DEPRECATED please use the gspca sonixb and
- sonixj modules instead.
-
- Say Y here if you want support for cameras based on SONiX SN9C101,
- SN9C102, SN9C103, SN9C105 and SN9C120 PC Camera Controllers.
-
- See <file:Documentation/video4linux/sn9c102.txt> for more info.
-
- To compile this driver as a module, choose M here: the
- module will be called sn9c102.
diff --git a/drivers/media/usb/sn9c102/Makefile b/drivers/media/usb/sn9c102/Makefile
deleted file mode 100644
index 7ecd5a90c7c..00000000000
--- a/drivers/media/usb/sn9c102/Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
-sn9c102-objs := sn9c102_core.o \
- sn9c102_hv7131d.o \
- sn9c102_hv7131r.o \
- sn9c102_mi0343.o \
- sn9c102_mi0360.o \
- sn9c102_mt9v111.o \
- sn9c102_ov7630.o \
- sn9c102_ov7660.o \
- sn9c102_pas106b.o \
- sn9c102_pas202bcb.o \
- sn9c102_tas5110c1b.o \
- sn9c102_tas5110d.o \
- sn9c102_tas5130d1b.o
-
-obj-$(CONFIG_USB_SN9C102) += sn9c102.o
diff --git a/drivers/media/usb/sn9c102/sn9c102.h b/drivers/media/usb/sn9c102/sn9c102.h
deleted file mode 100644
index 8a917f06050..00000000000
--- a/drivers/media/usb/sn9c102/sn9c102.h
+++ /dev/null
@@ -1,214 +0,0 @@
-/***************************************************************************
- * V4L2 driver for SN9C1xx PC Camera Controllers *
- * *
- * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the Free Software *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
- ***************************************************************************/
-
-#ifndef _SN9C102_H_
-#define _SN9C102_H_
-
-#include <linux/usb.h>
-#include <linux/videodev2.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
-#include <media/v4l2-device.h>
-#include <linux/device.h>
-#include <linux/list.h>
-#include <linux/spinlock.h>
-#include <linux/time.h>
-#include <linux/wait.h>
-#include <linux/types.h>
-#include <linux/param.h>
-#include <linux/rwsem.h>
-#include <linux/mutex.h>
-#include <linux/string.h>
-#include <linux/stddef.h>
-#include <linux/kref.h>
-
-#include "sn9c102_config.h"
-#include "sn9c102_sensor.h"
-#include "sn9c102_devtable.h"
-
-
-enum sn9c102_frame_state {
- F_UNUSED,
- F_QUEUED,
- F_GRABBING,
- F_DONE,
- F_ERROR,
-};
-
-struct sn9c102_frame_t {
- void* bufmem;
- struct v4l2_buffer buf;
- enum sn9c102_frame_state state;
- struct list_head frame;
- unsigned long vma_use_count;
-};
-
-enum sn9c102_dev_state {
- DEV_INITIALIZED = 0x01,
- DEV_DISCONNECTED = 0x02,
- DEV_MISCONFIGURED = 0x04,
-};
-
-enum sn9c102_io_method {
- IO_NONE,
- IO_READ,
- IO_MMAP,
-};
-
-enum sn9c102_stream_state {
- STREAM_OFF,
- STREAM_INTERRUPT,
- STREAM_ON,
-};
-
-typedef char sn9c102_sof_header_t[62];
-
-struct sn9c102_sof_t {
- sn9c102_sof_header_t header;
- u16 bytesread;
-};
-
-struct sn9c102_sysfs_attr {
- u16 reg, i2c_reg;
- sn9c102_sof_header_t frame_header;
-};
-
-struct sn9c102_module_param {
- u8 force_munmap;
- u16 frame_timeout;
-};
-
-static DEFINE_MUTEX(sn9c102_sysfs_lock);
-static DECLARE_RWSEM(sn9c102_dev_lock);
-
-struct sn9c102_device {
- struct video_device* v4ldev;
-
- struct v4l2_device v4l2_dev;
-
- enum sn9c102_bridge bridge;
- struct sn9c102_sensor sensor;
-
- struct usb_device* usbdev;
- struct urb* urb[SN9C102_URBS];
- void* transfer_buffer[SN9C102_URBS];
- u8* control_buffer;
-
- struct sn9c102_frame_t *frame_current, frame[SN9C102_MAX_FRAMES];
- struct list_head inqueue, outqueue;
- u32 frame_count, nbuffers, nreadbuffers;
-
- enum sn9c102_io_method io;
- enum sn9c102_stream_state stream;
-
- struct v4l2_jpegcompression compression;
-
- struct sn9c102_sysfs_attr sysfs;
- struct sn9c102_sof_t sof;
- u16 reg[384];
-
- struct sn9c102_module_param module_param;
-
- struct kref kref;
- enum sn9c102_dev_state state;
- u8 users;
-
- struct completion probe;
- struct mutex open_mutex, fileop_mutex;
- spinlock_t queue_lock;
- wait_queue_head_t wait_open, wait_frame, wait_stream;
-};
-
-/*****************************************************************************/
-
-struct sn9c102_device*
-sn9c102_match_id(struct sn9c102_device* cam, const struct usb_device_id *id)
-{
- return usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id) ? cam : NULL;
-}
-
-
-void
-sn9c102_attach_sensor(struct sn9c102_device* cam,
- const struct sn9c102_sensor* sensor)
-{
- memcpy(&cam->sensor, sensor, sizeof(struct sn9c102_sensor));
-}
-
-
-enum sn9c102_bridge
-sn9c102_get_bridge(struct sn9c102_device* cam)
-{
- return cam->bridge;
-}
-
-
-struct sn9c102_sensor* sn9c102_get_sensor(struct sn9c102_device* cam)
-{
- return &cam->sensor;
-}
-
-/*****************************************************************************/
-
-#undef DBG
-#undef KDBG
-#ifdef SN9C102_DEBUG
-# define DBG(level, fmt, args...) \
-do { \
- if (debug >= (level)) { \
- if ((level) == 1) \
- dev_err(&cam->usbdev->dev, fmt "\n", ## args); \
- else if ((level) == 2) \
- dev_info(&cam->usbdev->dev, fmt "\n", ## args); \
- else if ((level) >= 3) \
- dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n", \
- __func__, __LINE__ , ## args); \
- } \
-} while (0)
-# define V4LDBG(level, name, cmd) \
-do { \
- if (debug >= (level)) \
- v4l_printk_ioctl(name, cmd); \
-} while (0)
-# define KDBG(level, fmt, args...) \
-do { \
- if (debug >= (level)) { \
- if ((level) == 1 || (level) == 2) \
- pr_info("sn9c102: " fmt "\n", ## args); \
- else if ((level) == 3) \
- pr_debug("sn9c102: [%s:%d] " fmt "\n", \
- __func__, __LINE__ , ## args); \
- } \
-} while (0)
-#else
-# define DBG(level, fmt, args...) do {;} while(0)
-# define V4LDBG(level, name, cmd) do {;} while(0)
-# define KDBG(level, fmt, args...) do {;} while(0)
-#endif
-
-#undef PDBG
-#define PDBG(fmt, args...) \
-dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", __FILE__, __func__, \
- __LINE__ , ## args)
-
-#undef PDBGG
-#define PDBGG(fmt, args...) do {;} while(0) /* placeholder */
-
-#endif /* _SN9C102_H_ */
diff --git a/drivers/media/usb/sn9c102/sn9c102_config.h b/drivers/media/usb/sn9c102/sn9c102_config.h
deleted file mode 100644
index 0f4e0378b07..00000000000
--- a/drivers/media/usb/sn9c102/sn9c102_config.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/***************************************************************************
- * Global parameters for the V4L2 driver for SN9C1xx PC Camera Controllers *
- * *
- * Copyright (C) 2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the Free Software *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
- ***************************************************************************/
-
-#ifndef _SN9C102_CONFIG_H_
-#define _SN9C102_CONFIG_H_
-
-#include <linux/types.h>
-#include <linux/jiffies.h>
-
-#define SN9C102_DEBUG
-#define SN9C102_DEBUG_LEVEL 2
-#define SN9C102_MAX_DEVICES 64
-#define SN9C102_PRESERVE_IMGSCALE 0
-#define SN9C102_FORCE_MUNMAP 0
-#define SN9C102_MAX_FRAMES 32
-#define SN9C102_URBS 2
-#define SN9C102_ISO_PACKETS 7
-#define SN9C102_ALTERNATE_SETTING 8
-#define SN9C102_URB_TIMEOUT msecs_to_jiffies(2 * SN9C102_ISO_PACKETS)
-#define SN9C102_CTRL_TIMEOUT 300
-#define SN9C102_FRAME_TIMEOUT 0
-
-/*****************************************************************************/
-
-static const u8 SN9C102_Y_QTABLE0[64] = {
- 8, 5, 5, 8, 12, 20, 25, 30,
- 6, 6, 7, 9, 13, 29, 30, 27,
- 7, 6, 8, 12, 20, 28, 34, 28,
- 7, 8, 11, 14, 25, 43, 40, 31,
- 9, 11, 18, 28, 34, 54, 51, 38,
- 12, 17, 27, 32, 40, 52, 56, 46,
- 24, 32, 39, 43, 51, 60, 60, 50,
- 36, 46, 47, 49, 56, 50, 51, 49
-};
-
-static const u8 SN9C102_UV_QTABLE0[64] = {
- 8, 9, 12, 23, 49, 49, 49, 49,
- 9, 10, 13, 33, 49, 49, 49, 49,
- 12, 13, 28, 49, 49, 49, 49, 49,
- 23, 33, 49, 49, 49, 49, 49, 49,
- 49, 49, 49, 49, 49, 49, 49, 49,
- 49, 49, 49, 49, 49, 49, 49, 49,
- 49, 49, 49, 49, 49, 49, 49, 49,
- 49, 49, 49, 49, 49, 49, 49, 49
-};
-
-static const u8 SN9C102_Y_QTABLE1[64] = {
- 16, 11, 10, 16, 24, 40, 51, 61,
- 12, 12, 14, 19, 26, 58, 60, 55,
- 14, 13, 16, 24, 40, 57, 69, 56,
- 14, 17, 22, 29, 51, 87, 80, 62,
- 18, 22, 37, 56, 68, 109, 103, 77,
- 24, 35, 55, 64, 81, 104, 113, 92,
- 49, 64, 78, 87, 103, 121, 120, 101,
- 72, 92, 95, 98, 112, 100, 103, 99
-};
-
-static const u8 SN9C102_UV_QTABLE1[64] = {
- 17, 18, 24, 47, 99, 99, 99, 99,
- 18, 21, 26, 66, 99, 99, 99, 99,
- 24, 26, 56, 99, 99, 99, 99, 99,
- 47, 66, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99
-};
-
-#endif /* _SN9C102_CONFIG_H_ */
diff --git a/drivers/media/usb/sn9c102/sn9c102_core.c b/drivers/media/usb/sn9c102/sn9c102_core.c
deleted file mode 100644
index 2cb44de2b92..00000000000
--- a/drivers/media/usb/sn9c102/sn9c102_core.c
+++ /dev/null
@@ -1,3434 +0,0 @@
-/***************************************************************************
- * V4L2 driver for SN9C1xx PC Camera Controllers *
- * *
- * Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the Free Software *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
- ***************************************************************************/
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/device.h>
-#include <linux/fs.h>
-#include <linux/delay.h>
-#include <linux/compiler.h>
-#include <linux/ioctl.h>
-#include <linux/poll.h>
-#include <linux/stat.h>
-#include <linux/mm.h>
-#include <linux/vmalloc.h>
-#include <linux/version.h>
-#include <linux/page-flags.h>
-#include <asm/byteorder.h>
-#include <asm/page.h>
-#include <asm/uaccess.h>
-
-#include "sn9c102.h"
-
-/*****************************************************************************/
-
-#define SN9C102_MODULE_NAME "V4L2 driver for SN9C1xx PC Camera Controllers"
-#define SN9C102_MODULE_ALIAS "sn9c1xx"
-#define SN9C102_MODULE_AUTHOR "(C) 2004-2007 Luca Risolia"
-#define SN9C102_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>"
-#define SN9C102_MODULE_LICENSE "GPL"
-#define SN9C102_MODULE_VERSION "1:1.48"
-
-/*****************************************************************************/
-
-MODULE_DEVICE_TABLE(usb, sn9c102_id_table);
-
-MODULE_AUTHOR(SN9C102_MODULE_AUTHOR " " SN9C102_AUTHOR_EMAIL);
-MODULE_DESCRIPTION(SN9C102_MODULE_NAME);
-MODULE_ALIAS(SN9C102_MODULE_ALIAS);
-MODULE_VERSION(SN9C102_MODULE_VERSION);
-MODULE_LICENSE(SN9C102_MODULE_LICENSE);
-
-static short video_nr[] = {[0 ... SN9C102_MAX_DEVICES-1] = -1};
-module_param_array(video_nr, short, NULL, 0444);
-MODULE_PARM_DESC(video_nr,
- " <-1|n[,...]>"
- "\nSpecify V4L2 minor mode number."
- "\n-1 = use next available (default)"
- "\n n = use minor number n (integer >= 0)"
- "\nYou can specify up to "__MODULE_STRING(SN9C102_MAX_DEVICES)
- " cameras this way."
- "\nFor example:"
- "\nvideo_nr=-1,2,-1 would assign minor number 2 to"
- "\nthe second camera and use auto for the first"
- "\none and for every other camera."
- "\n");
-
-static bool force_munmap[] = {[0 ... SN9C102_MAX_DEVICES-1] =
- SN9C102_FORCE_MUNMAP};
-module_param_array(force_munmap, bool, NULL, 0444);
-MODULE_PARM_DESC(force_munmap,
- " <0|1[,...]>"
- "\nForce the application to unmap previously"
- "\nmapped buffer memory before calling any VIDIOC_S_CROP or"
- "\nVIDIOC_S_FMT ioctl's. Not all the applications support"
- "\nthis feature. This parameter is specific for each"
- "\ndetected camera."
- "\n0 = do not force memory unmapping"
- "\n1 = force memory unmapping (save memory)"
- "\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"."
- "\n");
-
-static unsigned int frame_timeout[] = {[0 ... SN9C102_MAX_DEVICES-1] =
- SN9C102_FRAME_TIMEOUT};
-module_param_array(frame_timeout, uint, NULL, 0644);
-MODULE_PARM_DESC(frame_timeout,
- " <0|n[,...]>"
- "\nTimeout for a video frame in seconds before"
- "\nreturning an I/O error; 0 for infinity."
- "\nThis parameter is specific for each detected camera."
- "\nDefault value is "__MODULE_STRING(SN9C102_FRAME_TIMEOUT)"."
- "\n");
-
-#ifdef SN9C102_DEBUG
-static unsigned short debug = SN9C102_DEBUG_LEVEL;
-module_param(debug, ushort, 0644);
-MODULE_PARM_DESC(debug,
- " <n>"
- "\nDebugging information level, from 0 to 3:"
- "\n0 = none (use carefully)"
- "\n1 = critical errors"
- "\n2 = significant informations"
- "\n3 = more verbose messages"
- "\nLevel 3 is useful for testing only."
- "\nDefault value is "__MODULE_STRING(SN9C102_DEBUG_LEVEL)"."
- "\n");
-#endif
-
-/*
- Add the probe entries to this table. Be sure to add the entry in the right
- place, since, on failure, the next probing routine is called according to
- the order of the list below, from top to bottom.
-*/
-static int (*sn9c102_sensor_table[])(struct sn9c102_device *) = {
- &sn9c102_probe_hv7131d, /* strong detection based on SENSOR ids */
- &sn9c102_probe_hv7131r, /* strong detection based on SENSOR ids */
- &sn9c102_probe_mi0343, /* strong detection based on SENSOR ids */
- &sn9c102_probe_mi0360, /* strong detection based on SENSOR ids */
- &sn9c102_probe_mt9v111, /* strong detection based on SENSOR ids */
- &sn9c102_probe_pas106b, /* strong detection based on SENSOR ids */
- &sn9c102_probe_pas202bcb, /* strong detection based on SENSOR ids */
- &sn9c102_probe_ov7630, /* strong detection based on SENSOR ids */
- &sn9c102_probe_ov7660, /* strong detection based on SENSOR ids */
- &sn9c102_probe_tas5110c1b, /* detection based on USB pid/vid */
- &sn9c102_probe_tas5110d, /* detection based on USB pid/vid */
- &sn9c102_probe_tas5130d1b, /* detection based on USB pid/vid */
-};
-
-/*****************************************************************************/
-
-static u32
-sn9c102_request_buffers(struct sn9c102_device* cam, u32 count,
- enum sn9c102_io_method io)
-{
- struct v4l2_pix_format* p = &(cam->sensor.pix_format);
- struct v4l2_rect* r = &(cam->sensor.cropcap.bounds);
- size_t imagesize = cam->module_param.force_munmap || io == IO_READ ?
- (p->width * p->height * p->priv) / 8 :
- (r->width * r->height * p->priv) / 8;
- void* buff = NULL;
- u32 i;
-
- if (count > SN9C102_MAX_FRAMES)
- count = SN9C102_MAX_FRAMES;
-
- if (cam->bridge == BRIDGE_SN9C105 || cam->bridge == BRIDGE_SN9C120)
- imagesize += 589 + 2; /* length of JPEG header + EOI marker */
-
- cam->nbuffers = count;
- while (cam->nbuffers > 0) {
- if ((buff = vmalloc_32_user(cam->nbuffers *
- PAGE_ALIGN(imagesize))))
- break;
- cam->nbuffers--;
- }
-
- for (i = 0; i < cam->nbuffers; i++) {
- cam->frame[i].bufmem = buff + i*PAGE_ALIGN(imagesize);
- cam->frame[i].buf.index = i;
- cam->frame[i].buf.m.offset = i*PAGE_ALIGN(imagesize);
- cam->frame[i].buf.length = imagesize;
- cam->frame[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- cam->frame[i].buf.sequence = 0;
- cam->frame[i].buf.field = V4L2_FIELD_NONE;
- cam->frame[i].buf.memory = V4L2_MEMORY_MMAP;
- cam->frame[i].buf.flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
- }
-
- return cam->nbuffers;
-}
-
-
-static void sn9c102_release_buffers(struct sn9c102_device* cam)
-{
- if (cam->nbuffers) {
- vfree(cam->frame[0].bufmem);
- cam->nbuffers = 0;
- }
- cam->frame_current = NULL;
-}
-
-
-static void sn9c102_empty_framequeues(struct sn9c102_device* cam)
-{
- u32 i;
-
- INIT_LIST_HEAD(&cam->inqueue);
- INIT_LIST_HEAD(&cam->outqueue);
-
- for (i = 0; i < SN9C102_MAX_FRAMES; i++) {
- cam->frame[i].state = F_UNUSED;
- cam->frame[i].buf.bytesused = 0;
- }
-}
-
-
-static void sn9c102_requeue_outqueue(struct sn9c102_device* cam)
-{
- struct sn9c102_frame_t *i;
-
- list_for_each_entry(i, &cam->outqueue, frame) {
- i->state = F_QUEUED;
- list_add(&i->frame, &cam->inqueue);
- }
-
- INIT_LIST_HEAD(&cam->outqueue);
-}
-
-
-static void sn9c102_queue_unusedframes(struct sn9c102_device* cam)
-{
- unsigned long lock_flags;
- u32 i;
-
- for (i = 0; i < cam->nbuffers; i++)
- if (cam->frame[i].state == F_UNUSED) {
- cam->frame[i].state = F_QUEUED;
- spin_lock_irqsave(&cam->queue_lock, lock_flags);
- list_add_tail(&cam->frame[i].frame, &cam->inqueue);
- spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
- }
-}
-
-/*****************************************************************************/
-
-/*
- Write a sequence of count value/register pairs. Returns -1 after the first
- failed write, or 0 for no errors.
-*/
-int sn9c102_write_regs(struct sn9c102_device* cam, const u8 valreg[][2],
- int count)
-{
- struct usb_device* udev = cam->usbdev;
- u8* buff = cam->control_buffer;
- int i, res;
-
- for (i = 0; i < count; i++) {
- u8 index = valreg[i][1];
-
- /*
- index is a u8, so it must be <256 and can't be out of range.
- If we put in a check anyway, gcc annoys us with a warning
- hat our check is useless. People get all uppity when they
- see warnings in the kernel compile.
- */
-
- *buff = valreg[i][0];
-
- res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08,
- 0x41, index, 0, buff, 1,
- SN9C102_CTRL_TIMEOUT);
-
- if (res < 0) {
- DBG(3, "Failed to write a register (value 0x%02X, "
- "index 0x%02X, error %d)", *buff, index, res);
- return -1;
- }
-
- cam->reg[index] = *buff;
- }
-
- return 0;
-}
-
-
-int sn9c102_write_reg(struct sn9c102_device* cam, u8 value, u16 index)
-{
- struct usb_device* udev = cam->usbdev;
- u8* buff = cam->control_buffer;
- int res;
-
- if (index >= ARRAY_SIZE(cam->reg))
- return -1;
-
- *buff = value;
-
- res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41,
- index, 0, buff, 1, SN9C102_CTRL_TIMEOUT);
- if (res < 0) {
- DBG(3, "Failed to write a register (value 0x%02X, index "
- "0x%02X, error %d)", value, index, res);
- return -1;
- }
-
- cam->reg[index] = value;
-
- return 0;
-}
-
-
-/* NOTE: with the SN9C10[123] reading some registers always returns 0 */
-int sn9c102_read_reg(struct sn9c102_device* cam, u16 index)
-{
- struct usb_device* udev = cam->usbdev;
- u8* buff = cam->control_buffer;
- int res;
-
- res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1,
- index, 0, buff, 1, SN9C102_CTRL_TIMEOUT);
- if (res < 0)
- DBG(3, "Failed to read a register (index 0x%02X, error %d)",
- index, res);
-
- return (res >= 0) ? (int)(*buff) : -1;
-}
-
-
-int sn9c102_pread_reg(struct sn9c102_device* cam, u16 index)
-{
- if (index >= ARRAY_SIZE(cam->reg))
- return -1;
-
- return cam->reg[index];
-}
-
-
-static int
-sn9c102_i2c_wait(struct sn9c102_device* cam,
- const struct sn9c102_sensor* sensor)
-{
- int i, r;
-
- for (i = 1; i <= 5; i++) {
- r = sn9c102_read_reg(cam, 0x08);
- if (r < 0)
- return -EIO;
- if (r & 0x04)
- return 0;
- if (sensor->frequency & SN9C102_I2C_400KHZ)
- udelay(5*16);
- else
- udelay(16*16);
- }
- return -EBUSY;
-}
-
-
-static int
-sn9c102_i2c_detect_read_error(struct sn9c102_device* cam,
- const struct sn9c102_sensor* sensor)
-{
- int r , err = 0;
-
- r = sn9c102_read_reg(cam, 0x08);
- if (r < 0)
- err += r;
-
- if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) {
- if (!(r & 0x08))
- err += -1;
- } else {
- if (r & 0x08)
- err += -1;
- }
-
- return err ? -EIO : 0;
-}
-
-
-static int
-sn9c102_i2c_detect_write_error(struct sn9c102_device* cam,
- const struct sn9c102_sensor* sensor)
-{
- int r;
- r = sn9c102_read_reg(cam, 0x08);
- return (r < 0 || (r >= 0 && (r & 0x08))) ? -EIO : 0;
-}
-
-
-int
-sn9c102_i2c_try_raw_read(struct sn9c102_device* cam,
- const struct sn9c102_sensor* sensor, u8 data0,
- u8 data1, u8 n, u8 buffer[])
-{
- struct usb_device* udev = cam->usbdev;
- u8* data = cam->control_buffer;
- int i = 0, err = 0, res;
-
- /* Write cycle */
- data[0] = ((sensor->interface == SN9C102_I2C_2WIRES) ? 0x80 : 0) |
- ((sensor->frequency & SN9C102_I2C_400KHZ) ? 0x01 : 0) | 0x10;
- data[1] = data0; /* I2C slave id */
- data[2] = data1; /* address */
- data[7] = 0x10;
- res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41,
- 0x08, 0, data, 8, SN9C102_CTRL_TIMEOUT);
- if (res < 0)
- err += res;
-
- err += sn9c102_i2c_wait(cam, sensor);
-
- /* Read cycle - n bytes */
- data[0] = ((sensor->interface == SN9C102_I2C_2WIRES) ? 0x80 : 0) |
- ((sensor->frequency & SN9C102_I2C_400KHZ) ? 0x01 : 0) |
- (n << 4) | 0x02;
- data[1] = data0;
- data[7] = 0x10;
- res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41,
- 0x08, 0, data, 8, SN9C102_CTRL_TIMEOUT);
- if (res < 0)
- err += res;
-
- err += sn9c102_i2c_wait(cam, sensor);
-
- /* The first read byte will be placed in data[4] */
- res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1,
- 0x0a, 0, data, 5, SN9C102_CTRL_TIMEOUT);
- if (res < 0)
- err += res;
-
- err += sn9c102_i2c_detect_read_error(cam, sensor);
-
- PDBGG("I2C read: address 0x%02X, first read byte: 0x%02X", data1,
- data[4]);
-
- if (err) {
- DBG(3, "I2C read failed for %s image sensor", sensor->name);
- return -1;
- }
-
- if (buffer)
- for (i = 0; i < n && i < 5; i++)
- buffer[n-i-1] = data[4-i];
-
- return (int)data[4];
-}
-
-
-int
-sn9c102_i2c_try_raw_write(struct sn9c102_device* cam,
- const struct sn9c102_sensor* sensor, u8 n, u8 data0,
- u8 data1, u8 data2, u8 data3, u8 data4, u8 data5)
-{
- struct usb_device* udev = cam->usbdev;
- u8* data = cam->control_buffer;
- int err = 0, res;
-
- /* Write cycle. It usually is address + value */
- data[0] = ((sensor->interface == SN9C102_I2C_2WIRES) ? 0x80 : 0) |
- ((sensor->frequency & SN9C102_I2C_400KHZ) ? 0x01 : 0)
- | ((n - 1) << 4);
- data[1] = data0;
- data[2] = data1;
- data[3] = data2;
- data[4] = data3;
- data[5] = data4;
- data[6] = data5;
- data[7] = 0x17;
- res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41,
- 0x08, 0, data, 8, SN9C102_CTRL_TIMEOUT);
- if (res < 0)
- err += res;
-
- err += sn9c102_i2c_wait(cam, sensor);
- err += sn9c102_i2c_detect_write_error(cam, sensor);
-
- if (err)
- DBG(3, "I2C write failed for %s image sensor", sensor->name);
-
- PDBGG("I2C raw write: %u bytes, data0 = 0x%02X, data1 = 0x%02X, "
- "data2 = 0x%02X, data3 = 0x%02X, data4 = 0x%02X, data5 = 0x%02X",
- n, data0, data1, data2, data3, data4, data5);
-
- return err ? -1 : 0;
-}
-
-
-int
-sn9c102_i2c_try_read(struct sn9c102_device* cam,
- const struct sn9c102_sensor* sensor, u8 address)
-{
- return sn9c102_i2c_try_raw_read(cam, sensor, sensor->i2c_slave_id,
- address, 1, NULL);
-}
-
-
-static int sn9c102_i2c_try_write(struct sn9c102_device* cam,
- const struct sn9c102_sensor* sensor,
- u8 address, u8 value)
-{
- return sn9c102_i2c_try_raw_write(cam, sensor, 3,
- sensor->i2c_slave_id, address,
- value, 0, 0, 0);
-}
-
-
-int sn9c102_i2c_read(struct sn9c102_device* cam, u8 address)
-{
- return sn9c102_i2c_try_read(cam, &cam->sensor, address);
-}
-
-
-int sn9c102_i2c_write(struct sn9c102_device* cam, u8 address, u8 value)
-{
- return sn9c102_i2c_try_write(cam, &cam->sensor, address, value);
-}
-
-/*****************************************************************************/
-
-static size_t sn9c102_sof_length(struct sn9c102_device* cam)
-{
- switch (cam->bridge) {
- case BRIDGE_SN9C101:
- case BRIDGE_SN9C102:
- return 12;
- case BRIDGE_SN9C103:
- return 18;
- case BRIDGE_SN9C105:
- case BRIDGE_SN9C120:
- return 62;
- }
-
- return 0;
-}
-
-
-static void*
-sn9c102_find_sof_header(struct sn9c102_device* cam, void* mem, size_t len)
-{
- static const char marker[6] = {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96};
- const char *m = mem;
- size_t soflen = 0, i, j;
-
- soflen = sn9c102_sof_length(cam);
-
- for (i = 0; i < len; i++) {
- size_t b;
-
- /* Read the variable part of the header */
- if (unlikely(cam->sof.bytesread >= sizeof(marker))) {
- cam->sof.header[cam->sof.bytesread] = *(m+i);
- if (++cam->sof.bytesread == soflen) {
- cam->sof.bytesread = 0;
- return mem + i;
- }
- continue;
- }
-
- /* Search for the SOF marker (fixed part) in the header */
- for (j = 0, b=cam->sof.bytesread; j+b < sizeof(marker); j++) {
- if (unlikely(i+j == len))
- return NULL;
- if (*(m+i+j) == marker[cam->sof.bytesread]) {
- cam->sof.header[cam->sof.bytesread] = *(m+i+j);
- if (++cam->sof.bytesread == sizeof(marker)) {
- PDBGG("Bytes to analyze: %zd. SOF "
- "starts at byte #%zd", len, i);
- i += j+1;
- break;
- }
- } else {
- cam->sof.bytesread = 0;
- break;
- }
- }
- }
-
- return NULL;
-}
-
-
-static void*
-sn9c102_find_eof_header(struct sn9c102_device* cam, void* mem, size_t len)
-{
- static const u8 eof_header[4][4] = {
- {0x00, 0x00, 0x00, 0x00},
- {0x40, 0x00, 0x00, 0x00},
- {0x80, 0x00, 0x00, 0x00},
- {0xc0, 0x00, 0x00, 0x00},
- };
- size_t i, j;
-
- /* The EOF header does not exist in compressed data */
- if (cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X ||
- cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_JPEG)
- return NULL;
-
- /*
- The EOF header might cross the packet boundary, but this is not a
- problem, since the end of a frame is determined by checking its size
- in the first place.
- */
- for (i = 0; (len >= 4) && (i <= len - 4); i++)
- for (j = 0; j < ARRAY_SIZE(eof_header); j++)
- if (!memcmp(mem + i, eof_header[j], 4))
- return mem + i;
-
- return NULL;
-}
-
-
-static void
-sn9c102_write_jpegheader(struct sn9c102_device* cam, struct sn9c102_frame_t* f)
-{
- static const u8 jpeg_header[589] = {
- 0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x06, 0x04, 0x05,
- 0x06, 0x05, 0x04, 0x06, 0x06, 0x05, 0x06, 0x07, 0x07, 0x06,
- 0x08, 0x0a, 0x10, 0x0a, 0x0a, 0x09, 0x09, 0x0a, 0x14, 0x0e,
- 0x0f, 0x0c, 0x10, 0x17, 0x14, 0x18, 0x18, 0x17, 0x14, 0x16,
- 0x16, 0x1a, 0x1d, 0x25, 0x1f, 0x1a, 0x1b, 0x23, 0x1c, 0x16,
- 0x16, 0x20, 0x2c, 0x20, 0x23, 0x26, 0x27, 0x29, 0x2a, 0x29,
- 0x19, 0x1f, 0x2d, 0x30, 0x2d, 0x28, 0x30, 0x25, 0x28, 0x29,
- 0x28, 0x01, 0x07, 0x07, 0x07, 0x0a, 0x08, 0x0a, 0x13, 0x0a,
- 0x0a, 0x13, 0x28, 0x1a, 0x16, 0x1a, 0x28, 0x28, 0x28, 0x28,
- 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
- 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
- 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
- 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
- 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0xff, 0xc4, 0x01, 0xa2,
- 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02,
- 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x01,
- 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03,
- 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x10, 0x00,
- 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04,
- 0x04, 0x00, 0x00, 0x01, 0x7d, 0x01, 0x02, 0x03, 0x00, 0x04,
- 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61,
- 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, 0x23,
- 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, 0x24, 0x33, 0x62,
- 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x25,
- 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38,
- 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a,
- 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64,
- 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76,
- 0x77, 0x78, 0x79, 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88,
- 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
- 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa,
- 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2,
- 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3,
- 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, 0xe3,
- 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3,
- 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0x11, 0x00, 0x02,
- 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04,
- 0x00, 0x01, 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, 0x04,
- 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
- 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1,
- 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72, 0xd1,
- 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19,
- 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
- 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a,
- 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64,
- 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76,
- 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
- 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
- 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9,
- 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba,
- 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
- 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe2, 0xe3,
- 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4,
- 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xff, 0xc0, 0x00, 0x11,
- 0x08, 0x01, 0xe0, 0x02, 0x80, 0x03, 0x01, 0x21, 0x00, 0x02,
- 0x11, 0x01, 0x03, 0x11, 0x01, 0xff, 0xda, 0x00, 0x0c, 0x03,
- 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00
- };
- u8 *pos = f->bufmem;
-
- memcpy(pos, jpeg_header, sizeof(jpeg_header));
- *(pos + 6) = 0x00;
- *(pos + 7 + 64) = 0x01;
- if (cam->compression.quality == 0) {
- memcpy(pos + 7, SN9C102_Y_QTABLE0, 64);
- memcpy(pos + 8 + 64, SN9C102_UV_QTABLE0, 64);
- } else if (cam->compression.quality == 1) {
- memcpy(pos + 7, SN9C102_Y_QTABLE1, 64);
- memcpy(pos + 8 + 64, SN9C102_UV_QTABLE1, 64);
- }
- *(pos + 564) = cam->sensor.pix_format.width & 0xFF;
- *(pos + 563) = (cam->sensor.pix_format.width >> 8) & 0xFF;
- *(pos + 562) = cam->sensor.pix_format.height & 0xFF;
- *(pos + 561) = (cam->sensor.pix_format.height >> 8) & 0xFF;
- *(pos + 567) = 0x21;
-
- f->buf.bytesused += sizeof(jpeg_header);
-}
-
-
-static void sn9c102_urb_complete(struct urb *urb)
-{
- struct sn9c102_device* cam = urb->context;
- struct sn9c102_frame_t** f;
- size_t imagesize, soflen;
- u8 i;
- int err = 0;
-
- if (urb->status == -ENOENT)
- return;
-
- f = &cam->frame_current;
-
- if (cam->stream == STREAM_INTERRUPT) {
- cam->stream = STREAM_OFF;
- if ((*f))
- (*f)->state = F_QUEUED;
- cam->sof.bytesread = 0;
- DBG(3, "Stream interrupted by application");
- wake_up(&cam->wait_stream);
- }
-
- if (cam->state & DEV_DISCONNECTED)
- return;
-
- if (cam->state & DEV_MISCONFIGURED) {
- wake_up_interruptible(&cam->wait_frame);
- return;
- }
-
- if (cam->stream == STREAM_OFF || list_empty(&cam->inqueue))
- goto resubmit_urb;
-
- if (!(*f))
- (*f) = list_entry(cam->inqueue.next, struct sn9c102_frame_t,
- frame);
-
- imagesize = (cam->sensor.pix_format.width *
- cam->sensor.pix_format.height *
- cam->sensor.pix_format.priv) / 8;
- if (cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_JPEG)
- imagesize += 589; /* length of jpeg header */
- soflen = sn9c102_sof_length(cam);
-
- for (i = 0; i < urb->number_of_packets; i++) {
- unsigned int img, len, status;
- void *pos, *sof, *eof;
-
- len = urb->iso_frame_desc[i].actual_length;
- status = urb->iso_frame_desc[i].status;
- pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer;
-
- if (status) {
- DBG(3, "Error in isochronous frame");
- (*f)->state = F_ERROR;
- cam->sof.bytesread = 0;
- continue;
- }
-
- PDBGG("Isochrnous frame: length %u, #%u i", len, i);
-
-redo:
- sof = sn9c102_find_sof_header(cam, pos, len);
- if (likely(!sof)) {
- eof = sn9c102_find_eof_header(cam, pos, len);
- if ((*f)->state == F_GRABBING) {
-end_of_frame:
- img = len;
-
- if (eof)
- img = (eof > pos) ? eof - pos - 1 : 0;
-
- if ((*f)->buf.bytesused + img > imagesize) {
- u32 b;
- b = (*f)->buf.bytesused + img -
- imagesize;
- img = imagesize - (*f)->buf.bytesused;
- PDBGG("Expected EOF not found: video "
- "frame cut");
- if (eof)
- DBG(3, "Exceeded limit: +%u "
- "bytes", (unsigned)(b));
- }
-
- memcpy((*f)->bufmem + (*f)->buf.bytesused, pos,
- img);
-
- if ((*f)->buf.bytesused == 0)
- v4l2_get_timestamp(
- &(*f)->buf.timestamp);
-
- (*f)->buf.bytesused += img;
-
- if ((*f)->buf.bytesused == imagesize ||
- ((cam->sensor.pix_format.pixelformat ==
- V4L2_PIX_FMT_SN9C10X ||
- cam->sensor.pix_format.pixelformat ==
- V4L2_PIX_FMT_JPEG) && eof)) {
- u32 b;
-
- b = (*f)->buf.bytesused;
- (*f)->state = F_DONE;
- (*f)->buf.sequence= ++cam->frame_count;
-
- spin_lock(&cam->queue_lock);
- list_move_tail(&(*f)->frame,
- &cam->outqueue);
- if (!list_empty(&cam->inqueue))
- (*f) = list_entry(
- cam->inqueue.next,
- struct sn9c102_frame_t,
- frame );
- else
- (*f) = NULL;
- spin_unlock(&cam->queue_lock);
-
- memcpy(cam->sysfs.frame_header,
- cam->sof.header, soflen);
-
- DBG(3, "Video frame captured: %lu "
- "bytes", (unsigned long)(b));
-
- if (!(*f))
- goto resubmit_urb;
-
- } else if (eof) {
- (*f)->state = F_ERROR;
- DBG(3, "Not expected EOF after %lu "
- "bytes of image data",
- (unsigned long)
- ((*f)->buf.bytesused));
- }
-
- if (sof) /* (1) */
- goto start_of_frame;
-
- } else if (eof) {
- DBG(3, "EOF without SOF");
- continue;
-
- } else {
- PDBGG("Ignoring pointless isochronous frame");
- continue;
- }
-
- } else if ((*f)->state == F_QUEUED || (*f)->state == F_ERROR) {
-start_of_frame:
- (*f)->state = F_GRABBING;
- (*f)->buf.bytesused = 0;
- len -= (sof - pos);
- pos = sof;
- if (cam->sensor.pix_format.pixelformat ==
- V4L2_PIX_FMT_JPEG)
- sn9c102_write_jpegheader(cam, (*f));
- DBG(3, "SOF detected: new video frame");
- if (len)
- goto redo;
-
- } else if ((*f)->state == F_GRABBING) {
- eof = sn9c102_find_eof_header(cam, pos, len);
- if (eof && eof < sof)
- goto end_of_frame; /* (1) */
- else {
- if (cam->sensor.pix_format.pixelformat ==
- V4L2_PIX_FMT_SN9C10X ||
- cam->sensor.pix_format.pixelformat ==
- V4L2_PIX_FMT_JPEG) {
- if (sof - pos >= soflen) {
- eof = sof - soflen;
- } else { /* remove header */
- eof = pos;
- (*f)->buf.bytesused -=
- (soflen - (sof - pos));
- }
- goto end_of_frame;
- } else {
- DBG(3, "SOF before expected EOF after "
- "%lu bytes of image data",
- (unsigned long)
- ((*f)->buf.bytesused));
- goto start_of_frame;
- }
- }
- }
- }
-
-resubmit_urb:
- urb->dev = cam->usbdev;
- err = usb_submit_urb(urb, GFP_ATOMIC);
- if (err < 0 && err != -EPERM) {
- cam->state |= DEV_MISCONFIGURED;
- DBG(1, "usb_submit_urb() failed");
- }
-
- wake_up_interruptible(&cam->wait_frame);
-}
-
-
-static int sn9c102_start_transfer(struct sn9c102_device* cam)
-{
- struct usb_device *udev = cam->usbdev;
- struct urb* urb;
- struct usb_host_interface* altsetting = usb_altnum_to_altsetting(
- usb_ifnum_to_if(udev, 0),
- SN9C102_ALTERNATE_SETTING);
- const unsigned int psz = le16_to_cpu(altsetting->
- endpoint[0].desc.wMaxPacketSize);
- s8 i, j;
- int err = 0;
-
- for (i = 0; i < SN9C102_URBS; i++) {
- cam->transfer_buffer[i] = kzalloc(SN9C102_ISO_PACKETS * psz,
- GFP_KERNEL);
- if (!cam->transfer_buffer[i]) {
- err = -ENOMEM;
- DBG(1, "Not enough memory");
- goto free_buffers;
- }
- }
-
- for (i = 0; i < SN9C102_URBS; i++) {
- urb = usb_alloc_urb(SN9C102_ISO_PACKETS, GFP_KERNEL);
- cam->urb[i] = urb;
- if (!urb) {
- err = -ENOMEM;
- DBG(1, "usb_alloc_urb() failed");
- goto free_urbs;
- }
- urb->dev = udev;
- urb->context = cam;
- urb->pipe = usb_rcvisocpipe(udev, 1);
- urb->transfer_flags = URB_ISO_ASAP;
- urb->number_of_packets = SN9C102_ISO_PACKETS;
- urb->complete = sn9c102_urb_complete;
- urb->transfer_buffer = cam->transfer_buffer[i];
- urb->transfer_buffer_length = psz * SN9C102_ISO_PACKETS;
- urb->interval = 1;
- for (j = 0; j < SN9C102_ISO_PACKETS; j++) {
- urb->iso_frame_desc[j].offset = psz * j;
- urb->iso_frame_desc[j].length = psz;
- }
- }
-
- /* Enable video */
- if (!(cam->reg[0x01] & 0x04)) {
- err = sn9c102_write_reg(cam, cam->reg[0x01] | 0x04, 0x01);
- if (err) {
- err = -EIO;
- DBG(1, "I/O hardware error");
- goto free_urbs;
- }
- }
-
- err = usb_set_interface(udev, 0, SN9C102_ALTERNATE_SETTING);
- if (err) {
- DBG(1, "usb_set_interface() failed");
- goto free_urbs;
- }
-
- cam->frame_current = NULL;
- cam->sof.bytesread = 0;
-
- for (i = 0; i < SN9C102_URBS; i++) {
- err = usb_submit_urb(cam->urb[i], GFP_KERNEL);
- if (err) {
- for (j = i-1; j >= 0; j--)
- usb_kill_urb(cam->urb[j]);
- DBG(1, "usb_submit_urb() failed, error %d", err);
- goto free_urbs;
- }
- }
-
- return 0;
-
-free_urbs:
- for (i = 0; (i < SN9C102_URBS) && cam->urb[i]; i++)
- usb_free_urb(cam->urb[i]);
-
-free_buffers:
- for (i = 0; (i < SN9C102_URBS) && cam->transfer_buffer[i]; i++)
- kfree(cam->transfer_buffer[i]);
-
- return err;
-}
-
-
-static int sn9c102_stop_transfer(struct sn9c102_device* cam)
-{
- struct usb_device *udev = cam->usbdev;
- s8 i;
- int err = 0;
-
- if (cam->state & DEV_DISCONNECTED)
- return 0;
-
- for (i = SN9C102_URBS-1; i >= 0; i--) {
- usb_kill_urb(cam->urb[i]);
- usb_free_urb(cam->urb[i]);
- kfree(cam->transfer_buffer[i]);
- }
-
- err = usb_set_interface(udev, 0, 0); /* 0 Mb/s */
- if (err)
- DBG(3, "usb_set_interface() failed");
-
- return err;
-}
-
-
-static int sn9c102_stream_interrupt(struct sn9c102_device* cam)
-{
- cam->stream = STREAM_INTERRUPT;
- wait_event_timeout(cam->wait_stream,
- (cam->stream == STREAM_OFF) ||
- (cam->state & DEV_DISCONNECTED),
- SN9C102_URB_TIMEOUT);
- if (cam->state & DEV_DISCONNECTED)
- return -ENODEV;
- else if (cam->stream != STREAM_OFF) {
- cam->state |= DEV_MISCONFIGURED;
- DBG(1, "URB timeout reached. The camera is misconfigured. "
- "To use it, close and open %s again.",
- video_device_node_name(cam->v4ldev));
- return -EIO;
- }
-
- return 0;
-}
-
-/*****************************************************************************/
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static u16 sn9c102_strtou16(const char* buff, size_t len, ssize_t* count)
-{
- char str[7];
- char* endp;
- unsigned long val;
-
- if (len < 6) {
- strncpy(str, buff, len);
- str[len] = '\0';
- } else {
- strncpy(str, buff, 6);
- str[6] = '\0';
- }
-
- val = simple_strtoul(str, &endp, 0);
-
- *count = 0;
- if (val <= 0xffff)
- *count = (ssize_t)(endp - str);
- if ((*count) && (len == *count+1) && (buff[*count] == '\n'))
- *count += 1;
-
- return (u16)val;
-}
-
-/*
- NOTE 1: being inside one of the following methods implies that the v4l
- device exists for sure (see kobjects and reference counters)
- NOTE 2: buffers are PAGE_SIZE long
-*/
-
-static ssize_t sn9c102_show_reg(struct device* cd,
- struct device_attribute *attr, char* buf)
-{
- struct sn9c102_device* cam;
- ssize_t count;
-
- if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
- return -ERESTARTSYS;
-
- cam = video_get_drvdata(container_of(cd, struct video_device, dev));
- if (!cam) {
- mutex_unlock(&sn9c102_sysfs_lock);
- return -ENODEV;
- }
-
- count = sprintf(buf, "%u\n", cam->sysfs.reg);
-
- mutex_unlock(&sn9c102_sysfs_lock);
-
- return count;
-}
-
-
-static ssize_t
-sn9c102_store_reg(struct device* cd, struct device_attribute *attr,
- const char* buf, size_t len)
-{
- struct sn9c102_device* cam;
- u16 index;
- ssize_t count;
-
- if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
- return -ERESTARTSYS;
-
- cam = video_get_drvdata(container_of(cd, struct video_device, dev));
- if (!cam) {
- mutex_unlock(&sn9c102_sysfs_lock);
- return -ENODEV;
- }
-
- index = sn9c102_strtou16(buf, len, &count);
- if (index >= ARRAY_SIZE(cam->reg) || !count) {
- mutex_unlock(&sn9c102_sysfs_lock);
- return -EINVAL;
- }
-
- cam->sysfs.reg = index;
-
- DBG(2, "Moved SN9C1XX register index to 0x%02X", cam->sysfs.reg);
- DBG(3, "Written bytes: %zd", count);
-
- mutex_unlock(&sn9c102_sysfs_lock);
-
- return count;
-}
-
-
-static ssize_t sn9c102_show_val(struct device* cd,
- struct device_attribute *attr, char* buf)
-{
- struct sn9c102_device* cam;
- ssize_t count;
- int val;
-
- if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
- return -ERESTARTSYS;
-
- cam = video_get_drvdata(container_of(cd, struct video_device, dev));
- if (!cam) {
- mutex_unlock(&sn9c102_sysfs_lock);
- return -ENODEV;
- }
-
- if ((val = sn9c102_read_reg(cam, cam->sysfs.reg)) < 0) {
- mutex_unlock(&sn9c102_sysfs_lock);
- return -EIO;
- }
-
- count = sprintf(buf, "%d\n", val);
-
- DBG(3, "Read bytes: %zd, value: %d", count, val);
-
- mutex_unlock(&sn9c102_sysfs_lock);
-
- return count;
-}
-
-
-static ssize_t
-sn9c102_store_val(struct device* cd, struct device_attribute *attr,
- const char* buf, size_t len)
-{
- struct sn9c102_device* cam;
- u16 value;
- ssize_t count;
- int err;
-
- if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
- return -ERESTARTSYS;
-
- cam = video_get_drvdata(container_of(cd, struct video_device, dev));
- if (!cam) {
- mutex_unlock(&sn9c102_sysfs_lock);
- return -ENODEV;
- }
-
- value = sn9c102_strtou16(buf, len, &count);
- if (!count) {
- mutex_unlock(&sn9c102_sysfs_lock);
- return -EINVAL;
- }
-
- err = sn9c102_write_reg(cam, value, cam->sysfs.reg);
- if (err) {
- mutex_unlock(&sn9c102_sysfs_lock);
- return -EIO;
- }
-
- DBG(2, "Written SN9C1XX reg. 0x%02X, val. 0x%02X",
- cam->sysfs.reg, value);
- DBG(3, "Written bytes: %zd", count);
-
- mutex_unlock(&sn9c102_sysfs_lock);
-
- return count;
-}
-
-
-static ssize_t sn9c102_show_i2c_reg(struct device* cd,
- struct device_attribute *attr, char* buf)
-{
- struct sn9c102_device* cam;
- ssize_t count;
-
- if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
- return -ERESTARTSYS;
-
- cam = video_get_drvdata(container_of(cd, struct video_device, dev));
- if (!cam) {
- mutex_unlock(&sn9c102_sysfs_lock);
- return -ENODEV;
- }
-
- count = sprintf(buf, "%u\n", cam->sysfs.i2c_reg);
-
- DBG(3, "Read bytes: %zd", count);
-
- mutex_unlock(&sn9c102_sysfs_lock);
-
- return count;
-}
-
-
-static ssize_t
-sn9c102_store_i2c_reg(struct device* cd, struct device_attribute *attr,
- const char* buf, size_t len)
-{
- struct sn9c102_device* cam;
- u16 index;
- ssize_t count;
-
- if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
- return -ERESTARTSYS;
-
- cam = video_get_drvdata(container_of(cd, struct video_device, dev));
- if (!cam) {
- mutex_unlock(&sn9c102_sysfs_lock);
- return -ENODEV;
- }
-
- index = sn9c102_strtou16(buf, len, &count);
- if (!count) {
- mutex_unlock(&sn9c102_sysfs_lock);
- return -EINVAL;
- }
-
- cam->sysfs.i2c_reg = index;
-
- DBG(2, "Moved sensor register index to 0x%02X", cam->sysfs.i2c_reg);
- DBG(3, "Written bytes: %zd", count);
-
- mutex_unlock(&sn9c102_sysfs_lock);
-
- return count;
-}
-
-
-static ssize_t sn9c102_show_i2c_val(struct device* cd,
- struct device_attribute *attr, char* buf)
-{
- struct sn9c102_device* cam;
- ssize_t count;
- int val;
-
- if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
- return -ERESTARTSYS;
-
- cam = video_get_drvdata(container_of(cd, struct video_device, dev));
- if (!cam) {
- mutex_unlock(&sn9c102_sysfs_lock);
- return -ENODEV;
- }
-
- if (!(cam->sensor.sysfs_ops & SN9C102_I2C_READ)) {
- mutex_unlock(&sn9c102_sysfs_lock);
- return -ENOSYS;
- }
-
- if ((val = sn9c102_i2c_read(cam, cam->sysfs.i2c_reg)) < 0) {
- mutex_unlock(&sn9c102_sysfs_lock);
- return -EIO;
- }
-
- count = sprintf(buf, "%d\n", val);
-
- DBG(3, "Read bytes: %zd, value: %d", count, val);
-
- mutex_unlock(&sn9c102_sysfs_lock);
-
- return count;
-}
-
-
-static ssize_t
-sn9c102_store_i2c_val(struct device* cd, struct device_attribute *attr,
- const char* buf, size_t len)
-{
- struct sn9c102_device* cam;
- u16 value;
- ssize_t count;
- int err;
-
- if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
- return -ERESTARTSYS;
-
- cam = video_get_drvdata(container_of(cd, struct video_device, dev));
- if (!cam) {
- mutex_unlock(&sn9c102_sysfs_lock);
- return -ENODEV;
- }
-
- if (!(cam->sensor.sysfs_ops & SN9C102_I2C_WRITE)) {
- mutex_unlock(&sn9c102_sysfs_lock);
- return -ENOSYS;
- }
-
- value = sn9c102_strtou16(buf, len, &count);
- if (!count) {
- mutex_unlock(&sn9c102_sysfs_lock);
- return -EINVAL;
- }
-
- err = sn9c102_i2c_write(cam, cam->sysfs.i2c_reg, value);
- if (err) {
- mutex_unlock(&sn9c102_sysfs_lock);
- return -EIO;
- }
-
- DBG(2, "Written sensor reg. 0x%02X, val. 0x%02X",
- cam->sysfs.i2c_reg, value);
- DBG(3, "Written bytes: %zd", count);
-
- mutex_unlock(&sn9c102_sysfs_lock);
-
- return count;
-}
-
-
-static ssize_t
-sn9c102_store_green(struct device* cd, struct device_attribute *attr,
- const char* buf, size_t len)
-{
- struct sn9c102_device* cam;
- enum sn9c102_bridge bridge;
- ssize_t res = 0;
- u16 value;
- ssize_t count;
-
- if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
- return -ERESTARTSYS;
-
- cam = video_get_drvdata(container_of(cd, struct video_device, dev));
- if (!cam) {
- mutex_unlock(&sn9c102_sysfs_lock);
- return -ENODEV;
- }
-
- bridge = cam->bridge;
-
- mutex_unlock(&sn9c102_sysfs_lock);
-
- value = sn9c102_strtou16(buf, len, &count);
- if (!count)
- return -EINVAL;
-
- switch (bridge) {
- case BRIDGE_SN9C101:
- case BRIDGE_SN9C102:
- if (value > 0x0f)
- return -EINVAL;
- if ((res = sn9c102_store_reg(cd, attr, "0x11", 4)) >= 0)
- res = sn9c102_store_val(cd, attr, buf, len);
- break;
- case BRIDGE_SN9C103:
- case BRIDGE_SN9C105:
- case BRIDGE_SN9C120:
- if (value > 0x7f)
- return -EINVAL;
- if ((res = sn9c102_store_reg(cd, attr, "0x07", 4)) >= 0)
- res = sn9c102_store_val(cd, attr, buf, len);
- break;
- }
-
- return res;
-}
-
-
-static ssize_t
-sn9c102_store_blue(struct device* cd, struct device_attribute *attr,
- const char* buf, size_t len)
-{
- ssize_t res = 0;
- u16 value;
- ssize_t count;
-
- value = sn9c102_strtou16(buf, len, &count);
- if (!count || value > 0x7f)
- return -EINVAL;
-
- if ((res = sn9c102_store_reg(cd, attr, "0x06", 4)) >= 0)
- res = sn9c102_store_val(cd, attr, buf, len);
-
- return res;
-}
-
-
-static ssize_t
-sn9c102_store_red(struct device* cd, struct device_attribute *attr,
- const char* buf, size_t len)
-{
- ssize_t res = 0;
- u16 value;
- ssize_t count;
-
- value = sn9c102_strtou16(buf, len, &count);
- if (!count || value > 0x7f)
- return -EINVAL;
-
- if ((res = sn9c102_store_reg(cd, attr, "0x05", 4)) >= 0)
- res = sn9c102_store_val(cd, attr, buf, len);
-
- return res;
-}
-
-
-static ssize_t sn9c102_show_frame_header(struct device* cd,
- struct device_attribute *attr,
- char* buf)
-{
- struct sn9c102_device* cam;
- ssize_t count;
-
- cam = video_get_drvdata(container_of(cd, struct video_device, dev));
- if (!cam)
- return -ENODEV;
-
- count = sizeof(cam->sysfs.frame_header);
- memcpy(buf, cam->sysfs.frame_header, count);
-
- DBG(3, "Frame header, read bytes: %zd", count);
-
- return count;
-}
-
-
-static DEVICE_ATTR(reg, S_IRUGO | S_IWUSR, sn9c102_show_reg, sn9c102_store_reg);
-static DEVICE_ATTR(val, S_IRUGO | S_IWUSR, sn9c102_show_val, sn9c102_store_val);
-static DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR,
- sn9c102_show_i2c_reg, sn9c102_store_i2c_reg);
-static DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR,
- sn9c102_show_i2c_val, sn9c102_store_i2c_val);
-static DEVICE_ATTR(green, S_IWUSR, NULL, sn9c102_store_green);
-static DEVICE_ATTR(blue, S_IWUSR, NULL, sn9c102_store_blue);
-static DEVICE_ATTR(red, S_IWUSR, NULL, sn9c102_store_red);
-static DEVICE_ATTR(frame_header, S_IRUGO, sn9c102_show_frame_header, NULL);
-
-
-static int sn9c102_create_sysfs(struct sn9c102_device* cam)
-{
- struct device *dev = &(cam->v4ldev->dev);
- int err = 0;
-
- if ((err = device_create_file(dev, &dev_attr_reg)))
- goto err_out;
- if ((err = device_create_file(dev, &dev_attr_val)))
- goto err_reg;
- if ((err = device_create_file(dev, &dev_attr_frame_header)))
- goto err_val;
-
- if (cam->sensor.sysfs_ops) {
- if ((err = device_create_file(dev, &dev_attr_i2c_reg)))
- goto err_frame_header;
- if ((err = device_create_file(dev, &dev_attr_i2c_val)))
- goto err_i2c_reg;
- }
-
- if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) {
- if ((err = device_create_file(dev, &dev_attr_green)))
- goto err_i2c_val;
- } else {
- if ((err = device_create_file(dev, &dev_attr_blue)))
- goto err_i2c_val;
- if ((err = device_create_file(dev, &dev_attr_red)))
- goto err_blue;
- }
-
- return 0;
-
-err_blue:
- device_remove_file(dev, &dev_attr_blue);
-err_i2c_val:
- if (cam->sensor.sysfs_ops)
- device_remove_file(dev, &dev_attr_i2c_val);
-err_i2c_reg:
- if (cam->sensor.sysfs_ops)
- device_remove_file(dev, &dev_attr_i2c_reg);
-err_frame_header:
- device_remove_file(dev, &dev_attr_frame_header);
-err_val:
- device_remove_file(dev, &dev_attr_val);
-err_reg:
- device_remove_file(dev, &dev_attr_reg);
-err_out:
- return err;
-}
-#endif /* CONFIG_VIDEO_ADV_DEBUG */
-
-/*****************************************************************************/
-
-static int
-sn9c102_set_pix_format(struct sn9c102_device* cam, struct v4l2_pix_format* pix)
-{
- int err = 0;
-
- if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X ||
- pix->pixelformat == V4L2_PIX_FMT_JPEG) {
- switch (cam->bridge) {
- case BRIDGE_SN9C101:
- case BRIDGE_SN9C102:
- case BRIDGE_SN9C103:
- err += sn9c102_write_reg(cam, cam->reg[0x18] | 0x80,
- 0x18);
- break;
- case BRIDGE_SN9C105:
- case BRIDGE_SN9C120:
- err += sn9c102_write_reg(cam, cam->reg[0x18] & 0x7f,
- 0x18);
- break;
- }
- } else {
- switch (cam->bridge) {
- case BRIDGE_SN9C101:
- case BRIDGE_SN9C102:
- case BRIDGE_SN9C103:
- err += sn9c102_write_reg(cam, cam->reg[0x18] & 0x7f,
- 0x18);
- break;
- case BRIDGE_SN9C105:
- case BRIDGE_SN9C120:
- err += sn9c102_write_reg(cam, cam->reg[0x18] | 0x80,
- 0x18);
- break;
- }
- }
-
- return err ? -EIO : 0;
-}
-
-
-static int
-sn9c102_set_compression(struct sn9c102_device* cam,
- struct v4l2_jpegcompression* compression)
-{
- int i, err = 0;
-
- switch (cam->bridge) {
- case BRIDGE_SN9C101:
- case BRIDGE_SN9C102:
- case BRIDGE_SN9C103:
- if (compression->quality == 0)
- err += sn9c102_write_reg(cam, cam->reg[0x17] | 0x01,
- 0x17);
- else if (compression->quality == 1)
- err += sn9c102_write_reg(cam, cam->reg[0x17] & 0xfe,
- 0x17);
- break;
- case BRIDGE_SN9C105:
- case BRIDGE_SN9C120:
- if (compression->quality == 0) {
- for (i = 0; i <= 63; i++) {
- err += sn9c102_write_reg(cam,
- SN9C102_Y_QTABLE1[i],
- 0x100 + i);
- err += sn9c102_write_reg(cam,
- SN9C102_UV_QTABLE1[i],
- 0x140 + i);
- }
- err += sn9c102_write_reg(cam, cam->reg[0x18] & 0xbf,
- 0x18);
- } else if (compression->quality == 1) {
- for (i = 0; i <= 63; i++) {
- err += sn9c102_write_reg(cam,
- SN9C102_Y_QTABLE1[i],
- 0x100 + i);
- err += sn9c102_write_reg(cam,
- SN9C102_UV_QTABLE1[i],
- 0x140 + i);
- }
- err += sn9c102_write_reg(cam, cam->reg[0x18] | 0x40,
- 0x18);
- }
- break;
- }
-
- return err ? -EIO : 0;
-}
-
-
-static int sn9c102_set_scale(struct sn9c102_device* cam, u8 scale)
-{
- u8 r = 0;
- int err = 0;
-
- if (scale == 1)
- r = cam->reg[0x18] & 0xcf;
- else if (scale == 2) {
- r = cam->reg[0x18] & 0xcf;
- r |= 0x10;
- } else if (scale == 4)
- r = cam->reg[0x18] | 0x20;
-
- err += sn9c102_write_reg(cam, r, 0x18);
- if (err)
- return -EIO;
-
- PDBGG("Scaling factor: %u", scale);
-
- return 0;
-}
-
-
-static int sn9c102_set_crop(struct sn9c102_device* cam, struct v4l2_rect* rect)
-{
- struct sn9c102_sensor* s = &cam->sensor;
- u8 h_start = (u8)(rect->left - s->cropcap.bounds.left),
- v_start = (u8)(rect->top - s->cropcap.bounds.top),
- h_size = (u8)(rect->width / 16),
- v_size = (u8)(rect->height / 16);
- int err = 0;
-
- err += sn9c102_write_reg(cam, h_start, 0x12);
- err += sn9c102_write_reg(cam, v_start, 0x13);
- err += sn9c102_write_reg(cam, h_size, 0x15);
- err += sn9c102_write_reg(cam, v_size, 0x16);
- if (err)
- return -EIO;
-
- PDBGG("h_start, v_start, h_size, v_size, ho_size, vo_size "
- "%u %u %u %u", h_start, v_start, h_size, v_size);
-
- return 0;
-}
-
-
-static int sn9c102_init(struct sn9c102_device* cam)
-{
- struct sn9c102_sensor* s = &cam->sensor;
- struct v4l2_control ctrl;
- struct v4l2_queryctrl *qctrl;
- struct v4l2_rect* rect;
- u8 i = 0;
- int err = 0;
-
- if (!(cam->state & DEV_INITIALIZED)) {
- mutex_init(&cam->open_mutex);
- init_waitqueue_head(&cam->wait_open);
- qctrl = s->qctrl;
- rect = &(s->cropcap.defrect);
- } else { /* use current values */
- qctrl = s->_qctrl;
- rect = &(s->_rect);
- }
-
- err += sn9c102_set_scale(cam, rect->width / s->pix_format.width);
- err += sn9c102_set_crop(cam, rect);
- if (err)
- return err;
-
- if (s->init) {
- err = s->init(cam);
- if (err) {
- DBG(3, "Sensor initialization failed");
- return err;
- }
- }
-
- if (!(cam->state & DEV_INITIALIZED))
- if (cam->bridge == BRIDGE_SN9C101 ||
- cam->bridge == BRIDGE_SN9C102 ||
- cam->bridge == BRIDGE_SN9C103) {
- if (s->pix_format.pixelformat == V4L2_PIX_FMT_JPEG)
- s->pix_format.pixelformat= V4L2_PIX_FMT_SBGGR8;
- cam->compression.quality = cam->reg[0x17] & 0x01 ?
- 0 : 1;
- } else {
- if (s->pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X)
- s->pix_format.pixelformat = V4L2_PIX_FMT_JPEG;
- cam->compression.quality = cam->reg[0x18] & 0x40 ?
- 0 : 1;
- err += sn9c102_set_compression(cam, &cam->compression);
- }
- else
- err += sn9c102_set_compression(cam, &cam->compression);
- err += sn9c102_set_pix_format(cam, &s->pix_format);
- if (s->set_pix_format)
- err += s->set_pix_format(cam, &s->pix_format);
- if (err)
- return err;
-
- if (s->pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X ||
- s->pix_format.pixelformat == V4L2_PIX_FMT_JPEG)
- DBG(3, "Compressed video format is active, quality %d",
- cam->compression.quality);
- else
- DBG(3, "Uncompressed video format is active");
-
- if (s->set_crop)
- if ((err = s->set_crop(cam, rect))) {
- DBG(3, "set_crop() failed");
- return err;
- }
-
- if (s->set_ctrl) {
- for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
- if (s->qctrl[i].id != 0 &&
- !(s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)) {
- ctrl.id = s->qctrl[i].id;
- ctrl.value = qctrl[i].default_value;
- err = s->set_ctrl(cam, &ctrl);
- if (err) {
- DBG(3, "Set %s control failed",
- s->qctrl[i].name);
- return err;
- }
- DBG(3, "Image sensor supports '%s' control",
- s->qctrl[i].name);
- }
- }
-
- if (!(cam->state & DEV_INITIALIZED)) {
- mutex_init(&cam->fileop_mutex);
- spin_lock_init(&cam->queue_lock);
- init_waitqueue_head(&cam->wait_frame);
- init_waitqueue_head(&cam->wait_stream);
- cam->nreadbuffers = 2;
- memcpy(s->_qctrl, s->qctrl, sizeof(s->qctrl));
- memcpy(&(s->_rect), &(s->cropcap.defrect),
- sizeof(struct v4l2_rect));
- cam->state |= DEV_INITIALIZED;
- }
-
- DBG(2, "Initialization succeeded");
- return 0;
-}
-
-/*****************************************************************************/
-
-static void sn9c102_release_resources(struct kref *kref)
-{
- struct sn9c102_device *cam;
-
- mutex_lock(&sn9c102_sysfs_lock);
-
- cam = container_of(kref, struct sn9c102_device, kref);
-
- DBG(2, "V4L2 device %s deregistered",
- video_device_node_name(cam->v4ldev));
- video_set_drvdata(cam->v4ldev, NULL);
- video_unregister_device(cam->v4ldev);
- v4l2_device_unregister(&cam->v4l2_dev);
- usb_put_dev(cam->usbdev);
- kfree(cam->control_buffer);
- kfree(cam);
-
- mutex_unlock(&sn9c102_sysfs_lock);
-
-}
-
-
-static int sn9c102_open(struct file *filp)
-{
- struct sn9c102_device* cam;
- int err = 0;
-
- /*
- A read_trylock() in open() is the only safe way to prevent race
- conditions with disconnect(), one close() and multiple (not
- necessarily simultaneous) attempts to open(). For example, it
- prevents from waiting for a second access, while the device
- structure is being deallocated, after a possible disconnect() and
- during a following close() holding the write lock: given that, after
- this deallocation, no access will be possible anymore, using the
- non-trylock version would have let open() gain the access to the
- device structure improperly.
- For this reason the lock must also not be per-device.
- */
- if (!down_read_trylock(&sn9c102_dev_lock))
- return -ERESTARTSYS;
-
- cam = video_drvdata(filp);
-
- if (wait_for_completion_interruptible(&cam->probe)) {
- up_read(&sn9c102_dev_lock);
- return -ERESTARTSYS;
- }
-
- kref_get(&cam->kref);
-
- /*
- Make sure to isolate all the simultaneous opens.
- */
- if (mutex_lock_interruptible(&cam->open_mutex)) {
- kref_put(&cam->kref, sn9c102_release_resources);
- up_read(&sn9c102_dev_lock);
- return -ERESTARTSYS;
- }
-
- if (cam->state & DEV_DISCONNECTED) {
- DBG(1, "Device not present");
- err = -ENODEV;
- goto out;
- }
-
- if (cam->users) {
- DBG(2, "Device %s is already in use",
- video_device_node_name(cam->v4ldev));
- DBG(3, "Simultaneous opens are not supported");
- /*
- open() must follow the open flags and should block
- eventually while the device is in use.
- */
- if ((filp->f_flags & O_NONBLOCK) ||
- (filp->f_flags & O_NDELAY)) {
- err = -EWOULDBLOCK;
- goto out;
- }
- DBG(2, "A blocking open() has been requested. Wait for the "
- "device to be released...");
- up_read(&sn9c102_dev_lock);
- /*
- We will not release the "open_mutex" lock, so that only one
- process can be in the wait queue below. This way the process
- will be sleeping while holding the lock, without losing its
- priority after any wake_up().
- */
- err = wait_event_interruptible_exclusive(cam->wait_open,
- (cam->state & DEV_DISCONNECTED)
- || !cam->users);
- down_read(&sn9c102_dev_lock);
- if (err)
- goto out;
- if (cam->state & DEV_DISCONNECTED) {
- err = -ENODEV;
- goto out;
- }
- }
-
- if (cam->state & DEV_MISCONFIGURED) {
- err = sn9c102_init(cam);
- if (err) {
- DBG(1, "Initialization failed again. "
- "I will retry on next open().");
- goto out;
- }
- cam->state &= ~DEV_MISCONFIGURED;
- }
-
- if ((err = sn9c102_start_transfer(cam)))
- goto out;
-
- filp->private_data = cam;
- cam->users++;
- cam->io = IO_NONE;
- cam->stream = STREAM_OFF;
- cam->nbuffers = 0;
- cam->frame_count = 0;
- sn9c102_empty_framequeues(cam);
-
- DBG(3, "Video device %s is open", video_device_node_name(cam->v4ldev));
-
-out:
- mutex_unlock(&cam->open_mutex);
- if (err)
- kref_put(&cam->kref, sn9c102_release_resources);
-
- up_read(&sn9c102_dev_lock);
- return err;
-}
-
-
-static int sn9c102_release(struct file *filp)
-{
- struct sn9c102_device* cam;
-
- down_write(&sn9c102_dev_lock);
-
- cam = video_drvdata(filp);
-
- sn9c102_stop_transfer(cam);
- sn9c102_release_buffers(cam);
- cam->users--;
- wake_up_interruptible_nr(&cam->wait_open, 1);
-
- DBG(3, "Video device %s closed", video_device_node_name(cam->v4ldev));
-
- kref_put(&cam->kref, sn9c102_release_resources);
-
- up_write(&sn9c102_dev_lock);
-
- return 0;
-}
-
-
-static ssize_t
-sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
-{
- struct sn9c102_device *cam = video_drvdata(filp);
- struct sn9c102_frame_t* f, * i;
- unsigned long lock_flags;
- long timeout;
- int err = 0;
-
- if (mutex_lock_interruptible(&cam->fileop_mutex))
- return -ERESTARTSYS;
-
- if (cam->state & DEV_DISCONNECTED) {
- DBG(1, "Device not present");
- mutex_unlock(&cam->fileop_mutex);
- return -ENODEV;
- }
-
- if (cam->state & DEV_MISCONFIGURED) {
- DBG(1, "The camera is misconfigured. Close and open it "
- "again.");
- mutex_unlock(&cam->fileop_mutex);
- return -EIO;
- }
-
- if (cam->io == IO_MMAP) {
- DBG(3, "Close and open the device again to choose "
- "the read method");
- mutex_unlock(&cam->fileop_mutex);
- return -EBUSY;
- }
-
- if (cam->io == IO_NONE) {
- if (!sn9c102_request_buffers(cam,cam->nreadbuffers, IO_READ)) {
- DBG(1, "read() failed, not enough memory");
- mutex_unlock(&cam->fileop_mutex);
- return -ENOMEM;
- }
- cam->io = IO_READ;
- cam->stream = STREAM_ON;
- }
-
- if (list_empty(&cam->inqueue)) {
- if (!list_empty(&cam->outqueue))
- sn9c102_empty_framequeues(cam);
- sn9c102_queue_unusedframes(cam);
- }
-
- if (!count) {
- mutex_unlock(&cam->fileop_mutex);
- return 0;
- }
-
- if (list_empty(&cam->outqueue)) {
- if (filp->f_flags & O_NONBLOCK) {
- mutex_unlock(&cam->fileop_mutex);
- return -EAGAIN;
- }
- if (!cam->module_param.frame_timeout) {
- err = wait_event_interruptible
- ( cam->wait_frame,
- (!list_empty(&cam->outqueue)) ||
- (cam->state & DEV_DISCONNECTED) ||
- (cam->state & DEV_MISCONFIGURED) );
- if (err) {
- mutex_unlock(&cam->fileop_mutex);
- return err;
- }
- } else {
- timeout = wait_event_interruptible_timeout
- ( cam->wait_frame,
- (!list_empty(&cam->outqueue)) ||
- (cam->state & DEV_DISCONNECTED) ||
- (cam->state & DEV_MISCONFIGURED),
- msecs_to_jiffies(
- cam->module_param.frame_timeout * 1000
- )
- );
- if (timeout < 0) {
- mutex_unlock(&cam->fileop_mutex);
- return timeout;
- } else if (timeout == 0 &&
- !(cam->state & DEV_DISCONNECTED)) {
- DBG(1, "Video frame timeout elapsed");
- mutex_unlock(&cam->fileop_mutex);
- return -EIO;
- }
- }
- if (cam->state & DEV_DISCONNECTED) {
- mutex_unlock(&cam->fileop_mutex);
- return -ENODEV;
- }
- if (cam->state & DEV_MISCONFIGURED) {
- mutex_unlock(&cam->fileop_mutex);
- return -EIO;
- }
- }
-
- f = list_entry(cam->outqueue.prev, struct sn9c102_frame_t, frame);
-
- if (count > f->buf.bytesused)
- count = f->buf.bytesused;
-
- if (copy_to_user(buf, f->bufmem, count)) {
- err = -EFAULT;
- goto exit;
- }
- *f_pos += count;
-
-exit:
- spin_lock_irqsave(&cam->queue_lock, lock_flags);
- list_for_each_entry(i, &cam->outqueue, frame)
- i->state = F_UNUSED;
- INIT_LIST_HEAD(&cam->outqueue);
- spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
-
- sn9c102_queue_unusedframes(cam);
-
- PDBGG("Frame #%lu, bytes read: %zu",
- (unsigned long)f->buf.index, count);
-
- mutex_unlock(&cam->fileop_mutex);
-
- return count;
-}
-
-
-static unsigned int sn9c102_poll(struct file *filp, poll_table *wait)
-{
- struct sn9c102_device *cam = video_drvdata(filp);
- struct sn9c102_frame_t* f;
- unsigned long lock_flags;
- unsigned int mask = 0;
-
- if (mutex_lock_interruptible(&cam->fileop_mutex))
- return POLLERR;
-
- if (cam->state & DEV_DISCONNECTED) {
- DBG(1, "Device not present");
- goto error;
- }
-
- if (cam->state & DEV_MISCONFIGURED) {
- DBG(1, "The camera is misconfigured. Close and open it "
- "again.");
- goto error;
- }
-
- if (cam->io == IO_NONE) {
- if (!sn9c102_request_buffers(cam, cam->nreadbuffers,
- IO_READ)) {
- DBG(1, "poll() failed, not enough memory");
- goto error;
- }
- cam->io = IO_READ;
- cam->stream = STREAM_ON;
- }
-
- if (cam->io == IO_READ) {
- spin_lock_irqsave(&cam->queue_lock, lock_flags);
- list_for_each_entry(f, &cam->outqueue, frame)
- f->state = F_UNUSED;
- INIT_LIST_HEAD(&cam->outqueue);
- spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
- sn9c102_queue_unusedframes(cam);
- }
-
- poll_wait(filp, &cam->wait_frame, wait);
-
- if (!list_empty(&cam->outqueue))
- mask |= POLLIN | POLLRDNORM;
-
- mutex_unlock(&cam->fileop_mutex);
-
- return mask;
-
-error:
- mutex_unlock(&cam->fileop_mutex);
- return POLLERR;
-}
-
-
-static void sn9c102_vm_open(struct vm_area_struct* vma)
-{
- struct sn9c102_frame_t* f = vma->vm_private_data;
- f->vma_use_count++;
-}
-
-
-static void sn9c102_vm_close(struct vm_area_struct* vma)
-{
- /* NOTE: buffers are not freed here */
- struct sn9c102_frame_t* f = vma->vm_private_data;
- f->vma_use_count--;
-}
-
-
-static const struct vm_operations_struct sn9c102_vm_ops = {
- .open = sn9c102_vm_open,
- .close = sn9c102_vm_close,
-};
-
-
-static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma)
-{
- struct sn9c102_device *cam = video_drvdata(filp);
- unsigned long size = vma->vm_end - vma->vm_start,
- start = vma->vm_start;
- void *pos;
- u32 i;
-
- if (mutex_lock_interruptible(&cam->fileop_mutex))
- return -ERESTARTSYS;
-
- if (cam->state & DEV_DISCONNECTED) {
- DBG(1, "Device not present");
- mutex_unlock(&cam->fileop_mutex);
- return -ENODEV;
- }
-
- if (cam->state & DEV_MISCONFIGURED) {
- DBG(1, "The camera is misconfigured. Close and open it "
- "again.");
- mutex_unlock(&cam->fileop_mutex);
- return -EIO;
- }
-
- if (!(vma->vm_flags & (VM_WRITE | VM_READ))) {
- mutex_unlock(&cam->fileop_mutex);
- return -EACCES;
- }
-
- if (cam->io != IO_MMAP ||
- size != PAGE_ALIGN(cam->frame[0].buf.length)) {
- mutex_unlock(&cam->fileop_mutex);
- return -EINVAL;
- }
-
- for (i = 0; i < cam->nbuffers; i++) {
- if ((cam->frame[i].buf.m.offset>>PAGE_SHIFT) == vma->vm_pgoff)
- break;
- }
- if (i == cam->nbuffers) {
- mutex_unlock(&cam->fileop_mutex);
- return -EINVAL;
- }
-
- vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP;
-
- pos = cam->frame[i].bufmem;
- while (size > 0) { /* size is page-aligned */
- if (vm_insert_page(vma, start, vmalloc_to_page(pos))) {
- mutex_unlock(&cam->fileop_mutex);
- return -EAGAIN;
- }
- start += PAGE_SIZE;
- pos += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
-
- vma->vm_ops = &sn9c102_vm_ops;
- vma->vm_private_data = &cam->frame[i];
- sn9c102_vm_open(vma);
-
- mutex_unlock(&cam->fileop_mutex);
-
- return 0;
-}
-
-/*****************************************************************************/
-
-static int
-sn9c102_vidioc_querycap(struct sn9c102_device* cam, void __user * arg)
-{
- struct v4l2_capability cap = {
- .driver = "sn9c102",
- .version = LINUX_VERSION_CODE,
- .capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
- V4L2_CAP_STREAMING,
- };
-
- strlcpy(cap.card, cam->v4ldev->name, sizeof(cap.card));
- if (usb_make_path(cam->usbdev, cap.bus_info, sizeof(cap.bus_info)) < 0)
- strlcpy(cap.bus_info, dev_name(&cam->usbdev->dev),
- sizeof(cap.bus_info));
-
- if (copy_to_user(arg, &cap, sizeof(cap)))
- return -EFAULT;
-
- return 0;
-}
-
-
-static int
-sn9c102_vidioc_enuminput(struct sn9c102_device* cam, void __user * arg)
-{
- struct v4l2_input i;
-
- if (copy_from_user(&i, arg, sizeof(i)))
- return -EFAULT;
-
- if (i.index)
- return -EINVAL;
-
- memset(&i, 0, sizeof(i));
- strcpy(i.name, "Camera");
- i.type = V4L2_INPUT_TYPE_CAMERA;
- i.capabilities = V4L2_IN_CAP_STD;
-
- if (copy_to_user(arg, &i, sizeof(i)))
- return -EFAULT;
-
- return 0;
-}
-
-
-static int
-sn9c102_vidioc_g_input(struct sn9c102_device* cam, void __user * arg)
-{
- int index = 0;
-
- if (copy_to_user(arg, &index, sizeof(index)))
- return -EFAULT;
-
- return 0;
-}
-
-
-static int
-sn9c102_vidioc_s_input(struct sn9c102_device* cam, void __user * arg)
-{
- int index;
-
- if (copy_from_user(&index, arg, sizeof(index)))
- return -EFAULT;
-
- if (index != 0)
- return -EINVAL;
-
- return 0;
-}
-
-
-static int
-sn9c102_vidioc_query_ctrl(struct sn9c102_device* cam, void __user * arg)
-{
- struct sn9c102_sensor* s = &cam->sensor;
- struct v4l2_queryctrl qc;
- u8 i;
-
- if (copy_from_user(&qc, arg, sizeof(qc)))
- return -EFAULT;
-
- for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
- if (qc.id && qc.id == s->qctrl[i].id) {
- memcpy(&qc, &(s->qctrl[i]), sizeof(qc));
- if (copy_to_user(arg, &qc, sizeof(qc)))
- return -EFAULT;
- return 0;
- }
-
- return -EINVAL;
-}
-
-
-static int
-sn9c102_vidioc_g_ctrl(struct sn9c102_device* cam, void __user * arg)
-{
- struct sn9c102_sensor* s = &cam->sensor;
- struct v4l2_control ctrl;
- int err = 0;
- u8 i;
-
- if (!s->get_ctrl && !s->set_ctrl)
- return -EINVAL;
-
- if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
- return -EFAULT;
-
- if (!s->get_ctrl) {
- for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
- if (ctrl.id && ctrl.id == s->qctrl[i].id) {
- ctrl.value = s->_qctrl[i].default_value;
- goto exit;
- }
- return -EINVAL;
- } else
- err = s->get_ctrl(cam, &ctrl);
-
-exit:
- if (copy_to_user(arg, &ctrl, sizeof(ctrl)))
- return -EFAULT;
-
- PDBGG("VIDIOC_G_CTRL: id %lu, value %lu",
- (unsigned long)ctrl.id, (unsigned long)ctrl.value);
-
- return err;
-}
-
-
-static int
-sn9c102_vidioc_s_ctrl(struct sn9c102_device* cam, void __user * arg)
-{
- struct sn9c102_sensor* s = &cam->sensor;
- struct v4l2_control ctrl;
- u8 i;
- int err = 0;
-
- if (!s->set_ctrl)
- return -EINVAL;
-
- if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
- return -EFAULT;
-
- for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) {
- if (ctrl.id == s->qctrl[i].id) {
- if (s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)
- return -EINVAL;
- if (ctrl.value < s->qctrl[i].minimum ||
- ctrl.value > s->qctrl[i].maximum)
- return -ERANGE;
- ctrl.value -= ctrl.value % s->qctrl[i].step;
- break;
- }
- }
- if (i == ARRAY_SIZE(s->qctrl))
- return -EINVAL;
- if ((err = s->set_ctrl(cam, &ctrl)))
- return err;
-
- s->_qctrl[i].default_value = ctrl.value;
-
- PDBGG("VIDIOC_S_CTRL: id %lu, value %lu",
- (unsigned long)ctrl.id, (unsigned long)ctrl.value);
-
- return 0;
-}
-
-
-static int
-sn9c102_vidioc_cropcap(struct sn9c102_device* cam, void __user * arg)
-{
- struct v4l2_cropcap* cc = &(cam->sensor.cropcap);
-
- cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- cc->pixelaspect.numerator = 1;
- cc->pixelaspect.denominator = 1;
-
- if (copy_to_user(arg, cc, sizeof(*cc)))
- return -EFAULT;
-
- return 0;
-}
-
-
-static int
-sn9c102_vidioc_g_crop(struct sn9c102_device* cam, void __user * arg)
-{
- struct sn9c102_sensor* s = &cam->sensor;
- struct v4l2_crop crop = {
- .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
- };
-
- memcpy(&(crop.c), &(s->_rect), sizeof(struct v4l2_rect));
-
- if (copy_to_user(arg, &crop, sizeof(crop)))
- return -EFAULT;
-
- return 0;
-}
-
-
-static int
-sn9c102_vidioc_s_crop(struct sn9c102_device* cam, void __user * arg)
-{
- struct sn9c102_sensor* s = &cam->sensor;
- struct v4l2_crop crop;
- struct v4l2_rect* rect;
- struct v4l2_rect* bounds = &(s->cropcap.bounds);
- struct v4l2_pix_format* pix_format = &(s->pix_format);
- u8 scale;
- const enum sn9c102_stream_state stream = cam->stream;
- const u32 nbuffers = cam->nbuffers;
- u32 i;
- int err = 0;
-
- if (copy_from_user(&crop, arg, sizeof(crop)))
- return -EFAULT;
-
- rect = &(crop.c);
-
- if (crop.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- if (cam->module_param.force_munmap)
- for (i = 0; i < cam->nbuffers; i++)
- if (cam->frame[i].vma_use_count) {
- DBG(3, "VIDIOC_S_CROP failed. "
- "Unmap the buffers first.");
- return -EBUSY;
- }
-
- /* Preserve R,G or B origin */
- rect->left = (s->_rect.left & 1L) ? rect->left | 1L : rect->left & ~1L;
- rect->top = (s->_rect.top & 1L) ? rect->top | 1L : rect->top & ~1L;
-
- if (rect->width < 16)
- rect->width = 16;
- if (rect->height < 16)
- rect->height = 16;
- if (rect->width > bounds->width)
- rect->width = bounds->width;
- if (rect->height > bounds->height)
- rect->height = bounds->height;
- if (rect->left < bounds->left)
- rect->left = bounds->left;
- if (rect->top < bounds->top)
- rect->top = bounds->top;
- if (rect->left + rect->width > bounds->left + bounds->width)
- rect->left = bounds->left+bounds->width - rect->width;
- if (rect->top + rect->height > bounds->top + bounds->height)
- rect->top = bounds->top+bounds->height - rect->height;
-
- rect->width &= ~15L;
- rect->height &= ~15L;
-
- if (SN9C102_PRESERVE_IMGSCALE) {
- /* Calculate the actual scaling factor */
- u32 a, b;
- a = rect->width * rect->height;
- b = pix_format->width * pix_format->height;
- scale = b ? (u8)((a / b) < 4 ? 1 : ((a / b) < 16 ? 2 : 4)) : 1;
- } else
- scale = 1;
-
- if (cam->stream == STREAM_ON)
- if ((err = sn9c102_stream_interrupt(cam)))
- return err;
-
- if (copy_to_user(arg, &crop, sizeof(crop))) {
- cam->stream = stream;
- return -EFAULT;
- }
-
- if (cam->module_param.force_munmap || cam->io == IO_READ)
- sn9c102_release_buffers(cam);
-
- err = sn9c102_set_crop(cam, rect);
- if (s->set_crop)
- err += s->set_crop(cam, rect);
- err += sn9c102_set_scale(cam, scale);
-
- if (err) { /* atomic, no rollback in ioctl() */
- cam->state |= DEV_MISCONFIGURED;
- DBG(1, "VIDIOC_S_CROP failed because of hardware problems. To "
- "use the camera, close and open %s again.",
- video_device_node_name(cam->v4ldev));
- return -EIO;
- }
-
- s->pix_format.width = rect->width/scale;
- s->pix_format.height = rect->height/scale;
- memcpy(&(s->_rect), rect, sizeof(*rect));
-
- if ((cam->module_param.force_munmap || cam->io == IO_READ) &&
- nbuffers != sn9c102_request_buffers(cam, nbuffers, cam->io)) {
- cam->state |= DEV_MISCONFIGURED;
- DBG(1, "VIDIOC_S_CROP failed because of not enough memory. To "
- "use the camera, close and open %s again.",
- video_device_node_name(cam->v4ldev));
- return -ENOMEM;
- }
-
- if (cam->io == IO_READ)
- sn9c102_empty_framequeues(cam);
- else if (cam->module_param.force_munmap)
- sn9c102_requeue_outqueue(cam);
-
- cam->stream = stream;
-
- return 0;
-}
-
-
-static int
-sn9c102_vidioc_enum_framesizes(struct sn9c102_device* cam, void __user * arg)
-{
- struct v4l2_frmsizeenum frmsize;
-
- if (copy_from_user(&frmsize, arg, sizeof(frmsize)))
- return -EFAULT;
-
- if (frmsize.index != 0)
- return -EINVAL;
-
- switch (cam->bridge) {
- case BRIDGE_SN9C101:
- case BRIDGE_SN9C102:
- case BRIDGE_SN9C103:
- if (frmsize.pixel_format != V4L2_PIX_FMT_SN9C10X &&
- frmsize.pixel_format != V4L2_PIX_FMT_SBGGR8)
- return -EINVAL;
- break;
- case BRIDGE_SN9C105:
- case BRIDGE_SN9C120:
- if (frmsize.pixel_format != V4L2_PIX_FMT_JPEG &&
- frmsize.pixel_format != V4L2_PIX_FMT_SBGGR8)
- return -EINVAL;
- break;
- }
-
- frmsize.type = V4L2_FRMSIZE_TYPE_STEPWISE;
- frmsize.stepwise.min_width = frmsize.stepwise.step_width = 16;
- frmsize.stepwise.min_height = frmsize.stepwise.step_height = 16;
- frmsize.stepwise.max_width = cam->sensor.cropcap.bounds.width;
- frmsize.stepwise.max_height = cam->sensor.cropcap.bounds.height;
- memset(&frmsize.reserved, 0, sizeof(frmsize.reserved));
-
- if (copy_to_user(arg, &frmsize, sizeof(frmsize)))
- return -EFAULT;
-
- return 0;
-}
-
-
-static int
-sn9c102_vidioc_enum_fmt(struct sn9c102_device* cam, void __user * arg)
-{
- struct v4l2_fmtdesc fmtd;
-
- if (copy_from_user(&fmtd, arg, sizeof(fmtd)))
- return -EFAULT;
-
- if (fmtd.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- if (fmtd.index == 0) {
- strcpy(fmtd.description, "bayer rgb");
- fmtd.pixelformat = V4L2_PIX_FMT_SBGGR8;
- } else if (fmtd.index == 1) {
- switch (cam->bridge) {
- case BRIDGE_SN9C101:
- case BRIDGE_SN9C102:
- case BRIDGE_SN9C103:
- strcpy(fmtd.description, "compressed");
- fmtd.pixelformat = V4L2_PIX_FMT_SN9C10X;
- break;
- case BRIDGE_SN9C105:
- case BRIDGE_SN9C120:
- strcpy(fmtd.description, "JPEG");
- fmtd.pixelformat = V4L2_PIX_FMT_JPEG;
- break;
- }
- fmtd.flags = V4L2_FMT_FLAG_COMPRESSED;
- } else
- return -EINVAL;
-
- fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- memset(&fmtd.reserved, 0, sizeof(fmtd.reserved));
-
- if (copy_to_user(arg, &fmtd, sizeof(fmtd)))
- return -EFAULT;
-
- return 0;
-}
-
-
-static int
-sn9c102_vidioc_g_fmt(struct sn9c102_device* cam, void __user * arg)
-{
- struct v4l2_format format;
- struct v4l2_pix_format* pfmt = &(cam->sensor.pix_format);
-
- if (copy_from_user(&format, arg, sizeof(format)))
- return -EFAULT;
-
- if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- pfmt->colorspace = (pfmt->pixelformat == V4L2_PIX_FMT_JPEG) ?
- V4L2_COLORSPACE_JPEG : V4L2_COLORSPACE_SRGB;
- pfmt->bytesperline = (pfmt->pixelformat == V4L2_PIX_FMT_SN9C10X ||
- pfmt->pixelformat == V4L2_PIX_FMT_JPEG)
- ? 0 : (pfmt->width * pfmt->priv) / 8;
- pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8);
- pfmt->field = V4L2_FIELD_NONE;
- memcpy(&(format.fmt.pix), pfmt, sizeof(*pfmt));
-
- if (copy_to_user(arg, &format, sizeof(format)))
- return -EFAULT;
-
- return 0;
-}
-
-
-static int
-sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd,
- void __user * arg)
-{
- struct sn9c102_sensor* s = &cam->sensor;
- struct v4l2_format format;
- struct v4l2_pix_format* pix;
- struct v4l2_pix_format* pfmt = &(s->pix_format);
- struct v4l2_rect* bounds = &(s->cropcap.bounds);
- struct v4l2_rect rect;
- u8 scale;
- const enum sn9c102_stream_state stream = cam->stream;
- const u32 nbuffers = cam->nbuffers;
- u32 i;
- int err = 0;
-
- if (copy_from_user(&format, arg, sizeof(format)))
- return -EFAULT;
-
- pix = &(format.fmt.pix);
-
- if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- memcpy(&rect, &(s->_rect), sizeof(rect));
-
- { /* calculate the actual scaling factor */
- u32 a, b;
- a = rect.width * rect.height;
- b = pix->width * pix->height;
- scale = b ? (u8)((a / b) < 4 ? 1 : ((a / b) < 16 ? 2 : 4)) : 1;
- }
-
- rect.width = scale * pix->width;
- rect.height = scale * pix->height;
-
- if (rect.width < 16)
- rect.width = 16;
- if (rect.height < 16)
- rect.height = 16;
- if (rect.width > bounds->left + bounds->width - rect.left)
- rect.width = bounds->left + bounds->width - rect.left;
- if (rect.height > bounds->top + bounds->height - rect.top)
- rect.height = bounds->top + bounds->height - rect.top;
-
- rect.width &= ~15L;
- rect.height &= ~15L;
-
- { /* adjust the scaling factor */
- u32 a, b;
- a = rect.width * rect.height;
- b = pix->width * pix->height;
- scale = b ? (u8)((a / b) < 4 ? 1 : ((a / b) < 16 ? 2 : 4)) : 1;
- }
-
- pix->width = rect.width / scale;
- pix->height = rect.height / scale;
-
- switch (cam->bridge) {
- case BRIDGE_SN9C101:
- case BRIDGE_SN9C102:
- case BRIDGE_SN9C103:
- if (pix->pixelformat != V4L2_PIX_FMT_SN9C10X &&
- pix->pixelformat != V4L2_PIX_FMT_SBGGR8)
- pix->pixelformat = pfmt->pixelformat;
- break;
- case BRIDGE_SN9C105:
- case BRIDGE_SN9C120:
- if (pix->pixelformat != V4L2_PIX_FMT_JPEG &&
- pix->pixelformat != V4L2_PIX_FMT_SBGGR8)
- pix->pixelformat = pfmt->pixelformat;
- break;
- }
- pix->priv = pfmt->priv; /* bpp */
- pix->colorspace = (pix->pixelformat == V4L2_PIX_FMT_JPEG) ?
- V4L2_COLORSPACE_JPEG : V4L2_COLORSPACE_SRGB;
- pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_SN9C10X ||
- pix->pixelformat == V4L2_PIX_FMT_JPEG)
- ? 0 : (pix->width * pix->priv) / 8;
- pix->sizeimage = pix->height * ((pix->width * pix->priv) / 8);
- pix->field = V4L2_FIELD_NONE;
-
- if (cmd == VIDIOC_TRY_FMT) {
- if (copy_to_user(arg, &format, sizeof(format)))
- return -EFAULT;
- return 0;
- }
-
- if (cam->module_param.force_munmap)
- for (i = 0; i < cam->nbuffers; i++)
- if (cam->frame[i].vma_use_count) {
- DBG(3, "VIDIOC_S_FMT failed. Unmap the "
- "buffers first.");
- return -EBUSY;
- }
-
- if (cam->stream == STREAM_ON)
- if ((err = sn9c102_stream_interrupt(cam)))
- return err;
-
- if (copy_to_user(arg, &format, sizeof(format))) {
- cam->stream = stream;
- return -EFAULT;
- }
-
- if (cam->module_param.force_munmap || cam->io == IO_READ)
- sn9c102_release_buffers(cam);
-
- err += sn9c102_set_pix_format(cam, pix);
- err += sn9c102_set_crop(cam, &rect);
- if (s->set_pix_format)
- err += s->set_pix_format(cam, pix);
- if (s->set_crop)
- err += s->set_crop(cam, &rect);
- err += sn9c102_set_scale(cam, scale);
-
- if (err) { /* atomic, no rollback in ioctl() */
- cam->state |= DEV_MISCONFIGURED;
- DBG(1, "VIDIOC_S_FMT failed because of hardware problems. To "
- "use the camera, close and open %s again.",
- video_device_node_name(cam->v4ldev));
- return -EIO;
- }
-
- memcpy(pfmt, pix, sizeof(*pix));
- memcpy(&(s->_rect), &rect, sizeof(rect));
-
- if ((cam->module_param.force_munmap || cam->io == IO_READ) &&
- nbuffers != sn9c102_request_buffers(cam, nbuffers, cam->io)) {
- cam->state |= DEV_MISCONFIGURED;
- DBG(1, "VIDIOC_S_FMT failed because of not enough memory. To "
- "use the camera, close and open %s again.",
- video_device_node_name(cam->v4ldev));
- return -ENOMEM;
- }
-
- if (cam->io == IO_READ)
- sn9c102_empty_framequeues(cam);
- else if (cam->module_param.force_munmap)
- sn9c102_requeue_outqueue(cam);
-
- cam->stream = stream;
-
- return 0;
-}
-
-
-static int
-sn9c102_vidioc_g_jpegcomp(struct sn9c102_device* cam, void __user * arg)
-{
- if (copy_to_user(arg, &cam->compression, sizeof(cam->compression)))
- return -EFAULT;
-
- return 0;
-}
-
-
-static int
-sn9c102_vidioc_s_jpegcomp(struct sn9c102_device* cam, void __user * arg)
-{
- struct v4l2_jpegcompression jc;
- const enum sn9c102_stream_state stream = cam->stream;
- int err = 0;
-
- if (copy_from_user(&jc, arg, sizeof(jc)))
- return -EFAULT;
-
- if (jc.quality != 0 && jc.quality != 1)
- return -EINVAL;
-
- if (cam->stream == STREAM_ON)
- if ((err = sn9c102_stream_interrupt(cam)))
- return err;
-
- err += sn9c102_set_compression(cam, &jc);
- if (err) { /* atomic, no rollback in ioctl() */
- cam->state |= DEV_MISCONFIGURED;
- DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware problems. "
- "To use the camera, close and open %s again.",
- video_device_node_name(cam->v4ldev));
- return -EIO;
- }
-
- cam->compression.quality = jc.quality;
-
- cam->stream = stream;
-
- return 0;
-}
-
-
-static int
-sn9c102_vidioc_reqbufs(struct sn9c102_device* cam, void __user * arg)
-{
- struct v4l2_requestbuffers rb;
- u32 i;
- int err;
-
- if (copy_from_user(&rb, arg, sizeof(rb)))
- return -EFAULT;
-
- if (rb.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
- rb.memory != V4L2_MEMORY_MMAP)
- return -EINVAL;
-
- if (cam->io == IO_READ) {
- DBG(3, "Close and open the device again to choose the mmap "
- "I/O method");
- return -EBUSY;
- }
-
- for (i = 0; i < cam->nbuffers; i++)
- if (cam->frame[i].vma_use_count) {
- DBG(3, "VIDIOC_REQBUFS failed. Previous buffers are "
- "still mapped.");
- return -EBUSY;
- }
-
- if (cam->stream == STREAM_ON)
- if ((err = sn9c102_stream_interrupt(cam)))
- return err;
-
- sn9c102_empty_framequeues(cam);
-
- sn9c102_release_buffers(cam);
- if (rb.count)
- rb.count = sn9c102_request_buffers(cam, rb.count, IO_MMAP);
-
- if (copy_to_user(arg, &rb, sizeof(rb))) {
- sn9c102_release_buffers(cam);
- cam->io = IO_NONE;
- return -EFAULT;
- }
-
- cam->io = rb.count ? IO_MMAP : IO_NONE;
-
- return 0;
-}
-
-
-static int
-sn9c102_vidioc_querybuf(struct sn9c102_device* cam, void __user * arg)
-{
- struct v4l2_buffer b;
-
- if (copy_from_user(&b, arg, sizeof(b)))
- return -EFAULT;
-
- if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
- b.index >= cam->nbuffers || cam->io != IO_MMAP)
- return -EINVAL;
-
- b = cam->frame[b.index].buf;
-
- if (cam->frame[b.index].vma_use_count)
- b.flags |= V4L2_BUF_FLAG_MAPPED;
-
- if (cam->frame[b.index].state == F_DONE)
- b.flags |= V4L2_BUF_FLAG_DONE;
- else if (cam->frame[b.index].state != F_UNUSED)
- b.flags |= V4L2_BUF_FLAG_QUEUED;
-
- if (copy_to_user(arg, &b, sizeof(b)))
- return -EFAULT;
-
- return 0;
-}
-
-
-static int
-sn9c102_vidioc_qbuf(struct sn9c102_device* cam, void __user * arg)
-{
- struct v4l2_buffer b;
- unsigned long lock_flags;
-
- if (copy_from_user(&b, arg, sizeof(b)))
- return -EFAULT;
-
- if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
- b.index >= cam->nbuffers || cam->io != IO_MMAP)
- return -EINVAL;
-
- if (cam->frame[b.index].state != F_UNUSED)
- return -EINVAL;
-
- cam->frame[b.index].state = F_QUEUED;
-
- spin_lock_irqsave(&cam->queue_lock, lock_flags);
- list_add_tail(&cam->frame[b.index].frame, &cam->inqueue);
- spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
-
- PDBGG("Frame #%lu queued", (unsigned long)b.index);
-
- return 0;
-}
-
-
-static int
-sn9c102_vidioc_dqbuf(struct sn9c102_device* cam, struct file* filp,
- void __user * arg)
-{
- struct v4l2_buffer b;
- struct sn9c102_frame_t *f;
- unsigned long lock_flags;
- long timeout;
- int err = 0;
-
- if (copy_from_user(&b, arg, sizeof(b)))
- return -EFAULT;
-
- if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
- return -EINVAL;
-
- if (list_empty(&cam->outqueue)) {
- if (cam->stream == STREAM_OFF)
- return -EINVAL;
- if (filp->f_flags & O_NONBLOCK)
- return -EAGAIN;
- if (!cam->module_param.frame_timeout) {
- err = wait_event_interruptible
- ( cam->wait_frame,
- (!list_empty(&cam->outqueue)) ||
- (cam->state & DEV_DISCONNECTED) ||
- (cam->state & DEV_MISCONFIGURED) );
- if (err)
- return err;
- } else {
- timeout = wait_event_interruptible_timeout
- ( cam->wait_frame,
- (!list_empty(&cam->outqueue)) ||
- (cam->state & DEV_DISCONNECTED) ||
- (cam->state & DEV_MISCONFIGURED),
- cam->module_param.frame_timeout *
- 1000 * msecs_to_jiffies(1) );
- if (timeout < 0)
- return timeout;
- else if (timeout == 0 &&
- !(cam->state & DEV_DISCONNECTED)) {
- DBG(1, "Video frame timeout elapsed");
- return -EIO;
- }
- }
- if (cam->state & DEV_DISCONNECTED)
- return -ENODEV;
- if (cam->state & DEV_MISCONFIGURED)
- return -EIO;
- }
-
- spin_lock_irqsave(&cam->queue_lock, lock_flags);
- f = list_entry(cam->outqueue.next, struct sn9c102_frame_t, frame);
- list_del(cam->outqueue.next);
- spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
-
- f->state = F_UNUSED;
-
- b = f->buf;
- if (f->vma_use_count)
- b.flags |= V4L2_BUF_FLAG_MAPPED;
-
- if (copy_to_user(arg, &b, sizeof(b)))
- return -EFAULT;
-
- PDBGG("Frame #%lu dequeued", (unsigned long)f->buf.index);
-
- return 0;
-}
-
-
-static int
-sn9c102_vidioc_streamon(struct sn9c102_device* cam, void __user * arg)
-{
- int type;
-
- if (copy_from_user(&type, arg, sizeof(type)))
- return -EFAULT;
-
- if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
- return -EINVAL;
-
- cam->stream = STREAM_ON;
-
- DBG(3, "Stream on");
-
- return 0;
-}
-
-
-static int
-sn9c102_vidioc_streamoff(struct sn9c102_device* cam, void __user * arg)
-{
- int type, err;
-
- if (copy_from_user(&type, arg, sizeof(type)))
- return -EFAULT;
-
- if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
- return -EINVAL;
-
- if (cam->stream == STREAM_ON)
- if ((err = sn9c102_stream_interrupt(cam)))
- return err;
-
- sn9c102_empty_framequeues(cam);
-
- DBG(3, "Stream off");
-
- return 0;
-}
-
-
-static int
-sn9c102_vidioc_g_parm(struct sn9c102_device* cam, void __user * arg)
-{
- struct v4l2_streamparm sp;
-
- if (copy_from_user(&sp, arg, sizeof(sp)))
- return -EFAULT;
-
- if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- sp.parm.capture.extendedmode = 0;
- sp.parm.capture.readbuffers = cam->nreadbuffers;
-
- if (copy_to_user(arg, &sp, sizeof(sp)))
- return -EFAULT;
-
- return 0;
-}
-
-
-static int
-sn9c102_vidioc_s_parm(struct sn9c102_device* cam, void __user * arg)
-{
- struct v4l2_streamparm sp;
-
- if (copy_from_user(&sp, arg, sizeof(sp)))
- return -EFAULT;
-
- if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- sp.parm.capture.extendedmode = 0;
-
- if (sp.parm.capture.readbuffers == 0)
- sp.parm.capture.readbuffers = cam->nreadbuffers;
-
- if (sp.parm.capture.readbuffers > SN9C102_MAX_FRAMES)
- sp.parm.capture.readbuffers = SN9C102_MAX_FRAMES;
-
- if (copy_to_user(arg, &sp, sizeof(sp)))
- return -EFAULT;
-
- cam->nreadbuffers = sp.parm.capture.readbuffers;
-
- return 0;
-}
-
-
-static int
-sn9c102_vidioc_enumaudio(struct sn9c102_device* cam, void __user * arg)
-{
- struct v4l2_audio audio;
-
- if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102)
- return -EINVAL;
-
- if (copy_from_user(&audio, arg, sizeof(audio)))
- return -EFAULT;
-
- if (audio.index != 0)
- return -EINVAL;
-
- strcpy(audio.name, "Microphone");
- audio.capability = 0;
- audio.mode = 0;
-
- if (copy_to_user(arg, &audio, sizeof(audio)))
- return -EFAULT;
-
- return 0;
-}
-
-
-static int
-sn9c102_vidioc_g_audio(struct sn9c102_device* cam, void __user * arg)
-{
- struct v4l2_audio audio;
-
- if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102)
- return -EINVAL;
-
- if (copy_from_user(&audio, arg, sizeof(audio)))
- return -EFAULT;
-
- memset(&audio, 0, sizeof(audio));
- strcpy(audio.name, "Microphone");
-
- if (copy_to_user(arg, &audio, sizeof(audio)))
- return -EFAULT;
-
- return 0;
-}
-
-
-static int
-sn9c102_vidioc_s_audio(struct sn9c102_device* cam, void __user * arg)
-{
- struct v4l2_audio audio;
-
- if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102)
- return -EINVAL;
-
- if (copy_from_user(&audio, arg, sizeof(audio)))
- return -EFAULT;
-
- if (audio.index != 0)
- return -EINVAL;
-
- return 0;
-}
-
-
-static long sn9c102_ioctl_v4l2(struct file *filp,
- unsigned int cmd, void __user *arg)
-{
- struct sn9c102_device *cam = video_drvdata(filp);
-
- switch (cmd) {
-
- case VIDIOC_QUERYCAP:
- return sn9c102_vidioc_querycap(cam, arg);
-
- case VIDIOC_ENUMINPUT:
- return sn9c102_vidioc_enuminput(cam, arg);
-
- case VIDIOC_G_INPUT:
- return sn9c102_vidioc_g_input(cam, arg);
-
- case VIDIOC_S_INPUT:
- return sn9c102_vidioc_s_input(cam, arg);
-
- case VIDIOC_QUERYCTRL:
- return sn9c102_vidioc_query_ctrl(cam, arg);
-
- case VIDIOC_G_CTRL:
- return sn9c102_vidioc_g_ctrl(cam, arg);
-
- case VIDIOC_S_CTRL:
- return sn9c102_vidioc_s_ctrl(cam, arg);
-
- case VIDIOC_CROPCAP:
- return sn9c102_vidioc_cropcap(cam, arg);
-
- case VIDIOC_G_CROP:
- return sn9c102_vidioc_g_crop(cam, arg);
-
- case VIDIOC_S_CROP:
- return sn9c102_vidioc_s_crop(cam, arg);
-
- case VIDIOC_ENUM_FRAMESIZES:
- return sn9c102_vidioc_enum_framesizes(cam, arg);
-
- case VIDIOC_ENUM_FMT:
- return sn9c102_vidioc_enum_fmt(cam, arg);
-
- case VIDIOC_G_FMT:
- return sn9c102_vidioc_g_fmt(cam, arg);
-
- case VIDIOC_TRY_FMT:
- case VIDIOC_S_FMT:
- return sn9c102_vidioc_try_s_fmt(cam, cmd, arg);
-
- case VIDIOC_G_JPEGCOMP:
- return sn9c102_vidioc_g_jpegcomp(cam, arg);
-
- case VIDIOC_S_JPEGCOMP:
- return sn9c102_vidioc_s_jpegcomp(cam, arg);
-
- case VIDIOC_REQBUFS:
- return sn9c102_vidioc_reqbufs(cam, arg);
-
- case VIDIOC_QUERYBUF:
- return sn9c102_vidioc_querybuf(cam, arg);
-
- case VIDIOC_QBUF:
- return sn9c102_vidioc_qbuf(cam, arg);
-
- case VIDIOC_DQBUF:
- return sn9c102_vidioc_dqbuf(cam, filp, arg);
-
- case VIDIOC_STREAMON:
- return sn9c102_vidioc_streamon(cam, arg);
-
- case VIDIOC_STREAMOFF:
- return sn9c102_vidioc_streamoff(cam, arg);
-
- case VIDIOC_G_PARM:
- return sn9c102_vidioc_g_parm(cam, arg);
-
- case VIDIOC_S_PARM:
- return sn9c102_vidioc_s_parm(cam, arg);
-
- case VIDIOC_ENUMAUDIO:
- return sn9c102_vidioc_enumaudio(cam, arg);
-
- case VIDIOC_G_AUDIO:
- return sn9c102_vidioc_g_audio(cam, arg);
-
- case VIDIOC_S_AUDIO:
- return sn9c102_vidioc_s_audio(cam, arg);
-
- default:
- return -ENOTTY;
-
- }
-}
-
-
-static long sn9c102_ioctl(struct file *filp,
- unsigned int cmd, unsigned long arg)
-{
- struct sn9c102_device *cam = video_drvdata(filp);
- int err = 0;
-
- if (mutex_lock_interruptible(&cam->fileop_mutex))
- return -ERESTARTSYS;
-
- if (cam->state & DEV_DISCONNECTED) {
- DBG(1, "Device not present");
- mutex_unlock(&cam->fileop_mutex);
- return -ENODEV;
- }
-
- if (cam->state & DEV_MISCONFIGURED) {
- DBG(1, "The camera is misconfigured. Close and open it "
- "again.");
- mutex_unlock(&cam->fileop_mutex);
- return -EIO;
- }
-
- V4LDBG(3, "sn9c102", cmd);
-
- err = sn9c102_ioctl_v4l2(filp, cmd, (void __user *)arg);
-
- mutex_unlock(&cam->fileop_mutex);
-
- return err;
-}
-
-/*****************************************************************************/
-
-static const struct v4l2_file_operations sn9c102_fops = {
- .owner = THIS_MODULE,
- .open = sn9c102_open,
- .release = sn9c102_release,
- .unlocked_ioctl = sn9c102_ioctl,
- .read = sn9c102_read,
- .poll = sn9c102_poll,
- .mmap = sn9c102_mmap,
-};
-
-/*****************************************************************************/
-
-/* It exists a single interface only. We do not need to validate anything. */
-static int
-sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
-{
- struct usb_device *udev = interface_to_usbdev(intf);
- struct sn9c102_device* cam;
- static unsigned int dev_nr;
- unsigned int i;
- int err = 0, r;
-
- if (!(cam = kzalloc(sizeof(struct sn9c102_device), GFP_KERNEL)))
- return -ENOMEM;
-
- cam->usbdev = udev;
-
- /* register v4l2_device early so it can be used for printks */
- if (v4l2_device_register(&intf->dev, &cam->v4l2_dev)) {
- dev_err(&intf->dev, "v4l2_device_register failed\n");
- err = -ENOMEM;
- goto fail;
- }
-
- if (!(cam->control_buffer = kzalloc(8, GFP_KERNEL))) {
- DBG(1, "kzalloc() failed");
- err = -ENOMEM;
- goto fail;
- }
-
- if (!(cam->v4ldev = video_device_alloc())) {
- DBG(1, "video_device_alloc() failed");
- err = -ENOMEM;
- goto fail;
- }
-
- r = sn9c102_read_reg(cam, 0x00);
- if (r < 0 || (r != 0x10 && r != 0x11 && r != 0x12)) {
- DBG(1, "Sorry, this is not a SN9C1xx-based camera "
- "(vid:pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
- err = -ENODEV;
- goto fail;
- }
-
- cam->bridge = id->driver_info;
- switch (cam->bridge) {
- case BRIDGE_SN9C101:
- case BRIDGE_SN9C102:
- DBG(2, "SN9C10[12] PC Camera Controller detected "
- "(vid:pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
- break;
- case BRIDGE_SN9C103:
- DBG(2, "SN9C103 PC Camera Controller detected "
- "(vid:pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
- break;
- case BRIDGE_SN9C105:
- DBG(2, "SN9C105 PC Camera Controller detected "
- "(vid:pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
- break;
- case BRIDGE_SN9C120:
- DBG(2, "SN9C120 PC Camera Controller detected "
- "(vid:pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
- break;
- }
-
- for (i = 0; i < ARRAY_SIZE(sn9c102_sensor_table); i++) {
- err = sn9c102_sensor_table[i](cam);
- if (!err)
- break;
- }
-
- if (!err) {
- DBG(2, "%s image sensor detected", cam->sensor.name);
- DBG(3, "Support for %s maintained by %s",
- cam->sensor.name, cam->sensor.maintainer);
- } else {
- DBG(1, "No supported image sensor detected for this bridge");
- err = -ENODEV;
- goto fail;
- }
-
- if (!(cam->bridge & cam->sensor.supported_bridge)) {
- DBG(1, "Bridge not supported");
- err = -ENODEV;
- goto fail;
- }
-
- if (sn9c102_init(cam)) {
- DBG(1, "Initialization failed. I will retry on open().");
- cam->state |= DEV_MISCONFIGURED;
- }
-
- strcpy(cam->v4ldev->name, "SN9C1xx PC Camera");
- cam->v4ldev->fops = &sn9c102_fops;
- cam->v4ldev->release = video_device_release;
- cam->v4ldev->v4l2_dev = &cam->v4l2_dev;
-
- init_completion(&cam->probe);
-
- err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
- video_nr[dev_nr]);
- if (err) {
- DBG(1, "V4L2 device registration failed");
- if (err == -ENFILE && video_nr[dev_nr] == -1)
- DBG(1, "Free /dev/videoX node not found");
- video_nr[dev_nr] = -1;
- dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0;
- complete_all(&cam->probe);
- goto fail;
- }
-
- DBG(2, "V4L2 device registered as %s",
- video_device_node_name(cam->v4ldev));
-
- video_set_drvdata(cam->v4ldev, cam);
- cam->module_param.force_munmap = force_munmap[dev_nr];
- cam->module_param.frame_timeout = frame_timeout[dev_nr];
-
- dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0;
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- err = sn9c102_create_sysfs(cam);
- if (!err)
- DBG(2, "Optional device control through 'sysfs' "
- "interface ready");
- else
- DBG(2, "Failed to create optional 'sysfs' interface for "
- "device controlling. Error #%d", err);
-#else
- DBG(2, "Optional device control through 'sysfs' interface disabled");
- DBG(3, "Compile the kernel with the 'CONFIG_VIDEO_ADV_DEBUG' "
- "configuration option to enable it.");
-#endif
-
- usb_set_intfdata(intf, cam);
- kref_init(&cam->kref);
- usb_get_dev(cam->usbdev);
-
- complete_all(&cam->probe);
-
- return 0;
-
-fail:
- if (cam) {
- kfree(cam->control_buffer);
- if (cam->v4ldev)
- video_device_release(cam->v4ldev);
- v4l2_device_unregister(&cam->v4l2_dev);
- kfree(cam);
- }
- return err;
-}
-
-
-static void sn9c102_usb_disconnect(struct usb_interface* intf)
-{
- struct sn9c102_device* cam;
-
- down_write(&sn9c102_dev_lock);
-
- cam = usb_get_intfdata(intf);
-
- DBG(2, "Disconnecting %s...", cam->v4ldev->name);
-
- if (cam->users) {
- DBG(2, "Device %s is open! Deregistration and memory "
- "deallocation are deferred.",
- video_device_node_name(cam->v4ldev));
- cam->state |= DEV_MISCONFIGURED;
- sn9c102_stop_transfer(cam);
- cam->state |= DEV_DISCONNECTED;
- wake_up_interruptible(&cam->wait_frame);
- wake_up(&cam->wait_stream);
- } else
- cam->state |= DEV_DISCONNECTED;
-
- wake_up_interruptible_all(&cam->wait_open);
-
- v4l2_device_disconnect(&cam->v4l2_dev);
-
- kref_put(&cam->kref, sn9c102_release_resources);
-
- up_write(&sn9c102_dev_lock);
-}
-
-
-static struct usb_driver sn9c102_usb_driver = {
- .name = "sn9c102",
- .id_table = sn9c102_id_table,
- .probe = sn9c102_usb_probe,
- .disconnect = sn9c102_usb_disconnect,
-};
-
-module_usb_driver(sn9c102_usb_driver);
diff --git a/drivers/media/usb/sn9c102/sn9c102_devtable.h b/drivers/media/usb/sn9c102/sn9c102_devtable.h
deleted file mode 100644
index b3d2cc72965..00000000000
--- a/drivers/media/usb/sn9c102/sn9c102_devtable.h
+++ /dev/null
@@ -1,147 +0,0 @@
-/***************************************************************************
- * Table of device identifiers of the SN9C1xx PC Camera Controllers *
- * *
- * Copyright (C) 2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the Free Software *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
- ***************************************************************************/
-
-#ifndef _SN9C102_DEVTABLE_H_
-#define _SN9C102_DEVTABLE_H_
-
-#include <linux/usb.h>
-
-struct sn9c102_device;
-
-/*
- Each SN9C1xx camera has proper PID/VID identifiers.
- SN9C103, SN9C105, SN9C120 support multiple interfaces, but we only have to
- handle the video class interface.
-*/
-#define SN9C102_USB_DEVICE(vend, prod, bridge) \
- .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \
- USB_DEVICE_ID_MATCH_INT_CLASS, \
- .idVendor = (vend), \
- .idProduct = (prod), \
- .bInterfaceClass = 0xff, \
- .driver_info = (bridge)
-
-static const struct usb_device_id sn9c102_id_table[] = {
- /* SN9C101 and SN9C102 */
-#if !defined CONFIG_USB_GSPCA_SONIXB && !defined CONFIG_USB_GSPCA_SONIXB_MODULE
- { SN9C102_USB_DEVICE(0x0c45, 0x6001, BRIDGE_SN9C102), },
- { SN9C102_USB_DEVICE(0x0c45, 0x6005, BRIDGE_SN9C102), },
- { SN9C102_USB_DEVICE(0x0c45, 0x6007, BRIDGE_SN9C102), },
- { SN9C102_USB_DEVICE(0x0c45, 0x6009, BRIDGE_SN9C102), },
- { SN9C102_USB_DEVICE(0x0c45, 0x600d, BRIDGE_SN9C102), },
-/* { SN9C102_USB_DEVICE(0x0c45, 0x6011, BRIDGE_SN9C102), }, OV6650 */
- { SN9C102_USB_DEVICE(0x0c45, 0x6019, BRIDGE_SN9C102), },
-#endif
- { SN9C102_USB_DEVICE(0x0c45, 0x6024, BRIDGE_SN9C102), },
- { SN9C102_USB_DEVICE(0x0c45, 0x6025, BRIDGE_SN9C102), },
-#if !defined CONFIG_USB_GSPCA_SONIXB && !defined CONFIG_USB_GSPCA_SONIXB_MODULE
- { SN9C102_USB_DEVICE(0x0c45, 0x6028, BRIDGE_SN9C102), },
- { SN9C102_USB_DEVICE(0x0c45, 0x6029, BRIDGE_SN9C102), },
- { SN9C102_USB_DEVICE(0x0c45, 0x602a, BRIDGE_SN9C102), },
-#endif
- { SN9C102_USB_DEVICE(0x0c45, 0x602b, BRIDGE_SN9C102), }, /* not in sonixb */
-#if !defined CONFIG_USB_GSPCA_SONIXB && !defined CONFIG_USB_GSPCA_SONIXB_MODULE
- { SN9C102_USB_DEVICE(0x0c45, 0x602c, BRIDGE_SN9C102), },
-/* { SN9C102_USB_DEVICE(0x0c45, 0x602d, BRIDGE_SN9C102), }, HV7131R */
- { SN9C102_USB_DEVICE(0x0c45, 0x602e, BRIDGE_SN9C102), },
-#endif
- { SN9C102_USB_DEVICE(0x0c45, 0x6030, BRIDGE_SN9C102), }, /* not in sonixb */
- /* SN9C103 */
-/* { SN9C102_USB_DEVICE(0x0c45, 0x6080, BRIDGE_SN9C103), }, non existent ? */
- { SN9C102_USB_DEVICE(0x0c45, 0x6082, BRIDGE_SN9C103), }, /* not in sonixb */
-#if !defined CONFIG_USB_GSPCA_SONIXB && !defined CONFIG_USB_GSPCA_SONIXB_MODULE
-/* { SN9C102_USB_DEVICE(0x0c45, 0x6083, BRIDGE_SN9C103), }, HY7131D/E */
-/* { SN9C102_USB_DEVICE(0x0c45, 0x6088, BRIDGE_SN9C103), }, non existent ? */
-/* { SN9C102_USB_DEVICE(0x0c45, 0x608a, BRIDGE_SN9C103), }, non existent ? */
-/* { SN9C102_USB_DEVICE(0x0c45, 0x608b, BRIDGE_SN9C103), }, non existent ? */
- { SN9C102_USB_DEVICE(0x0c45, 0x608c, BRIDGE_SN9C103), },
-/* { SN9C102_USB_DEVICE(0x0c45, 0x608e, BRIDGE_SN9C103), }, CISVF10 */
- { SN9C102_USB_DEVICE(0x0c45, 0x608f, BRIDGE_SN9C103), },
-/* { SN9C102_USB_DEVICE(0x0c45, 0x60a0, BRIDGE_SN9C103), }, non existent ? */
-/* { SN9C102_USB_DEVICE(0x0c45, 0x60a2, BRIDGE_SN9C103), }, non existent ? */
-/* { SN9C102_USB_DEVICE(0x0c45, 0x60a3, BRIDGE_SN9C103), }, non existent ? */
-/* { SN9C102_USB_DEVICE(0x0c45, 0x60a8, BRIDGE_SN9C103), }, PAS106 */
-/* { SN9C102_USB_DEVICE(0x0c45, 0x60aa, BRIDGE_SN9C103), }, TAS5130 */
-/* { SN9C102_USB_DEVICE(0x0c45, 0x60ab, BRIDGE_SN9C103), }, TAS5110, non existent */
-/* { SN9C102_USB_DEVICE(0x0c45, 0x60ac, BRIDGE_SN9C103), }, non existent ? */
-/* { SN9C102_USB_DEVICE(0x0c45, 0x60ae, BRIDGE_SN9C103), }, non existent ? */
- { SN9C102_USB_DEVICE(0x0c45, 0x60af, BRIDGE_SN9C103), },
- { SN9C102_USB_DEVICE(0x0c45, 0x60b0, BRIDGE_SN9C103), },
-/* { SN9C102_USB_DEVICE(0x0c45, 0x60b2, BRIDGE_SN9C103), }, non existent ? */
-/* { SN9C102_USB_DEVICE(0x0c45, 0x60b3, BRIDGE_SN9C103), }, non existent ? */
-/* { SN9C102_USB_DEVICE(0x0c45, 0x60b8, BRIDGE_SN9C103), }, non existent ? */
-/* { SN9C102_USB_DEVICE(0x0c45, 0x60ba, BRIDGE_SN9C103), }, non existent ? */
-/* { SN9C102_USB_DEVICE(0x0c45, 0x60bb, BRIDGE_SN9C103), }, non existent ? */
-/* { SN9C102_USB_DEVICE(0x0c45, 0x60bc, BRIDGE_SN9C103), }, non existent ? */
-/* { SN9C102_USB_DEVICE(0x0c45, 0x60be, BRIDGE_SN9C103), }, non existent ? */
-#endif
- /* SN9C105 */
-#if !defined CONFIG_USB_GSPCA_SONIXJ && !defined CONFIG_USB_GSPCA_SONIXJ_MODULE
- { SN9C102_USB_DEVICE(0x045e, 0x00f5, BRIDGE_SN9C105), },
- { SN9C102_USB_DEVICE(0x045e, 0x00f7, BRIDGE_SN9C105), },
- { SN9C102_USB_DEVICE(0x0471, 0x0327, BRIDGE_SN9C105), },
- { SN9C102_USB_DEVICE(0x0471, 0x0328, BRIDGE_SN9C105), },
- { SN9C102_USB_DEVICE(0x0c45, 0x60c0, BRIDGE_SN9C105), },
-/* { SN9C102_USB_DEVICE(0x0c45, 0x60c2, BRIDGE_SN9C105), }, PO1030 */
-/* { SN9C102_USB_DEVICE(0x0c45, 0x60c8, BRIDGE_SN9C105), }, OM6801 */
-/* { SN9C102_USB_DEVICE(0x0c45, 0x60cc, BRIDGE_SN9C105), }, HV7131GP */
-/* { SN9C102_USB_DEVICE(0x0c45, 0x60ea, BRIDGE_SN9C105), }, non existent ? */
-/* { SN9C102_USB_DEVICE(0x0c45, 0x60ec, BRIDGE_SN9C105), }, MO4000 */
-/* { SN9C102_USB_DEVICE(0x0c45, 0x60ef, BRIDGE_SN9C105), }, ICM105C */
-/* { SN9C102_USB_DEVICE(0x0c45, 0x60fa, BRIDGE_SN9C105), }, OV7648 */
- { SN9C102_USB_DEVICE(0x0c45, 0x60fb, BRIDGE_SN9C105), },
- { SN9C102_USB_DEVICE(0x0c45, 0x60fc, BRIDGE_SN9C105), },
- { SN9C102_USB_DEVICE(0x0c45, 0x60fe, BRIDGE_SN9C105), },
- /* SN9C120 */
- { SN9C102_USB_DEVICE(0x0458, 0x7025, BRIDGE_SN9C120), },
-/* { SN9C102_USB_DEVICE(0x0c45, 0x6102, BRIDGE_SN9C120), }, po2030 */
-/* { SN9C102_USB_DEVICE(0x0c45, 0x6108, BRIDGE_SN9C120), }, om6801 */
-/* { SN9C102_USB_DEVICE(0x0c45, 0x610f, BRIDGE_SN9C120), }, S5K53BEB */
- { SN9C102_USB_DEVICE(0x0c45, 0x6130, BRIDGE_SN9C120), },
-/* { SN9C102_USB_DEVICE(0x0c45, 0x6138, BRIDGE_SN9C120), }, MO8000 */
- { SN9C102_USB_DEVICE(0x0c45, 0x613a, BRIDGE_SN9C120), },
- { SN9C102_USB_DEVICE(0x0c45, 0x613b, BRIDGE_SN9C120), },
- { SN9C102_USB_DEVICE(0x0c45, 0x613c, BRIDGE_SN9C120), },
- { SN9C102_USB_DEVICE(0x0c45, 0x613e, BRIDGE_SN9C120), },
-#endif
- { }
-};
-
-/*
- Probing functions: on success, you must attach the sensor to the camera
- by calling sn9c102_attach_sensor().
- To enable the I2C communication, you might need to perform a really basic
- initialization of the SN9C1XX chip.
- Functions must return 0 on success, the appropriate error otherwise.
-*/
-extern int sn9c102_probe_hv7131d(struct sn9c102_device* cam);
-extern int sn9c102_probe_hv7131r(struct sn9c102_device* cam);
-extern int sn9c102_probe_mi0343(struct sn9c102_device* cam);
-extern int sn9c102_probe_mi0360(struct sn9c102_device* cam);
-extern int sn9c102_probe_mt9v111(struct sn9c102_device *cam);
-extern int sn9c102_probe_ov7630(struct sn9c102_device* cam);
-extern int sn9c102_probe_ov7660(struct sn9c102_device* cam);
-extern int sn9c102_probe_pas106b(struct sn9c102_device* cam);
-extern int sn9c102_probe_pas202bcb(struct sn9c102_device* cam);
-extern int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam);
-extern int sn9c102_probe_tas5110d(struct sn9c102_device* cam);
-extern int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam);
-
-#endif /* _SN9C102_DEVTABLE_H_ */
diff --git a/drivers/media/usb/sn9c102/sn9c102_hv7131d.c b/drivers/media/usb/sn9c102/sn9c102_hv7131d.c
deleted file mode 100644
index 2dce5c908c8..00000000000
--- a/drivers/media/usb/sn9c102/sn9c102_hv7131d.c
+++ /dev/null
@@ -1,264 +0,0 @@
-/***************************************************************************
- * Plug-in for HV7131D image sensor connected to the SN9C1xx PC Camera *
- * Controllers *
- * *
- * Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the Free Software *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
- ***************************************************************************/
-
-#include "sn9c102_sensor.h"
-#include "sn9c102_devtable.h"
-
-
-static int hv7131d_init(struct sn9c102_device* cam)
-{
- int err;
-
- err = sn9c102_write_const_regs(cam, {0x00, 0x10}, {0x00, 0x11},
- {0x00, 0x14}, {0x60, 0x17},
- {0x0e, 0x18}, {0xf2, 0x19});
-
- err += sn9c102_i2c_write(cam, 0x01, 0x04);
- err += sn9c102_i2c_write(cam, 0x02, 0x00);
- err += sn9c102_i2c_write(cam, 0x28, 0x00);
-
- return err;
-}
-
-
-static int hv7131d_get_ctrl(struct sn9c102_device* cam,
- struct v4l2_control* ctrl)
-{
- switch (ctrl->id) {
- case V4L2_CID_EXPOSURE:
- {
- int r1 = sn9c102_i2c_read(cam, 0x26),
- r2 = sn9c102_i2c_read(cam, 0x27);
- if (r1 < 0 || r2 < 0)
- return -EIO;
- ctrl->value = (r1 << 8) | (r2 & 0xff);
- }
- return 0;
- case V4L2_CID_RED_BALANCE:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x31)) < 0)
- return -EIO;
- ctrl->value = 0x3f - (ctrl->value & 0x3f);
- return 0;
- case V4L2_CID_BLUE_BALANCE:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x33)) < 0)
- return -EIO;
- ctrl->value = 0x3f - (ctrl->value & 0x3f);
- return 0;
- case SN9C102_V4L2_CID_GREEN_BALANCE:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x32)) < 0)
- return -EIO;
- ctrl->value = 0x3f - (ctrl->value & 0x3f);
- return 0;
- case SN9C102_V4L2_CID_RESET_LEVEL:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x30)) < 0)
- return -EIO;
- ctrl->value &= 0x3f;
- return 0;
- case SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x34)) < 0)
- return -EIO;
- ctrl->value &= 0x07;
- return 0;
- default:
- return -EINVAL;
- }
-}
-
-
-static int hv7131d_set_ctrl(struct sn9c102_device* cam,
- const struct v4l2_control* ctrl)
-{
- int err = 0;
-
- switch (ctrl->id) {
- case V4L2_CID_EXPOSURE:
- err += sn9c102_i2c_write(cam, 0x26, ctrl->value >> 8);
- err += sn9c102_i2c_write(cam, 0x27, ctrl->value & 0xff);
- break;
- case V4L2_CID_RED_BALANCE:
- err += sn9c102_i2c_write(cam, 0x31, 0x3f - ctrl->value);
- break;
- case V4L2_CID_BLUE_BALANCE:
- err += sn9c102_i2c_write(cam, 0x33, 0x3f - ctrl->value);
- break;
- case SN9C102_V4L2_CID_GREEN_BALANCE:
- err += sn9c102_i2c_write(cam, 0x32, 0x3f - ctrl->value);
- break;
- case SN9C102_V4L2_CID_RESET_LEVEL:
- err += sn9c102_i2c_write(cam, 0x30, ctrl->value);
- break;
- case SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE:
- err += sn9c102_i2c_write(cam, 0x34, ctrl->value);
- break;
- default:
- return -EINVAL;
- }
-
- return err ? -EIO : 0;
-}
-
-
-static int hv7131d_set_crop(struct sn9c102_device* cam,
- const struct v4l2_rect* rect)
-{
- struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
- int err = 0;
- u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 2,
- v_start = (u8)(rect->top - s->cropcap.bounds.top) + 2;
-
- err += sn9c102_write_reg(cam, h_start, 0x12);
- err += sn9c102_write_reg(cam, v_start, 0x13);
-
- return err;
-}
-
-
-static int hv7131d_set_pix_format(struct sn9c102_device* cam,
- const struct v4l2_pix_format* pix)
-{
- int err = 0;
-
- if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
- err += sn9c102_write_reg(cam, 0x42, 0x19);
- else
- err += sn9c102_write_reg(cam, 0xf2, 0x19);
-
- return err;
-}
-
-
-static const struct sn9c102_sensor hv7131d = {
- .name = "HV7131D",
- .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
- .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102,
- .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
- .frequency = SN9C102_I2C_100KHZ,
- .interface = SN9C102_I2C_2WIRES,
- .i2c_slave_id = 0x11,
- .init = &hv7131d_init,
- .qctrl = {
- {
- .id = V4L2_CID_EXPOSURE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "exposure",
- .minimum = 0x0250,
- .maximum = 0xffff,
- .step = 0x0001,
- .default_value = 0x0250,
- .flags = 0,
- },
- {
- .id = V4L2_CID_RED_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "red balance",
- .minimum = 0x00,
- .maximum = 0x3f,
- .step = 0x01,
- .default_value = 0x00,
- .flags = 0,
- },
- {
- .id = V4L2_CID_BLUE_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "blue balance",
- .minimum = 0x00,
- .maximum = 0x3f,
- .step = 0x01,
- .default_value = 0x20,
- .flags = 0,
- },
- {
- .id = SN9C102_V4L2_CID_GREEN_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "green balance",
- .minimum = 0x00,
- .maximum = 0x3f,
- .step = 0x01,
- .default_value = 0x1e,
- .flags = 0,
- },
- {
- .id = SN9C102_V4L2_CID_RESET_LEVEL,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "reset level",
- .minimum = 0x19,
- .maximum = 0x3f,
- .step = 0x01,
- .default_value = 0x30,
- .flags = 0,
- },
- {
- .id = SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "pixel bias voltage",
- .minimum = 0x00,
- .maximum = 0x07,
- .step = 0x01,
- .default_value = 0x02,
- .flags = 0,
- },
- },
- .get_ctrl = &hv7131d_get_ctrl,
- .set_ctrl = &hv7131d_set_ctrl,
- .cropcap = {
- .bounds = {
- .left = 0,
- .top = 0,
- .width = 640,
- .height = 480,
- },
- .defrect = {
- .left = 0,
- .top = 0,
- .width = 640,
- .height = 480,
- },
- },
- .set_crop = &hv7131d_set_crop,
- .pix_format = {
- .width = 640,
- .height = 480,
- .pixelformat = V4L2_PIX_FMT_SBGGR8,
- .priv = 8,
- },
- .set_pix_format = &hv7131d_set_pix_format
-};
-
-
-int sn9c102_probe_hv7131d(struct sn9c102_device* cam)
-{
- int r0 = 0, r1 = 0, err;
-
- err = sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x00, 0x01},
- {0x28, 0x17});
-
- r0 = sn9c102_i2c_try_read(cam, &hv7131d, 0x00);
- r1 = sn9c102_i2c_try_read(cam, &hv7131d, 0x01);
- if (err || r0 < 0 || r1 < 0)
- return -EIO;
-
- if ((r0 != 0x00 && r0 != 0x01) || r1 != 0x04)
- return -ENODEV;
-
- sn9c102_attach_sensor(cam, &hv7131d);
-
- return 0;
-}
diff --git a/drivers/media/usb/sn9c102/sn9c102_hv7131r.c b/drivers/media/usb/sn9c102/sn9c102_hv7131r.c
deleted file mode 100644
index 4295887ff60..00000000000
--- a/drivers/media/usb/sn9c102/sn9c102_hv7131r.c
+++ /dev/null
@@ -1,363 +0,0 @@
-/***************************************************************************
- * Plug-in for HV7131R image sensor connected to the SN9C1xx PC Camera *
- * Controllers *
- * *
- * Copyright (C) 2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the Free Software *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
- ***************************************************************************/
-
-#include "sn9c102_sensor.h"
-#include "sn9c102_devtable.h"
-
-
-static int hv7131r_init(struct sn9c102_device* cam)
-{
- int err = 0;
-
- switch (sn9c102_get_bridge(cam)) {
- case BRIDGE_SN9C103:
- err = sn9c102_write_const_regs(cam, {0x00, 0x03}, {0x1a, 0x04},
- {0x20, 0x05}, {0x20, 0x06},
- {0x03, 0x10}, {0x00, 0x14},
- {0x60, 0x17}, {0x0a, 0x18},
- {0xf0, 0x19}, {0x1d, 0x1a},
- {0x10, 0x1b}, {0x02, 0x1c},
- {0x03, 0x1d}, {0x0f, 0x1e},
- {0x0c, 0x1f}, {0x00, 0x20},
- {0x10, 0x21}, {0x20, 0x22},
- {0x30, 0x23}, {0x40, 0x24},
- {0x50, 0x25}, {0x60, 0x26},
- {0x70, 0x27}, {0x80, 0x28},
- {0x90, 0x29}, {0xa0, 0x2a},
- {0xb0, 0x2b}, {0xc0, 0x2c},
- {0xd0, 0x2d}, {0xe0, 0x2e},
- {0xf0, 0x2f}, {0xff, 0x30});
- break;
- case BRIDGE_SN9C105:
- case BRIDGE_SN9C120:
- err = sn9c102_write_const_regs(cam, {0x44, 0x01}, {0x40, 0x02},
- {0x00, 0x03}, {0x1a, 0x04},
- {0x44, 0x05}, {0x3e, 0x06},
- {0x1a, 0x07}, {0x03, 0x10},
- {0x08, 0x14}, {0xa3, 0x17},
- {0x4b, 0x18}, {0x00, 0x19},
- {0x1d, 0x1a}, {0x10, 0x1b},
- {0x02, 0x1c}, {0x03, 0x1d},
- {0x0f, 0x1e}, {0x0c, 0x1f},
- {0x00, 0x20}, {0x29, 0x21},
- {0x40, 0x22}, {0x54, 0x23},
- {0x66, 0x24}, {0x76, 0x25},
- {0x85, 0x26}, {0x94, 0x27},
- {0xa1, 0x28}, {0xae, 0x29},
- {0xbb, 0x2a}, {0xc7, 0x2b},
- {0xd3, 0x2c}, {0xde, 0x2d},
- {0xea, 0x2e}, {0xf4, 0x2f},
- {0xff, 0x30}, {0x00, 0x3F},
- {0xC7, 0x40}, {0x01, 0x41},
- {0x44, 0x42}, {0x00, 0x43},
- {0x44, 0x44}, {0x00, 0x45},
- {0x44, 0x46}, {0x00, 0x47},
- {0xC7, 0x48}, {0x01, 0x49},
- {0xC7, 0x4A}, {0x01, 0x4B},
- {0xC7, 0x4C}, {0x01, 0x4D},
- {0x44, 0x4E}, {0x00, 0x4F},
- {0x44, 0x50}, {0x00, 0x51},
- {0x44, 0x52}, {0x00, 0x53},
- {0xC7, 0x54}, {0x01, 0x55},
- {0xC7, 0x56}, {0x01, 0x57},
- {0xC7, 0x58}, {0x01, 0x59},
- {0x44, 0x5A}, {0x00, 0x5B},
- {0x44, 0x5C}, {0x00, 0x5D},
- {0x44, 0x5E}, {0x00, 0x5F},
- {0xC7, 0x60}, {0x01, 0x61},
- {0xC7, 0x62}, {0x01, 0x63},
- {0xC7, 0x64}, {0x01, 0x65},
- {0x44, 0x66}, {0x00, 0x67},
- {0x44, 0x68}, {0x00, 0x69},
- {0x44, 0x6A}, {0x00, 0x6B},
- {0xC7, 0x6C}, {0x01, 0x6D},
- {0xC7, 0x6E}, {0x01, 0x6F},
- {0xC7, 0x70}, {0x01, 0x71},
- {0x44, 0x72}, {0x00, 0x73},
- {0x44, 0x74}, {0x00, 0x75},
- {0x44, 0x76}, {0x00, 0x77},
- {0xC7, 0x78}, {0x01, 0x79},
- {0xC7, 0x7A}, {0x01, 0x7B},
- {0xC7, 0x7C}, {0x01, 0x7D},
- {0x44, 0x7E}, {0x00, 0x7F},
- {0x14, 0x84}, {0x00, 0x85},
- {0x27, 0x86}, {0x00, 0x87},
- {0x07, 0x88}, {0x00, 0x89},
- {0xEC, 0x8A}, {0x0f, 0x8B},
- {0xD8, 0x8C}, {0x0f, 0x8D},
- {0x3D, 0x8E}, {0x00, 0x8F},
- {0x3D, 0x90}, {0x00, 0x91},
- {0xCD, 0x92}, {0x0f, 0x93},
- {0xf7, 0x94}, {0x0f, 0x95},
- {0x0C, 0x96}, {0x00, 0x97},
- {0x00, 0x98}, {0x66, 0x99},
- {0x05, 0x9A}, {0x00, 0x9B},
- {0x04, 0x9C}, {0x00, 0x9D},
- {0x08, 0x9E}, {0x00, 0x9F},
- {0x2D, 0xC0}, {0x2D, 0xC1},
- {0x3A, 0xC2}, {0x05, 0xC3},
- {0x04, 0xC4}, {0x3F, 0xC5},
- {0x00, 0xC6}, {0x00, 0xC7},
- {0x50, 0xC8}, {0x3C, 0xC9},
- {0x28, 0xCA}, {0xD8, 0xCB},
- {0x14, 0xCC}, {0xEC, 0xCD},
- {0x32, 0xCE}, {0xDD, 0xCF},
- {0x32, 0xD0}, {0xDD, 0xD1},
- {0x6A, 0xD2}, {0x50, 0xD3},
- {0x00, 0xD4}, {0x00, 0xD5},
- {0x00, 0xD6});
- break;
- default:
- break;
- }
-
- err += sn9c102_i2c_write(cam, 0x20, 0x00);
- err += sn9c102_i2c_write(cam, 0x21, 0xd6);
- err += sn9c102_i2c_write(cam, 0x25, 0x06);
-
- return err;
-}
-
-
-static int hv7131r_get_ctrl(struct sn9c102_device* cam,
- struct v4l2_control* ctrl)
-{
- switch (ctrl->id) {
- case V4L2_CID_GAIN:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x30)) < 0)
- return -EIO;
- return 0;
- case V4L2_CID_RED_BALANCE:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x31)) < 0)
- return -EIO;
- ctrl->value = ctrl->value & 0x3f;
- return 0;
- case V4L2_CID_BLUE_BALANCE:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x33)) < 0)
- return -EIO;
- ctrl->value = ctrl->value & 0x3f;
- return 0;
- case SN9C102_V4L2_CID_GREEN_BALANCE:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x32)) < 0)
- return -EIO;
- ctrl->value = ctrl->value & 0x3f;
- return 0;
- case V4L2_CID_BLACK_LEVEL:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x01)) < 0)
- return -EIO;
- ctrl->value = (ctrl->value & 0x08) ? 1 : 0;
- return 0;
- default:
- return -EINVAL;
- }
-}
-
-
-static int hv7131r_set_ctrl(struct sn9c102_device* cam,
- const struct v4l2_control* ctrl)
-{
- int err = 0;
-
- switch (ctrl->id) {
- case V4L2_CID_GAIN:
- err += sn9c102_i2c_write(cam, 0x30, ctrl->value);
- break;
- case V4L2_CID_RED_BALANCE:
- err += sn9c102_i2c_write(cam, 0x31, ctrl->value);
- break;
- case V4L2_CID_BLUE_BALANCE:
- err += sn9c102_i2c_write(cam, 0x33, ctrl->value);
- break;
- case SN9C102_V4L2_CID_GREEN_BALANCE:
- err += sn9c102_i2c_write(cam, 0x32, ctrl->value);
- break;
- case V4L2_CID_BLACK_LEVEL:
- {
- int r = sn9c102_i2c_read(cam, 0x01);
- if (r < 0)
- return -EIO;
- err += sn9c102_i2c_write(cam, 0x01,
- (ctrl->value<<3) | (r&0xf7));
- }
- break;
- default:
- return -EINVAL;
- }
-
- return err ? -EIO : 0;
-}
-
-
-static int hv7131r_set_crop(struct sn9c102_device* cam,
- const struct v4l2_rect* rect)
-{
- struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
- int err = 0;
- u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 1,
- v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1;
-
- err += sn9c102_write_reg(cam, h_start, 0x12);
- err += sn9c102_write_reg(cam, v_start, 0x13);
-
- return err;
-}
-
-
-static int hv7131r_set_pix_format(struct sn9c102_device* cam,
- const struct v4l2_pix_format* pix)
-{
- int err = 0;
-
- switch (sn9c102_get_bridge(cam)) {
- case BRIDGE_SN9C103:
- if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) {
- err += sn9c102_write_reg(cam, 0xa0, 0x19);
- err += sn9c102_i2c_write(cam, 0x01, 0x04);
- } else {
- err += sn9c102_write_reg(cam, 0x30, 0x19);
- err += sn9c102_i2c_write(cam, 0x01, 0x04);
- }
- break;
- case BRIDGE_SN9C105:
- case BRIDGE_SN9C120:
- if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) {
- err += sn9c102_write_reg(cam, 0xa5, 0x17);
- err += sn9c102_i2c_write(cam, 0x01, 0x24);
- } else {
- err += sn9c102_write_reg(cam, 0xa3, 0x17);
- err += sn9c102_i2c_write(cam, 0x01, 0x04);
- }
- break;
- default:
- break;
- }
-
- return err;
-}
-
-
-static const struct sn9c102_sensor hv7131r = {
- .name = "HV7131R",
- .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
- .supported_bridge = BRIDGE_SN9C103 | BRIDGE_SN9C105 | BRIDGE_SN9C120,
- .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
- .frequency = SN9C102_I2C_100KHZ,
- .interface = SN9C102_I2C_2WIRES,
- .i2c_slave_id = 0x11,
- .init = &hv7131r_init,
- .qctrl = {
- {
- .id = V4L2_CID_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "global gain",
- .minimum = 0x00,
- .maximum = 0xff,
- .step = 0x01,
- .default_value = 0x40,
- .flags = 0,
- },
- {
- .id = V4L2_CID_RED_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "red balance",
- .minimum = 0x00,
- .maximum = 0x3f,
- .step = 0x01,
- .default_value = 0x08,
- .flags = 0,
- },
- {
- .id = V4L2_CID_BLUE_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "blue balance",
- .minimum = 0x00,
- .maximum = 0x3f,
- .step = 0x01,
- .default_value = 0x1a,
- .flags = 0,
- },
- {
- .id = SN9C102_V4L2_CID_GREEN_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "green balance",
- .minimum = 0x00,
- .maximum = 0x3f,
- .step = 0x01,
- .default_value = 0x2f,
- .flags = 0,
- },
- {
- .id = V4L2_CID_BLACK_LEVEL,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "auto black level compensation",
- .minimum = 0x00,
- .maximum = 0x01,
- .step = 0x01,
- .default_value = 0x00,
- .flags = 0,
- },
- },
- .get_ctrl = &hv7131r_get_ctrl,
- .set_ctrl = &hv7131r_set_ctrl,
- .cropcap = {
- .bounds = {
- .left = 0,
- .top = 0,
- .width = 640,
- .height = 480,
- },
- .defrect = {
- .left = 0,
- .top = 0,
- .width = 640,
- .height = 480,
- },
- },
- .set_crop = &hv7131r_set_crop,
- .pix_format = {
- .width = 640,
- .height = 480,
- .pixelformat = V4L2_PIX_FMT_SBGGR8,
- .priv = 8,
- },
- .set_pix_format = &hv7131r_set_pix_format
-};
-
-
-int sn9c102_probe_hv7131r(struct sn9c102_device* cam)
-{
- int devid, err;
-
- err = sn9c102_write_const_regs(cam, {0x09, 0x01}, {0x44, 0x02},
- {0x34, 0x01}, {0x20, 0x17},
- {0x34, 0x01}, {0x46, 0x01});
-
- devid = sn9c102_i2c_try_read(cam, &hv7131r, 0x00);
- if (err || devid < 0)
- return -EIO;
-
- if (devid != 0x02)
- return -ENODEV;
-
- sn9c102_attach_sensor(cam, &hv7131r);
-
- return 0;
-}
diff --git a/drivers/media/usb/sn9c102/sn9c102_mi0343.c b/drivers/media/usb/sn9c102/sn9c102_mi0343.c
deleted file mode 100644
index 1f5b09bec89..00000000000
--- a/drivers/media/usb/sn9c102/sn9c102_mi0343.c
+++ /dev/null
@@ -1,352 +0,0 @@
-/***************************************************************************
- * Plug-in for MI-0343 image sensor connected to the SN9C1xx PC Camera *
- * Controllers *
- * *
- * Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the Free Software *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
- ***************************************************************************/
-
-#include "sn9c102_sensor.h"
-#include "sn9c102_devtable.h"
-
-
-static int mi0343_init(struct sn9c102_device* cam)
-{
- struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
- int err = 0;
-
- err = sn9c102_write_const_regs(cam, {0x00, 0x10}, {0x00, 0x11},
- {0x0a, 0x14}, {0x40, 0x01},
- {0x20, 0x17}, {0x07, 0x18},
- {0xa0, 0x19});
-
- err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d,
- 0x00, 0x01, 0, 0);
- err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d,
- 0x00, 0x00, 0, 0);
- err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x03,
- 0x01, 0xe1, 0, 0);
- err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x04,
- 0x02, 0x81, 0, 0);
- err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x05,
- 0x00, 0x17, 0, 0);
- err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x06,
- 0x00, 0x11, 0, 0);
- err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x62,
- 0x04, 0x9a, 0, 0);
-
- return err;
-}
-
-
-static int mi0343_get_ctrl(struct sn9c102_device* cam,
- struct v4l2_control* ctrl)
-{
- struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
- u8 data[2];
-
- switch (ctrl->id) {
- case V4L2_CID_EXPOSURE:
- if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x09, 2,
- data) < 0)
- return -EIO;
- ctrl->value = data[0];
- return 0;
- case V4L2_CID_GAIN:
- if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x35, 2,
- data) < 0)
- return -EIO;
- break;
- case V4L2_CID_HFLIP:
- if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20, 2,
- data) < 0)
- return -EIO;
- ctrl->value = data[1] & 0x20 ? 1 : 0;
- return 0;
- case V4L2_CID_VFLIP:
- if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20, 2,
- data) < 0)
- return -EIO;
- ctrl->value = data[1] & 0x80 ? 1 : 0;
- return 0;
- case V4L2_CID_RED_BALANCE:
- if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2d, 2,
- data) < 0)
- return -EIO;
- break;
- case V4L2_CID_BLUE_BALANCE:
- if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2c, 2,
- data) < 0)
- return -EIO;
- break;
- case SN9C102_V4L2_CID_GREEN_BALANCE:
- if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2e, 2,
- data) < 0)
- return -EIO;
- break;
- default:
- return -EINVAL;
- }
-
- switch (ctrl->id) {
- case V4L2_CID_GAIN:
- case V4L2_CID_RED_BALANCE:
- case V4L2_CID_BLUE_BALANCE:
- case SN9C102_V4L2_CID_GREEN_BALANCE:
- ctrl->value = data[1] | (data[0] << 8);
- if (ctrl->value >= 0x10 && ctrl->value <= 0x3f)
- ctrl->value -= 0x10;
- else if (ctrl->value >= 0x60 && ctrl->value <= 0x7f)
- ctrl->value -= 0x60;
- else if (ctrl->value >= 0xe0 && ctrl->value <= 0xff)
- ctrl->value -= 0xe0;
- }
-
- return 0;
-}
-
-
-static int mi0343_set_ctrl(struct sn9c102_device* cam,
- const struct v4l2_control* ctrl)
-{
- struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
- u16 reg = 0;
- int err = 0;
-
- switch (ctrl->id) {
- case V4L2_CID_GAIN:
- case V4L2_CID_RED_BALANCE:
- case V4L2_CID_BLUE_BALANCE:
- case SN9C102_V4L2_CID_GREEN_BALANCE:
- if (ctrl->value <= (0x3f-0x10))
- reg = 0x10 + ctrl->value;
- else if (ctrl->value <= ((0x3f-0x10) + (0x7f-0x60)))
- reg = 0x60 + (ctrl->value - (0x3f-0x10));
- else
- reg = 0xe0 + (ctrl->value - (0x3f-0x10) - (0x7f-0x60));
- break;
- }
-
- switch (ctrl->id) {
- case V4L2_CID_EXPOSURE:
- err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
- 0x09, ctrl->value, 0x00,
- 0, 0);
- break;
- case V4L2_CID_GAIN:
- err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
- 0x35, reg >> 8, reg & 0xff,
- 0, 0);
- break;
- case V4L2_CID_HFLIP:
- err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
- 0x20, ctrl->value ? 0x40:0x00,
- ctrl->value ? 0x20:0x00,
- 0, 0);
- break;
- case V4L2_CID_VFLIP:
- err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
- 0x20, ctrl->value ? 0x80:0x00,
- ctrl->value ? 0x80:0x00,
- 0, 0);
- break;
- case V4L2_CID_RED_BALANCE:
- err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
- 0x2d, reg >> 8, reg & 0xff,
- 0, 0);
- break;
- case V4L2_CID_BLUE_BALANCE:
- err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
- 0x2c, reg >> 8, reg & 0xff,
- 0, 0);
- break;
- case SN9C102_V4L2_CID_GREEN_BALANCE:
- err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
- 0x2b, reg >> 8, reg & 0xff,
- 0, 0);
- err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
- 0x2e, reg >> 8, reg & 0xff,
- 0, 0);
- break;
- default:
- return -EINVAL;
- }
-
- return err ? -EIO : 0;
-}
-
-
-static int mi0343_set_crop(struct sn9c102_device* cam,
- const struct v4l2_rect* rect)
-{
- struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
- int err = 0;
- u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 0,
- v_start = (u8)(rect->top - s->cropcap.bounds.top) + 2;
-
- err += sn9c102_write_reg(cam, h_start, 0x12);
- err += sn9c102_write_reg(cam, v_start, 0x13);
-
- return err;
-}
-
-
-static int mi0343_set_pix_format(struct sn9c102_device* cam,
- const struct v4l2_pix_format* pix)
-{
- struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
- int err = 0;
-
- if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) {
- err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
- 0x0a, 0x00, 0x03, 0, 0);
- err += sn9c102_write_reg(cam, 0x20, 0x19);
- } else {
- err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
- 0x0a, 0x00, 0x05, 0, 0);
- err += sn9c102_write_reg(cam, 0xa0, 0x19);
- }
-
- return err;
-}
-
-
-static const struct sn9c102_sensor mi0343 = {
- .name = "MI-0343",
- .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
- .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102,
- .frequency = SN9C102_I2C_100KHZ,
- .interface = SN9C102_I2C_2WIRES,
- .i2c_slave_id = 0x5d,
- .init = &mi0343_init,
- .qctrl = {
- {
- .id = V4L2_CID_EXPOSURE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "exposure",
- .minimum = 0x00,
- .maximum = 0x0f,
- .step = 0x01,
- .default_value = 0x06,
- .flags = 0,
- },
- {
- .id = V4L2_CID_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "global gain",
- .minimum = 0x00,
- .maximum = (0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0),/*0x6d*/
- .step = 0x01,
- .default_value = 0x00,
- .flags = 0,
- },
- {
- .id = V4L2_CID_HFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "horizontal mirror",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- .flags = 0,
- },
- {
- .id = V4L2_CID_VFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "vertical mirror",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- .flags = 0,
- },
- {
- .id = V4L2_CID_RED_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "red balance",
- .minimum = 0x00,
- .maximum = (0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0),
- .step = 0x01,
- .default_value = 0x00,
- .flags = 0,
- },
- {
- .id = V4L2_CID_BLUE_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "blue balance",
- .minimum = 0x00,
- .maximum = (0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0),
- .step = 0x01,
- .default_value = 0x00,
- .flags = 0,
- },
- {
- .id = SN9C102_V4L2_CID_GREEN_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "green balance",
- .minimum = 0x00,
- .maximum = ((0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0)),
- .step = 0x01,
- .default_value = 0x00,
- .flags = 0,
- },
- },
- .get_ctrl = &mi0343_get_ctrl,
- .set_ctrl = &mi0343_set_ctrl,
- .cropcap = {
- .bounds = {
- .left = 0,
- .top = 0,
- .width = 640,
- .height = 480,
- },
- .defrect = {
- .left = 0,
- .top = 0,
- .width = 640,
- .height = 480,
- },
- },
- .set_crop = &mi0343_set_crop,
- .pix_format = {
- .width = 640,
- .height = 480,
- .pixelformat = V4L2_PIX_FMT_SBGGR8,
- .priv = 8,
- },
- .set_pix_format = &mi0343_set_pix_format
-};
-
-
-int sn9c102_probe_mi0343(struct sn9c102_device* cam)
-{
- u8 data[2];
-
- if (sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x00, 0x01},
- {0x28, 0x17}))
- return -EIO;
-
- if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, 0x00,
- 2, data) < 0)
- return -EIO;
-
- if (data[1] != 0x42 || data[0] != 0xe3)
- return -ENODEV;
-
- sn9c102_attach_sensor(cam, &mi0343);
-
- return 0;
-}
diff --git a/drivers/media/usb/sn9c102/sn9c102_mi0360.c b/drivers/media/usb/sn9c102/sn9c102_mi0360.c
deleted file mode 100644
index d973fc1973d..00000000000
--- a/drivers/media/usb/sn9c102/sn9c102_mi0360.c
+++ /dev/null
@@ -1,453 +0,0 @@
-/***************************************************************************
- * Plug-in for MI-0360 image sensor connected to the SN9C1xx PC Camera *
- * Controllers *
- * *
- * Copyright (C) 2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the Free Software *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
- ***************************************************************************/
-
-#include "sn9c102_sensor.h"
-#include "sn9c102_devtable.h"
-
-
-static int mi0360_init(struct sn9c102_device* cam)
-{
- struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
- int err = 0;
-
- switch (sn9c102_get_bridge(cam)) {
- case BRIDGE_SN9C103:
- err = sn9c102_write_const_regs(cam, {0x00, 0x10}, {0x00, 0x11},
- {0x0a, 0x14}, {0x40, 0x01},
- {0x20, 0x17}, {0x07, 0x18},
- {0xa0, 0x19}, {0x02, 0x1c},
- {0x03, 0x1d}, {0x0f, 0x1e},
- {0x0c, 0x1f}, {0x00, 0x20},
- {0x10, 0x21}, {0x20, 0x22},
- {0x30, 0x23}, {0x40, 0x24},
- {0x50, 0x25}, {0x60, 0x26},
- {0x70, 0x27}, {0x80, 0x28},
- {0x90, 0x29}, {0xa0, 0x2a},
- {0xb0, 0x2b}, {0xc0, 0x2c},
- {0xd0, 0x2d}, {0xe0, 0x2e},
- {0xf0, 0x2f}, {0xff, 0x30});
- break;
- case BRIDGE_SN9C105:
- case BRIDGE_SN9C120:
- err = sn9c102_write_const_regs(cam, {0x44, 0x01}, {0x40, 0x02},
- {0x00, 0x03}, {0x1a, 0x04},
- {0x50, 0x05}, {0x20, 0x06},
- {0x10, 0x07}, {0x03, 0x10},
- {0x08, 0x14}, {0xa2, 0x17},
- {0x47, 0x18}, {0x00, 0x19},
- {0x1d, 0x1a}, {0x10, 0x1b},
- {0x02, 0x1c}, {0x03, 0x1d},
- {0x0f, 0x1e}, {0x0c, 0x1f},
- {0x00, 0x20}, {0x29, 0x21},
- {0x40, 0x22}, {0x54, 0x23},
- {0x66, 0x24}, {0x76, 0x25},
- {0x85, 0x26}, {0x94, 0x27},
- {0xa1, 0x28}, {0xae, 0x29},
- {0xbb, 0x2a}, {0xc7, 0x2b},
- {0xd3, 0x2c}, {0xde, 0x2d},
- {0xea, 0x2e}, {0xf4, 0x2f},
- {0xff, 0x30}, {0x00, 0x3F},
- {0xC7, 0x40}, {0x01, 0x41},
- {0x44, 0x42}, {0x00, 0x43},
- {0x44, 0x44}, {0x00, 0x45},
- {0x44, 0x46}, {0x00, 0x47},
- {0xC7, 0x48}, {0x01, 0x49},
- {0xC7, 0x4A}, {0x01, 0x4B},
- {0xC7, 0x4C}, {0x01, 0x4D},
- {0x44, 0x4E}, {0x00, 0x4F},
- {0x44, 0x50}, {0x00, 0x51},
- {0x44, 0x52}, {0x00, 0x53},
- {0xC7, 0x54}, {0x01, 0x55},
- {0xC7, 0x56}, {0x01, 0x57},
- {0xC7, 0x58}, {0x01, 0x59},
- {0x44, 0x5A}, {0x00, 0x5B},
- {0x44, 0x5C}, {0x00, 0x5D},
- {0x44, 0x5E}, {0x00, 0x5F},
- {0xC7, 0x60}, {0x01, 0x61},
- {0xC7, 0x62}, {0x01, 0x63},
- {0xC7, 0x64}, {0x01, 0x65},
- {0x44, 0x66}, {0x00, 0x67},
- {0x44, 0x68}, {0x00, 0x69},
- {0x44, 0x6A}, {0x00, 0x6B},
- {0xC7, 0x6C}, {0x01, 0x6D},
- {0xC7, 0x6E}, {0x01, 0x6F},
- {0xC7, 0x70}, {0x01, 0x71},
- {0x44, 0x72}, {0x00, 0x73},
- {0x44, 0x74}, {0x00, 0x75},
- {0x44, 0x76}, {0x00, 0x77},
- {0xC7, 0x78}, {0x01, 0x79},
- {0xC7, 0x7A}, {0x01, 0x7B},
- {0xC7, 0x7C}, {0x01, 0x7D},
- {0x44, 0x7E}, {0x00, 0x7F},
- {0x14, 0x84}, {0x00, 0x85},
- {0x27, 0x86}, {0x00, 0x87},
- {0x07, 0x88}, {0x00, 0x89},
- {0xEC, 0x8A}, {0x0f, 0x8B},
- {0xD8, 0x8C}, {0x0f, 0x8D},
- {0x3D, 0x8E}, {0x00, 0x8F},
- {0x3D, 0x90}, {0x00, 0x91},
- {0xCD, 0x92}, {0x0f, 0x93},
- {0xf7, 0x94}, {0x0f, 0x95},
- {0x0C, 0x96}, {0x00, 0x97},
- {0x00, 0x98}, {0x66, 0x99},
- {0x05, 0x9A}, {0x00, 0x9B},
- {0x04, 0x9C}, {0x00, 0x9D},
- {0x08, 0x9E}, {0x00, 0x9F},
- {0x2D, 0xC0}, {0x2D, 0xC1},
- {0x3A, 0xC2}, {0x05, 0xC3},
- {0x04, 0xC4}, {0x3F, 0xC5},
- {0x00, 0xC6}, {0x00, 0xC7},
- {0x50, 0xC8}, {0x3C, 0xC9},
- {0x28, 0xCA}, {0xD8, 0xCB},
- {0x14, 0xCC}, {0xEC, 0xCD},
- {0x32, 0xCE}, {0xDD, 0xCF},
- {0x32, 0xD0}, {0xDD, 0xD1},
- {0x6A, 0xD2}, {0x50, 0xD3},
- {0x00, 0xD4}, {0x00, 0xD5},
- {0x00, 0xD6});
- break;
- default:
- break;
- }
-
- err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d,
- 0x00, 0x01, 0, 0);
- err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d,
- 0x00, 0x00, 0, 0);
- err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x03,
- 0x01, 0xe1, 0, 0);
- err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x04,
- 0x02, 0x81, 0, 0);
- err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x05,
- 0x00, 0x17, 0, 0);
- err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x06,
- 0x00, 0x11, 0, 0);
- err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x62,
- 0x04, 0x9a, 0, 0);
-
- return err;
-}
-
-
-static int mi0360_get_ctrl(struct sn9c102_device* cam,
- struct v4l2_control* ctrl)
-{
- struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
- u8 data[2];
-
- switch (ctrl->id) {
- case V4L2_CID_EXPOSURE:
- if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x09, 2,
- data) < 0)
- return -EIO;
- ctrl->value = data[0];
- return 0;
- case V4L2_CID_GAIN:
- if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x35, 2,
- data) < 0)
- return -EIO;
- ctrl->value = data[1];
- return 0;
- case V4L2_CID_RED_BALANCE:
- if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2c, 2,
- data) < 0)
- return -EIO;
- ctrl->value = data[1];
- return 0;
- case V4L2_CID_BLUE_BALANCE:
- if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2d, 2,
- data) < 0)
- return -EIO;
- ctrl->value = data[1];
- return 0;
- case SN9C102_V4L2_CID_GREEN_BALANCE:
- if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2e, 2,
- data) < 0)
- return -EIO;
- ctrl->value = data[1];
- return 0;
- case V4L2_CID_HFLIP:
- if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20, 2,
- data) < 0)
- return -EIO;
- ctrl->value = data[1] & 0x20 ? 1 : 0;
- return 0;
- case V4L2_CID_VFLIP:
- if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20, 2,
- data) < 0)
- return -EIO;
- ctrl->value = data[1] & 0x80 ? 1 : 0;
- return 0;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-
-static int mi0360_set_ctrl(struct sn9c102_device* cam,
- const struct v4l2_control* ctrl)
-{
- struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
- int err = 0;
-
- switch (ctrl->id) {
- case V4L2_CID_EXPOSURE:
- err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
- 0x09, ctrl->value, 0x00,
- 0, 0);
- break;
- case V4L2_CID_GAIN:
- err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
- 0x35, 0x03, ctrl->value,
- 0, 0);
- break;
- case V4L2_CID_RED_BALANCE:
- err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
- 0x2c, 0x03, ctrl->value,
- 0, 0);
- break;
- case V4L2_CID_BLUE_BALANCE:
- err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
- 0x2d, 0x03, ctrl->value,
- 0, 0);
- break;
- case SN9C102_V4L2_CID_GREEN_BALANCE:
- err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
- 0x2b, 0x03, ctrl->value,
- 0, 0);
- err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
- 0x2e, 0x03, ctrl->value,
- 0, 0);
- break;
- case V4L2_CID_HFLIP:
- err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
- 0x20, ctrl->value ? 0x40:0x00,
- ctrl->value ? 0x20:0x00,
- 0, 0);
- break;
- case V4L2_CID_VFLIP:
- err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
- 0x20, ctrl->value ? 0x80:0x00,
- ctrl->value ? 0x80:0x00,
- 0, 0);
- break;
- default:
- return -EINVAL;
- }
-
- return err ? -EIO : 0;
-}
-
-
-static int mi0360_set_crop(struct sn9c102_device* cam,
- const struct v4l2_rect* rect)
-{
- struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
- int err = 0;
- u8 h_start = 0, v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1;
-
- switch (sn9c102_get_bridge(cam)) {
- case BRIDGE_SN9C103:
- h_start = (u8)(rect->left - s->cropcap.bounds.left) + 0;
- break;
- case BRIDGE_SN9C105:
- case BRIDGE_SN9C120:
- h_start = (u8)(rect->left - s->cropcap.bounds.left) + 1;
- break;
- default:
- break;
- }
-
- err += sn9c102_write_reg(cam, h_start, 0x12);
- err += sn9c102_write_reg(cam, v_start, 0x13);
-
- return err;
-}
-
-
-static int mi0360_set_pix_format(struct sn9c102_device* cam,
- const struct v4l2_pix_format* pix)
-{
- struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
- int err = 0;
-
- if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) {
- err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
- 0x0a, 0x00, 0x05, 0, 0);
- err += sn9c102_write_reg(cam, 0x60, 0x19);
- if (sn9c102_get_bridge(cam) == BRIDGE_SN9C105 ||
- sn9c102_get_bridge(cam) == BRIDGE_SN9C120)
- err += sn9c102_write_reg(cam, 0xa6, 0x17);
- } else {
- err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
- 0x0a, 0x00, 0x02, 0, 0);
- err += sn9c102_write_reg(cam, 0x20, 0x19);
- if (sn9c102_get_bridge(cam) == BRIDGE_SN9C105 ||
- sn9c102_get_bridge(cam) == BRIDGE_SN9C120)
- err += sn9c102_write_reg(cam, 0xa2, 0x17);
- }
-
- return err;
-}
-
-
-static const struct sn9c102_sensor mi0360 = {
- .name = "MI-0360",
- .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
- .supported_bridge = BRIDGE_SN9C103 | BRIDGE_SN9C105 | BRIDGE_SN9C120,
- .frequency = SN9C102_I2C_100KHZ,
- .interface = SN9C102_I2C_2WIRES,
- .i2c_slave_id = 0x5d,
- .init = &mi0360_init,
- .qctrl = {
- {
- .id = V4L2_CID_EXPOSURE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "exposure",
- .minimum = 0x00,
- .maximum = 0x0f,
- .step = 0x01,
- .default_value = 0x05,
- .flags = 0,
- },
- {
- .id = V4L2_CID_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "global gain",
- .minimum = 0x00,
- .maximum = 0x7f,
- .step = 0x01,
- .default_value = 0x25,
- .flags = 0,
- },
- {
- .id = V4L2_CID_HFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "horizontal mirror",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- .flags = 0,
- },
- {
- .id = V4L2_CID_VFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "vertical mirror",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- .flags = 0,
- },
- {
- .id = V4L2_CID_BLUE_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "blue balance",
- .minimum = 0x00,
- .maximum = 0x7f,
- .step = 0x01,
- .default_value = 0x0f,
- .flags = 0,
- },
- {
- .id = V4L2_CID_RED_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "red balance",
- .minimum = 0x00,
- .maximum = 0x7f,
- .step = 0x01,
- .default_value = 0x32,
- .flags = 0,
- },
- {
- .id = SN9C102_V4L2_CID_GREEN_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "green balance",
- .minimum = 0x00,
- .maximum = 0x7f,
- .step = 0x01,
- .default_value = 0x25,
- .flags = 0,
- },
- },
- .get_ctrl = &mi0360_get_ctrl,
- .set_ctrl = &mi0360_set_ctrl,
- .cropcap = {
- .bounds = {
- .left = 0,
- .top = 0,
- .width = 640,
- .height = 480,
- },
- .defrect = {
- .left = 0,
- .top = 0,
- .width = 640,
- .height = 480,
- },
- },
- .set_crop = &mi0360_set_crop,
- .pix_format = {
- .width = 640,
- .height = 480,
- .pixelformat = V4L2_PIX_FMT_SBGGR8,
- .priv = 8,
- },
- .set_pix_format = &mi0360_set_pix_format
-};
-
-
-int sn9c102_probe_mi0360(struct sn9c102_device* cam)
-{
-
- u8 data[2];
-
- switch (sn9c102_get_bridge(cam)) {
- case BRIDGE_SN9C103:
- if (sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x00, 0x01},
- {0x28, 0x17}))
- return -EIO;
- break;
- case BRIDGE_SN9C105:
- case BRIDGE_SN9C120:
- if (sn9c102_write_const_regs(cam, {0x01, 0xf1}, {0x00, 0xf1},
- {0x01, 0x01}, {0x00, 0x01},
- {0x28, 0x17}))
- return -EIO;
- break;
- default:
- break;
- }
-
- if (sn9c102_i2c_try_raw_read(cam, &mi0360, mi0360.i2c_slave_id, 0x00,
- 2, data) < 0)
- return -EIO;
-
- if (data[0] != 0x82 || data[1] != 0x43)
- return -ENODEV;
-
- sn9c102_attach_sensor(cam, &mi0360);
-
- return 0;
-}
diff --git a/drivers/media/usb/sn9c102/sn9c102_mt9v111.c b/drivers/media/usb/sn9c102/sn9c102_mt9v111.c
deleted file mode 100644
index 95986eb492e..00000000000
--- a/drivers/media/usb/sn9c102/sn9c102_mt9v111.c
+++ /dev/null
@@ -1,260 +0,0 @@
-/***************************************************************************
- * Plug-in for MT9V111 image sensor connected to the SN9C1xx PC Camera *
- * Controllers *
- * *
- * Copyright (C) 2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the Free Software *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
- ***************************************************************************/
-
-#include "sn9c102_sensor.h"
-#include "sn9c102_devtable.h"
-
-
-static int mt9v111_init(struct sn9c102_device *cam)
-{
- struct sn9c102_sensor *s = sn9c102_get_sensor(cam);
- int err = 0;
-
- err = sn9c102_write_const_regs(cam, {0x44, 0x01}, {0x40, 0x02},
- {0x00, 0x03}, {0x1a, 0x04},
- {0x1f, 0x05}, {0x20, 0x06},
- {0x1f, 0x07}, {0x81, 0x08},
- {0x5c, 0x09}, {0x00, 0x0a},
- {0x00, 0x0b}, {0x00, 0x0c},
- {0x00, 0x0d}, {0x00, 0x0e},
- {0x00, 0x0f}, {0x03, 0x10},
- {0x00, 0x11}, {0x00, 0x12},
- {0x02, 0x13}, {0x14, 0x14},
- {0x28, 0x15}, {0x1e, 0x16},
- {0xe2, 0x17}, {0x06, 0x18},
- {0x00, 0x19}, {0x00, 0x1a},
- {0x00, 0x1b}, {0x08, 0x20},
- {0x39, 0x21}, {0x51, 0x22},
- {0x63, 0x23}, {0x73, 0x24},
- {0x82, 0x25}, {0x8f, 0x26},
- {0x9b, 0x27}, {0xa7, 0x28},
- {0xb1, 0x29}, {0xbc, 0x2a},
- {0xc6, 0x2b}, {0xcf, 0x2c},
- {0xd8, 0x2d}, {0xe1, 0x2e},
- {0xea, 0x2f}, {0xf2, 0x30},
- {0x13, 0x84}, {0x00, 0x85},
- {0x25, 0x86}, {0x00, 0x87},
- {0x07, 0x88}, {0x00, 0x89},
- {0xee, 0x8a}, {0x0f, 0x8b},
- {0xe5, 0x8c}, {0x0f, 0x8d},
- {0x2e, 0x8e}, {0x00, 0x8f},
- {0x30, 0x90}, {0x00, 0x91},
- {0xd4, 0x92}, {0x0f, 0x93},
- {0xfc, 0x94}, {0x0f, 0x95},
- {0x14, 0x96}, {0x00, 0x97},
- {0x00, 0x98}, {0x60, 0x99},
- {0x07, 0x9a}, {0x40, 0x9b},
- {0x20, 0x9c}, {0x00, 0x9d},
- {0x00, 0x9e}, {0x00, 0x9f},
- {0x2d, 0xc0}, {0x2d, 0xc1},
- {0x3a, 0xc2}, {0x05, 0xc3},
- {0x04, 0xc4}, {0x3f, 0xc5},
- {0x00, 0xc6}, {0x00, 0xc7},
- {0x50, 0xc8}, {0x3c, 0xc9},
- {0x28, 0xca}, {0xd8, 0xcb},
- {0x14, 0xcc}, {0xec, 0xcd},
- {0x32, 0xce}, {0xdd, 0xcf},
- {0x2d, 0xd0}, {0xdd, 0xd1},
- {0x6a, 0xd2}, {0x50, 0xd3},
- {0x60, 0xd4}, {0x00, 0xd5},
- {0x00, 0xd6});
-
- err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x01,
- 0x00, 0x01, 0, 0);
- err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d,
- 0x00, 0x01, 0, 0);
- err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d,
- 0x00, 0x00, 0, 0);
- err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x08,
- 0x04, 0x80, 0, 0);
- err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x01,
- 0x00, 0x04, 0, 0);
- err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x08,
- 0x00, 0x08, 0, 0);
- err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x02,
- 0x00, 0x16, 0, 0);
- err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x03,
- 0x01, 0xe7, 0, 0);
- err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x04,
- 0x02, 0x87, 0, 0);
- err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x06,
- 0x00, 0x40, 0, 0);
- err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x05,
- 0x00, 0x09, 0, 0);
- err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x07,
- 0x30, 0x02, 0, 0);
- err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0c,
- 0x00, 0x00, 0, 0);
- err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x12,
- 0x00, 0xb0, 0, 0);
- err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x13,
- 0x00, 0x7c, 0, 0);
- err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x1e,
- 0x00, 0x00, 0, 0);
- err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x20,
- 0x00, 0x00, 0, 0);
- err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x20,
- 0x00, 0x00, 0, 0);
- err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x01,
- 0x00, 0x04, 0, 0);
-
- return err;
-}
-
-static int mt9v111_get_ctrl(struct sn9c102_device *cam,
- struct v4l2_control *ctrl)
-{
- struct sn9c102_sensor *s = sn9c102_get_sensor(cam);
- u8 data[2];
- int err = 0;
-
- switch (ctrl->id) {
- case V4L2_CID_VFLIP:
- if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20, 2,
- data) < 0)
- return -EIO;
- ctrl->value = data[1] & 0x80 ? 1 : 0;
- return 0;
- default:
- return -EINVAL;
- }
-
- return err ? -EIO : 0;
-}
-
-static int mt9v111_set_ctrl(struct sn9c102_device *cam,
- const struct v4l2_control *ctrl)
-{
- struct sn9c102_sensor *s = sn9c102_get_sensor(cam);
- int err = 0;
-
- switch (ctrl->id) {
- case V4L2_CID_VFLIP:
- err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
- 0x20,
- ctrl->value ? 0x80 : 0x00,
- ctrl->value ? 0x80 : 0x00, 0,
- 0);
- break;
- default:
- return -EINVAL;
- }
-
- return err ? -EIO : 0;
-}
-
-static int mt9v111_set_crop(struct sn9c102_device *cam,
- const struct v4l2_rect *rect)
-{
- struct sn9c102_sensor *s = sn9c102_get_sensor(cam);
- int err = 0;
- u8 v_start = (u8) (rect->top - s->cropcap.bounds.top) + 2;
-
- err += sn9c102_write_reg(cam, v_start, 0x13);
-
- return err;
-}
-
-static int mt9v111_set_pix_format(struct sn9c102_device *cam,
- const struct v4l2_pix_format *pix)
-{
- int err = 0;
-
- if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) {
- err += sn9c102_write_reg(cam, 0xb4, 0x17);
- } else {
- err += sn9c102_write_reg(cam, 0xe2, 0x17);
- }
-
- return err;
-}
-
-
-static const struct sn9c102_sensor mt9v111 = {
- .name = "MT9V111",
- .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
- .supported_bridge = BRIDGE_SN9C105 | BRIDGE_SN9C120,
- .frequency = SN9C102_I2C_100KHZ,
- .interface = SN9C102_I2C_2WIRES,
- .i2c_slave_id = 0x5c,
- .init = &mt9v111_init,
- .qctrl = {
- {
- .id = V4L2_CID_VFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "vertical mirror",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- .flags = 0,
- },
- },
- .get_ctrl = &mt9v111_get_ctrl,
- .set_ctrl = &mt9v111_set_ctrl,
- .cropcap = {
- .bounds = {
- .left = 0,
- .top = 0,
- .width = 640,
- .height = 480,
- },
- .defrect = {
- .left = 0,
- .top = 0,
- .width = 640,
- .height = 480,
- },
- },
- .set_crop = &mt9v111_set_crop,
- .pix_format = {
- .width = 640,
- .height = 480,
- .pixelformat = V4L2_PIX_FMT_SBGGR8,
- .priv = 8,
- },
- .set_pix_format = &mt9v111_set_pix_format
-};
-
-
-int sn9c102_probe_mt9v111(struct sn9c102_device *cam)
-{
- u8 data[2];
- int err = 0;
-
- err += sn9c102_write_const_regs(cam, {0x01, 0xf1}, {0x00, 0xf1},
- {0x29, 0x01}, {0x42, 0x17},
- {0x62, 0x17}, {0x08, 0x01});
- err += sn9c102_i2c_try_raw_write(cam, &mt9v111, 4,
- mt9v111.i2c_slave_id, 0x01, 0x00,
- 0x04, 0, 0);
- if (err || sn9c102_i2c_try_raw_read(cam, &mt9v111,
- mt9v111.i2c_slave_id, 0x36, 2,
- data) < 0)
- return -EIO;
-
- if (data[0] != 0x82 || data[1] != 0x3a)
- return -ENODEV;
-
- sn9c102_attach_sensor(cam, &mt9v111);
-
- return 0;
-}
diff --git a/drivers/media/usb/sn9c102/sn9c102_ov7630.c b/drivers/media/usb/sn9c102/sn9c102_ov7630.c
deleted file mode 100644
index 803712c29f0..00000000000
--- a/drivers/media/usb/sn9c102/sn9c102_ov7630.c
+++ /dev/null
@@ -1,626 +0,0 @@
-/***************************************************************************
- * Plug-in for OV7630 image sensor connected to the SN9C1xx PC Camera *
- * Controllers *
- * *
- * Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the Free Software *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
- ***************************************************************************/
-
-#include "sn9c102_sensor.h"
-#include "sn9c102_devtable.h"
-
-
-static int ov7630_init(struct sn9c102_device* cam)
-{
- int err = 0;
-
- switch (sn9c102_get_bridge(cam)) {
- case BRIDGE_SN9C101:
- case BRIDGE_SN9C102:
- err = sn9c102_write_const_regs(cam, {0x00, 0x14}, {0x60, 0x17},
- {0x0f, 0x18}, {0x50, 0x19});
-
- err += sn9c102_i2c_write(cam, 0x12, 0x8d);
- err += sn9c102_i2c_write(cam, 0x12, 0x0d);
- err += sn9c102_i2c_write(cam, 0x11, 0x00);
- err += sn9c102_i2c_write(cam, 0x15, 0x35);
- err += sn9c102_i2c_write(cam, 0x16, 0x03);
- err += sn9c102_i2c_write(cam, 0x17, 0x1c);
- err += sn9c102_i2c_write(cam, 0x18, 0xbd);
- err += sn9c102_i2c_write(cam, 0x19, 0x06);
- err += sn9c102_i2c_write(cam, 0x1a, 0xf6);
- err += sn9c102_i2c_write(cam, 0x1b, 0x04);
- err += sn9c102_i2c_write(cam, 0x20, 0x44);
- err += sn9c102_i2c_write(cam, 0x23, 0xee);
- err += sn9c102_i2c_write(cam, 0x26, 0xa0);
- err += sn9c102_i2c_write(cam, 0x27, 0x9a);
- err += sn9c102_i2c_write(cam, 0x28, 0x20);
- err += sn9c102_i2c_write(cam, 0x29, 0x30);
- err += sn9c102_i2c_write(cam, 0x2f, 0x3d);
- err += sn9c102_i2c_write(cam, 0x30, 0x24);
- err += sn9c102_i2c_write(cam, 0x32, 0x86);
- err += sn9c102_i2c_write(cam, 0x60, 0xa9);
- err += sn9c102_i2c_write(cam, 0x61, 0x42);
- err += sn9c102_i2c_write(cam, 0x65, 0x00);
- err += sn9c102_i2c_write(cam, 0x69, 0x38);
- err += sn9c102_i2c_write(cam, 0x6f, 0x88);
- err += sn9c102_i2c_write(cam, 0x70, 0x0b);
- err += sn9c102_i2c_write(cam, 0x71, 0x00);
- err += sn9c102_i2c_write(cam, 0x74, 0x21);
- err += sn9c102_i2c_write(cam, 0x7d, 0xf7);
- break;
- case BRIDGE_SN9C103:
- err = sn9c102_write_const_regs(cam, {0x00, 0x02}, {0x00, 0x03},
- {0x1a, 0x04}, {0x20, 0x05},
- {0x20, 0x06}, {0x20, 0x07},
- {0x03, 0x10}, {0x0a, 0x14},
- {0x60, 0x17}, {0x0f, 0x18},
- {0x50, 0x19}, {0x1d, 0x1a},
- {0x10, 0x1b}, {0x02, 0x1c},
- {0x03, 0x1d}, {0x0f, 0x1e},
- {0x0c, 0x1f}, {0x00, 0x20},
- {0x10, 0x21}, {0x20, 0x22},
- {0x30, 0x23}, {0x40, 0x24},
- {0x50, 0x25}, {0x60, 0x26},
- {0x70, 0x27}, {0x80, 0x28},
- {0x90, 0x29}, {0xa0, 0x2a},
- {0xb0, 0x2b}, {0xc0, 0x2c},
- {0xd0, 0x2d}, {0xe0, 0x2e},
- {0xf0, 0x2f}, {0xff, 0x30});
-
- err += sn9c102_i2c_write(cam, 0x12, 0x8d);
- err += sn9c102_i2c_write(cam, 0x12, 0x0d);
- err += sn9c102_i2c_write(cam, 0x15, 0x34);
- err += sn9c102_i2c_write(cam, 0x11, 0x01);
- err += sn9c102_i2c_write(cam, 0x1b, 0x04);
- err += sn9c102_i2c_write(cam, 0x20, 0x44);
- err += sn9c102_i2c_write(cam, 0x23, 0xee);
- err += sn9c102_i2c_write(cam, 0x26, 0xa0);
- err += sn9c102_i2c_write(cam, 0x27, 0x9a);
- err += sn9c102_i2c_write(cam, 0x28, 0x20);
- err += sn9c102_i2c_write(cam, 0x29, 0x30);
- err += sn9c102_i2c_write(cam, 0x2f, 0x3d);
- err += sn9c102_i2c_write(cam, 0x30, 0x24);
- err += sn9c102_i2c_write(cam, 0x32, 0x86);
- err += sn9c102_i2c_write(cam, 0x60, 0xa9);
- err += sn9c102_i2c_write(cam, 0x61, 0x42);
- err += sn9c102_i2c_write(cam, 0x65, 0x00);
- err += sn9c102_i2c_write(cam, 0x69, 0x38);
- err += sn9c102_i2c_write(cam, 0x6f, 0x88);
- err += sn9c102_i2c_write(cam, 0x70, 0x0b);
- err += sn9c102_i2c_write(cam, 0x71, 0x00);
- err += sn9c102_i2c_write(cam, 0x74, 0x21);
- err += sn9c102_i2c_write(cam, 0x7d, 0xf7);
- break;
- case BRIDGE_SN9C105:
- case BRIDGE_SN9C120:
- err = sn9c102_write_const_regs(cam, {0x40, 0x02}, {0x00, 0x03},
- {0x1a, 0x04}, {0x03, 0x10},
- {0x0a, 0x14}, {0xe2, 0x17},
- {0x0b, 0x18}, {0x00, 0x19},
- {0x1d, 0x1a}, {0x10, 0x1b},
- {0x02, 0x1c}, {0x03, 0x1d},
- {0x0f, 0x1e}, {0x0c, 0x1f},
- {0x00, 0x20}, {0x24, 0x21},
- {0x3b, 0x22}, {0x47, 0x23},
- {0x60, 0x24}, {0x71, 0x25},
- {0x80, 0x26}, {0x8f, 0x27},
- {0x9d, 0x28}, {0xaa, 0x29},
- {0xb8, 0x2a}, {0xc4, 0x2b},
- {0xd1, 0x2c}, {0xdd, 0x2d},
- {0xe8, 0x2e}, {0xf4, 0x2f},
- {0xff, 0x30}, {0x00, 0x3f},
- {0xc7, 0x40}, {0x01, 0x41},
- {0x44, 0x42}, {0x00, 0x43},
- {0x44, 0x44}, {0x00, 0x45},
- {0x44, 0x46}, {0x00, 0x47},
- {0xc7, 0x48}, {0x01, 0x49},
- {0xc7, 0x4a}, {0x01, 0x4b},
- {0xc7, 0x4c}, {0x01, 0x4d},
- {0x44, 0x4e}, {0x00, 0x4f},
- {0x44, 0x50}, {0x00, 0x51},
- {0x44, 0x52}, {0x00, 0x53},
- {0xc7, 0x54}, {0x01, 0x55},
- {0xc7, 0x56}, {0x01, 0x57},
- {0xc7, 0x58}, {0x01, 0x59},
- {0x44, 0x5a}, {0x00, 0x5b},
- {0x44, 0x5c}, {0x00, 0x5d},
- {0x44, 0x5e}, {0x00, 0x5f},
- {0xc7, 0x60}, {0x01, 0x61},
- {0xc7, 0x62}, {0x01, 0x63},
- {0xc7, 0x64}, {0x01, 0x65},
- {0x44, 0x66}, {0x00, 0x67},
- {0x44, 0x68}, {0x00, 0x69},
- {0x44, 0x6a}, {0x00, 0x6b},
- {0xc7, 0x6c}, {0x01, 0x6d},
- {0xc7, 0x6e}, {0x01, 0x6f},
- {0xc7, 0x70}, {0x01, 0x71},
- {0x44, 0x72}, {0x00, 0x73},
- {0x44, 0x74}, {0x00, 0x75},
- {0x44, 0x76}, {0x00, 0x77},
- {0xc7, 0x78}, {0x01, 0x79},
- {0xc7, 0x7a}, {0x01, 0x7b},
- {0xc7, 0x7c}, {0x01, 0x7d},
- {0x44, 0x7e}, {0x00, 0x7f},
- {0x17, 0x84}, {0x00, 0x85},
- {0x2e, 0x86}, {0x00, 0x87},
- {0x09, 0x88}, {0x00, 0x89},
- {0xe8, 0x8a}, {0x0f, 0x8b},
- {0xda, 0x8c}, {0x0f, 0x8d},
- {0x40, 0x8e}, {0x00, 0x8f},
- {0x37, 0x90}, {0x00, 0x91},
- {0xcf, 0x92}, {0x0f, 0x93},
- {0xfa, 0x94}, {0x0f, 0x95},
- {0x00, 0x96}, {0x00, 0x97},
- {0x00, 0x98}, {0x66, 0x99},
- {0x00, 0x9a}, {0x40, 0x9b},
- {0x20, 0x9c}, {0x00, 0x9d},
- {0x00, 0x9e}, {0x00, 0x9f},
- {0x2d, 0xc0}, {0x2d, 0xc1},
- {0x3a, 0xc2}, {0x00, 0xc3},
- {0x04, 0xc4}, {0x3f, 0xc5},
- {0x00, 0xc6}, {0x00, 0xc7},
- {0x50, 0xc8}, {0x3c, 0xc9},
- {0x28, 0xca}, {0xd8, 0xcb},
- {0x14, 0xcc}, {0xec, 0xcd},
- {0x32, 0xce}, {0xdd, 0xcf},
- {0x32, 0xd0}, {0xdd, 0xd1},
- {0x6a, 0xd2}, {0x50, 0xd3},
- {0x60, 0xd4}, {0x00, 0xd5},
- {0x00, 0xd6});
-
- err += sn9c102_i2c_write(cam, 0x12, 0x80);
- err += sn9c102_i2c_write(cam, 0x12, 0x48);
- err += sn9c102_i2c_write(cam, 0x01, 0x80);
- err += sn9c102_i2c_write(cam, 0x02, 0x80);
- err += sn9c102_i2c_write(cam, 0x03, 0x80);
- err += sn9c102_i2c_write(cam, 0x04, 0x10);
- err += sn9c102_i2c_write(cam, 0x05, 0x20);
- err += sn9c102_i2c_write(cam, 0x06, 0x80);
- err += sn9c102_i2c_write(cam, 0x11, 0x00);
- err += sn9c102_i2c_write(cam, 0x0c, 0x20);
- err += sn9c102_i2c_write(cam, 0x0d, 0x20);
- err += sn9c102_i2c_write(cam, 0x15, 0x80);
- err += sn9c102_i2c_write(cam, 0x16, 0x03);
- err += sn9c102_i2c_write(cam, 0x17, 0x1b);
- err += sn9c102_i2c_write(cam, 0x18, 0xbd);
- err += sn9c102_i2c_write(cam, 0x19, 0x05);
- err += sn9c102_i2c_write(cam, 0x1a, 0xf6);
- err += sn9c102_i2c_write(cam, 0x1b, 0x04);
- err += sn9c102_i2c_write(cam, 0x21, 0x1b);
- err += sn9c102_i2c_write(cam, 0x22, 0x00);
- err += sn9c102_i2c_write(cam, 0x23, 0xde);
- err += sn9c102_i2c_write(cam, 0x24, 0x10);
- err += sn9c102_i2c_write(cam, 0x25, 0x8a);
- err += sn9c102_i2c_write(cam, 0x26, 0xa0);
- err += sn9c102_i2c_write(cam, 0x27, 0xca);
- err += sn9c102_i2c_write(cam, 0x28, 0xa2);
- err += sn9c102_i2c_write(cam, 0x29, 0x74);
- err += sn9c102_i2c_write(cam, 0x2a, 0x88);
- err += sn9c102_i2c_write(cam, 0x2b, 0x34);
- err += sn9c102_i2c_write(cam, 0x2c, 0x88);
- err += sn9c102_i2c_write(cam, 0x2e, 0x00);
- err += sn9c102_i2c_write(cam, 0x2f, 0x00);
- err += sn9c102_i2c_write(cam, 0x30, 0x00);
- err += sn9c102_i2c_write(cam, 0x32, 0xc2);
- err += sn9c102_i2c_write(cam, 0x33, 0x08);
- err += sn9c102_i2c_write(cam, 0x4c, 0x40);
- err += sn9c102_i2c_write(cam, 0x4d, 0xf3);
- err += sn9c102_i2c_write(cam, 0x60, 0x05);
- err += sn9c102_i2c_write(cam, 0x61, 0x40);
- err += sn9c102_i2c_write(cam, 0x62, 0x12);
- err += sn9c102_i2c_write(cam, 0x63, 0x57);
- err += sn9c102_i2c_write(cam, 0x64, 0x73);
- err += sn9c102_i2c_write(cam, 0x65, 0x00);
- err += sn9c102_i2c_write(cam, 0x66, 0x55);
- err += sn9c102_i2c_write(cam, 0x67, 0x01);
- err += sn9c102_i2c_write(cam, 0x68, 0xac);
- err += sn9c102_i2c_write(cam, 0x69, 0x38);
- err += sn9c102_i2c_write(cam, 0x6f, 0x1f);
- err += sn9c102_i2c_write(cam, 0x70, 0x01);
- err += sn9c102_i2c_write(cam, 0x71, 0x00);
- err += sn9c102_i2c_write(cam, 0x72, 0x10);
- err += sn9c102_i2c_write(cam, 0x73, 0x50);
- err += sn9c102_i2c_write(cam, 0x74, 0x20);
- err += sn9c102_i2c_write(cam, 0x76, 0x01);
- err += sn9c102_i2c_write(cam, 0x77, 0xf3);
- err += sn9c102_i2c_write(cam, 0x78, 0x90);
- err += sn9c102_i2c_write(cam, 0x79, 0x98);
- err += sn9c102_i2c_write(cam, 0x7a, 0x98);
- err += sn9c102_i2c_write(cam, 0x7b, 0x00);
- err += sn9c102_i2c_write(cam, 0x7c, 0x38);
- err += sn9c102_i2c_write(cam, 0x7d, 0xff);
- break;
- default:
- break;
- }
-
- return err;
-}
-
-
-static int ov7630_get_ctrl(struct sn9c102_device* cam,
- struct v4l2_control* ctrl)
-{
- enum sn9c102_bridge bridge = sn9c102_get_bridge(cam);
- int err = 0;
-
- switch (ctrl->id) {
- case V4L2_CID_EXPOSURE:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x10)) < 0)
- return -EIO;
- break;
- case V4L2_CID_RED_BALANCE:
- if (bridge == BRIDGE_SN9C105 || bridge == BRIDGE_SN9C120)
- ctrl->value = sn9c102_pread_reg(cam, 0x05);
- else
- ctrl->value = sn9c102_pread_reg(cam, 0x07);
- break;
- case V4L2_CID_BLUE_BALANCE:
- ctrl->value = sn9c102_pread_reg(cam, 0x06);
- break;
- case SN9C102_V4L2_CID_GREEN_BALANCE:
- if (bridge == BRIDGE_SN9C105 || bridge == BRIDGE_SN9C120)
- ctrl->value = sn9c102_pread_reg(cam, 0x07);
- else
- ctrl->value = sn9c102_pread_reg(cam, 0x05);
- break;
- break;
- case V4L2_CID_GAIN:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x00)) < 0)
- return -EIO;
- ctrl->value &= 0x3f;
- break;
- case V4L2_CID_DO_WHITE_BALANCE:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x0c)) < 0)
- return -EIO;
- ctrl->value &= 0x3f;
- break;
- case V4L2_CID_WHITENESS:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x0d)) < 0)
- return -EIO;
- ctrl->value &= 0x3f;
- break;
- case V4L2_CID_AUTOGAIN:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x13)) < 0)
- return -EIO;
- ctrl->value &= 0x01;
- break;
- case V4L2_CID_VFLIP:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x75)) < 0)
- return -EIO;
- ctrl->value = (ctrl->value & 0x80) ? 1 : 0;
- break;
- case SN9C102_V4L2_CID_GAMMA:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x14)) < 0)
- return -EIO;
- ctrl->value = (ctrl->value & 0x02) ? 1 : 0;
- break;
- case SN9C102_V4L2_CID_BAND_FILTER:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x2d)) < 0)
- return -EIO;
- ctrl->value = (ctrl->value & 0x02) ? 1 : 0;
- break;
- default:
- return -EINVAL;
- }
-
- return err ? -EIO : 0;
-}
-
-
-static int ov7630_set_ctrl(struct sn9c102_device* cam,
- const struct v4l2_control* ctrl)
-{
- enum sn9c102_bridge bridge = sn9c102_get_bridge(cam);
- int err = 0;
-
- switch (ctrl->id) {
- case V4L2_CID_EXPOSURE:
- err += sn9c102_i2c_write(cam, 0x10, ctrl->value);
- break;
- case V4L2_CID_RED_BALANCE:
- if (bridge == BRIDGE_SN9C105 || bridge == BRIDGE_SN9C120)
- err += sn9c102_write_reg(cam, ctrl->value, 0x05);
- else
- err += sn9c102_write_reg(cam, ctrl->value, 0x07);
- break;
- case V4L2_CID_BLUE_BALANCE:
- err += sn9c102_write_reg(cam, ctrl->value, 0x06);
- break;
- case SN9C102_V4L2_CID_GREEN_BALANCE:
- if (bridge == BRIDGE_SN9C105 || bridge == BRIDGE_SN9C120)
- err += sn9c102_write_reg(cam, ctrl->value, 0x07);
- else
- err += sn9c102_write_reg(cam, ctrl->value, 0x05);
- break;
- case V4L2_CID_GAIN:
- err += sn9c102_i2c_write(cam, 0x00, ctrl->value);
- break;
- case V4L2_CID_DO_WHITE_BALANCE:
- err += sn9c102_i2c_write(cam, 0x0c, ctrl->value);
- break;
- case V4L2_CID_WHITENESS:
- err += sn9c102_i2c_write(cam, 0x0d, ctrl->value);
- break;
- case V4L2_CID_AUTOGAIN:
- err += sn9c102_i2c_write(cam, 0x13, ctrl->value |
- (ctrl->value << 1));
- break;
- case V4L2_CID_VFLIP:
- err += sn9c102_i2c_write(cam, 0x75, 0x0e | (ctrl->value << 7));
- break;
- case SN9C102_V4L2_CID_GAMMA:
- err += sn9c102_i2c_write(cam, 0x14, ctrl->value << 2);
- break;
- case SN9C102_V4L2_CID_BAND_FILTER:
- err += sn9c102_i2c_write(cam, 0x2d, ctrl->value << 2);
- break;
- default:
- return -EINVAL;
- }
-
- return err ? -EIO : 0;
-}
-
-
-static int ov7630_set_crop(struct sn9c102_device* cam,
- const struct v4l2_rect* rect)
-{
- struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
- int err = 0;
- u8 h_start = 0, v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1;
-
- switch (sn9c102_get_bridge(cam)) {
- case BRIDGE_SN9C101:
- case BRIDGE_SN9C102:
- case BRIDGE_SN9C103:
- h_start = (u8)(rect->left - s->cropcap.bounds.left) + 1;
- break;
- case BRIDGE_SN9C105:
- case BRIDGE_SN9C120:
- h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4;
- break;
- default:
- break;
- }
-
- err += sn9c102_write_reg(cam, h_start, 0x12);
- err += sn9c102_write_reg(cam, v_start, 0x13);
-
- return err;
-}
-
-
-static int ov7630_set_pix_format(struct sn9c102_device* cam,
- const struct v4l2_pix_format* pix)
-{
- int err = 0;
-
- switch (sn9c102_get_bridge(cam)) {
- case BRIDGE_SN9C101:
- case BRIDGE_SN9C102:
- case BRIDGE_SN9C103:
- if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8)
- err += sn9c102_write_reg(cam, 0x50, 0x19);
- else
- err += sn9c102_write_reg(cam, 0x20, 0x19);
- break;
- case BRIDGE_SN9C105:
- case BRIDGE_SN9C120:
- if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) {
- err += sn9c102_write_reg(cam, 0xe5, 0x17);
- err += sn9c102_i2c_write(cam, 0x11, 0x04);
- } else {
- err += sn9c102_write_reg(cam, 0xe2, 0x17);
- err += sn9c102_i2c_write(cam, 0x11, 0x02);
- }
- break;
- default:
- break;
- }
-
- return err;
-}
-
-
-static const struct sn9c102_sensor ov7630 = {
- .name = "OV7630",
- .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
- .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103 |
- BRIDGE_SN9C105 | BRIDGE_SN9C120,
- .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
- .frequency = SN9C102_I2C_100KHZ,
- .interface = SN9C102_I2C_2WIRES,
- .i2c_slave_id = 0x21,
- .init = &ov7630_init,
- .qctrl = {
- {
- .id = V4L2_CID_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "global gain",
- .minimum = 0x00,
- .maximum = 0x3f,
- .step = 0x01,
- .default_value = 0x14,
- .flags = 0,
- },
- {
- .id = V4L2_CID_EXPOSURE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "exposure",
- .minimum = 0x00,
- .maximum = 0xff,
- .step = 0x01,
- .default_value = 0x60,
- .flags = 0,
- },
- {
- .id = V4L2_CID_WHITENESS,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "white balance background: red",
- .minimum = 0x00,
- .maximum = 0x3f,
- .step = 0x01,
- .default_value = 0x20,
- .flags = 0,
- },
- {
- .id = V4L2_CID_DO_WHITE_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "white balance background: blue",
- .minimum = 0x00,
- .maximum = 0x3f,
- .step = 0x01,
- .default_value = 0x20,
- .flags = 0,
- },
- {
- .id = V4L2_CID_RED_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "red balance",
- .minimum = 0x00,
- .maximum = 0x7f,
- .step = 0x01,
- .default_value = 0x20,
- .flags = 0,
- },
- {
- .id = V4L2_CID_BLUE_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "blue balance",
- .minimum = 0x00,
- .maximum = 0x7f,
- .step = 0x01,
- .default_value = 0x20,
- .flags = 0,
- },
- {
- .id = V4L2_CID_AUTOGAIN,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "auto adjust",
- .minimum = 0x00,
- .maximum = 0x01,
- .step = 0x01,
- .default_value = 0x00,
- .flags = 0,
- },
- {
- .id = V4L2_CID_VFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "vertical flip",
- .minimum = 0x00,
- .maximum = 0x01,
- .step = 0x01,
- .default_value = 0x01,
- .flags = 0,
- },
- {
- .id = SN9C102_V4L2_CID_GREEN_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "green balance",
- .minimum = 0x00,
- .maximum = 0x7f,
- .step = 0x01,
- .default_value = 0x20,
- .flags = 0,
- },
- {
- .id = SN9C102_V4L2_CID_BAND_FILTER,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "band filter",
- .minimum = 0x00,
- .maximum = 0x01,
- .step = 0x01,
- .default_value = 0x00,
- .flags = 0,
- },
- {
- .id = SN9C102_V4L2_CID_GAMMA,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "rgb gamma",
- .minimum = 0x00,
- .maximum = 0x01,
- .step = 0x01,
- .default_value = 0x00,
- .flags = 0,
- },
- },
- .get_ctrl = &ov7630_get_ctrl,
- .set_ctrl = &ov7630_set_ctrl,
- .cropcap = {
- .bounds = {
- .left = 0,
- .top = 0,
- .width = 640,
- .height = 480,
- },
- .defrect = {
- .left = 0,
- .top = 0,
- .width = 640,
- .height = 480,
- },
- },
- .set_crop = &ov7630_set_crop,
- .pix_format = {
- .width = 640,
- .height = 480,
- .pixelformat = V4L2_PIX_FMT_SN9C10X,
- .priv = 8,
- },
- .set_pix_format = &ov7630_set_pix_format
-};
-
-
-int sn9c102_probe_ov7630(struct sn9c102_device* cam)
-{
- int pid, ver, err = 0;
-
- switch (sn9c102_get_bridge(cam)) {
- case BRIDGE_SN9C101:
- case BRIDGE_SN9C102:
- err = sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x00, 0x01},
- {0x28, 0x17});
- break;
- case BRIDGE_SN9C103: /* do _not_ change anything! */
- err = sn9c102_write_const_regs(cam, {0x09, 0x01}, {0x42, 0x01},
- {0x28, 0x17}, {0x44, 0x02});
- pid = sn9c102_i2c_try_read(cam, &ov7630, 0x0a);
- if (err || pid < 0) /* try a different initialization */
- err += sn9c102_write_const_regs(cam, {0x01, 0x01},
- {0x00, 0x01});
- break;
- case BRIDGE_SN9C105:
- case BRIDGE_SN9C120:
- err = sn9c102_write_const_regs(cam, {0x01, 0xf1}, {0x00, 0xf1},
- {0x29, 0x01}, {0x74, 0x02},
- {0x0e, 0x01}, {0x44, 0x01});
- break;
- default:
- break;
- }
-
- pid = sn9c102_i2c_try_read(cam, &ov7630, 0x0a);
- ver = sn9c102_i2c_try_read(cam, &ov7630, 0x0b);
- if (err || pid < 0 || ver < 0)
- return -EIO;
- if (pid != 0x76 || ver != 0x31)
- return -ENODEV;
- sn9c102_attach_sensor(cam, &ov7630);
-
- return 0;
-}
diff --git a/drivers/media/usb/sn9c102/sn9c102_ov7660.c b/drivers/media/usb/sn9c102/sn9c102_ov7660.c
deleted file mode 100644
index 7977795d342..00000000000
--- a/drivers/media/usb/sn9c102/sn9c102_ov7660.c
+++ /dev/null
@@ -1,538 +0,0 @@
-/***************************************************************************
- * Plug-in for OV7660 image sensor connected to the SN9C1xx PC Camera *
- * Controllers *
- * *
- * Copyright (C) 2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the Free Software *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
- ***************************************************************************/
-
-#include "sn9c102_sensor.h"
-#include "sn9c102_devtable.h"
-
-
-static int ov7660_init(struct sn9c102_device* cam)
-{
- int err = 0;
-
- err = sn9c102_write_const_regs(cam, {0x40, 0x02}, {0x00, 0x03},
- {0x1a, 0x04}, {0x03, 0x10},
- {0x08, 0x14}, {0x20, 0x17},
- {0x8b, 0x18}, {0x00, 0x19},
- {0x1d, 0x1a}, {0x10, 0x1b},
- {0x02, 0x1c}, {0x03, 0x1d},
- {0x0f, 0x1e}, {0x0c, 0x1f},
- {0x00, 0x20}, {0x29, 0x21},
- {0x40, 0x22}, {0x54, 0x23},
- {0x66, 0x24}, {0x76, 0x25},
- {0x85, 0x26}, {0x94, 0x27},
- {0xa1, 0x28}, {0xae, 0x29},
- {0xbb, 0x2a}, {0xc7, 0x2b},
- {0xd3, 0x2c}, {0xde, 0x2d},
- {0xea, 0x2e}, {0xf4, 0x2f},
- {0xff, 0x30}, {0x00, 0x3f},
- {0xc7, 0x40}, {0x01, 0x41},
- {0x44, 0x42}, {0x00, 0x43},
- {0x44, 0x44}, {0x00, 0x45},
- {0x44, 0x46}, {0x00, 0x47},
- {0xc7, 0x48}, {0x01, 0x49},
- {0xc7, 0x4a}, {0x01, 0x4b},
- {0xc7, 0x4c}, {0x01, 0x4d},
- {0x44, 0x4e}, {0x00, 0x4f},
- {0x44, 0x50}, {0x00, 0x51},
- {0x44, 0x52}, {0x00, 0x53},
- {0xc7, 0x54}, {0x01, 0x55},
- {0xc7, 0x56}, {0x01, 0x57},
- {0xc7, 0x58}, {0x01, 0x59},
- {0x44, 0x5a}, {0x00, 0x5b},
- {0x44, 0x5c}, {0x00, 0x5d},
- {0x44, 0x5e}, {0x00, 0x5f},
- {0xc7, 0x60}, {0x01, 0x61},
- {0xc7, 0x62}, {0x01, 0x63},
- {0xc7, 0x64}, {0x01, 0x65},
- {0x44, 0x66}, {0x00, 0x67},
- {0x44, 0x68}, {0x00, 0x69},
- {0x44, 0x6a}, {0x00, 0x6b},
- {0xc7, 0x6c}, {0x01, 0x6d},
- {0xc7, 0x6e}, {0x01, 0x6f},
- {0xc7, 0x70}, {0x01, 0x71},
- {0x44, 0x72}, {0x00, 0x73},
- {0x44, 0x74}, {0x00, 0x75},
- {0x44, 0x76}, {0x00, 0x77},
- {0xc7, 0x78}, {0x01, 0x79},
- {0xc7, 0x7a}, {0x01, 0x7b},
- {0xc7, 0x7c}, {0x01, 0x7d},
- {0x44, 0x7e}, {0x00, 0x7f},
- {0x14, 0x84}, {0x00, 0x85},
- {0x27, 0x86}, {0x00, 0x87},
- {0x07, 0x88}, {0x00, 0x89},
- {0xec, 0x8a}, {0x0f, 0x8b},
- {0xd8, 0x8c}, {0x0f, 0x8d},
- {0x3d, 0x8e}, {0x00, 0x8f},
- {0x3d, 0x90}, {0x00, 0x91},
- {0xcd, 0x92}, {0x0f, 0x93},
- {0xf7, 0x94}, {0x0f, 0x95},
- {0x0c, 0x96}, {0x00, 0x97},
- {0x00, 0x98}, {0x66, 0x99},
- {0x05, 0x9a}, {0x00, 0x9b},
- {0x04, 0x9c}, {0x00, 0x9d},
- {0x08, 0x9e}, {0x00, 0x9f},
- {0x2d, 0xc0}, {0x2d, 0xc1},
- {0x3a, 0xc2}, {0x05, 0xc3},
- {0x04, 0xc4}, {0x3f, 0xc5},
- {0x00, 0xc6}, {0x00, 0xc7},
- {0x50, 0xc8}, {0x3C, 0xc9},
- {0x28, 0xca}, {0xd8, 0xcb},
- {0x14, 0xcc}, {0xec, 0xcd},
- {0x32, 0xce}, {0xdd, 0xcf},
- {0x32, 0xd0}, {0xdd, 0xd1},
- {0x6a, 0xd2}, {0x50, 0xd3},
- {0x00, 0xd4}, {0x00, 0xd5},
- {0x00, 0xd6});
-
- err += sn9c102_i2c_write(cam, 0x12, 0x80);
- err += sn9c102_i2c_write(cam, 0x11, 0x09);
- err += sn9c102_i2c_write(cam, 0x00, 0x0A);
- err += sn9c102_i2c_write(cam, 0x01, 0x80);
- err += sn9c102_i2c_write(cam, 0x02, 0x80);
- err += sn9c102_i2c_write(cam, 0x03, 0x00);
- err += sn9c102_i2c_write(cam, 0x04, 0x00);
- err += sn9c102_i2c_write(cam, 0x05, 0x08);
- err += sn9c102_i2c_write(cam, 0x06, 0x0B);
- err += sn9c102_i2c_write(cam, 0x07, 0x00);
- err += sn9c102_i2c_write(cam, 0x08, 0x1C);
- err += sn9c102_i2c_write(cam, 0x09, 0x01);
- err += sn9c102_i2c_write(cam, 0x0A, 0x76);
- err += sn9c102_i2c_write(cam, 0x0B, 0x60);
- err += sn9c102_i2c_write(cam, 0x0C, 0x00);
- err += sn9c102_i2c_write(cam, 0x0D, 0x08);
- err += sn9c102_i2c_write(cam, 0x0E, 0x04);
- err += sn9c102_i2c_write(cam, 0x0F, 0x6F);
- err += sn9c102_i2c_write(cam, 0x10, 0x20);
- err += sn9c102_i2c_write(cam, 0x11, 0x03);
- err += sn9c102_i2c_write(cam, 0x12, 0x05);
- err += sn9c102_i2c_write(cam, 0x13, 0xC7);
- err += sn9c102_i2c_write(cam, 0x14, 0x2C);
- err += sn9c102_i2c_write(cam, 0x15, 0x00);
- err += sn9c102_i2c_write(cam, 0x16, 0x02);
- err += sn9c102_i2c_write(cam, 0x17, 0x10);
- err += sn9c102_i2c_write(cam, 0x18, 0x60);
- err += sn9c102_i2c_write(cam, 0x19, 0x02);
- err += sn9c102_i2c_write(cam, 0x1A, 0x7B);
- err += sn9c102_i2c_write(cam, 0x1B, 0x02);
- err += sn9c102_i2c_write(cam, 0x1C, 0x7F);
- err += sn9c102_i2c_write(cam, 0x1D, 0xA2);
- err += sn9c102_i2c_write(cam, 0x1E, 0x01);
- err += sn9c102_i2c_write(cam, 0x1F, 0x0E);
- err += sn9c102_i2c_write(cam, 0x20, 0x05);
- err += sn9c102_i2c_write(cam, 0x21, 0x05);
- err += sn9c102_i2c_write(cam, 0x22, 0x05);
- err += sn9c102_i2c_write(cam, 0x23, 0x05);
- err += sn9c102_i2c_write(cam, 0x24, 0x68);
- err += sn9c102_i2c_write(cam, 0x25, 0x58);
- err += sn9c102_i2c_write(cam, 0x26, 0xD4);
- err += sn9c102_i2c_write(cam, 0x27, 0x80);
- err += sn9c102_i2c_write(cam, 0x28, 0x80);
- err += sn9c102_i2c_write(cam, 0x29, 0x30);
- err += sn9c102_i2c_write(cam, 0x2A, 0x00);
- err += sn9c102_i2c_write(cam, 0x2B, 0x00);
- err += sn9c102_i2c_write(cam, 0x2C, 0x80);
- err += sn9c102_i2c_write(cam, 0x2D, 0x00);
- err += sn9c102_i2c_write(cam, 0x2E, 0x00);
- err += sn9c102_i2c_write(cam, 0x2F, 0x0E);
- err += sn9c102_i2c_write(cam, 0x30, 0x08);
- err += sn9c102_i2c_write(cam, 0x31, 0x30);
- err += sn9c102_i2c_write(cam, 0x32, 0xB4);
- err += sn9c102_i2c_write(cam, 0x33, 0x00);
- err += sn9c102_i2c_write(cam, 0x34, 0x07);
- err += sn9c102_i2c_write(cam, 0x35, 0x84);
- err += sn9c102_i2c_write(cam, 0x36, 0x00);
- err += sn9c102_i2c_write(cam, 0x37, 0x0C);
- err += sn9c102_i2c_write(cam, 0x38, 0x02);
- err += sn9c102_i2c_write(cam, 0x39, 0x43);
- err += sn9c102_i2c_write(cam, 0x3A, 0x00);
- err += sn9c102_i2c_write(cam, 0x3B, 0x0A);
- err += sn9c102_i2c_write(cam, 0x3C, 0x6C);
- err += sn9c102_i2c_write(cam, 0x3D, 0x99);
- err += sn9c102_i2c_write(cam, 0x3E, 0x0E);
- err += sn9c102_i2c_write(cam, 0x3F, 0x41);
- err += sn9c102_i2c_write(cam, 0x40, 0xC1);
- err += sn9c102_i2c_write(cam, 0x41, 0x22);
- err += sn9c102_i2c_write(cam, 0x42, 0x08);
- err += sn9c102_i2c_write(cam, 0x43, 0xF0);
- err += sn9c102_i2c_write(cam, 0x44, 0x10);
- err += sn9c102_i2c_write(cam, 0x45, 0x78);
- err += sn9c102_i2c_write(cam, 0x46, 0xA8);
- err += sn9c102_i2c_write(cam, 0x47, 0x60);
- err += sn9c102_i2c_write(cam, 0x48, 0x80);
- err += sn9c102_i2c_write(cam, 0x49, 0x00);
- err += sn9c102_i2c_write(cam, 0x4A, 0x00);
- err += sn9c102_i2c_write(cam, 0x4B, 0x00);
- err += sn9c102_i2c_write(cam, 0x4C, 0x00);
- err += sn9c102_i2c_write(cam, 0x4D, 0x00);
- err += sn9c102_i2c_write(cam, 0x4E, 0x00);
- err += sn9c102_i2c_write(cam, 0x4F, 0x46);
- err += sn9c102_i2c_write(cam, 0x50, 0x36);
- err += sn9c102_i2c_write(cam, 0x51, 0x0F);
- err += sn9c102_i2c_write(cam, 0x52, 0x17);
- err += sn9c102_i2c_write(cam, 0x53, 0x7F);
- err += sn9c102_i2c_write(cam, 0x54, 0x96);
- err += sn9c102_i2c_write(cam, 0x55, 0x40);
- err += sn9c102_i2c_write(cam, 0x56, 0x40);
- err += sn9c102_i2c_write(cam, 0x57, 0x40);
- err += sn9c102_i2c_write(cam, 0x58, 0x0F);
- err += sn9c102_i2c_write(cam, 0x59, 0xBA);
- err += sn9c102_i2c_write(cam, 0x5A, 0x9A);
- err += sn9c102_i2c_write(cam, 0x5B, 0x22);
- err += sn9c102_i2c_write(cam, 0x5C, 0xB9);
- err += sn9c102_i2c_write(cam, 0x5D, 0x9B);
- err += sn9c102_i2c_write(cam, 0x5E, 0x10);
- err += sn9c102_i2c_write(cam, 0x5F, 0xF0);
- err += sn9c102_i2c_write(cam, 0x60, 0x05);
- err += sn9c102_i2c_write(cam, 0x61, 0x60);
- err += sn9c102_i2c_write(cam, 0x62, 0x00);
- err += sn9c102_i2c_write(cam, 0x63, 0x00);
- err += sn9c102_i2c_write(cam, 0x64, 0x50);
- err += sn9c102_i2c_write(cam, 0x65, 0x30);
- err += sn9c102_i2c_write(cam, 0x66, 0x00);
- err += sn9c102_i2c_write(cam, 0x67, 0x80);
- err += sn9c102_i2c_write(cam, 0x68, 0x7A);
- err += sn9c102_i2c_write(cam, 0x69, 0x90);
- err += sn9c102_i2c_write(cam, 0x6A, 0x80);
- err += sn9c102_i2c_write(cam, 0x6B, 0x0A);
- err += sn9c102_i2c_write(cam, 0x6C, 0x30);
- err += sn9c102_i2c_write(cam, 0x6D, 0x48);
- err += sn9c102_i2c_write(cam, 0x6E, 0x80);
- err += sn9c102_i2c_write(cam, 0x6F, 0x74);
- err += sn9c102_i2c_write(cam, 0x70, 0x64);
- err += sn9c102_i2c_write(cam, 0x71, 0x60);
- err += sn9c102_i2c_write(cam, 0x72, 0x5C);
- err += sn9c102_i2c_write(cam, 0x73, 0x58);
- err += sn9c102_i2c_write(cam, 0x74, 0x54);
- err += sn9c102_i2c_write(cam, 0x75, 0x4C);
- err += sn9c102_i2c_write(cam, 0x76, 0x40);
- err += sn9c102_i2c_write(cam, 0x77, 0x38);
- err += sn9c102_i2c_write(cam, 0x78, 0x34);
- err += sn9c102_i2c_write(cam, 0x79, 0x30);
- err += sn9c102_i2c_write(cam, 0x7A, 0x2F);
- err += sn9c102_i2c_write(cam, 0x7B, 0x2B);
- err += sn9c102_i2c_write(cam, 0x7C, 0x03);
- err += sn9c102_i2c_write(cam, 0x7D, 0x07);
- err += sn9c102_i2c_write(cam, 0x7E, 0x17);
- err += sn9c102_i2c_write(cam, 0x7F, 0x34);
- err += sn9c102_i2c_write(cam, 0x80, 0x41);
- err += sn9c102_i2c_write(cam, 0x81, 0x4D);
- err += sn9c102_i2c_write(cam, 0x82, 0x58);
- err += sn9c102_i2c_write(cam, 0x83, 0x63);
- err += sn9c102_i2c_write(cam, 0x84, 0x6E);
- err += sn9c102_i2c_write(cam, 0x85, 0x77);
- err += sn9c102_i2c_write(cam, 0x86, 0x87);
- err += sn9c102_i2c_write(cam, 0x87, 0x95);
- err += sn9c102_i2c_write(cam, 0x88, 0xAF);
- err += sn9c102_i2c_write(cam, 0x89, 0xC7);
- err += sn9c102_i2c_write(cam, 0x8A, 0xDF);
- err += sn9c102_i2c_write(cam, 0x8B, 0x99);
- err += sn9c102_i2c_write(cam, 0x8C, 0x99);
- err += sn9c102_i2c_write(cam, 0x8D, 0xCF);
- err += sn9c102_i2c_write(cam, 0x8E, 0x20);
- err += sn9c102_i2c_write(cam, 0x8F, 0x26);
- err += sn9c102_i2c_write(cam, 0x90, 0x10);
- err += sn9c102_i2c_write(cam, 0x91, 0x0C);
- err += sn9c102_i2c_write(cam, 0x92, 0x25);
- err += sn9c102_i2c_write(cam, 0x93, 0x00);
- err += sn9c102_i2c_write(cam, 0x94, 0x50);
- err += sn9c102_i2c_write(cam, 0x95, 0x50);
- err += sn9c102_i2c_write(cam, 0x96, 0x00);
- err += sn9c102_i2c_write(cam, 0x97, 0x01);
- err += sn9c102_i2c_write(cam, 0x98, 0x10);
- err += sn9c102_i2c_write(cam, 0x99, 0x40);
- err += sn9c102_i2c_write(cam, 0x9A, 0x40);
- err += sn9c102_i2c_write(cam, 0x9B, 0x20);
- err += sn9c102_i2c_write(cam, 0x9C, 0x00);
- err += sn9c102_i2c_write(cam, 0x9D, 0x99);
- err += sn9c102_i2c_write(cam, 0x9E, 0x7F);
- err += sn9c102_i2c_write(cam, 0x9F, 0x00);
- err += sn9c102_i2c_write(cam, 0xA0, 0x00);
- err += sn9c102_i2c_write(cam, 0xA1, 0x00);
-
- return err;
-}
-
-
-static int ov7660_get_ctrl(struct sn9c102_device* cam,
- struct v4l2_control* ctrl)
-{
- int err = 0;
-
- switch (ctrl->id) {
- case V4L2_CID_EXPOSURE:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x10)) < 0)
- return -EIO;
- break;
- case V4L2_CID_DO_WHITE_BALANCE:
- if ((ctrl->value = sn9c102_read_reg(cam, 0x02)) < 0)
- return -EIO;
- ctrl->value = (ctrl->value & 0x04) ? 1 : 0;
- break;
- case V4L2_CID_RED_BALANCE:
- if ((ctrl->value = sn9c102_read_reg(cam, 0x05)) < 0)
- return -EIO;
- ctrl->value &= 0x7f;
- break;
- case V4L2_CID_BLUE_BALANCE:
- if ((ctrl->value = sn9c102_read_reg(cam, 0x06)) < 0)
- return -EIO;
- ctrl->value &= 0x7f;
- break;
- case SN9C102_V4L2_CID_GREEN_BALANCE:
- if ((ctrl->value = sn9c102_read_reg(cam, 0x07)) < 0)
- return -EIO;
- ctrl->value &= 0x7f;
- break;
- case SN9C102_V4L2_CID_BAND_FILTER:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x3b)) < 0)
- return -EIO;
- ctrl->value &= 0x08;
- break;
- case V4L2_CID_GAIN:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x00)) < 0)
- return -EIO;
- ctrl->value &= 0x1f;
- break;
- case V4L2_CID_AUTOGAIN:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x13)) < 0)
- return -EIO;
- ctrl->value &= 0x01;
- break;
- default:
- return -EINVAL;
- }
-
- return err ? -EIO : 0;
-}
-
-
-static int ov7660_set_ctrl(struct sn9c102_device* cam,
- const struct v4l2_control* ctrl)
-{
- int err = 0;
-
- switch (ctrl->id) {
- case V4L2_CID_EXPOSURE:
- err += sn9c102_i2c_write(cam, 0x10, ctrl->value);
- break;
- case V4L2_CID_DO_WHITE_BALANCE:
- err += sn9c102_write_reg(cam, 0x43 | (ctrl->value << 2), 0x02);
- break;
- case V4L2_CID_RED_BALANCE:
- err += sn9c102_write_reg(cam, ctrl->value, 0x05);
- break;
- case V4L2_CID_BLUE_BALANCE:
- err += sn9c102_write_reg(cam, ctrl->value, 0x06);
- break;
- case SN9C102_V4L2_CID_GREEN_BALANCE:
- err += sn9c102_write_reg(cam, ctrl->value, 0x07);
- break;
- case SN9C102_V4L2_CID_BAND_FILTER:
- err += sn9c102_i2c_write(cam, ctrl->value << 3, 0x3b);
- break;
- case V4L2_CID_GAIN:
- err += sn9c102_i2c_write(cam, 0x00, 0x60 + ctrl->value);
- break;
- case V4L2_CID_AUTOGAIN:
- err += sn9c102_i2c_write(cam, 0x13, 0xc0 |
- (ctrl->value * 0x07));
- break;
- default:
- return -EINVAL;
- }
-
- return err ? -EIO : 0;
-}
-
-
-static int ov7660_set_crop(struct sn9c102_device* cam,
- const struct v4l2_rect* rect)
-{
- struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
- int err = 0;
- u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 1,
- v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1;
-
- err += sn9c102_write_reg(cam, h_start, 0x12);
- err += sn9c102_write_reg(cam, v_start, 0x13);
-
- return err;
-}
-
-
-static int ov7660_set_pix_format(struct sn9c102_device* cam,
- const struct v4l2_pix_format* pix)
-{
- int r0, err = 0;
-
- r0 = sn9c102_pread_reg(cam, 0x01);
-
- if (pix->pixelformat == V4L2_PIX_FMT_JPEG) {
- err += sn9c102_write_reg(cam, r0 | 0x40, 0x01);
- err += sn9c102_write_reg(cam, 0xa2, 0x17);
- err += sn9c102_i2c_write(cam, 0x11, 0x00);
- } else {
- err += sn9c102_write_reg(cam, r0 | 0x40, 0x01);
- err += sn9c102_write_reg(cam, 0xa2, 0x17);
- err += sn9c102_i2c_write(cam, 0x11, 0x0d);
- }
-
- return err;
-}
-
-
-static const struct sn9c102_sensor ov7660 = {
- .name = "OV7660",
- .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
- .supported_bridge = BRIDGE_SN9C105 | BRIDGE_SN9C120,
- .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
- .frequency = SN9C102_I2C_100KHZ,
- .interface = SN9C102_I2C_2WIRES,
- .i2c_slave_id = 0x21,
- .init = &ov7660_init,
- .qctrl = {
- {
- .id = V4L2_CID_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "global gain",
- .minimum = 0x00,
- .maximum = 0x1f,
- .step = 0x01,
- .default_value = 0x09,
- .flags = 0,
- },
- {
- .id = V4L2_CID_EXPOSURE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "exposure",
- .minimum = 0x00,
- .maximum = 0xff,
- .step = 0x01,
- .default_value = 0x27,
- .flags = 0,
- },
- {
- .id = V4L2_CID_DO_WHITE_BALANCE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "night mode",
- .minimum = 0x00,
- .maximum = 0x01,
- .step = 0x01,
- .default_value = 0x00,
- .flags = 0,
- },
- {
- .id = V4L2_CID_RED_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "red balance",
- .minimum = 0x00,
- .maximum = 0x7f,
- .step = 0x01,
- .default_value = 0x14,
- .flags = 0,
- },
- {
- .id = V4L2_CID_BLUE_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "blue balance",
- .minimum = 0x00,
- .maximum = 0x7f,
- .step = 0x01,
- .default_value = 0x14,
- .flags = 0,
- },
- {
- .id = V4L2_CID_AUTOGAIN,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "auto adjust",
- .minimum = 0x00,
- .maximum = 0x01,
- .step = 0x01,
- .default_value = 0x01,
- .flags = 0,
- },
- {
- .id = SN9C102_V4L2_CID_GREEN_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "green balance",
- .minimum = 0x00,
- .maximum = 0x7f,
- .step = 0x01,
- .default_value = 0x14,
- .flags = 0,
- },
- {
- .id = SN9C102_V4L2_CID_BAND_FILTER,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "band filter",
- .minimum = 0x00,
- .maximum = 0x01,
- .step = 0x01,
- .default_value = 0x00,
- .flags = 0,
- },
- },
- .get_ctrl = &ov7660_get_ctrl,
- .set_ctrl = &ov7660_set_ctrl,
- .cropcap = {
- .bounds = {
- .left = 0,
- .top = 0,
- .width = 640,
- .height = 480,
- },
- .defrect = {
- .left = 0,
- .top = 0,
- .width = 640,
- .height = 480,
- },
- },
- .set_crop = &ov7660_set_crop,
- .pix_format = {
- .width = 640,
- .height = 480,
- .pixelformat = V4L2_PIX_FMT_JPEG,
- .priv = 8,
- },
- .set_pix_format = &ov7660_set_pix_format
-};
-
-
-int sn9c102_probe_ov7660(struct sn9c102_device* cam)
-{
- int pid, ver, err;
-
- err = sn9c102_write_const_regs(cam, {0x01, 0xf1}, {0x00, 0xf1},
- {0x01, 0x01}, {0x00, 0x01},
- {0x28, 0x17});
-
- pid = sn9c102_i2c_try_read(cam, &ov7660, 0x0a);
- ver = sn9c102_i2c_try_read(cam, &ov7660, 0x0b);
- if (err || pid < 0 || ver < 0)
- return -EIO;
- if (pid != 0x76 || ver != 0x60)
- return -ENODEV;
-
- sn9c102_attach_sensor(cam, &ov7660);
-
- return 0;
-}
diff --git a/drivers/media/usb/sn9c102/sn9c102_pas106b.c b/drivers/media/usb/sn9c102/sn9c102_pas106b.c
deleted file mode 100644
index 81cd969c1b7..00000000000
--- a/drivers/media/usb/sn9c102/sn9c102_pas106b.c
+++ /dev/null
@@ -1,302 +0,0 @@
-/***************************************************************************
- * Plug-in for PAS106B image sensor connected to the SN9C1xx PC Camera *
- * Controllers *
- * *
- * Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the Free Software *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
- ***************************************************************************/
-
-#include <linux/delay.h>
-#include "sn9c102_sensor.h"
-#include "sn9c102_devtable.h"
-
-
-static int pas106b_init(struct sn9c102_device* cam)
-{
- int err = 0;
-
- err = sn9c102_write_const_regs(cam, {0x00, 0x10}, {0x00, 0x11},
- {0x00, 0x14}, {0x20, 0x17},
- {0x20, 0x19}, {0x09, 0x18});
-
- err += sn9c102_i2c_write(cam, 0x02, 0x0c);
- err += sn9c102_i2c_write(cam, 0x05, 0x5a);
- err += sn9c102_i2c_write(cam, 0x06, 0x88);
- err += sn9c102_i2c_write(cam, 0x07, 0x80);
- err += sn9c102_i2c_write(cam, 0x10, 0x06);
- err += sn9c102_i2c_write(cam, 0x11, 0x06);
- err += sn9c102_i2c_write(cam, 0x12, 0x00);
- err += sn9c102_i2c_write(cam, 0x14, 0x02);
- err += sn9c102_i2c_write(cam, 0x13, 0x01);
-
- msleep(400);
-
- return err;
-}
-
-
-static int pas106b_get_ctrl(struct sn9c102_device* cam,
- struct v4l2_control* ctrl)
-{
- switch (ctrl->id) {
- case V4L2_CID_EXPOSURE:
- {
- int r1 = sn9c102_i2c_read(cam, 0x03),
- r2 = sn9c102_i2c_read(cam, 0x04);
- if (r1 < 0 || r2 < 0)
- return -EIO;
- ctrl->value = (r1 << 4) | (r2 & 0x0f);
- }
- return 0;
- case V4L2_CID_RED_BALANCE:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x0c)) < 0)
- return -EIO;
- ctrl->value &= 0x1f;
- return 0;
- case V4L2_CID_BLUE_BALANCE:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x09)) < 0)
- return -EIO;
- ctrl->value &= 0x1f;
- return 0;
- case V4L2_CID_GAIN:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x0e)) < 0)
- return -EIO;
- ctrl->value &= 0x1f;
- return 0;
- case V4L2_CID_CONTRAST:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x0f)) < 0)
- return -EIO;
- ctrl->value &= 0x07;
- return 0;
- case SN9C102_V4L2_CID_GREEN_BALANCE:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x0a)) < 0)
- return -EIO;
- ctrl->value = (ctrl->value & 0x1f) << 1;
- return 0;
- case SN9C102_V4L2_CID_DAC_MAGNITUDE:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x08)) < 0)
- return -EIO;
- ctrl->value &= 0xf8;
- return 0;
- default:
- return -EINVAL;
- }
-}
-
-
-static int pas106b_set_ctrl(struct sn9c102_device* cam,
- const struct v4l2_control* ctrl)
-{
- int err = 0;
-
- switch (ctrl->id) {
- case V4L2_CID_EXPOSURE:
- err += sn9c102_i2c_write(cam, 0x03, ctrl->value >> 4);
- err += sn9c102_i2c_write(cam, 0x04, ctrl->value & 0x0f);
- break;
- case V4L2_CID_RED_BALANCE:
- err += sn9c102_i2c_write(cam, 0x0c, ctrl->value);
- break;
- case V4L2_CID_BLUE_BALANCE:
- err += sn9c102_i2c_write(cam, 0x09, ctrl->value);
- break;
- case V4L2_CID_GAIN:
- err += sn9c102_i2c_write(cam, 0x0e, ctrl->value);
- break;
- case V4L2_CID_CONTRAST:
- err += sn9c102_i2c_write(cam, 0x0f, ctrl->value);
- break;
- case SN9C102_V4L2_CID_GREEN_BALANCE:
- err += sn9c102_i2c_write(cam, 0x0a, ctrl->value >> 1);
- err += sn9c102_i2c_write(cam, 0x0b, ctrl->value >> 1);
- break;
- case SN9C102_V4L2_CID_DAC_MAGNITUDE:
- err += sn9c102_i2c_write(cam, 0x08, ctrl->value << 3);
- break;
- default:
- return -EINVAL;
- }
- err += sn9c102_i2c_write(cam, 0x13, 0x01);
-
- return err ? -EIO : 0;
-}
-
-
-static int pas106b_set_crop(struct sn9c102_device* cam,
- const struct v4l2_rect* rect)
-{
- struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
- int err = 0;
- u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4,
- v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3;
-
- err += sn9c102_write_reg(cam, h_start, 0x12);
- err += sn9c102_write_reg(cam, v_start, 0x13);
-
- return err;
-}
-
-
-static int pas106b_set_pix_format(struct sn9c102_device* cam,
- const struct v4l2_pix_format* pix)
-{
- int err = 0;
-
- if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
- err += sn9c102_write_reg(cam, 0x2c, 0x17);
- else
- err += sn9c102_write_reg(cam, 0x20, 0x17);
-
- return err;
-}
-
-
-static const struct sn9c102_sensor pas106b = {
- .name = "PAS106B",
- .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
- .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102,
- .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
- .frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ,
- .interface = SN9C102_I2C_2WIRES,
- .i2c_slave_id = 0x40,
- .init = &pas106b_init,
- .qctrl = {
- {
- .id = V4L2_CID_EXPOSURE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "exposure",
- .minimum = 0x125,
- .maximum = 0xfff,
- .step = 0x001,
- .default_value = 0x140,
- .flags = 0,
- },
- {
- .id = V4L2_CID_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "global gain",
- .minimum = 0x00,
- .maximum = 0x1f,
- .step = 0x01,
- .default_value = 0x0d,
- .flags = 0,
- },
- {
- .id = V4L2_CID_CONTRAST,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "contrast",
- .minimum = 0x00,
- .maximum = 0x07,
- .step = 0x01,
- .default_value = 0x00, /* 0x00~0x03 have same effect */
- .flags = 0,
- },
- {
- .id = V4L2_CID_RED_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "red balance",
- .minimum = 0x00,
- .maximum = 0x1f,
- .step = 0x01,
- .default_value = 0x04,
- .flags = 0,
- },
- {
- .id = V4L2_CID_BLUE_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "blue balance",
- .minimum = 0x00,
- .maximum = 0x1f,
- .step = 0x01,
- .default_value = 0x06,
- .flags = 0,
- },
- {
- .id = SN9C102_V4L2_CID_GREEN_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "green balance",
- .minimum = 0x00,
- .maximum = 0x3e,
- .step = 0x02,
- .default_value = 0x02,
- .flags = 0,
- },
- {
- .id = SN9C102_V4L2_CID_DAC_MAGNITUDE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "DAC magnitude",
- .minimum = 0x00,
- .maximum = 0x1f,
- .step = 0x01,
- .default_value = 0x01,
- .flags = 0,
- },
- },
- .get_ctrl = &pas106b_get_ctrl,
- .set_ctrl = &pas106b_set_ctrl,
- .cropcap = {
- .bounds = {
- .left = 0,
- .top = 0,
- .width = 352,
- .height = 288,
- },
- .defrect = {
- .left = 0,
- .top = 0,
- .width = 352,
- .height = 288,
- },
- },
- .set_crop = &pas106b_set_crop,
- .pix_format = {
- .width = 352,
- .height = 288,
- .pixelformat = V4L2_PIX_FMT_SBGGR8,
- .priv = 8, /* we use this field as 'bits per pixel' */
- },
- .set_pix_format = &pas106b_set_pix_format
-};
-
-
-int sn9c102_probe_pas106b(struct sn9c102_device* cam)
-{
- int r0 = 0, r1 = 0;
- unsigned int pid = 0;
-
- /*
- Minimal initialization to enable the I2C communication
- NOTE: do NOT change the values!
- */
- if (sn9c102_write_const_regs(cam,
- {0x01, 0x01}, /* sensor power down */
- {0x00, 0x01}, /* sensor power on */
- {0x28, 0x17})) /* sensor clock at 24 MHz */
- return -EIO;
-
- r0 = sn9c102_i2c_try_read(cam, &pas106b, 0x00);
- r1 = sn9c102_i2c_try_read(cam, &pas106b, 0x01);
- if (r0 < 0 || r1 < 0)
- return -EIO;
-
- pid = (r0 << 11) | ((r1 & 0xf0) >> 4);
- if (pid != 0x007)
- return -ENODEV;
-
- sn9c102_attach_sensor(cam, &pas106b);
-
- return 0;
-}
diff --git a/drivers/media/usb/sn9c102/sn9c102_pas202bcb.c b/drivers/media/usb/sn9c102/sn9c102_pas202bcb.c
deleted file mode 100644
index 2e86fdc8698..00000000000
--- a/drivers/media/usb/sn9c102/sn9c102_pas202bcb.c
+++ /dev/null
@@ -1,335 +0,0 @@
-/***************************************************************************
- * Plug-in for PAS202BCB image sensor connected to the SN9C1xx PC Camera *
- * Controllers *
- * *
- * Copyright (C) 2004 by Carlos Eduardo Medaglia Dyonisio *
- * <medaglia@undl.org.br> *
- * *
- * Support for SN9C103, DAC Magnitude, exposure and green gain controls *
- * added by Luca Risolia <luca.risolia@studio.unibo.it> *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the Free Software *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
- ***************************************************************************/
-
-#include <linux/delay.h>
-#include "sn9c102_sensor.h"
-#include "sn9c102_devtable.h"
-
-
-static int pas202bcb_init(struct sn9c102_device* cam)
-{
- int err = 0;
-
- switch (sn9c102_get_bridge(cam)) {
- case BRIDGE_SN9C101:
- case BRIDGE_SN9C102:
- err = sn9c102_write_const_regs(cam, {0x00, 0x10}, {0x00, 0x11},
- {0x00, 0x14}, {0x20, 0x17},
- {0x30, 0x19}, {0x09, 0x18});
- break;
- case BRIDGE_SN9C103:
- err = sn9c102_write_const_regs(cam, {0x00, 0x02}, {0x00, 0x03},
- {0x1a, 0x04}, {0x20, 0x05},
- {0x20, 0x06}, {0x20, 0x07},
- {0x00, 0x10}, {0x00, 0x11},
- {0x00, 0x14}, {0x20, 0x17},
- {0x30, 0x19}, {0x09, 0x18},
- {0x02, 0x1c}, {0x03, 0x1d},
- {0x0f, 0x1e}, {0x0c, 0x1f},
- {0x00, 0x20}, {0x10, 0x21},
- {0x20, 0x22}, {0x30, 0x23},
- {0x40, 0x24}, {0x50, 0x25},
- {0x60, 0x26}, {0x70, 0x27},
- {0x80, 0x28}, {0x90, 0x29},
- {0xa0, 0x2a}, {0xb0, 0x2b},
- {0xc0, 0x2c}, {0xd0, 0x2d},
- {0xe0, 0x2e}, {0xf0, 0x2f},
- {0xff, 0x30});
- break;
- default:
- break;
- }
-
- err += sn9c102_i2c_write(cam, 0x02, 0x14);
- err += sn9c102_i2c_write(cam, 0x03, 0x40);
- err += sn9c102_i2c_write(cam, 0x0d, 0x2c);
- err += sn9c102_i2c_write(cam, 0x0e, 0x01);
- err += sn9c102_i2c_write(cam, 0x0f, 0xa9);
- err += sn9c102_i2c_write(cam, 0x10, 0x08);
- err += sn9c102_i2c_write(cam, 0x13, 0x63);
- err += sn9c102_i2c_write(cam, 0x15, 0x70);
- err += sn9c102_i2c_write(cam, 0x11, 0x01);
-
- msleep(400);
-
- return err;
-}
-
-
-static int pas202bcb_get_ctrl(struct sn9c102_device* cam,
- struct v4l2_control* ctrl)
-{
- switch (ctrl->id) {
- case V4L2_CID_EXPOSURE:
- {
- int r1 = sn9c102_i2c_read(cam, 0x04),
- r2 = sn9c102_i2c_read(cam, 0x05);
- if (r1 < 0 || r2 < 0)
- return -EIO;
- ctrl->value = (r1 << 6) | (r2 & 0x3f);
- }
- return 0;
- case V4L2_CID_RED_BALANCE:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x09)) < 0)
- return -EIO;
- ctrl->value &= 0x0f;
- return 0;
- case V4L2_CID_BLUE_BALANCE:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x07)) < 0)
- return -EIO;
- ctrl->value &= 0x0f;
- return 0;
- case V4L2_CID_GAIN:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x10)) < 0)
- return -EIO;
- ctrl->value &= 0x1f;
- return 0;
- case SN9C102_V4L2_CID_GREEN_BALANCE:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x08)) < 0)
- return -EIO;
- ctrl->value &= 0x0f;
- return 0;
- case SN9C102_V4L2_CID_DAC_MAGNITUDE:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x0c)) < 0)
- return -EIO;
- return 0;
- default:
- return -EINVAL;
- }
-}
-
-
-static int pas202bcb_set_pix_format(struct sn9c102_device* cam,
- const struct v4l2_pix_format* pix)
-{
- int err = 0;
-
- if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
- err += sn9c102_write_reg(cam, 0x28, 0x17);
- else
- err += sn9c102_write_reg(cam, 0x20, 0x17);
-
- return err;
-}
-
-
-static int pas202bcb_set_ctrl(struct sn9c102_device* cam,
- const struct v4l2_control* ctrl)
-{
- int err = 0;
-
- switch (ctrl->id) {
- case V4L2_CID_EXPOSURE:
- err += sn9c102_i2c_write(cam, 0x04, ctrl->value >> 6);
- err += sn9c102_i2c_write(cam, 0x05, ctrl->value & 0x3f);
- break;
- case V4L2_CID_RED_BALANCE:
- err += sn9c102_i2c_write(cam, 0x09, ctrl->value);
- break;
- case V4L2_CID_BLUE_BALANCE:
- err += sn9c102_i2c_write(cam, 0x07, ctrl->value);
- break;
- case V4L2_CID_GAIN:
- err += sn9c102_i2c_write(cam, 0x10, ctrl->value);
- break;
- case SN9C102_V4L2_CID_GREEN_BALANCE:
- err += sn9c102_i2c_write(cam, 0x08, ctrl->value);
- break;
- case SN9C102_V4L2_CID_DAC_MAGNITUDE:
- err += sn9c102_i2c_write(cam, 0x0c, ctrl->value);
- break;
- default:
- return -EINVAL;
- }
- err += sn9c102_i2c_write(cam, 0x11, 0x01);
-
- return err ? -EIO : 0;
-}
-
-
-static int pas202bcb_set_crop(struct sn9c102_device* cam,
- const struct v4l2_rect* rect)
-{
- struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
- int err = 0;
- u8 h_start = 0,
- v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3;
-
- switch (sn9c102_get_bridge(cam)) {
- case BRIDGE_SN9C101:
- case BRIDGE_SN9C102:
- h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4;
- break;
- case BRIDGE_SN9C103:
- h_start = (u8)(rect->left - s->cropcap.bounds.left) + 3;
- break;
- default:
- break;
- }
-
- err += sn9c102_write_reg(cam, h_start, 0x12);
- err += sn9c102_write_reg(cam, v_start, 0x13);
-
- return err;
-}
-
-
-static const struct sn9c102_sensor pas202bcb = {
- .name = "PAS202BCB",
- .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
- .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103,
- .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
- .frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ,
- .interface = SN9C102_I2C_2WIRES,
- .i2c_slave_id = 0x40,
- .init = &pas202bcb_init,
- .qctrl = {
- {
- .id = V4L2_CID_EXPOSURE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "exposure",
- .minimum = 0x01e5,
- .maximum = 0x3fff,
- .step = 0x0001,
- .default_value = 0x01e5,
- .flags = 0,
- },
- {
- .id = V4L2_CID_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "global gain",
- .minimum = 0x00,
- .maximum = 0x1f,
- .step = 0x01,
- .default_value = 0x0b,
- .flags = 0,
- },
- {
- .id = V4L2_CID_RED_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "red balance",
- .minimum = 0x00,
- .maximum = 0x0f,
- .step = 0x01,
- .default_value = 0x00,
- .flags = 0,
- },
- {
- .id = V4L2_CID_BLUE_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "blue balance",
- .minimum = 0x00,
- .maximum = 0x0f,
- .step = 0x01,
- .default_value = 0x05,
- .flags = 0,
- },
- {
- .id = SN9C102_V4L2_CID_GREEN_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "green balance",
- .minimum = 0x00,
- .maximum = 0x0f,
- .step = 0x01,
- .default_value = 0x00,
- .flags = 0,
- },
- {
- .id = SN9C102_V4L2_CID_DAC_MAGNITUDE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "DAC magnitude",
- .minimum = 0x00,
- .maximum = 0xff,
- .step = 0x01,
- .default_value = 0x04,
- .flags = 0,
- },
- },
- .get_ctrl = &pas202bcb_get_ctrl,
- .set_ctrl = &pas202bcb_set_ctrl,
- .cropcap = {
- .bounds = {
- .left = 0,
- .top = 0,
- .width = 640,
- .height = 480,
- },
- .defrect = {
- .left = 0,
- .top = 0,
- .width = 640,
- .height = 480,
- },
- },
- .set_crop = &pas202bcb_set_crop,
- .pix_format = {
- .width = 640,
- .height = 480,
- .pixelformat = V4L2_PIX_FMT_SBGGR8,
- .priv = 8,
- },
- .set_pix_format = &pas202bcb_set_pix_format
-};
-
-
-int sn9c102_probe_pas202bcb(struct sn9c102_device* cam)
-{
- int r0 = 0, r1 = 0, err = 0;
- unsigned int pid = 0;
-
- /*
- * Minimal initialization to enable the I2C communication
- * NOTE: do NOT change the values!
- */
- switch (sn9c102_get_bridge(cam)) {
- case BRIDGE_SN9C101:
- case BRIDGE_SN9C102:
- err = sn9c102_write_const_regs(cam,
- {0x01, 0x01}, /* power down */
- {0x40, 0x01}, /* power on */
- {0x28, 0x17});/* clock 24 MHz */
- break;
- case BRIDGE_SN9C103: /* do _not_ change anything! */
- err = sn9c102_write_const_regs(cam, {0x09, 0x01}, {0x44, 0x01},
- {0x44, 0x02}, {0x29, 0x17});
- break;
- default:
- break;
- }
-
- r0 = sn9c102_i2c_try_read(cam, &pas202bcb, 0x00);
- r1 = sn9c102_i2c_try_read(cam, &pas202bcb, 0x01);
-
- if (err || r0 < 0 || r1 < 0)
- return -EIO;
-
- pid = (r0 << 4) | ((r1 & 0xf0) >> 4);
- if (pid != 0x017)
- return -ENODEV;
-
- sn9c102_attach_sensor(cam, &pas202bcb);
-
- return 0;
-}
diff --git a/drivers/media/usb/sn9c102/sn9c102_sensor.h b/drivers/media/usb/sn9c102/sn9c102_sensor.h
deleted file mode 100644
index 3679970dba2..00000000000
--- a/drivers/media/usb/sn9c102/sn9c102_sensor.h
+++ /dev/null
@@ -1,307 +0,0 @@
-/***************************************************************************
- * API for image sensors connected to the SN9C1xx PC Camera Controllers *
- * *
- * Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the Free Software *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
- ***************************************************************************/
-
-#ifndef _SN9C102_SENSOR_H_
-#define _SN9C102_SENSOR_H_
-
-#include <linux/usb.h>
-#include <linux/videodev2.h>
-#include <linux/device.h>
-#include <linux/stddef.h>
-#include <linux/errno.h>
-#include <asm/types.h>
-
-struct sn9c102_device;
-struct sn9c102_sensor;
-
-/*****************************************************************************/
-
-/*
- OVERVIEW.
- This is a small interface that allows you to add support for any CCD/CMOS
- image sensors connected to the SN9C1XX bridges. The entire API is documented
- below. In the most general case, to support a sensor there are three steps
- you have to follow:
- 1) define the main "sn9c102_sensor" structure by setting the basic fields;
- 2) write a probing function to be called by the core module when the USB
- camera is recognized, then add both the USB ids and the name of that
- function to the two corresponding tables in sn9c102_devtable.h;
- 3) implement the methods that you want/need (and fill the rest of the main
- structure accordingly).
- "sn9c102_pas106b.c" is an example of all this stuff. Remember that you do
- NOT need to touch the source code of the core module for the things to work
- properly, unless you find bugs or flaws in it. Finally, do not forget to
- read the V4L2 API for completeness.
-*/
-
-/*****************************************************************************/
-
-enum sn9c102_bridge {
- BRIDGE_SN9C101 = 0x01,
- BRIDGE_SN9C102 = 0x02,
- BRIDGE_SN9C103 = 0x04,
- BRIDGE_SN9C105 = 0x08,
- BRIDGE_SN9C120 = 0x10,
-};
-
-/* Return the bridge name */
-enum sn9c102_bridge sn9c102_get_bridge(struct sn9c102_device* cam);
-
-/* Return a pointer the sensor struct attached to the camera */
-struct sn9c102_sensor* sn9c102_get_sensor(struct sn9c102_device* cam);
-
-/* Identify a device */
-extern struct sn9c102_device*
-sn9c102_match_id(struct sn9c102_device* cam, const struct usb_device_id *id);
-
-/* Attach a probed sensor to the camera. */
-extern void
-sn9c102_attach_sensor(struct sn9c102_device* cam,
- const struct sn9c102_sensor* sensor);
-
-/*
- Read/write routines: they always return -1 on error, 0 or the read value
- otherwise. NOTE that a real read operation is not supported by the SN9C1XX
- chip for some of its registers. To work around this problem, a pseudo-read
- call is provided instead: it returns the last successfully written value
- on the register (0 if it has never been written), the usual -1 on error.
-*/
-
-/* The "try" I2C I/O versions are used when probing the sensor */
-extern int sn9c102_i2c_try_read(struct sn9c102_device*,
- const struct sn9c102_sensor*, u8 address);
-
-/*
- These must be used if and only if the sensor doesn't implement the standard
- I2C protocol. There are a number of good reasons why you must use the
- single-byte versions of these functions: do not abuse. The first function
- writes n bytes, from data0 to datan, to registers 0x09 - 0x09+n of SN9C1XX
- chip. The second one programs the registers 0x09 and 0x10 with data0 and
- data1, and places the n bytes read from the sensor register table in the
- buffer pointed by 'buffer'. Both the functions return -1 on error; the write
- version returns 0 on success, while the read version returns the first read
- byte.
-*/
-extern int sn9c102_i2c_try_raw_write(struct sn9c102_device* cam,
- const struct sn9c102_sensor* sensor, u8 n,
- u8 data0, u8 data1, u8 data2, u8 data3,
- u8 data4, u8 data5);
-extern int sn9c102_i2c_try_raw_read(struct sn9c102_device* cam,
- const struct sn9c102_sensor* sensor,
- u8 data0, u8 data1, u8 n, u8 buffer[]);
-
-/* To be used after the sensor struct has been attached to the camera struct */
-extern int sn9c102_i2c_write(struct sn9c102_device*, u8 address, u8 value);
-extern int sn9c102_i2c_read(struct sn9c102_device*, u8 address);
-
-/* I/O on registers in the bridge. Could be used by the sensor methods too */
-extern int sn9c102_read_reg(struct sn9c102_device*, u16 index);
-extern int sn9c102_pread_reg(struct sn9c102_device*, u16 index);
-extern int sn9c102_write_reg(struct sn9c102_device*, u8 value, u16 index);
-extern int sn9c102_write_regs(struct sn9c102_device*, const u8 valreg[][2],
- int count);
-/*
- Write multiple registers with constant values. For example:
- sn9c102_write_const_regs(cam, {0x00, 0x14}, {0x60, 0x17}, {0x0f, 0x18});
- Register addresses must be < 256.
-*/
-#define sn9c102_write_const_regs(sn9c102_device, data...) \
- ({ static const u8 _valreg[][2] = {data}; \
- sn9c102_write_regs(sn9c102_device, _valreg, ARRAY_SIZE(_valreg)); })
-
-/*****************************************************************************/
-
-enum sn9c102_i2c_sysfs_ops {
- SN9C102_I2C_READ = 0x01,
- SN9C102_I2C_WRITE = 0x02,
-};
-
-enum sn9c102_i2c_frequency { /* sensors may support both the frequencies */
- SN9C102_I2C_100KHZ = 0x01,
- SN9C102_I2C_400KHZ = 0x02,
-};
-
-enum sn9c102_i2c_interface {
- SN9C102_I2C_2WIRES,
- SN9C102_I2C_3WIRES,
-};
-
-#define SN9C102_MAX_CTRLS (V4L2_CID_LASTP1-V4L2_CID_BASE+10)
-
-struct sn9c102_sensor {
- char name[32], /* sensor name */
- maintainer[64]; /* name of the maintainer <email> */
-
- enum sn9c102_bridge supported_bridge; /* supported SN9C1xx bridges */
-
- /* Supported operations through the 'sysfs' interface */
- enum sn9c102_i2c_sysfs_ops sysfs_ops;
-
- /*
- These sensor capabilities must be provided if the SN9C1XX controller
- needs to communicate through the sensor serial interface by using
- at least one of the i2c functions available.
- */
- enum sn9c102_i2c_frequency frequency;
- enum sn9c102_i2c_interface interface;
-
- /*
- This identifier must be provided if the image sensor implements
- the standard I2C protocol.
- */
- u8 i2c_slave_id; /* reg. 0x09 */
-
- /*
- NOTE: Where not noted,most of the functions below are not mandatory.
- Set to null if you do not implement them. If implemented,
- they must return 0 on success, the proper error otherwise.
- */
-
- int (*init)(struct sn9c102_device* cam);
- /*
- This function will be called after the sensor has been attached.
- It should be used to initialize the sensor only, but may also
- configure part of the SN9C1XX chip if necessary. You don't need to
- setup picture settings like brightness, contrast, etc.. here, if
- the corresponding controls are implemented (see below), since
- they are adjusted in the core driver by calling the set_ctrl()
- method after init(), where the arguments are the default values
- specified in the v4l2_queryctrl list of supported controls;
- Same suggestions apply for other settings, _if_ the corresponding
- methods are present; if not, the initialization must configure the
- sensor according to the default configuration structures below.
- */
-
- struct v4l2_queryctrl qctrl[SN9C102_MAX_CTRLS];
- /*
- Optional list of default controls, defined as indicated in the
- V4L2 API. Menu type controls are not handled by this interface.
- */
-
- int (*get_ctrl)(struct sn9c102_device* cam, struct v4l2_control* ctrl);
- int (*set_ctrl)(struct sn9c102_device* cam,
- const struct v4l2_control* ctrl);
- /*
- You must implement at least the set_ctrl method if you have defined
- the list above. The returned value must follow the V4L2
- specifications for the VIDIOC_G|C_CTRL ioctls. V4L2_CID_H|VCENTER
- are not supported by this driver, so do not implement them. Also,
- you don't have to check whether the passed values are out of bounds,
- given that this is done by the core module.
- */
-
- struct v4l2_cropcap cropcap;
- /*
- Think the image sensor as a grid of R,G,B monochromatic pixels
- disposed according to a particular Bayer pattern, which describes
- the complete array of pixels, from (0,0) to (xmax, ymax). We will
- use this coordinate system from now on. It is assumed the sensor
- chip can be programmed to capture/transmit a subsection of that
- array of pixels: we will call this subsection "active window".
- It is not always true that the largest achievable active window can
- cover the whole array of pixels. The V4L2 API defines another
- area called "source rectangle", which, in turn, is a subrectangle of
- the active window. The SN9C1XX chip is always programmed to read the
- source rectangle.
- The bounds of both the active window and the source rectangle are
- specified in the cropcap substructures 'bounds' and 'defrect'.
- By default, the source rectangle should cover the largest possible
- area. Again, it is not always true that the largest source rectangle
- can cover the entire active window, although it is a rare case for
- the hardware we have. The bounds of the source rectangle _must_ be
- multiple of 16 and must use the same coordinate system as indicated
- before; their centers shall align initially.
- If necessary, the sensor chip must be initialized during init() to
- set the bounds of the active sensor window; however, by default, it
- usually covers the largest achievable area (maxwidth x maxheight)
- of pixels, so no particular initialization is needed, if you have
- defined the correct default bounds in the structures.
- See the V4L2 API for further details.
- NOTE: once you have defined the bounds of the active window
- (struct cropcap.bounds) you must not change them.anymore.
- Only 'bounds' and 'defrect' fields are mandatory, other fields
- will be ignored.
- */
-
- int (*set_crop)(struct sn9c102_device* cam,
- const struct v4l2_rect* rect);
- /*
- To be called on VIDIOC_C_SETCROP. The core module always calls a
- default routine which configures the appropriate SN9C1XX regs (also
- scaling), but you may need to override/adjust specific stuff.
- 'rect' contains width and height values that are multiple of 16: in
- case you override the default function, you always have to program
- the chip to match those values; on error return the corresponding
- error code without rolling back.
- NOTE: in case, you must program the SN9C1XX chip to get rid of
- blank pixels or blank lines at the _start_ of each line or
- frame after each HSYNC or VSYNC, so that the image starts with
- real RGB data (see regs 0x12, 0x13) (having set H_SIZE and,
- V_SIZE you don't have to care about blank pixels or blank
- lines at the end of each line or frame).
- */
-
- struct v4l2_pix_format pix_format;
- /*
- What you have to define here are: 1) initial 'width' and 'height' of
- the target rectangle 2) the initial 'pixelformat', which can be
- either V4L2_PIX_FMT_SN9C10X, V4L2_PIX_FMT_JPEG (for ompressed video)
- or V4L2_PIX_FMT_SBGGR8 3) 'priv', which we'll be used to indicate
- the number of bits per pixel for uncompressed video, 8 or 9 (despite
- the current value of 'pixelformat').
- NOTE 1: both 'width' and 'height' _must_ be either 1/1 or 1/2 or 1/4
- of cropcap.defrect.width and cropcap.defrect.height. I
- suggest 1/1.
- NOTE 2: The initial compression quality is defined by the first bit
- of reg 0x17 during the initialization of the image sensor.
- NOTE 3: as said above, you have to program the SN9C1XX chip to get
- rid of any blank pixels, so that the output of the sensor
- matches the RGB bayer sequence (i.e. BGBGBG...GRGRGR).
- */
-
- int (*set_pix_format)(struct sn9c102_device* cam,
- const struct v4l2_pix_format* pix);
- /*
- To be called on VIDIOC_S_FMT, when switching from the SBGGR8 to
- SN9C10X pixel format or viceversa. On error return the corresponding
- error code without rolling back.
- */
-
- /*
- Do NOT write to the data below, it's READ ONLY. It is used by the
- core module to store successfully updated values of the above
- settings, for rollbacks..etc..in case of errors during atomic I/O
- */
- struct v4l2_queryctrl _qctrl[SN9C102_MAX_CTRLS];
- struct v4l2_rect _rect;
-};
-
-/*****************************************************************************/
-
-/* Private ioctl's for control settings supported by some image sensors */
-#define SN9C102_V4L2_CID_DAC_MAGNITUDE (V4L2_CID_PRIVATE_BASE + 0)
-#define SN9C102_V4L2_CID_GREEN_BALANCE (V4L2_CID_PRIVATE_BASE + 1)
-#define SN9C102_V4L2_CID_RESET_LEVEL (V4L2_CID_PRIVATE_BASE + 2)
-#define SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE (V4L2_CID_PRIVATE_BASE + 3)
-#define SN9C102_V4L2_CID_GAMMA (V4L2_CID_PRIVATE_BASE + 4)
-#define SN9C102_V4L2_CID_BAND_FILTER (V4L2_CID_PRIVATE_BASE + 5)
-#define SN9C102_V4L2_CID_BRIGHT_LEVEL (V4L2_CID_PRIVATE_BASE + 6)
-
-#endif /* _SN9C102_SENSOR_H_ */
diff --git a/drivers/media/usb/sn9c102/sn9c102_tas5110c1b.c b/drivers/media/usb/sn9c102/sn9c102_tas5110c1b.c
deleted file mode 100644
index 04cdfdde856..00000000000
--- a/drivers/media/usb/sn9c102/sn9c102_tas5110c1b.c
+++ /dev/null
@@ -1,154 +0,0 @@
-/***************************************************************************
- * Plug-in for TAS5110C1B image sensor connected to the SN9C1xx PC Camera *
- * Controllers *
- * *
- * Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the Free Software *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
- ***************************************************************************/
-
-#include "sn9c102_sensor.h"
-#include "sn9c102_devtable.h"
-
-
-static int tas5110c1b_init(struct sn9c102_device* cam)
-{
- int err = 0;
-
- err = sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x44, 0x01},
- {0x00, 0x10}, {0x00, 0x11},
- {0x0a, 0x14}, {0x60, 0x17},
- {0x06, 0x18}, {0xfb, 0x19});
-
- err += sn9c102_i2c_write(cam, 0xc0, 0x80);
-
- return err;
-}
-
-
-static int tas5110c1b_set_ctrl(struct sn9c102_device* cam,
- const struct v4l2_control* ctrl)
-{
- int err = 0;
-
- switch (ctrl->id) {
- case V4L2_CID_GAIN:
- err += sn9c102_i2c_write(cam, 0x20, 0xf6 - ctrl->value);
- break;
- default:
- return -EINVAL;
- }
-
- return err ? -EIO : 0;
-}
-
-
-static int tas5110c1b_set_crop(struct sn9c102_device* cam,
- const struct v4l2_rect* rect)
-{
- struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
- int err = 0;
- u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 69,
- v_start = (u8)(rect->top - s->cropcap.bounds.top) + 9;
-
- err += sn9c102_write_reg(cam, h_start, 0x12);
- err += sn9c102_write_reg(cam, v_start, 0x13);
-
- /* Don't change ! */
- err += sn9c102_write_reg(cam, 0x14, 0x1a);
- err += sn9c102_write_reg(cam, 0x0a, 0x1b);
- err += sn9c102_write_reg(cam, sn9c102_pread_reg(cam, 0x19), 0x19);
-
- return err;
-}
-
-
-static int tas5110c1b_set_pix_format(struct sn9c102_device* cam,
- const struct v4l2_pix_format* pix)
-{
- int err = 0;
-
- if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
- err += sn9c102_write_reg(cam, 0x2b, 0x19);
- else
- err += sn9c102_write_reg(cam, 0xfb, 0x19);
-
- return err;
-}
-
-
-static const struct sn9c102_sensor tas5110c1b = {
- .name = "TAS5110C1B",
- .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
- .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102,
- .sysfs_ops = SN9C102_I2C_WRITE,
- .frequency = SN9C102_I2C_100KHZ,
- .interface = SN9C102_I2C_3WIRES,
- .init = &tas5110c1b_init,
- .qctrl = {
- {
- .id = V4L2_CID_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "global gain",
- .minimum = 0x00,
- .maximum = 0xf6,
- .step = 0x01,
- .default_value = 0x40,
- .flags = 0,
- },
- },
- .set_ctrl = &tas5110c1b_set_ctrl,
- .cropcap = {
- .bounds = {
- .left = 0,
- .top = 0,
- .width = 352,
- .height = 288,
- },
- .defrect = {
- .left = 0,
- .top = 0,
- .width = 352,
- .height = 288,
- },
- },
- .set_crop = &tas5110c1b_set_crop,
- .pix_format = {
- .width = 352,
- .height = 288,
- .pixelformat = V4L2_PIX_FMT_SBGGR8,
- .priv = 8,
- },
- .set_pix_format = &tas5110c1b_set_pix_format
-};
-
-
-int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam)
-{
- const struct usb_device_id tas5110c1b_id_table[] = {
- { USB_DEVICE(0x0c45, 0x6001), },
- { USB_DEVICE(0x0c45, 0x6005), },
- { USB_DEVICE(0x0c45, 0x60ab), },
- { }
- };
-
- /* Sensor detection is based on USB pid/vid */
- if (!sn9c102_match_id(cam, tas5110c1b_id_table))
- return -ENODEV;
-
- sn9c102_attach_sensor(cam, &tas5110c1b);
-
- return 0;
-}
diff --git a/drivers/media/usb/sn9c102/sn9c102_tas5110d.c b/drivers/media/usb/sn9c102/sn9c102_tas5110d.c
deleted file mode 100644
index 9372e6f9fcf..00000000000
--- a/drivers/media/usb/sn9c102/sn9c102_tas5110d.c
+++ /dev/null
@@ -1,119 +0,0 @@
-/***************************************************************************
- * Plug-in for TAS5110D image sensor connected to the SN9C1xx PC Camera *
- * Controllers *
- * *
- * Copyright (C) 2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the Free Software *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
- ***************************************************************************/
-
-#include "sn9c102_sensor.h"
-#include "sn9c102_devtable.h"
-
-
-static int tas5110d_init(struct sn9c102_device* cam)
-{
- int err;
-
- err = sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x04, 0x01},
- {0x0a, 0x14}, {0x60, 0x17},
- {0x06, 0x18}, {0xfb, 0x19});
-
- err += sn9c102_i2c_write(cam, 0x9a, 0xca);
-
- return err;
-}
-
-
-static int tas5110d_set_crop(struct sn9c102_device* cam,
- const struct v4l2_rect* rect)
-{
- struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
- int err = 0;
- u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 69,
- v_start = (u8)(rect->top - s->cropcap.bounds.top) + 9;
-
- err += sn9c102_write_reg(cam, h_start, 0x12);
- err += sn9c102_write_reg(cam, v_start, 0x13);
-
- err += sn9c102_write_reg(cam, 0x14, 0x1a);
- err += sn9c102_write_reg(cam, 0x0a, 0x1b);
-
- return err;
-}
-
-
-static int tas5110d_set_pix_format(struct sn9c102_device* cam,
- const struct v4l2_pix_format* pix)
-{
- int err = 0;
-
- if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
- err += sn9c102_write_reg(cam, 0x3b, 0x19);
- else
- err += sn9c102_write_reg(cam, 0xfb, 0x19);
-
- return err;
-}
-
-
-static const struct sn9c102_sensor tas5110d = {
- .name = "TAS5110D",
- .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
- .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102,
- .sysfs_ops = SN9C102_I2C_WRITE,
- .frequency = SN9C102_I2C_100KHZ,
- .interface = SN9C102_I2C_2WIRES,
- .i2c_slave_id = 0x61,
- .init = &tas5110d_init,
- .cropcap = {
- .bounds = {
- .left = 0,
- .top = 0,
- .width = 352,
- .height = 288,
- },
- .defrect = {
- .left = 0,
- .top = 0,
- .width = 352,
- .height = 288,
- },
- },
- .set_crop = &tas5110d_set_crop,
- .pix_format = {
- .width = 352,
- .height = 288,
- .pixelformat = V4L2_PIX_FMT_SBGGR8,
- .priv = 8,
- },
- .set_pix_format = &tas5110d_set_pix_format
-};
-
-
-int sn9c102_probe_tas5110d(struct sn9c102_device* cam)
-{
- const struct usb_device_id tas5110d_id_table[] = {
- { USB_DEVICE(0x0c45, 0x6007), },
- { }
- };
-
- if (!sn9c102_match_id(cam, tas5110d_id_table))
- return -ENODEV;
-
- sn9c102_attach_sensor(cam, &tas5110d);
-
- return 0;
-}
diff --git a/drivers/media/usb/sn9c102/sn9c102_tas5130d1b.c b/drivers/media/usb/sn9c102/sn9c102_tas5130d1b.c
deleted file mode 100644
index a30bbc4389f..00000000000
--- a/drivers/media/usb/sn9c102/sn9c102_tas5130d1b.c
+++ /dev/null
@@ -1,165 +0,0 @@
-/***************************************************************************
- * Plug-in for TAS5130D1B image sensor connected to the SN9C1xx PC Camera *
- * Controllers *
- * *
- * Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the Free Software *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
- ***************************************************************************/
-
-#include "sn9c102_sensor.h"
-#include "sn9c102_devtable.h"
-
-
-static int tas5130d1b_init(struct sn9c102_device* cam)
-{
- int err;
-
- err = sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x20, 0x17},
- {0x04, 0x01}, {0x01, 0x10},
- {0x00, 0x11}, {0x00, 0x14},
- {0x60, 0x17}, {0x07, 0x18});
-
- return err;
-}
-
-
-static int tas5130d1b_set_ctrl(struct sn9c102_device* cam,
- const struct v4l2_control* ctrl)
-{
- int err = 0;
-
- switch (ctrl->id) {
- case V4L2_CID_GAIN:
- err += sn9c102_i2c_write(cam, 0x20, 0xf6 - ctrl->value);
- break;
- case V4L2_CID_EXPOSURE:
- err += sn9c102_i2c_write(cam, 0x40, 0x47 - ctrl->value);
- break;
- default:
- return -EINVAL;
- }
-
- return err ? -EIO : 0;
-}
-
-
-static int tas5130d1b_set_crop(struct sn9c102_device* cam,
- const struct v4l2_rect* rect)
-{
- struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
- u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 104,
- v_start = (u8)(rect->top - s->cropcap.bounds.top) + 12;
- int err = 0;
-
- err += sn9c102_write_reg(cam, h_start, 0x12);
- err += sn9c102_write_reg(cam, v_start, 0x13);
-
- /* Do NOT change! */
- err += sn9c102_write_reg(cam, 0x1f, 0x1a);
- err += sn9c102_write_reg(cam, 0x1a, 0x1b);
- err += sn9c102_write_reg(cam, sn9c102_pread_reg(cam, 0x19), 0x19);
-
- return err;
-}
-
-
-static int tas5130d1b_set_pix_format(struct sn9c102_device* cam,
- const struct v4l2_pix_format* pix)
-{
- int err = 0;
-
- if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
- err += sn9c102_write_reg(cam, 0x63, 0x19);
- else
- err += sn9c102_write_reg(cam, 0xf3, 0x19);
-
- return err;
-}
-
-
-static const struct sn9c102_sensor tas5130d1b = {
- .name = "TAS5130D1B",
- .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
- .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102,
- .sysfs_ops = SN9C102_I2C_WRITE,
- .frequency = SN9C102_I2C_100KHZ,
- .interface = SN9C102_I2C_3WIRES,
- .init = &tas5130d1b_init,
- .qctrl = {
- {
- .id = V4L2_CID_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "global gain",
- .minimum = 0x00,
- .maximum = 0xf6,
- .step = 0x02,
- .default_value = 0x00,
- .flags = 0,
- },
- {
- .id = V4L2_CID_EXPOSURE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "exposure",
- .minimum = 0x00,
- .maximum = 0x47,
- .step = 0x01,
- .default_value = 0x00,
- .flags = 0,
- },
- },
- .set_ctrl = &tas5130d1b_set_ctrl,
- .cropcap = {
- .bounds = {
- .left = 0,
- .top = 0,
- .width = 640,
- .height = 480,
- },
- .defrect = {
- .left = 0,
- .top = 0,
- .width = 640,
- .height = 480,
- },
- },
- .set_crop = &tas5130d1b_set_crop,
- .pix_format = {
- .width = 640,
- .height = 480,
- .pixelformat = V4L2_PIX_FMT_SBGGR8,
- .priv = 8,
- },
- .set_pix_format = &tas5130d1b_set_pix_format
-};
-
-
-int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam)
-{
- const struct usb_device_id tas5130d1b_id_table[] = {
- { USB_DEVICE(0x0c45, 0x6024), },
- { USB_DEVICE(0x0c45, 0x6025), },
- { USB_DEVICE(0x0c45, 0x60aa), },
- { }
- };
-
- /* Sensor detection is based on USB pid/vid */
- if (!sn9c102_match_id(cam, tas5130d1b_id_table))
- return -ENODEV;
-
- sn9c102_attach_sensor(cam, &tas5130d1b);
-
- return 0;
-}
diff --git a/drivers/media/usb/stk1160/stk1160-ac97.c b/drivers/media/usb/stk1160/stk1160-ac97.c
index c8583c262c3..2dd308f9541 100644
--- a/drivers/media/usb/stk1160/stk1160-ac97.c
+++ b/drivers/media/usb/stk1160/stk1160-ac97.c
@@ -98,19 +98,17 @@ int stk1160_ac97_register(struct stk1160 *dev)
* Just want a card to access ac96 controls,
* the actual capture interface will be handled by snd-usb-audio
*/
- rc = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
- THIS_MODULE, 0, &card);
+ rc = snd_card_new(dev->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
+ THIS_MODULE, 0, &card);
if (rc < 0)
return rc;
- snd_card_set_dev(card, dev->dev);
-
/* TODO: I'm not sure where should I get these names :-( */
snprintf(card->shortname, sizeof(card->shortname),
"stk1160-mixer");
snprintf(card->longname, sizeof(card->longname),
"stk1160 ac97 codec mixer control");
- strncpy(card->driver, dev->dev->driver->name, sizeof(card->driver));
+ strlcpy(card->driver, dev->dev->driver->name, sizeof(card->driver));
rc = snd_ac97_bus(card, 0, &stk1160_ac97_ops, NULL, &ac97_bus);
if (rc)
diff --git a/drivers/media/usb/stk1160/stk1160-core.c b/drivers/media/usb/stk1160/stk1160-core.c
index 34a26e0cfe7..03504dcf3c5 100644
--- a/drivers/media/usb/stk1160/stk1160-core.c
+++ b/drivers/media/usb/stk1160/stk1160-core.c
@@ -67,17 +67,25 @@ int stk1160_read_reg(struct stk1160 *dev, u16 reg, u8 *value)
{
int ret;
int pipe = usb_rcvctrlpipe(dev->udev, 0);
+ u8 *buf;
*value = 0;
+
+ buf = kmalloc(sizeof(u8), GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
ret = usb_control_msg(dev->udev, pipe, 0x00,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0x00, reg, value, sizeof(u8), HZ);
+ 0x00, reg, buf, sizeof(u8), HZ);
if (ret < 0) {
stk1160_err("read failed on reg 0x%x (%d)\n",
reg, ret);
+ kfree(buf);
return ret;
}
+ *value = *buf;
+ kfree(buf);
return 0;
}
diff --git a/drivers/media/usb/stk1160/stk1160-v4l.c b/drivers/media/usb/stk1160/stk1160-v4l.c
index c45c9881bb5..5461341a31c 100644
--- a/drivers/media/usb/stk1160/stk1160-v4l.c
+++ b/drivers/media/usb/stk1160/stk1160-v4l.c
@@ -406,7 +406,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm)
stk1160_set_std(dev);
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std,
+ v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_std,
dev->norm);
return 0;
@@ -583,10 +583,10 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count)
}
/* abort streaming and wait for last buffer */
-static int stop_streaming(struct vb2_queue *vq)
+static void stop_streaming(struct vb2_queue *vq)
{
struct stk1160 *dev = vb2_get_drv_priv(vq);
- return stk1160_stop_streaming(dev);
+ stk1160_stop_streaming(dev);
}
static struct vb2_ops stk1160_video_qops = {
@@ -641,7 +641,7 @@ int stk1160_vb2_setup(struct stk1160 *dev)
q->buf_struct_size = sizeof(struct stk1160_buffer);
q->ops = &stk1160_video_qops;
q->mem_ops = &vb2_vmalloc_memops;
- q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
rc = vb2_queue_init(q);
if (rc < 0)
@@ -682,7 +682,7 @@ int stk1160_video_register(struct stk1160 *dev)
dev->fmt = &format[0];
stk1160_set_std(dev);
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std,
+ v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_std,
dev->norm);
video_set_drvdata(&dev->vdev, dev);
diff --git a/drivers/media/usb/stk1160/stk1160.h b/drivers/media/usb/stk1160/stk1160.h
index 05b05b160e1..abdea484c99 100644
--- a/drivers/media/usb/stk1160/stk1160.h
+++ b/drivers/media/usb/stk1160/stk1160.h
@@ -143,7 +143,6 @@ struct stk1160 {
int num_alt;
struct stk1160_isoc_ctl isoc_ctl;
- char urb_buf[255]; /* urb control msg buffer */
/* frame properties */
int width; /* current frame width */
diff --git a/drivers/media/usb/stkwebcam/stk-webcam.c b/drivers/media/usb/stkwebcam/stk-webcam.c
index c43c8d32be4..be77482c307 100644
--- a/drivers/media/usb/stkwebcam/stk-webcam.c
+++ b/drivers/media/usb/stkwebcam/stk-webcam.c
@@ -111,6 +111,13 @@ static const struct dmi_system_id stk_upside_down_dmi_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "F3JC")
}
},
+ {
+ .ident = "T12Rg-H",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "HCL Infosystems Limited"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "T12Rg-H")
+ }
+ },
{}
};
diff --git a/drivers/media/usb/tlg2300/pd-alsa.c b/drivers/media/usb/tlg2300/pd-alsa.c
index 3f3e141f70f..dd8fe100590 100644
--- a/drivers/media/usb/tlg2300/pd-alsa.c
+++ b/drivers/media/usb/tlg2300/pd-alsa.c
@@ -300,7 +300,8 @@ int poseidon_audio_init(struct poseidon *p)
struct snd_pcm *pcm;
int ret;
- ret = snd_card_create(-1, "Telegent", THIS_MODULE, 0, &card);
+ ret = snd_card_new(&p->interface->dev, -1, "Telegent",
+ THIS_MODULE, 0, &card);
if (ret != 0)
return ret;
diff --git a/drivers/media/usb/tlg2300/pd-main.c b/drivers/media/usb/tlg2300/pd-main.c
index 95f94e5aa66..3316caa4733 100644
--- a/drivers/media/usb/tlg2300/pd-main.c
+++ b/drivers/media/usb/tlg2300/pd-main.c
@@ -232,7 +232,7 @@ static int firmware_download(struct usb_device *udev)
goto out;
}
- max_packet_size = udev->ep_out[0x1]->desc.wMaxPacketSize;
+ max_packet_size = le16_to_cpu(udev->ep_out[0x1]->desc.wMaxPacketSize);
log("\t\t download size : %d", (int)max_packet_size);
for (offset = 0; offset < fwlength; offset += max_packet_size) {
diff --git a/drivers/media/usb/tm6000/tm6000-alsa.c b/drivers/media/usb/tm6000/tm6000-alsa.c
index 813c1ec5360..74e5697d867 100644
--- a/drivers/media/usb/tm6000/tm6000-alsa.c
+++ b/drivers/media/usb/tm6000/tm6000-alsa.c
@@ -1,7 +1,7 @@
/*
*
* Support for audio capture for tm5600/6000/6010
- * (c) 2007-2008 Mauro Carvalho Chehab <mchehab@redhat.com>
+ * (c) 2007-2008 Mauro Carvalho Chehab
*
* Based on cx88-alsa.c
*
@@ -56,7 +56,7 @@ MODULE_PARM_DESC(index, "Index value for tm6000x capture interface(s).");
****************************************************************************/
MODULE_DESCRIPTION("ALSA driver module for tm5600/tm6000/tm6010 based TV cards");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
MODULE_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("{{Trident,tm5600},"
"{{Trident,tm6000},"
@@ -431,7 +431,8 @@ static int tm6000_audio_init(struct tm6000_core *dev)
if (!enable[devnr])
return -ENOENT;
- rc = snd_card_create(index[devnr], "tm6000", THIS_MODULE, 0, &card);
+ rc = snd_card_new(&dev->udev->dev, index[devnr], "tm6000",
+ THIS_MODULE, 0, &card);
if (rc < 0) {
snd_printk(KERN_ERR "cannot create card instance %d\n", devnr);
return rc;
@@ -445,7 +446,6 @@ static int tm6000_audio_init(struct tm6000_core *dev)
le16_to_cpu(dev->udev->descriptor.idVendor),
le16_to_cpu(dev->udev->descriptor.idProduct));
snd_component_add(card, component);
- snd_card_set_dev(card, &dev->udev->dev);
chip = kzalloc(sizeof(struct snd_tm6000_card), GFP_KERNEL);
if (!chip) {
diff --git a/drivers/media/usb/tm6000/tm6000-cards.c b/drivers/media/usb/tm6000/tm6000-cards.c
index 1ccaaddaa30..2e8c3afe4ec 100644
--- a/drivers/media/usb/tm6000/tm6000-cards.c
+++ b/drivers/media/usb/tm6000/tm6000-cards.c
@@ -1120,7 +1120,7 @@ static int tm6000_init_dev(struct tm6000_core *dev)
tm6000_config_tuner(dev);
/* Set video standard */
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm);
+ v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_std, dev->norm);
/* Set tuner frequency - also loads firmware on xc2028/xc3028 */
f.tuner = 0;
diff --git a/drivers/media/usb/tm6000/tm6000-dvb.c b/drivers/media/usb/tm6000/tm6000-dvb.c
index 9fc1e940a82..095f5db1a79 100644
--- a/drivers/media/usb/tm6000/tm6000-dvb.c
+++ b/drivers/media/usb/tm6000/tm6000-dvb.c
@@ -32,7 +32,7 @@
#include "xc5000.h"
MODULE_DESCRIPTION("DVB driver extension module for tm5600/6000/6010 based TV cards");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
MODULE_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("{{Trident, tm5600},"
diff --git a/drivers/media/usb/tm6000/tm6000-input.c b/drivers/media/usb/tm6000/tm6000-input.c
index 8a6bbf1d80e..d1af5438c16 100644
--- a/drivers/media/usb/tm6000/tm6000-input.c
+++ b/drivers/media/usb/tm6000/tm6000-input.c
@@ -422,7 +422,7 @@ int tm6000_ir_init(struct tm6000_core *dev)
ir->rc = rc;
/* input setup */
- rc->allowed_protos = RC_BIT_RC5 | RC_BIT_NEC;
+ rc_set_allowed_protocols(rc, RC_BIT_RC5 | RC_BIT_NEC);
/* Neded, in order to support NEC remotes with 24 or 32 bits */
rc->scanmask = 0xffff;
rc->priv = ir;
diff --git a/drivers/media/usb/tm6000/tm6000-stds.c b/drivers/media/usb/tm6000/tm6000-stds.c
index 5e28d6a2412..93a4b2434b6 100644
--- a/drivers/media/usb/tm6000/tm6000-stds.c
+++ b/drivers/media/usb/tm6000/tm6000-stds.c
@@ -1,7 +1,7 @@
/*
* tm6000-stds.c - driver for TM5600/TM6000/TM6010 USB video capture devices
*
- * Copyright (C) 2007 Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (C) 2007 Mauro Carvalho Chehab
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/usb/tm6000/tm6000-video.c b/drivers/media/usb/tm6000/tm6000-video.c
index cc1aa14996f..e6b3d5d83d4 100644
--- a/drivers/media/usb/tm6000/tm6000-video.c
+++ b/drivers/media/usb/tm6000/tm6000-video.c
@@ -1071,7 +1071,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm)
if (rc < 0)
return rc;
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm);
+ v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_std, dev->norm);
return 0;
}
diff --git a/drivers/media/usb/ttusb-dec/ttusb_dec.c b/drivers/media/usb/ttusb-dec/ttusb_dec.c
index e52c3b97f30..29724af9b9a 100644
--- a/drivers/media/usb/ttusb-dec/ttusb_dec.c
+++ b/drivers/media/usb/ttusb-dec/ttusb_dec.c
@@ -366,7 +366,7 @@ static int ttusb_dec_get_stb_state (struct ttusb_dec *dec, unsigned int *mode,
}
return 0;
} else {
- return -1;
+ return -ENOENT;
}
}
@@ -1241,6 +1241,8 @@ static void ttusb_dec_init_v_pes(struct ttusb_dec *dec)
static int ttusb_dec_init_usb(struct ttusb_dec *dec)
{
+ int result;
+
dprintk("%s\n", __func__);
mutex_init(&dec->usb_mutex);
@@ -1258,7 +1260,7 @@ static int ttusb_dec_init_usb(struct ttusb_dec *dec)
return -ENOMEM;
}
dec->irq_buffer = usb_alloc_coherent(dec->udev,IRQ_PACKET_SIZE,
- GFP_ATOMIC, &dec->irq_dma_handle);
+ GFP_KERNEL, &dec->irq_dma_handle);
if(!dec->irq_buffer) {
usb_free_urb(dec->irq_urb);
return -ENOMEM;
@@ -1270,7 +1272,13 @@ static int ttusb_dec_init_usb(struct ttusb_dec *dec)
dec->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
}
- return ttusb_dec_alloc_iso_urbs(dec);
+ result = ttusb_dec_alloc_iso_urbs(dec);
+ if (result) {
+ usb_free_urb(dec->irq_urb);
+ usb_free_coherent(dec->udev, IRQ_PACKET_SIZE,
+ dec->irq_buffer, dec->irq_dma_handle);
+ }
+ return result;
}
static int ttusb_dec_boot_dsp(struct ttusb_dec *dec)
@@ -1293,10 +1301,11 @@ static int ttusb_dec_boot_dsp(struct ttusb_dec *dec)
dprintk("%s\n", __func__);
- if (request_firmware(&fw_entry, dec->firmware_name, &dec->udev->dev)) {
+ result = request_firmware(&fw_entry, dec->firmware_name, &dec->udev->dev);
+ if (result) {
printk(KERN_ERR "%s: Firmware (%s) unavailable.\n",
__func__, dec->firmware_name);
- return 1;
+ return result;
}
firmware = fw_entry->data;
@@ -1306,7 +1315,7 @@ static int ttusb_dec_boot_dsp(struct ttusb_dec *dec)
printk("%s: firmware size too small for DSP code (%zu < 60).\n",
__func__, firmware_size);
release_firmware(fw_entry);
- return -1;
+ return -ENOENT;
}
/* a 32 bit checksum over the first 56 bytes of the DSP Code is stored
@@ -1320,7 +1329,7 @@ static int ttusb_dec_boot_dsp(struct ttusb_dec *dec)
"0x%08x != 0x%08x in file), file invalid.\n",
__func__, crc32_csum, crc32_check);
release_firmware(fw_entry);
- return -1;
+ return -ENOENT;
}
memcpy(idstring, &firmware[36], 20);
idstring[20] = '\0';
@@ -1389,55 +1398,48 @@ static int ttusb_dec_init_stb(struct ttusb_dec *dec)
dprintk("%s\n", __func__);
result = ttusb_dec_get_stb_state(dec, &mode, &model, &version);
+ if (result)
+ return result;
- if (!result) {
- if (!mode) {
- if (version == 0xABCDEFAB)
- printk(KERN_INFO "ttusb_dec: no version "
- "info in Firmware\n");
- else
- printk(KERN_INFO "ttusb_dec: Firmware "
- "%x.%02x%c%c\n",
- version >> 24, (version >> 16) & 0xff,
- (version >> 8) & 0xff, version & 0xff);
-
- result = ttusb_dec_boot_dsp(dec);
- if (result)
- return result;
- else
- return 1;
- } else {
- /* We can't trust the USB IDs that some firmwares
- give the box */
- switch (model) {
- case 0x00070001:
- case 0x00070008:
- case 0x0007000c:
- ttusb_dec_set_model(dec, TTUSB_DEC3000S);
- break;
- case 0x00070009:
- case 0x00070013:
- ttusb_dec_set_model(dec, TTUSB_DEC2000T);
- break;
- case 0x00070011:
- ttusb_dec_set_model(dec, TTUSB_DEC2540T);
- break;
- default:
- printk(KERN_ERR "%s: unknown model returned "
- "by firmware (%08x) - please report\n",
- __func__, model);
- return -1;
- break;
- }
+ if (!mode) {
+ if (version == 0xABCDEFAB)
+ printk(KERN_INFO "ttusb_dec: no version "
+ "info in Firmware\n");
+ else
+ printk(KERN_INFO "ttusb_dec: Firmware "
+ "%x.%02x%c%c\n",
+ version >> 24, (version >> 16) & 0xff,
+ (version >> 8) & 0xff, version & 0xff);
+ result = ttusb_dec_boot_dsp(dec);
+ if (result)
+ return result;
+ } else {
+ /* We can't trust the USB IDs that some firmwares
+ give the box */
+ switch (model) {
+ case 0x00070001:
+ case 0x00070008:
+ case 0x0007000c:
+ ttusb_dec_set_model(dec, TTUSB_DEC3000S);
+ break;
+ case 0x00070009:
+ case 0x00070013:
+ ttusb_dec_set_model(dec, TTUSB_DEC2000T);
+ break;
+ case 0x00070011:
+ ttusb_dec_set_model(dec, TTUSB_DEC2540T);
+ break;
+ default:
+ printk(KERN_ERR "%s: unknown model returned "
+ "by firmware (%08x) - please report\n",
+ __func__, model);
+ return -ENOENT;
+ }
if (version >= 0x01770000)
dec->can_playback = 1;
-
- return 0;
- }
}
- else
- return result;
+ return 0;
}
static int ttusb_dec_init_dvb(struct ttusb_dec *dec)
@@ -1539,19 +1541,7 @@ static void ttusb_dec_exit_dvb(struct ttusb_dec *dec)
static void ttusb_dec_exit_rc(struct ttusb_dec *dec)
{
-
dprintk("%s\n", __func__);
- /* we have to check whether the irq URB is already submitted.
- * As the irq is submitted after the interface is changed,
- * this is the best method i figured out.
- * Any others?*/
- if (dec->interface == TTUSB_DEC_INTERFACE_IN)
- usb_kill_urb(dec->irq_urb);
-
- usb_free_urb(dec->irq_urb);
-
- usb_free_coherent(dec->udev,IRQ_PACKET_SIZE,
- dec->irq_buffer, dec->irq_dma_handle);
if (dec->rc_input_dev) {
input_unregister_device(dec->rc_input_dev);
@@ -1566,6 +1556,20 @@ static void ttusb_dec_exit_usb(struct ttusb_dec *dec)
dprintk("%s\n", __func__);
+ if (enable_rc) {
+ /* we have to check whether the irq URB is already submitted.
+ * As the irq is submitted after the interface is changed,
+ * this is the best method i figured out.
+ * Any others?*/
+ if (dec->interface == TTUSB_DEC_INTERFACE_IN)
+ usb_kill_urb(dec->irq_urb);
+
+ usb_free_urb(dec->irq_urb);
+
+ usb_free_coherent(dec->udev, IRQ_PACKET_SIZE,
+ dec->irq_buffer, dec->irq_dma_handle);
+ }
+
dec->iso_stream_count = 0;
for (i = 0; i < ISO_BUF_COUNT; i++)
@@ -1623,6 +1627,7 @@ static int ttusb_dec_probe(struct usb_interface *intf,
{
struct usb_device *udev;
struct ttusb_dec *dec;
+ int result;
dprintk("%s\n", __func__);
@@ -1651,13 +1656,15 @@ static int ttusb_dec_probe(struct usb_interface *intf,
dec->udev = udev;
- if (ttusb_dec_init_usb(dec))
- return 0;
- if (ttusb_dec_init_stb(dec)) {
- ttusb_dec_exit_usb(dec);
- return 0;
- }
- ttusb_dec_init_dvb(dec);
+ result = ttusb_dec_init_usb(dec);
+ if (result)
+ goto err_usb;
+ result = ttusb_dec_init_stb(dec);
+ if (result)
+ goto err_stb;
+ result = ttusb_dec_init_dvb(dec);
+ if (result)
+ goto err_stb;
dec->adapter.priv = dec;
switch (id->idProduct) {
@@ -1696,6 +1703,11 @@ static int ttusb_dec_probe(struct usb_interface *intf,
ttusb_init_rc(dec);
return 0;
+err_stb:
+ ttusb_dec_exit_usb(dec);
+err_usb:
+ kfree(dec);
+ return result;
}
static void ttusb_dec_disconnect(struct usb_interface *intf)
diff --git a/drivers/media/usb/usbtv/Makefile b/drivers/media/usb/usbtv/Makefile
index 28b872fa94e..775316a88ea 100644
--- a/drivers/media/usb/usbtv/Makefile
+++ b/drivers/media/usb/usbtv/Makefile
@@ -1 +1,4 @@
+usbtv-y := usbtv-core.o \
+ usbtv-video.o
+
obj-$(CONFIG_VIDEO_USBTV) += usbtv.o
diff --git a/drivers/media/usb/usbtv/usbtv-core.c b/drivers/media/usb/usbtv/usbtv-core.c
new file mode 100644
index 00000000000..2f87ddfa469
--- /dev/null
+++ b/drivers/media/usb/usbtv/usbtv-core.c
@@ -0,0 +1,134 @@
+/*
+ * Fushicai USBTV007 Video Grabber Driver
+ *
+ * Product web site:
+ * http://www.fushicai.com/products_detail/&productId=d05449ee-b690-42f9-a661-aa7353894bed.html
+ *
+ * Following LWN articles were very useful in construction of this driver:
+ * Video4Linux2 API series: http://lwn.net/Articles/203924/
+ * videobuf2 API explanation: http://lwn.net/Articles/447435/
+ * Thanks go to Jonathan Corbet for providing this quality documentation.
+ * He is awesome.
+ *
+ * Copyright (c) 2013 Lubomir Rintel
+ * All rights reserved.
+ * No physical hardware was harmed running Windows during the
+ * reverse-engineering activity
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL").
+ */
+
+#include "usbtv.h"
+
+int usbtv_set_regs(struct usbtv *usbtv, const u16 regs[][2], int size)
+{
+ int ret;
+ int pipe = usb_rcvctrlpipe(usbtv->udev, 0);
+ int i;
+
+ for (i = 0; i < size; i++) {
+ u16 index = regs[i][0];
+ u16 value = regs[i][1];
+
+ ret = usb_control_msg(usbtv->udev, pipe, USBTV_REQUEST_REG,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value, index, NULL, 0, 0);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int usbtv_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ int ret;
+ int size;
+ struct device *dev = &intf->dev;
+ struct usbtv *usbtv;
+
+ /* Checks that the device is what we think it is. */
+ if (intf->num_altsetting != 2)
+ return -ENODEV;
+ if (intf->altsetting[1].desc.bNumEndpoints != 4)
+ return -ENODEV;
+
+ /* Packet size is split into 11 bits of base size and count of
+ * extra multiplies of it.*/
+ size = usb_endpoint_maxp(&intf->altsetting[1].endpoint[0].desc);
+ size = (size & 0x07ff) * (((size & 0x1800) >> 11) + 1);
+
+ /* Device structure */
+ usbtv = kzalloc(sizeof(struct usbtv), GFP_KERNEL);
+ if (usbtv == NULL)
+ return -ENOMEM;
+ usbtv->dev = dev;
+ usbtv->udev = usb_get_dev(interface_to_usbdev(intf));
+
+ usbtv->iso_size = size;
+
+ usb_set_intfdata(intf, usbtv);
+
+ ret = usbtv_video_init(usbtv);
+ if (ret < 0)
+ goto usbtv_video_fail;
+
+ /* for simplicity we exploit the v4l2_device reference counting */
+ v4l2_device_get(&usbtv->v4l2_dev);
+
+ dev_info(dev, "Fushicai USBTV007 Video Grabber\n");
+ return 0;
+
+usbtv_video_fail:
+ kfree(usbtv);
+
+ return ret;
+}
+
+static void usbtv_disconnect(struct usb_interface *intf)
+{
+ struct usbtv *usbtv = usb_get_intfdata(intf);
+ usb_set_intfdata(intf, NULL);
+
+ if (!usbtv)
+ return;
+
+ usbtv_video_free(usbtv);
+
+ usb_put_dev(usbtv->udev);
+ usbtv->udev = NULL;
+
+ /* the usbtv structure will be deallocated when v4l2 will be
+ done using it */
+ v4l2_device_put(&usbtv->v4l2_dev);
+}
+
+static struct usb_device_id usbtv_id_table[] = {
+ { USB_DEVICE(0x1b71, 0x3002) },
+ {}
+};
+MODULE_DEVICE_TABLE(usb, usbtv_id_table);
+
+MODULE_AUTHOR("Lubomir Rintel");
+MODULE_DESCRIPTION("Fushicai USBTV007 Video Grabber Driver");
+MODULE_LICENSE("Dual BSD/GPL");
+
+static struct usb_driver usbtv_usb_driver = {
+ .name = "usbtv",
+ .id_table = usbtv_id_table,
+ .probe = usbtv_probe,
+ .disconnect = usbtv_disconnect,
+};
+
+module_usb_driver(usbtv_usb_driver);
diff --git a/drivers/media/usb/usbtv/usbtv.c b/drivers/media/usb/usbtv/usbtv-video.c
index 8a505a90d31..2967e808408 100644
--- a/drivers/media/usb/usbtv/usbtv.c
+++ b/drivers/media/usb/usbtv/usbtv-video.c
@@ -28,95 +28,46 @@
* GNU General Public License ("GPL").
*/
-#include <linux/init.h>
-#include <linux/list.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/usb.h>
-#include <linux/videodev2.h>
-
-#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#include <media/videobuf2-core.h>
-#include <media/videobuf2-vmalloc.h>
-
-/* Hardware. */
-#define USBTV_VIDEO_ENDP 0x81
-#define USBTV_BASE 0xc000
-#define USBTV_REQUEST_REG 12
-
-/* Number of concurrent isochronous urbs submitted.
- * Higher numbers was seen to overly saturate the USB bus. */
-#define USBTV_ISOC_TRANSFERS 16
-#define USBTV_ISOC_PACKETS 8
-
-#define USBTV_WIDTH 720
-#define USBTV_HEIGHT 480
-
-#define USBTV_CHUNK_SIZE 256
-#define USBTV_CHUNK 240
-#define USBTV_CHUNKS (USBTV_WIDTH * USBTV_HEIGHT \
- / 4 / USBTV_CHUNK)
-
-/* Chunk header. */
-#define USBTV_MAGIC_OK(chunk) ((be32_to_cpu(chunk[0]) & 0xff000000) \
- == 0x88000000)
-#define USBTV_FRAME_ID(chunk) ((be32_to_cpu(chunk[0]) & 0x00ff0000) >> 16)
-#define USBTV_ODD(chunk) ((be32_to_cpu(chunk[0]) & 0x0000f000) >> 15)
-#define USBTV_CHUNK_NO(chunk) (be32_to_cpu(chunk[0]) & 0x00000fff)
-
-/* A single videobuf2 frame buffer. */
-struct usbtv_buf {
- struct vb2_buffer vb;
- struct list_head list;
-};
-/* Per-device structure. */
-struct usbtv {
- struct device *dev;
- struct usb_device *udev;
- struct v4l2_device v4l2_dev;
- struct video_device vdev;
- struct vb2_queue vb2q;
- struct mutex v4l2_lock;
- struct mutex vb2q_lock;
-
- /* List of videobuf2 buffers protected by a lock. */
- spinlock_t buflock;
- struct list_head bufs;
-
- /* Number of currently processed frame, useful find
- * out when a new one begins. */
- u32 frame_id;
- int chunks_done;
-
- enum {
- USBTV_COMPOSITE_INPUT,
- USBTV_SVIDEO_INPUT,
- } input;
- int iso_size;
- unsigned int sequence;
- struct urb *isoc_urbs[USBTV_ISOC_TRANSFERS];
+#include "usbtv.h"
+
+static struct usbtv_norm_params norm_params[] = {
+ {
+ .norm = V4L2_STD_525_60,
+ .cap_width = 720,
+ .cap_height = 480,
+ },
+ {
+ .norm = V4L2_STD_PAL,
+ .cap_width = 720,
+ .cap_height = 576,
+ }
};
-static int usbtv_set_regs(struct usbtv *usbtv, const u16 regs[][2], int size)
+static int usbtv_configure_for_norm(struct usbtv *usbtv, v4l2_std_id norm)
{
- int ret;
- int pipe = usb_rcvctrlpipe(usbtv->udev, 0);
- int i;
-
- for (i = 0; i < size; i++) {
- u16 index = regs[i][0];
- u16 value = regs[i][1];
+ int i, ret = 0;
+ struct usbtv_norm_params *params = NULL;
- ret = usb_control_msg(usbtv->udev, pipe, USBTV_REQUEST_REG,
- USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- value, index, NULL, 0, 0);
- if (ret < 0)
- return ret;
+ for (i = 0; i < ARRAY_SIZE(norm_params); i++) {
+ if (norm_params[i].norm & norm) {
+ params = &norm_params[i];
+ break;
+ }
}
- return 0;
+ if (params) {
+ usbtv->width = params->cap_width;
+ usbtv->height = params->cap_height;
+ usbtv->n_chunks = usbtv->width * usbtv->height
+ / 4 / USBTV_CHUNK;
+ usbtv->norm = params->norm;
+ } else
+ ret = -EINVAL;
+
+ return ret;
}
static int usbtv_select_input(struct usbtv *usbtv, int input)
@@ -158,6 +109,57 @@ static int usbtv_select_input(struct usbtv *usbtv, int input)
return ret;
}
+static int usbtv_select_norm(struct usbtv *usbtv, v4l2_std_id norm)
+{
+ int ret;
+ static const u16 pal[][2] = {
+ { USBTV_BASE + 0x001a, 0x0068 },
+ { USBTV_BASE + 0x010e, 0x0072 },
+ { USBTV_BASE + 0x010f, 0x00a2 },
+ { USBTV_BASE + 0x0112, 0x00b0 },
+ { USBTV_BASE + 0x0117, 0x0001 },
+ { USBTV_BASE + 0x0118, 0x002c },
+ { USBTV_BASE + 0x012d, 0x0010 },
+ { USBTV_BASE + 0x012f, 0x0020 },
+ { USBTV_BASE + 0x024f, 0x0002 },
+ { USBTV_BASE + 0x0254, 0x0059 },
+ { USBTV_BASE + 0x025a, 0x0016 },
+ { USBTV_BASE + 0x025b, 0x0035 },
+ { USBTV_BASE + 0x0263, 0x0017 },
+ { USBTV_BASE + 0x0266, 0x0016 },
+ { USBTV_BASE + 0x0267, 0x0036 }
+ };
+
+ static const u16 ntsc[][2] = {
+ { USBTV_BASE + 0x001a, 0x0079 },
+ { USBTV_BASE + 0x010e, 0x0068 },
+ { USBTV_BASE + 0x010f, 0x009c },
+ { USBTV_BASE + 0x0112, 0x00f0 },
+ { USBTV_BASE + 0x0117, 0x0000 },
+ { USBTV_BASE + 0x0118, 0x00fc },
+ { USBTV_BASE + 0x012d, 0x0004 },
+ { USBTV_BASE + 0x012f, 0x0008 },
+ { USBTV_BASE + 0x024f, 0x0001 },
+ { USBTV_BASE + 0x0254, 0x005f },
+ { USBTV_BASE + 0x025a, 0x0012 },
+ { USBTV_BASE + 0x025b, 0x0001 },
+ { USBTV_BASE + 0x0263, 0x001c },
+ { USBTV_BASE + 0x0266, 0x0011 },
+ { USBTV_BASE + 0x0267, 0x0005 }
+ };
+
+ ret = usbtv_configure_for_norm(usbtv, norm);
+
+ if (!ret) {
+ if (norm & V4L2_STD_525_60)
+ ret = usbtv_set_regs(usbtv, ntsc, ARRAY_SIZE(ntsc));
+ else if (norm & V4L2_STD_PAL)
+ ret = usbtv_set_regs(usbtv, pal, ARRAY_SIZE(pal));
+ }
+
+ return ret;
+}
+
static int usbtv_setup_capture(struct usbtv *usbtv)
{
int ret;
@@ -225,26 +227,11 @@ static int usbtv_setup_capture(struct usbtv *usbtv)
{ USBTV_BASE + 0x0284, 0x0088 },
{ USBTV_BASE + 0x0003, 0x0004 },
- { USBTV_BASE + 0x001a, 0x0079 },
{ USBTV_BASE + 0x0100, 0x00d3 },
- { USBTV_BASE + 0x010e, 0x0068 },
- { USBTV_BASE + 0x010f, 0x009c },
- { USBTV_BASE + 0x0112, 0x00f0 },
{ USBTV_BASE + 0x0115, 0x0015 },
- { USBTV_BASE + 0x0117, 0x0000 },
- { USBTV_BASE + 0x0118, 0x00fc },
- { USBTV_BASE + 0x012d, 0x0004 },
- { USBTV_BASE + 0x012f, 0x0008 },
{ USBTV_BASE + 0x0220, 0x002e },
{ USBTV_BASE + 0x0225, 0x0008 },
{ USBTV_BASE + 0x024e, 0x0002 },
- { USBTV_BASE + 0x024f, 0x0001 },
- { USBTV_BASE + 0x0254, 0x005f },
- { USBTV_BASE + 0x025a, 0x0012 },
- { USBTV_BASE + 0x025b, 0x0001 },
- { USBTV_BASE + 0x0263, 0x001c },
- { USBTV_BASE + 0x0266, 0x0011 },
- { USBTV_BASE + 0x0267, 0x0005 },
{ USBTV_BASE + 0x024e, 0x0002 },
{ USBTV_BASE + 0x024f, 0x0002 },
};
@@ -253,6 +240,10 @@ static int usbtv_setup_capture(struct usbtv *usbtv)
if (ret)
return ret;
+ ret = usbtv_select_norm(usbtv, usbtv->norm);
+ if (ret)
+ return ret;
+
ret = usbtv_select_input(usbtv, usbtv->input);
if (ret)
return ret;
@@ -296,7 +287,7 @@ static void usbtv_image_chunk(struct usbtv *usbtv, u32 *chunk)
frame_id = USBTV_FRAME_ID(chunk);
odd = USBTV_ODD(chunk);
chunk_no = USBTV_CHUNK_NO(chunk);
- if (chunk_no >= USBTV_CHUNKS)
+ if (chunk_no >= usbtv->n_chunks)
return;
/* Beginning of a frame. */
@@ -324,10 +315,10 @@ static void usbtv_image_chunk(struct usbtv *usbtv, u32 *chunk)
usbtv->chunks_done++;
/* Last chunk in a frame, signalling an end */
- if (odd && chunk_no == USBTV_CHUNKS-1) {
+ if (odd && chunk_no == usbtv->n_chunks-1) {
int size = vb2_plane_size(&buf->vb, 0);
enum vb2_buffer_state state = usbtv->chunks_done ==
- USBTV_CHUNKS ?
+ usbtv->n_chunks ?
VB2_BUF_STATE_DONE :
VB2_BUF_STATE_ERROR;
@@ -477,12 +468,6 @@ start_fail:
return ret;
}
-struct usb_device_id usbtv_id_table[] = {
- { USB_DEVICE(0x1b71, 0x3002) },
- {}
-};
-MODULE_DEVICE_TABLE(usb, usbtv_id_table);
-
static int usbtv_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
@@ -500,6 +485,8 @@ static int usbtv_querycap(struct file *file, void *priv,
static int usbtv_enum_input(struct file *file, void *priv,
struct v4l2_input *i)
{
+ struct usbtv *dev = video_drvdata(file);
+
switch (i->index) {
case USBTV_COMPOSITE_INPUT:
strlcpy(i->name, "Composite", sizeof(i->name));
@@ -512,7 +499,7 @@ static int usbtv_enum_input(struct file *file, void *priv,
}
i->type = V4L2_INPUT_TYPE_CAMERA;
- i->std = V4L2_STD_525_60;
+ i->std = dev->vdev.tvnorms;
return 0;
}
@@ -531,23 +518,37 @@ static int usbtv_enum_fmt_vid_cap(struct file *file, void *priv,
static int usbtv_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- f->fmt.pix.width = USBTV_WIDTH;
- f->fmt.pix.height = USBTV_HEIGHT;
+ struct usbtv *usbtv = video_drvdata(file);
+
+ f->fmt.pix.width = usbtv->width;
+ f->fmt.pix.height = usbtv->height;
f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
f->fmt.pix.field = V4L2_FIELD_INTERLACED;
- f->fmt.pix.bytesperline = USBTV_WIDTH * 2;
+ f->fmt.pix.bytesperline = usbtv->width * 2;
f->fmt.pix.sizeimage = (f->fmt.pix.bytesperline * f->fmt.pix.height);
f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
- f->fmt.pix.priv = 0;
+
return 0;
}
static int usbtv_g_std(struct file *file, void *priv, v4l2_std_id *norm)
{
- *norm = V4L2_STD_525_60;
+ struct usbtv *usbtv = video_drvdata(file);
+ *norm = usbtv->norm;
return 0;
}
+static int usbtv_s_std(struct file *file, void *priv, v4l2_std_id norm)
+{
+ int ret = -EINVAL;
+ struct usbtv *usbtv = video_drvdata(file);
+
+ if ((norm & V4L2_STD_525_60) || (norm & V4L2_STD_PAL))
+ ret = usbtv_select_norm(usbtv, norm);
+
+ return ret;
+}
+
static int usbtv_g_input(struct file *file, void *priv, unsigned int *i)
{
struct usbtv *usbtv = video_drvdata(file);
@@ -561,14 +562,7 @@ static int usbtv_s_input(struct file *file, void *priv, unsigned int i)
return usbtv_select_input(usbtv, i);
}
-static int usbtv_s_std(struct file *file, void *priv, v4l2_std_id norm)
-{
- if (norm & V4L2_STD_525_60)
- return 0;
- return -EINVAL;
-}
-
-struct v4l2_ioctl_ops usbtv_ioctl_ops = {
+static struct v4l2_ioctl_ops usbtv_ioctl_ops = {
.vidioc_querycap = usbtv_querycap,
.vidioc_enum_input = usbtv_enum_input,
.vidioc_enum_fmt_vid_cap = usbtv_enum_fmt_vid_cap,
@@ -590,7 +584,7 @@ struct v4l2_ioctl_ops usbtv_ioctl_ops = {
.vidioc_streamoff = vb2_ioctl_streamoff,
};
-struct v4l2_file_operations usbtv_fops = {
+static struct v4l2_file_operations usbtv_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = video_ioctl2,
.mmap = vb2_fop_mmap,
@@ -604,10 +598,12 @@ static int usbtv_queue_setup(struct vb2_queue *vq,
const struct v4l2_format *v4l_fmt, unsigned int *nbuffers,
unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[])
{
+ struct usbtv *usbtv = vb2_get_drv_priv(vq);
+
if (*nbuffers < 2)
*nbuffers = 2;
*nplanes = 1;
- sizes[0] = USBTV_WIDTH * USBTV_HEIGHT / 2 * sizeof(u32);
+ sizes[0] = USBTV_CHUNK * usbtv->n_chunks * 2 * sizeof(u32);
return 0;
}
@@ -638,18 +634,15 @@ static int usbtv_start_streaming(struct vb2_queue *vq, unsigned int count)
return usbtv_start(usbtv);
}
-static int usbtv_stop_streaming(struct vb2_queue *vq)
+static void usbtv_stop_streaming(struct vb2_queue *vq)
{
struct usbtv *usbtv = vb2_get_drv_priv(vq);
- if (usbtv->udev == NULL)
- return -ENODEV;
-
- usbtv_stop(usbtv);
- return 0;
+ if (usbtv->udev)
+ usbtv_stop(usbtv);
}
-struct vb2_ops usbtv_vb2_ops = {
+static struct vb2_ops usbtv_vb2_ops = {
.queue_setup = usbtv_queue_setup,
.buf_queue = usbtv_buf_queue,
.start_streaming = usbtv_start_streaming,
@@ -665,32 +658,12 @@ static void usbtv_release(struct v4l2_device *v4l2_dev)
kfree(usbtv);
}
-static int usbtv_probe(struct usb_interface *intf,
- const struct usb_device_id *id)
+int usbtv_video_init(struct usbtv *usbtv)
{
int ret;
- int size;
- struct device *dev = &intf->dev;
- struct usbtv *usbtv;
- /* Checks that the device is what we think it is. */
- if (intf->num_altsetting != 2)
- return -ENODEV;
- if (intf->altsetting[1].desc.bNumEndpoints != 4)
- return -ENODEV;
+ (void)usbtv_configure_for_norm(usbtv, V4L2_STD_525_60);
- /* Packet size is split into 11 bits of base size and count of
- * extra multiplies of it.*/
- size = usb_endpoint_maxp(&intf->altsetting[1].endpoint[0].desc);
- size = (size & 0x07ff) * (((size & 0x1800) >> 11) + 1);
-
- /* Device structure */
- usbtv = kzalloc(sizeof(struct usbtv), GFP_KERNEL);
- if (usbtv == NULL)
- return -ENOMEM;
- usbtv->dev = dev;
- usbtv->udev = usb_get_dev(interface_to_usbdev(intf));
- usbtv->iso_size = size;
spin_lock_init(&usbtv->buflock);
mutex_init(&usbtv->v4l2_lock);
mutex_init(&usbtv->vb2q_lock);
@@ -703,83 +676,60 @@ static int usbtv_probe(struct usb_interface *intf,
usbtv->vb2q.buf_struct_size = sizeof(struct usbtv_buf);
usbtv->vb2q.ops = &usbtv_vb2_ops;
usbtv->vb2q.mem_ops = &vb2_vmalloc_memops;
- usbtv->vb2q.timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ usbtv->vb2q.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
usbtv->vb2q.lock = &usbtv->vb2q_lock;
ret = vb2_queue_init(&usbtv->vb2q);
if (ret < 0) {
- dev_warn(dev, "Could not initialize videobuf2 queue\n");
- goto usbtv_fail;
+ dev_warn(usbtv->dev, "Could not initialize videobuf2 queue\n");
+ return ret;
}
/* v4l2 structure */
usbtv->v4l2_dev.release = usbtv_release;
- ret = v4l2_device_register(dev, &usbtv->v4l2_dev);
+ ret = v4l2_device_register(usbtv->dev, &usbtv->v4l2_dev);
if (ret < 0) {
- dev_warn(dev, "Could not register v4l2 device\n");
+ dev_warn(usbtv->dev, "Could not register v4l2 device\n");
goto v4l2_fail;
}
- usb_set_intfdata(intf, usbtv);
-
/* Video structure */
strlcpy(usbtv->vdev.name, "usbtv", sizeof(usbtv->vdev.name));
usbtv->vdev.v4l2_dev = &usbtv->v4l2_dev;
usbtv->vdev.release = video_device_release_empty;
usbtv->vdev.fops = &usbtv_fops;
usbtv->vdev.ioctl_ops = &usbtv_ioctl_ops;
- usbtv->vdev.tvnorms = V4L2_STD_525_60;
+ usbtv->vdev.tvnorms = USBTV_TV_STD;
usbtv->vdev.queue = &usbtv->vb2q;
usbtv->vdev.lock = &usbtv->v4l2_lock;
set_bit(V4L2_FL_USE_FH_PRIO, &usbtv->vdev.flags);
video_set_drvdata(&usbtv->vdev, usbtv);
ret = video_register_device(&usbtv->vdev, VFL_TYPE_GRABBER, -1);
if (ret < 0) {
- dev_warn(dev, "Could not register video device\n");
+ dev_warn(usbtv->dev, "Could not register video device\n");
goto vdev_fail;
}
- dev_info(dev, "Fushicai USBTV007 Video Grabber\n");
return 0;
vdev_fail:
v4l2_device_unregister(&usbtv->v4l2_dev);
v4l2_fail:
vb2_queue_release(&usbtv->vb2q);
-usbtv_fail:
- kfree(usbtv);
return ret;
}
-static void usbtv_disconnect(struct usb_interface *intf)
+void usbtv_video_free(struct usbtv *usbtv)
{
- struct usbtv *usbtv = usb_get_intfdata(intf);
-
mutex_lock(&usbtv->vb2q_lock);
mutex_lock(&usbtv->v4l2_lock);
usbtv_stop(usbtv);
- usb_set_intfdata(intf, NULL);
video_unregister_device(&usbtv->vdev);
v4l2_device_disconnect(&usbtv->v4l2_dev);
- usb_put_dev(usbtv->udev);
- usbtv->udev = NULL;
mutex_unlock(&usbtv->v4l2_lock);
mutex_unlock(&usbtv->vb2q_lock);
v4l2_device_put(&usbtv->v4l2_dev);
}
-
-MODULE_AUTHOR("Lubomir Rintel");
-MODULE_DESCRIPTION("Fushicai USBTV007 Video Grabber Driver");
-MODULE_LICENSE("Dual BSD/GPL");
-
-struct usb_driver usbtv_usb_driver = {
- .name = "usbtv",
- .id_table = usbtv_id_table,
- .probe = usbtv_probe,
- .disconnect = usbtv_disconnect,
-};
-
-module_usb_driver(usbtv_usb_driver);
diff --git a/drivers/media/usb/usbtv/usbtv.h b/drivers/media/usb/usbtv/usbtv.h
new file mode 100644
index 00000000000..cb1d388cc64
--- /dev/null
+++ b/drivers/media/usb/usbtv/usbtv.h
@@ -0,0 +1,99 @@
+/*
+ * Fushicai USBTV007 Video Grabber Driver
+ *
+ * Copyright (c) 2013 Lubomir Rintel
+ * All rights reserved.
+ * No physical hardware was harmed running Windows during the
+ * reverse-engineering activity
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL").
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+
+#include <media/v4l2-device.h>
+#include <media/videobuf2-vmalloc.h>
+
+/* Hardware. */
+#define USBTV_VIDEO_ENDP 0x81
+#define USBTV_BASE 0xc000
+#define USBTV_REQUEST_REG 12
+
+/* Number of concurrent isochronous urbs submitted.
+ * Higher numbers was seen to overly saturate the USB bus. */
+#define USBTV_ISOC_TRANSFERS 16
+#define USBTV_ISOC_PACKETS 8
+
+#define USBTV_CHUNK_SIZE 256
+#define USBTV_CHUNK 240
+
+/* Chunk header. */
+#define USBTV_MAGIC_OK(chunk) ((be32_to_cpu(chunk[0]) & 0xff000000) \
+ == 0x88000000)
+#define USBTV_FRAME_ID(chunk) ((be32_to_cpu(chunk[0]) & 0x00ff0000) >> 16)
+#define USBTV_ODD(chunk) ((be32_to_cpu(chunk[0]) & 0x0000f000) >> 15)
+#define USBTV_CHUNK_NO(chunk) (be32_to_cpu(chunk[0]) & 0x00000fff)
+
+#define USBTV_TV_STD (V4L2_STD_525_60 | V4L2_STD_PAL)
+
+/* parameters for supported TV norms */
+struct usbtv_norm_params {
+ v4l2_std_id norm;
+ int cap_width, cap_height;
+};
+
+/* A single videobuf2 frame buffer. */
+struct usbtv_buf {
+ struct vb2_buffer vb;
+ struct list_head list;
+};
+
+/* Per-device structure. */
+struct usbtv {
+ struct device *dev;
+ struct usb_device *udev;
+
+ /* video */
+ struct v4l2_device v4l2_dev;
+ struct video_device vdev;
+ struct vb2_queue vb2q;
+ struct mutex v4l2_lock;
+ struct mutex vb2q_lock;
+
+ /* List of videobuf2 buffers protected by a lock. */
+ spinlock_t buflock;
+ struct list_head bufs;
+
+ /* Number of currently processed frame, useful find
+ * out when a new one begins. */
+ u32 frame_id;
+ int chunks_done;
+
+ enum {
+ USBTV_COMPOSITE_INPUT,
+ USBTV_SVIDEO_INPUT,
+ } input;
+ v4l2_std_id norm;
+ int width, height;
+ int n_chunks;
+ int iso_size;
+ unsigned int sequence;
+ struct urb *isoc_urbs[USBTV_ISOC_TRANSFERS];
+};
+
+int usbtv_set_regs(struct usbtv *usbtv, const u16 regs[][2], int size);
+
+int usbtv_video_init(struct usbtv *usbtv);
+void usbtv_video_free(struct usbtv *usbtv);
diff --git a/drivers/media/usb/usbvision/usbvision-video.c b/drivers/media/usb/usbvision/usbvision-video.c
index 5c9e3123ad2..68bc9615660 100644
--- a/drivers/media/usb/usbvision/usbvision-video.c
+++ b/drivers/media/usb/usbvision/usbvision-video.c
@@ -597,7 +597,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id)
usbvision->tvnorm_id = id;
- call_all(usbvision, core, s_std, usbvision->tvnorm_id);
+ call_all(usbvision, video, s_std, usbvision->tvnorm_id);
/* propagate the change to the decoder */
usbvision_muxsel(usbvision, usbvision->ctl_input);
diff --git a/drivers/media/usb/usbvision/usbvision.h b/drivers/media/usb/usbvision/usbvision.h
index 8a25876d72c..a0c73cf1517 100644
--- a/drivers/media/usb/usbvision/usbvision.h
+++ b/drivers/media/usb/usbvision/usbvision.h
@@ -203,14 +203,6 @@ enum {
mr = LIMIT_RGB(mm_r); \
}
-/* Debugging aid */
-#define USBVISION_SAY_AND_WAIT(what) { \
- wait_queue_head_t wq; \
- init_waitqueue_head(&wq); \
- printk(KERN_INFO "Say: %s\n", what); \
- interruptible_sleep_on_timeout(&wq, HZ * 3); \
-}
-
/*
* This macro checks if usbvision is still operational. The 'usbvision'
* pointer must be valid, usbvision->dev must be valid, we are not
diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index a2f4501c23c..0eb82106d2f 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -664,7 +664,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.size = 32,
.offset = 0,
.v4l2_type = V4L2_CTRL_TYPE_INTEGER,
- .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED,
+ .data_type = UVC_CTRL_DATA_TYPE_SIGNED,
},
{
.id = V4L2_CID_TILT_ABSOLUTE,
@@ -674,7 +674,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.size = 32,
.offset = 32,
.v4l2_type = V4L2_CTRL_TYPE_INTEGER,
- .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED,
+ .data_type = UVC_CTRL_DATA_TYPE_SIGNED,
},
{
.id = V4L2_CID_PRIVACY,
diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
index 81695d48c13..ad47c5cb539 100644
--- a/drivers/media/usb/uvc/uvc_driver.c
+++ b/drivers/media/usb/uvc/uvc_driver.c
@@ -108,11 +108,31 @@ static struct uvc_format_desc uvc_fmts[] = {
.fcc = V4L2_PIX_FMT_Y16,
},
{
- .name = "RGB Bayer",
+ .name = "BGGR Bayer (BY8 )",
.guid = UVC_GUID_FORMAT_BY8,
.fcc = V4L2_PIX_FMT_SBGGR8,
},
{
+ .name = "BGGR Bayer (BA81)",
+ .guid = UVC_GUID_FORMAT_BA81,
+ .fcc = V4L2_PIX_FMT_SBGGR8,
+ },
+ {
+ .name = "GBRG Bayer (GBRG)",
+ .guid = UVC_GUID_FORMAT_GBRG,
+ .fcc = V4L2_PIX_FMT_SGBRG8,
+ },
+ {
+ .name = "GRBG Bayer (GRBG)",
+ .guid = UVC_GUID_FORMAT_GRBG,
+ .fcc = V4L2_PIX_FMT_SGRBG8,
+ },
+ {
+ .name = "RGGB Bayer (RGGB)",
+ .guid = UVC_GUID_FORMAT_RGGB,
+ .fcc = V4L2_PIX_FMT_SRGGB8,
+ },
+ {
.name = "RGB565",
.guid = UVC_GUID_FORMAT_RGBP,
.fcc = V4L2_PIX_FMT_RGB565,
@@ -925,7 +945,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
case UVC_VC_HEADER:
n = buflen >= 12 ? buffer[11] : 0;
- if (buflen < 12 || buflen < 12 + n) {
+ if (buflen < 12 + n) {
uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
"interface %d HEADER error\n", udev->devnum,
alts->desc.bInterfaceNumber);
@@ -2090,6 +2110,15 @@ static struct usb_device_id uvc_ids[] = {
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
.driver_info = UVC_QUIRK_PROBE_MINMAX },
+ /* Microsoft Lifecam NX-3000 */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x045e,
+ .idProduct = 0x0721,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_PROBE_DEF },
/* Microsoft Lifecam VX-7000 */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
@@ -2174,6 +2203,15 @@ static struct usb_device_id uvc_ids[] = {
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
.driver_info = UVC_QUIRK_PROBE_DEF },
+ /* Dell SP2008WFP Monitor */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x05a9,
+ .idProduct = 0x2641,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_PROBE_DEF },
/* Dell Alienware X51 */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
diff --git a/drivers/media/usb/uvc/uvc_queue.c b/drivers/media/usb/uvc/uvc_queue.c
index cd962be860c..6e92d208025 100644
--- a/drivers/media/usb/uvc/uvc_queue.c
+++ b/drivers/media/usb/uvc/uvc_queue.c
@@ -48,12 +48,14 @@ static int uvc_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
struct uvc_streaming *stream =
container_of(queue, struct uvc_streaming, queue);
- if (*nbuffers > UVC_MAX_VIDEO_BUFFERS)
- *nbuffers = UVC_MAX_VIDEO_BUFFERS;
+ /* Make sure the image size is large enough. */
+ if (fmt && fmt->fmt.pix.sizeimage < stream->ctrl.dwMaxVideoFrameSize)
+ return -EINVAL;
*nplanes = 1;
- sizes[0] = stream->ctrl.dwMaxVideoFrameSize;
+ sizes[0] = fmt ? fmt->fmt.pix.sizeimage
+ : stream->ctrl.dwMaxVideoFrameSize;
return 0;
}
@@ -104,15 +106,15 @@ static void uvc_buffer_queue(struct vb2_buffer *vb)
spin_unlock_irqrestore(&queue->irqlock, flags);
}
-static int uvc_buffer_finish(struct vb2_buffer *vb)
+static void uvc_buffer_finish(struct vb2_buffer *vb)
{
struct uvc_video_queue *queue = vb2_get_drv_priv(vb->vb2_queue);
struct uvc_streaming *stream =
container_of(queue, struct uvc_streaming, queue);
struct uvc_buffer *buf = container_of(vb, struct uvc_buffer, buf);
- uvc_video_clock_update(stream, &vb->v4l2_buf, buf);
- return 0;
+ if (vb->state == VB2_BUF_STATE_DONE)
+ uvc_video_clock_update(stream, &vb->v4l2_buf, buf);
}
static void uvc_wait_prepare(struct vb2_queue *vq)
@@ -149,7 +151,8 @@ int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type,
queue->queue.buf_struct_size = sizeof(struct uvc_buffer);
queue->queue.ops = &uvc_queue_qops;
queue->queue.mem_ops = &vb2_vmalloc_memops;
- queue->queue.timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ queue->queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC
+ | V4L2_BUF_FLAG_TSTAMP_SRC_SOE;
ret = vb2_queue_init(&queue->queue);
if (ret)
return ret;
@@ -196,6 +199,18 @@ int uvc_query_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf)
return ret;
}
+int uvc_create_buffers(struct uvc_video_queue *queue,
+ struct v4l2_create_buffers *cb)
+{
+ int ret;
+
+ mutex_lock(&queue->mutex);
+ ret = vb2_create_bufs(&queue->queue, cb);
+ mutex_unlock(&queue->mutex);
+
+ return ret;
+}
+
int uvc_queue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf)
{
int ret;
diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
index 3afff92804d..378ae02e593 100644
--- a/drivers/media/usb/uvc/uvc_v4l2.c
+++ b/drivers/media/usb/uvc/uvc_v4l2.c
@@ -1000,6 +1000,17 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
return uvc_query_buffer(&stream->queue, buf);
}
+ case VIDIOC_CREATE_BUFS:
+ {
+ struct v4l2_create_buffers *cb = arg;
+
+ ret = uvc_acquire_privileges(handle);
+ if (ret < 0)
+ return ret;
+
+ return uvc_create_buffers(&stream->queue, cb);
+ }
+
case VIDIOC_QBUF:
if (!uvc_has_privileges(handle))
return -EBUSY;
diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c
index 3394c343201..9144a2f3ed8 100644
--- a/drivers/media/usb/uvc/uvc_video.c
+++ b/drivers/media/usb/uvc/uvc_video.c
@@ -361,6 +361,14 @@ static int uvc_commit_video(struct uvc_streaming *stream,
* Clocks and timestamps
*/
+static inline void uvc_video_get_ts(struct timespec *ts)
+{
+ if (uvc_clock_param == CLOCK_MONOTONIC)
+ ktime_get_ts(ts);
+ else
+ ktime_get_real_ts(ts);
+}
+
static void
uvc_video_clock_decode(struct uvc_streaming *stream, struct uvc_buffer *buf,
const __u8 *data, int len)
@@ -420,7 +428,7 @@ uvc_video_clock_decode(struct uvc_streaming *stream, struct uvc_buffer *buf,
stream->clock.last_sof = dev_sof;
host_sof = usb_get_current_frame_number(stream->dev->udev);
- ktime_get_ts(&ts);
+ uvc_video_get_ts(&ts);
/* The UVC specification allows device implementations that can't obtain
* the USB frame number to keep their own frame counters as long as they
@@ -556,7 +564,7 @@ static u16 uvc_video_clock_host_sof(const struct uvc_clock_sample *sample)
*
* SOF = ((SOF2 - SOF1) * PTS + SOF1 * STC2 - SOF2 * STC1) / (STC2 - STC1) (1)
*
- * to avoid loosing precision in the division. Similarly, the host timestamp is
+ * to avoid losing precision in the division. Similarly, the host timestamp is
* computed with
*
* TS = ((TS2 - TS1) * PTS + TS1 * SOF2 - TS2 * SOF1) / (SOF2 - SOF1) (2)
@@ -680,7 +688,8 @@ void uvc_video_clock_update(struct uvc_streaming *stream,
stream->dev->name,
sof >> 16, div_u64(((u64)sof & 0xffff) * 1000000LLU, 65536),
y, ts.tv_sec, ts.tv_nsec / NSEC_PER_USEC,
- v4l2_buf->timestamp.tv_sec, v4l2_buf->timestamp.tv_usec,
+ v4l2_buf->timestamp.tv_sec,
+ (unsigned long)v4l2_buf->timestamp.tv_usec,
x1, first->host_sof, first->dev_sof,
x2, last->host_sof, last->dev_sof, y1, y2);
@@ -1010,10 +1019,7 @@ static int uvc_video_decode_start(struct uvc_streaming *stream,
return -ENODATA;
}
- if (uvc_clock_param == CLOCK_MONOTONIC)
- ktime_get_ts(&ts);
- else
- ktime_get_real_ts(&ts);
+ uvc_video_get_ts(&ts);
buf->buf.v4l2_buf.sequence = stream->sequence;
buf->buf.v4l2_buf.timestamp.tv_sec = ts.tv_sec;
@@ -1132,6 +1138,17 @@ static int uvc_video_encode_data(struct uvc_streaming *stream,
*/
/*
+ * Set error flag for incomplete buffer.
+ */
+static void uvc_video_validate_buffer(const struct uvc_streaming *stream,
+ struct uvc_buffer *buf)
+{
+ if (buf->length != buf->bytesused &&
+ !(stream->cur_format->flags & UVC_FMT_FLAG_COMPRESSED))
+ buf->error = 1;
+}
+
+/*
* Completion handler for video URBs.
*/
static void uvc_video_decode_isoc(struct urb *urb, struct uvc_streaming *stream,
@@ -1155,9 +1172,11 @@ static void uvc_video_decode_isoc(struct urb *urb, struct uvc_streaming *stream,
do {
ret = uvc_video_decode_start(stream, buf, mem,
urb->iso_frame_desc[i].actual_length);
- if (ret == -EAGAIN)
+ if (ret == -EAGAIN) {
+ uvc_video_validate_buffer(stream, buf);
buf = uvc_queue_next_buffer(&stream->queue,
buf);
+ }
} while (ret == -EAGAIN);
if (ret < 0)
@@ -1172,11 +1191,7 @@ static void uvc_video_decode_isoc(struct urb *urb, struct uvc_streaming *stream,
urb->iso_frame_desc[i].actual_length);
if (buf->state == UVC_BUF_STATE_READY) {
- if (buf->length != buf->bytesused &&
- !(stream->cur_format->flags &
- UVC_FMT_FLAG_COMPRESSED))
- buf->error = 1;
-
+ uvc_video_validate_buffer(stream, buf);
buf = uvc_queue_next_buffer(&stream->queue, buf);
}
}
@@ -1452,6 +1467,9 @@ static unsigned int uvc_endpoint_max_bpi(struct usb_device *dev,
case USB_SPEED_HIGH:
psize = usb_endpoint_maxp(&ep->desc);
return (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
+ case USB_SPEED_WIRELESS:
+ psize = usb_endpoint_maxp(&ep->desc);
+ return psize;
default:
psize = usb_endpoint_maxp(&ep->desc);
return psize & 0x07ff;
@@ -1846,7 +1864,25 @@ int uvc_video_enable(struct uvc_streaming *stream, int enable)
if (!enable) {
uvc_uninit_video(stream, 1);
- usb_set_interface(stream->dev->udev, stream->intfnum, 0);
+ if (stream->intf->num_altsetting > 1) {
+ usb_set_interface(stream->dev->udev,
+ stream->intfnum, 0);
+ } else {
+ /* UVC doesn't specify how to inform a bulk-based device
+ * when the video stream is stopped. Windows sends a
+ * CLEAR_FEATURE(HALT) request to the video streaming
+ * bulk endpoint, mimic the same behaviour.
+ */
+ unsigned int epnum = stream->header.bEndpointAddress
+ & USB_ENDPOINT_NUMBER_MASK;
+ unsigned int dir = stream->header.bEndpointAddress
+ & USB_ENDPOINT_DIR_MASK;
+ unsigned int pipe;
+
+ pipe = usb_sndbulkpipe(stream->dev->udev, epnum) | dir;
+ usb_clear_halt(stream->dev->udev, pipe);
+ }
+
uvc_queue_enable(&stream->queue, 0);
uvc_video_clock_cleanup(stream);
return 0;
diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
index 9e35982d099..b1f69a6d406 100644
--- a/drivers/media/usb/uvc/uvcvideo.h
+++ b/drivers/media/usb/uvc/uvcvideo.h
@@ -94,6 +94,18 @@
#define UVC_GUID_FORMAT_BY8 \
{ 'B', 'Y', '8', ' ', 0x00, 0x00, 0x10, 0x00, \
0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_BA81 \
+ { 'B', 'A', '8', '1', 0x00, 0x00, 0x10, 0x00, \
+ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_GBRG \
+ { 'G', 'B', 'R', 'G', 0x00, 0x00, 0x10, 0x00, \
+ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_GRBG \
+ { 'G', 'R', 'B', 'G', 0x00, 0x00, 0x10, 0x00, \
+ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_RGGB \
+ { 'R', 'G', 'G', 'B', 0x00, 0x00, 0x10, 0x00, \
+ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
#define UVC_GUID_FORMAT_RGBP \
{ 'R', 'G', 'B', 'P', 0x00, 0x00, 0x10, 0x00, \
0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
@@ -115,8 +127,6 @@
#define UVC_URBS 5
/* Maximum number of packets per URB. */
#define UVC_MAX_PACKETS 32
-/* Maximum number of video buffers. */
-#define UVC_MAX_VIDEO_BUFFERS 32
/* Maximum status buffer size in bytes of interrupt URB. */
#define UVC_MAX_STATUS_SIZE 16
@@ -616,6 +626,8 @@ extern int uvc_alloc_buffers(struct uvc_video_queue *queue,
extern void uvc_free_buffers(struct uvc_video_queue *queue);
extern int uvc_query_buffer(struct uvc_video_queue *queue,
struct v4l2_buffer *v4l2_buf);
+extern int uvc_create_buffers(struct uvc_video_queue *queue,
+ struct v4l2_create_buffers *v4l2_cb);
extern int uvc_queue_buffer(struct uvc_video_queue *queue,
struct v4l2_buffer *v4l2_buf);
extern int uvc_dequeue_buffer(struct uvc_video_queue *queue,