summaryrefslogtreecommitdiff
path: root/linux/drivers/media/video
diff options
context:
space:
mode:
Diffstat (limited to 'linux/drivers/media/video')
-rw-r--r--linux/drivers/media/video/Kconfig15
-rw-r--r--linux/drivers/media/video/Makefile4
-rw-r--r--linux/drivers/media/video/au0828/au0828-cards.c18
-rw-r--r--linux/drivers/media/video/au0828/au0828-dvb.c23
-rw-r--r--linux/drivers/media/video/au0828/au0828-i2c.c2
-rw-r--r--linux/drivers/media/video/bt8xx/bt832.c29
-rw-r--r--linux/drivers/media/video/bt8xx/bttv-cards.c28
-rw-r--r--linux/drivers/media/video/bt8xx/bttv-driver.c58
-rw-r--r--linux/drivers/media/video/bt8xx/bttv-i2c.c63
-rw-r--r--linux/drivers/media/video/bt8xx/bttv-input.c2
-rw-r--r--linux/drivers/media/video/bt8xx/bttv-risc.c8
-rw-r--r--linux/drivers/media/video/bt8xx/bttv.h10
-rw-r--r--linux/drivers/media/video/bt8xx/bttvp.h13
-rw-r--r--linux/drivers/media/video/btcx-risc.c2
-rw-r--r--linux/drivers/media/video/btcx-risc.h4
-rw-r--r--linux/drivers/media/video/compat_ioctl32.c2
-rw-r--r--linux/drivers/media/video/cs5345.c23
-rw-r--r--linux/drivers/media/video/cs53l32a.c32
-rw-r--r--linux/drivers/media/video/cx18/Kconfig4
-rw-r--r--linux/drivers/media/video/cx18/cx18-audio.c15
-rw-r--r--linux/drivers/media/video/cx18/cx18-av-audio.c12
-rw-r--r--linux/drivers/media/video/cx18/cx18-av-core.c14
-rw-r--r--linux/drivers/media/video/cx18/cx18-av-core.h9
-rw-r--r--linux/drivers/media/video/cx18/cx18-av-firmware.c72
-rw-r--r--linux/drivers/media/video/cx18/cx18-av-vbi.c25
-rw-r--r--linux/drivers/media/video/cx18/cx18-cards.c145
-rw-r--r--linux/drivers/media/video/cx18/cx18-cards.h58
-rw-r--r--linux/drivers/media/video/cx18/cx18-controls.c216
-rw-r--r--linux/drivers/media/video/cx18/cx18-controls.h7
-rw-r--r--linux/drivers/media/video/cx18/cx18-driver.c42
-rw-r--r--linux/drivers/media/video/cx18/cx18-driver.h6
-rw-r--r--linux/drivers/media/video/cx18/cx18-dvb.c17
-rw-r--r--linux/drivers/media/video/cx18/cx18-fileops.c3
-rw-r--r--linux/drivers/media/video/cx18/cx18-firmware.c9
-rw-r--r--linux/drivers/media/video/cx18/cx18-gpio.c62
-rw-r--r--linux/drivers/media/video/cx18/cx18-gpio.h2
-rw-r--r--linux/drivers/media/video/cx18/cx18-i2c.c43
-rw-r--r--linux/drivers/media/video/cx18/cx18-ioctl.c1272
-rw-r--r--linux/drivers/media/video/cx18/cx18-ioctl.h6
-rw-r--r--linux/drivers/media/video/cx18/cx18-irq.c12
-rw-r--r--linux/drivers/media/video/cx18/cx18-mailbox.c9
-rw-r--r--linux/drivers/media/video/cx18/cx18-streams.c18
-rw-r--r--linux/drivers/media/video/cx18/cx23418.h5
-rw-r--r--linux/drivers/media/video/cx2341x.c32
-rw-r--r--linux/drivers/media/video/cx23885/cx23885-417.c717
-rw-r--r--linux/drivers/media/video/cx23885/cx23885-core.c18
-rw-r--r--linux/drivers/media/video/cx23885/cx23885-i2c.c2
-rw-r--r--linux/drivers/media/video/cx23885/cx23885-video.c21
-rw-r--r--linux/drivers/media/video/cx25840/cx25840-audio.c3
-rw-r--r--linux/drivers/media/video/cx25840/cx25840-core.c24
-rw-r--r--linux/drivers/media/video/cx25840/cx25840-firmware.c8
-rw-r--r--linux/drivers/media/video/cx88/cx88-alsa.c19
-rw-r--r--linux/drivers/media/video/cx88/cx88-blackbird.c10
-rw-r--r--linux/drivers/media/video/cx88/cx88-cards.c26
-rw-r--r--linux/drivers/media/video/cx88/cx88-core.c10
-rw-r--r--linux/drivers/media/video/cx88/cx88-i2c.c11
-rw-r--r--linux/drivers/media/video/cx88/cx88-input.c4
-rw-r--r--linux/drivers/media/video/cx88/cx88-mpeg.c18
-rw-r--r--linux/drivers/media/video/cx88/cx88-tvaudio.c2
-rw-r--r--linux/drivers/media/video/cx88/cx88-video.c35
-rw-r--r--linux/drivers/media/video/cx88/cx88-vp3054-i2c.c10
-rw-r--r--linux/drivers/media/video/cx88/cx88.h6
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-audio.c18
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-cards.c78
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-dvb.c62
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-i2c.c19
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-input.c107
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-reg.h1
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-video.c62
-rw-r--r--linux/drivers/media/video/em28xx/em28xx.h16
-rw-r--r--linux/drivers/media/video/et61x251/et61x251_core.c2
-rw-r--r--linux/drivers/media/video/gspca/Kconfig13
-rw-r--r--linux/drivers/media/video/gspca/Makefile29
-rw-r--r--linux/drivers/media/video/gspca/conex.c1084
-rw-r--r--linux/drivers/media/video/gspca/etoms.c961
-rw-r--r--linux/drivers/media/video/gspca/gspca.c1816
-rw-r--r--linux/drivers/media/video/gspca/gspca.h173
-rw-r--r--linux/drivers/media/video/gspca/jpeg.h301
-rw-r--r--linux/drivers/media/video/gspca/mars.c452
-rw-r--r--linux/drivers/media/video/gspca/ov519.c2242
-rw-r--r--linux/drivers/media/video/gspca/pac207.c681
-rw-r--r--linux/drivers/media/video/gspca/pac7311.c790
-rw-r--r--linux/drivers/media/video/gspca/sonixb.c921
-rw-r--r--linux/drivers/media/video/gspca/sonixj.c1686
-rw-r--r--linux/drivers/media/video/gspca/spca500.c1234
-rw-r--r--linux/drivers/media/video/gspca/spca501.c2241
-rw-r--r--linux/drivers/media/video/gspca/spca505.c1022
-rw-r--r--linux/drivers/media/video/gspca/spca506.c850
-rw-r--r--linux/drivers/media/video/gspca/spca508.c1832
-rw-r--r--linux/drivers/media/video/gspca/spca561.c1045
-rw-r--r--linux/drivers/media/video/gspca/stk014.c596
-rw-r--r--linux/drivers/media/video/gspca/sunplus.c1701
-rw-r--r--linux/drivers/media/video/gspca/t613.c1086
-rw-r--r--linux/drivers/media/video/gspca/tv8532.c727
-rw-r--r--linux/drivers/media/video/gspca/vc032x.c2029
-rw-r--r--linux/drivers/media/video/gspca/zc3xx.c7615
-rw-r--r--linux/drivers/media/video/ir-kbd-i2c.c4
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-cards.c34
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-controls.c225
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-controls.h6
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-driver.c16
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-driver.h10
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-fileops.c27
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-i2c.c28
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-ioctl.c2192
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-ioctl.h9
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-irq.c8
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-queue.c2
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-streams.c7
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-yuv.c2
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-yuv.h2
-rw-r--r--linux/drivers/media/video/ivtv/ivtvfb.c3
-rw-r--r--linux/drivers/media/video/m52790.c25
-rw-r--r--linux/drivers/media/video/msp3400-driver.c89
-rw-r--r--linux/drivers/media/video/msp3400-driver.h4
-rw-r--r--linux/drivers/media/video/msp3400-kthreads.c45
-rw-r--r--linux/drivers/media/video/mt9m001.c4
-rw-r--r--linux/drivers/media/video/mt9v022.c5
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c35
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c6
-rw-r--r--linux/drivers/media/video/pwc/pwc-ctrl.c21
-rw-r--r--linux/drivers/media/video/pwc/pwc-if.c28
-rw-r--r--linux/drivers/media/video/pwc/pwc-ioctl.h5
-rw-r--r--linux/drivers/media/video/pxa_camera.c4
-rw-r--r--linux/drivers/media/video/s2255drv.c2487
-rw-r--r--linux/drivers/media/video/saa5246a.c4
-rw-r--r--linux/drivers/media/video/saa5249.c4
-rw-r--r--linux/drivers/media/video/saa6588.c30
-rw-r--r--linux/drivers/media/video/saa7115.c63
-rw-r--r--linux/drivers/media/video/saa711x.c618
-rw-r--r--linux/drivers/media/video/saa7127.c29
-rw-r--r--linux/drivers/media/video/saa7134/saa6752hs.c126
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-alsa.c23
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-cards.c169
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-core.c34
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-dvb.c50
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-empress.c125
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-i2c.c8
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-input.c13
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-reg.h1
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-tvaudio.c49
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-video.c40
-rw-r--r--linux/drivers/media/video/saa7134/saa7134.h10
-rw-r--r--linux/drivers/media/video/saa717x.c24
-rw-r--r--linux/drivers/media/video/sn9c102/sn9c102_core.c2
-rw-r--r--linux/drivers/media/video/soc_camera.c34
-rw-r--r--linux/drivers/media/video/tcm825x.c15
-rw-r--r--linux/drivers/media/video/tda7432.c28
-rw-r--r--linux/drivers/media/video/tda9840.c7
-rw-r--r--linux/drivers/media/video/tda9875.c29
-rw-r--r--linux/drivers/media/video/tea6415c.c7
-rw-r--r--linux/drivers/media/video/tea6420.c7
-rw-r--r--linux/drivers/media/video/tlv320aic23b.c19
-rw-r--r--linux/drivers/media/video/tuner-core.c61
-rw-r--r--linux/drivers/media/video/tvaudio.c39
-rw-r--r--linux/drivers/media/video/tveeprom.c3
-rw-r--r--linux/drivers/media/video/tvmixer.c50
-rw-r--r--linux/drivers/media/video/tvp5150.c21
-rw-r--r--linux/drivers/media/video/upd64031a.c19
-rw-r--r--linux/drivers/media/video/upd64083.c19
-rw-r--r--linux/drivers/media/video/usbvideo/konicawc.c4
-rw-r--r--linux/drivers/media/video/usbvideo/quickcam_messenger.c4
-rw-r--r--linux/drivers/media/video/usbvision/usbvision-core.c110
-rw-r--r--linux/drivers/media/video/usbvision/usbvision-i2c.c36
-rw-r--r--linux/drivers/media/video/usbvision/usbvision-video.c183
-rw-r--r--linux/drivers/media/video/usbvision/usbvision.h4
-rw-r--r--linux/drivers/media/video/uvc/Kconfig17
-rw-r--r--linux/drivers/media/video/uvc/Makefile3
-rw-r--r--linux/drivers/media/video/uvc/uvc_ctrl.c1257
-rw-r--r--linux/drivers/media/video/uvc/uvc_driver.c1966
-rw-r--r--linux/drivers/media/video/uvc/uvc_isight.c134
-rw-r--r--linux/drivers/media/video/uvc/uvc_queue.c478
-rw-r--r--linux/drivers/media/video/uvc/uvc_status.c221
-rw-r--r--linux/drivers/media/video/uvc/uvc_v4l2.c1106
-rw-r--r--linux/drivers/media/video/uvc/uvc_video.c967
-rw-r--r--linux/drivers/media/video/uvc/uvcvideo.h799
-rw-r--r--linux/drivers/media/video/v4l2-common.c3
-rw-r--r--linux/drivers/media/video/videobuf-dma-sg.c15
-rw-r--r--linux/drivers/media/video/videobuf-dvb.c27
-rw-r--r--linux/drivers/media/video/videodev.c759
-rw-r--r--linux/drivers/media/video/vivi.c91
-rw-r--r--linux/drivers/media/video/vp27smpx.c27
-rw-r--r--linux/drivers/media/video/wm8739.c28
-rw-r--r--linux/drivers/media/video/wm8775.c23
-rw-r--r--linux/drivers/media/video/zc0301/zc0301_core.c2
-rw-r--r--linux/drivers/media/video/zoran.h4
-rw-r--r--linux/drivers/media/video/zoran_card.c23
-rw-r--r--linux/drivers/media/video/zoran_device.c4
-rw-r--r--linux/drivers/media/video/zoran_driver.c11
189 files changed, 47035 insertions, 5271 deletions
diff --git a/linux/drivers/media/video/Kconfig b/linux/drivers/media/video/Kconfig
index 89d8d3783..45c90b8bc 100644
--- a/linux/drivers/media/video/Kconfig
+++ b/linux/drivers/media/video/Kconfig
@@ -793,6 +793,10 @@ menuconfig V4L_USB_DRIVERS
if V4L_USB_DRIVERS && USB
+source "drivers/media/video/uvc/Kconfig"
+
+source "drivers/media/video/gspca/Kconfig"
+
source "drivers/media/video/pvrusb2/Kconfig"
source "drivers/media/video/em28xx/Kconfig"
@@ -897,11 +901,20 @@ config USB_STKWEBCAM
To compile this driver as a module, choose M here: the
module will be called stkwebcam.
+config USB_S2255
+ tristate "USB Sensoray 2255 video capture device"
+ depends on VIDEO_V4L2
+ select VIDEOBUF_VMALLOC
+ default n
+ help
+ Say Y here if you want support for the Sensoray 2255 USB device.
+ This driver can be compiled as a module, called s2255drv.
+
endif # V4L_USB_DRIVERS
config SOC_CAMERA
tristate "SoC camera support"
- depends on VIDEO_V4L2
+ depends on VIDEO_V4L2 && HAS_DMA
select VIDEOBUF_DMA_SG
help
SoC Camera is a common API to several cameras, not connecting
diff --git a/linux/drivers/media/video/Makefile b/linux/drivers/media/video/Makefile
index 29139b53d..0a1837c99 100644
--- a/linux/drivers/media/video/Makefile
+++ b/linux/drivers/media/video/Makefile
@@ -118,11 +118,13 @@ obj-$(CONFIG_USB_SN9C102) += sn9c102/
obj-$(CONFIG_USB_ET61X251) += et61x251/
obj-$(CONFIG_USB_PWC) += pwc/
obj-$(CONFIG_USB_ZC0301) += zc0301/
+obj-$(CONFIG_USB_GSPCA) += gspca/
obj-$(CONFIG_USB_IBMCAM) += usbvideo/
obj-$(CONFIG_USB_KONICAWC) += usbvideo/
obj-$(CONFIG_USB_VICAM) += usbvideo/
obj-$(CONFIG_USB_QUICKCAM_MESSENGER) += usbvideo/
+obj-$(CONFIG_USB_S2255) += s2255drv.o
obj-$(CONFIG_VIDEO_IVTV) += ivtv/
obj-$(CONFIG_VIDEO_CX18) += cx18/
@@ -137,6 +139,8 @@ obj-$(CONFIG_SOC_CAMERA_MT9V022) += mt9v022.o
obj-$(CONFIG_VIDEO_AU0828) += au0828/
+obj-$(CONFIG_USB_VIDEO_CLASS) += uvc/
+
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
EXTRA_CFLAGS += -Idrivers/media/common/tuners
diff --git a/linux/drivers/media/video/au0828/au0828-cards.c b/linux/drivers/media/video/au0828/au0828-cards.c
index a2a698344..898e12395 100644
--- a/linux/drivers/media/video/au0828/au0828-cards.c
+++ b/linux/drivers/media/video/au0828/au0828-cards.c
@@ -77,8 +77,14 @@ static void hauppauge_eeprom(struct au0828_dev *dev, u8 *eeprom_data)
/* Make sure we support the board model */
switch (tv.model) {
+ case 72000: /* WinTV-HVR950q (Retail, IR, ATSC/QAM */
case 72001: /* WinTV-HVR950q (Retail, IR, ATSC/QAM and basic analog video */
+ case 72211: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and basic analog video */
+ case 72221: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and basic analog video */
+ case 72231: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and basic analog video */
+ case 72241: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM and basic analog video */
case 72301: /* WinTV-HVR850 (Retail, IR, ATSC and basic analog video */
+ case 72500: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM */
break;
default:
printk(KERN_WARNING "%s: warning: "
@@ -175,6 +181,18 @@ struct usb_device_id au0828_usb_id_table [] = {
.driver_info = AU0828_BOARD_HAUPPAUGE_HVR850 },
{ USB_DEVICE(0x0fe9, 0xd620),
.driver_info = AU0828_BOARD_DVICO_FUSIONHDTV7 },
+ { USB_DEVICE(0x2040, 0x7210),
+ .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
+ { USB_DEVICE(0x2040, 0x7217),
+ .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
+ { USB_DEVICE(0x2040, 0x721b),
+ .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
+ { USB_DEVICE(0x2040, 0x721f),
+ .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
+ { USB_DEVICE(0x2040, 0x7280),
+ .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
+ { USB_DEVICE(0x0fd9, 0x0008),
+ .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
{ },
};
diff --git a/linux/drivers/media/video/au0828/au0828-dvb.c b/linux/drivers/media/video/au0828/au0828-dvb.c
index 709a703fe..0a835354f 100644
--- a/linux/drivers/media/video/au0828/au0828-dvb.c
+++ b/linux/drivers/media/video/au0828/au0828-dvb.c
@@ -224,17 +224,10 @@ static int dvb_register(struct au0828_dev *dev)
"(errno = %d)\n", DRIVER_NAME, result);
goto fail_adapter;
}
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12))
dvb->adapter.priv = dev;
/* register frontend */
result = dvb_register_frontend(&dvb->adapter, dvb->frontend);
-#else
- dvb->adapter->priv = dev;
-
- /* register frontend */
- result = dvb_register_frontend(dvb->adapter, dvb->frontend);
-#endif
if (result < 0) {
printk(KERN_ERR "%s: dvb_register_frontend failed "
"(errno = %d)\n", DRIVER_NAME, result);
@@ -260,11 +253,7 @@ static int dvb_register(struct au0828_dev *dev)
dvb->dmxdev.filternum = 256;
dvb->dmxdev.demux = &dvb->demux.dmx;
dvb->dmxdev.capabilities = 0;
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12))
result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter);
-#else
- result = dvb_dmxdev_init(&dvb->dmxdev, dvb->adapter);
-#endif
if (result < 0) {
printk(KERN_ERR "%s: dvb_dmxdev_init failed (errno = %d)\n",
DRIVER_NAME, result);
@@ -295,11 +284,7 @@ static int dvb_register(struct au0828_dev *dev)
}
/* register network adapter */
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12))
dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx);
-#else
- dvb_net_init(dvb->adapter, &dvb->net, &dvb->demux.dmx);
-#endif
return 0;
fail_fe_conn:
@@ -314,11 +299,7 @@ fail_dmx:
dvb_unregister_frontend(dvb->frontend);
fail_frontend:
dvb_frontend_detach(dvb->frontend);
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12))
dvb_unregister_adapter(&dvb->adapter);
-#else
- dvb_unregister_adapter(dvb->adapter);
-#endif
fail_adapter:
return result;
}
@@ -339,11 +320,7 @@ void au0828_dvb_unregister(struct au0828_dev *dev)
dvb_dmx_release(&dvb->demux);
dvb_unregister_frontend(dvb->frontend);
dvb_frontend_detach(dvb->frontend);
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12))
dvb_unregister_adapter(&dvb->adapter);
-#else
- dvb_unregister_adapter(dvb->adapter);
-#endif
}
/* All the DVB attach calls go here, this function get's modified
diff --git a/linux/drivers/media/video/au0828/au0828-i2c.c b/linux/drivers/media/video/au0828/au0828-i2c.c
index b40a086e4..32858dceb 100644
--- a/linux/drivers/media/video/au0828/au0828-i2c.c
+++ b/linux/drivers/media/video/au0828/au0828-i2c.c
@@ -307,9 +307,7 @@ static struct i2c_algorithm au0828_i2c_algo_template = {
static struct i2c_adapter au0828_i2c_adap_template = {
.name = DRIVER_NAME,
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
.owner = THIS_MODULE,
-#endif
.id = I2C_HW_B_AU0828,
.algo = &au0828_i2c_algo_template,
.class = I2C_CLASS_TV_ANALOG,
diff --git a/linux/drivers/media/video/bt8xx/bt832.c b/linux/drivers/media/video/bt8xx/bt832.c
index 4eefaba8f..e860f7725 100644
--- a/linux/drivers/media/video/bt8xx/bt832.c
+++ b/linux/drivers/media/video/bt8xx/bt832.c
@@ -33,9 +33,6 @@
#include <linux/slab.h>
#include <media/v4l2-common.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-#include "i2c-compat.h"
-#endif
#include "bttv.h"
#include "bt832.h"
@@ -44,17 +41,10 @@ MODULE_LICENSE("GPL");
/* Addresses to scan */
static unsigned short normal_i2c[] = { I2C_ADDR_BT832_ALT1>>1, I2C_ADDR_BT832_ALT2>>1,
I2C_CLIENT_END };
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13)
-static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
-#endif
I2C_CLIENT_INSMOD;
int debug; /* debug output */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
module_param(debug, int, 0644);
-#else
-MODULE_PARM(debug, "i");
-#endif
/* ---------------------------------------------------------------------- */
@@ -187,12 +177,7 @@ int bt832_init(struct i2c_client *i2c_client_s)
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
static int bt832_attach(struct i2c_adapter *adap, int addr, int kind)
-#else
-static int bt832_attach(struct i2c_adapter *adap, int addr,
- unsigned short flags, int kind)
-#endif
{
struct bt832 *t;
@@ -207,10 +192,6 @@ static int bt832_attach(struct i2c_adapter *adap, int addr,
v4l_info(&t->client,"chip found @ 0x%x\n", addr<<1);
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
- MOD_INC_USE_COUNT;
-#endif
if(! bt832_init(&t->client)) {
bt832_detach(&t->client);
return -1;
@@ -221,13 +202,8 @@ static int bt832_attach(struct i2c_adapter *adap, int addr,
static int bt832_probe(struct i2c_adapter *adap)
{
-#ifdef I2C_CLASS_TV_ANALOG
if (adap->class & I2C_CLASS_TV_ANALOG)
return i2c_probe(adap, &addr_data, bt832_attach);
-#else
- if (adap->id == I2C_HW_B_BT848)
- return i2c_probe(adap, &addr_data, bt832_attach);
-#endif
return 0;
}
@@ -238,9 +214,6 @@ static int bt832_detach(struct i2c_client *client)
v4l_info(&t->client,"dettach\n");
i2c_detach_client(client);
kfree(t);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
- MOD_DEC_USE_COUNT;
-#endif
return 0;
}
@@ -277,7 +250,7 @@ bt832_command(struct i2c_client *client, unsigned int cmd, void *arg)
/* ----------------------------------------------------------------------- */
static struct i2c_driver driver = {
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))&&(LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15))
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15)
.owner = THIS_MODULE,
#endif
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15)
diff --git a/linux/drivers/media/video/bt8xx/bttv-cards.c b/linux/drivers/media/video/bt8xx/bttv-cards.c
index 177b75ebc..4d283be22 100644
--- a/linux/drivers/media/video/bt8xx/bttv-cards.c
+++ b/linux/drivers/media/video/bt8xx/bttv-cards.c
@@ -35,6 +35,7 @@
#include <net/checksum.h>
#include "compat.h"
+#include <asm/unaligned.h>
#include <asm/io.h>
#include "bttvp.h"
@@ -114,31 +115,12 @@ module_param(gpiomask, int, 0444);
module_param(audioall, int, 0444);
module_param(autoload, int, 0444);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-MODULE_PARM(card,"1-" __stringify(BTTV_MAX) "i");
-MODULE_PARM(pll,"1-" __stringify(BTTV_MAX) "i");
-MODULE_PARM(tuner,"1-" __stringify(BTTV_MAX) "i");
-MODULE_PARM(svhs,"1-" __stringify(BTTV_MAX) "i");
-MODULE_PARM(remote,"1-" __stringify(BTTV_MAX) "i");
-MODULE_PARM(audiomux,"1-" __stringify(BTTV_MAX) "i");
-#else
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
-static int dummy;
-module_param_array(card, int, dummy, 0444);
-module_param_array(pll, int, dummy, 0444);
-module_param_array(tuner, int, dummy, 0444);
-module_param_array(svhs, int, dummy, 0444);
-module_param_array(remote, int, dummy, 0444);
-module_param_array(audiomux, int, dummy, 0444);
-#else
module_param_array(card, int, NULL, 0444);
module_param_array(pll, int, NULL, 0444);
module_param_array(tuner, int, NULL, 0444);
module_param_array(svhs, int, NULL, 0444);
module_param_array(remote, int, NULL, 0444);
module_param_array(audiomux, int, NULL, 0444);
-#endif
-#endif
MODULE_PARM_DESC(triton1,"set ETBF pci config bit "
"[enable bug compatibility for triton1 + others]");
@@ -3869,11 +3851,7 @@ static int __devinit pvr_boot(struct bttv *btv)
const struct firmware *fw_entry;
int rc;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
rc = request_firmware(&fw_entry, "hcwamc.rbf", &btv->c.pci->dev);
-#else
- rc = request_firmware(&fw_entry, "hcwamc.rbf", pci_name(btv->c.pci));
-#endif
if (rc != 0) {
printk(KERN_WARNING "bttv%d: no altera firmware [via hotplug]\n",
btv->c.nr);
@@ -3922,7 +3900,7 @@ static void __devinit osprey_eeprom(struct bttv *btv, const u8 ee[256])
ee += i;
/* found a valid descriptor */
- type = be16_to_cpup((u16*)(ee+4));
+ type = get_unaligned_be16((__be16 *)(ee+4));
switch(type) {
/* 848 based */
@@ -3982,7 +3960,7 @@ static void __devinit osprey_eeprom(struct bttv *btv, const u8 ee[256])
btv->c.nr, type);
break;
}
- serial = be32_to_cpup((u32*)(ee+6));
+ serial = get_unaligned_be32((__be32 *)(ee+6));
}
printk(KERN_INFO "bttv%d: osprey eeprom: card=%d '%s' serial=%u\n",
diff --git a/linux/drivers/media/video/bt8xx/bttv-driver.c b/linux/drivers/media/video/bt8xx/bttv-driver.c
index bb9ad09f8..36efd08f8 100644
--- a/linux/drivers/media/video/bt8xx/bttv-driver.c
+++ b/linux/drivers/media/video/bt8xx/bttv-driver.c
@@ -48,9 +48,7 @@
#include <media/tvaudio.h>
#include <media/msp3400.h>
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
#include <linux/dma-mapping.h>
-#endif
#include <asm/io.h>
#include <asm/byteorder.h>
@@ -132,16 +130,7 @@ module_param(uv_ratio, int, 0444);
module_param(full_luma_range, int, 0444);
module_param(coring, int, 0444);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-MODULE_PARM(radio,"1-" __stringify(BTTV_MAX) "i");
-#else
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
-static int dummy;
-module_param_array(radio, int, dummy, 0444);
-#else
module_param_array(radio, int, NULL, 0444);
-#endif
-#endif
MODULE_PARM_DESC(radio,"The TV card supports radio, default is 0 (no)");
MODULE_PARM_DESC(bigendian,"byte order of the framebuffer, default is native endian");
@@ -171,20 +160,14 @@ MODULE_LICENSE("GPL");
/* ----------------------------------------------------------------------- */
/* sysfs */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13)
static ssize_t show_card(struct device *cd,
struct device_attribute *attr, char *buf)
-#else
-static ssize_t show_card(struct class_device *cd, char *buf)
-#endif
{
struct video_device *vfd = container_of(cd, struct video_device, class_dev);
struct bttv *btv = dev_get_drvdata(vfd->dev);
return sprintf(buf, "%d\n", btv ? btv->c.type : UNSET);
}
static DEVICE_ATTR(card, S_IRUGO, show_card, NULL);
-#endif
/* ----------------------------------------------------------------------- */
/* dvb auto-load setup */
@@ -198,9 +181,6 @@ static void request_module_async(struct work_struct *work)
request_module("dvb-bt8xx");
}
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-#define request_modules(dev)
-#else
static void request_modules(struct bttv *dev)
{
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
@@ -210,7 +190,6 @@ static void request_modules(struct bttv *dev)
#endif
schedule_work(&dev->request_module_wk);
}
-#endif
#else
#define request_modules(dev)
#endif /* CONFIG_MODULES */
@@ -3391,9 +3370,7 @@ static const struct file_operations bttv_fops =
.open = bttv_open,
.release = bttv_release,
.ioctl = video_ioctl2,
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11)
.compat_ioctl = v4l_compat_ioctl32,
-#endif
.llseek = no_llseek,
.read = bttv_read,
.mmap = bttv_mmap,
@@ -3672,9 +3649,7 @@ static const struct file_operations radio_fops =
.open = radio_open,
.read = radio_read,
.release = radio_release,
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11)
.compat_ioctl = v4l_compat_ioctl32,
-#endif
.ioctl = video_ioctl2,
.llseek = no_llseek,
.poll = radio_poll,
@@ -3750,7 +3725,7 @@ static void bttv_risc_disasm(struct bttv *btv,
for (i = 0; i < (risc->size >> 2); i += n) {
printk("%s: 0x%lx: ", btv->c.name,
(unsigned long)(risc->dma + (i<<2)));
- n = bttv_risc_decode(risc->cpu[i]);
+ n = bttv_risc_decode(le32_to_cpu(risc->cpu[i]));
for (j = 1; j < n; j++)
printk("%s: 0x%lx: 0x%08x [ arg #%d ]\n",
btv->c.name, (unsigned long)(risc->dma + ((i+j)<<2)),
@@ -3819,8 +3794,8 @@ static void bttv_irq_debug_low_latency(struct bttv *btv, u32 rc)
printk("bttv%d: irq: skipped frame [main=%lx,o_vbi=%lx,o_field=%lx,rc=%lx]\n",
btv->c.nr,
(unsigned long)btv->main.dma,
- (unsigned long)btv->main.cpu[RISC_SLOT_O_VBI+1],
- (unsigned long)btv->main.cpu[RISC_SLOT_O_FIELD+1],
+ (unsigned long)le32_to_cpu(btv->main.cpu[RISC_SLOT_O_VBI+1]),
+ (unsigned long)le32_to_cpu(btv->main.cpu[RISC_SLOT_O_FIELD+1]),
(unsigned long)rc);
if (0 == (btread(BT848_DSTATUS) & BT848_DSTATUS_HLOC)) {
@@ -4115,10 +4090,8 @@ static irqreturn_t bttv_irq(int irq, void *dev_id)
btv=(struct bttv *)dev_id;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
if (btv->custom_irq)
handled = btv->custom_irq(btv);
-#endif
count=0;
while (1) {
@@ -4156,9 +4129,7 @@ static irqreturn_t bttv_irq(int irq, void *dev_id)
if ((astat & BT848_INT_GPINT) && btv->remote) {
wake_up(&btv->gpioq);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
bttv_input_irq(btv);
-#endif
}
if (astat & BT848_INT_I2CDONE) {
@@ -4238,11 +4209,10 @@ static struct video_device *vdev_init(struct bttv *btv,
return NULL;
*vfd = *template;
vfd->minor = -1;
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
vfd->dev = &btv->c.pci->dev;
vfd->release = video_device_release;
-#endif
vfd->type = type;
+ vfd->debug = bttv_debug;
snprintf(vfd->name, sizeof(vfd->name), "BT%d%s %s (%s)",
btv->id, (btv->id==848 && btv->revision==0x12) ? "A" : "",
type_name, bttv_tvcards[btv->c.type].name);
@@ -4393,11 +4363,7 @@ static int __devinit bttv_probe(struct pci_dev *dev,
btv->c.nr);
return -EIO;
}
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,7)
- if (pci_set_dma_mask(dev, 0xffffffff)) {
-#else
if (pci_set_dma_mask(dev, DMA_32BIT_MASK)) {
-#endif
printk(KERN_WARNING "bttv%d: No suitable DMA available.\n",
btv->c.nr);
return -EIO;
@@ -4508,13 +4474,11 @@ static int __devinit bttv_probe(struct pci_dev *dev,
disclaim_video_lines(btv);
}
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
/* add subdevices and autoload dvb-bt8xx if needed */
if (bttv_tvcards[btv->c.type].has_dvb) {
bttv_sub_add_device(&btv->c, "dvb");
request_modules(btv);
}
-#endif
bttv_input_init(btv);
@@ -4553,9 +4517,7 @@ static void __devexit bttv_remove(struct pci_dev *pci_dev)
btv->shutdown=1;
wake_up(&btv->gpioq);
bttv_input_fini(btv);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
bttv_sub_del_devices(&btv->c);
-#endif
/* unregister i2c_bus + input */
fini_bttv_i2c(btv);
@@ -4608,11 +4570,7 @@ static int bttv_suspend(struct pci_dev *pci_dev, pm_message_t state)
btv->state.gpio_data = gpio_read();
/* save pci state */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
- pci_save_state(pci_dev, btv->state.pci_cfg);
-#else
pci_save_state(pci_dev);
-#endif
if (0 != pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state))) {
pci_disable_device(pci_dev);
btv->state.disabled = 1;
@@ -4647,11 +4605,7 @@ static int bttv_resume(struct pci_dev *pci_dev)
return err;
}
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
- pci_restore_state(pci_dev, btv->state.pci_cfg);
-#else
pci_restore_state(pci_dev);
-#endif
/* restore bt878 state */
bttv_reinit_bt848(btv);
@@ -4721,13 +4675,11 @@ static int __init bttv_init_module(void)
bttv_check_chipset();
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
ret = bus_register(&bttv_sub_bus_type);
if (ret < 0) {
printk(KERN_WARNING "bttv: bus_register error: %d\n", ret);
return ret;
}
-#endif
ret = pci_register_driver(&bttv_pci_driver);
if (ret < 0)
bus_unregister(&bttv_sub_bus_type);
@@ -4738,9 +4690,7 @@ static int __init bttv_init_module(void)
static void __exit bttv_cleanup_module(void)
{
pci_unregister_driver(&bttv_pci_driver);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
bus_unregister(&bttv_sub_bus_type);
-#endif
}
module_init(bttv_init_module);
diff --git a/linux/drivers/media/video/bt8xx/bttv-i2c.c b/linux/drivers/media/video/bt8xx/bttv-i2c.c
index a3101696b..4f48dfb26 100644
--- a/linux/drivers/media/video/bt8xx/bttv-i2c.c
+++ b/linux/drivers/media/video/bt8xx/bttv-i2c.c
@@ -33,16 +33,9 @@
#include "bttvp.h"
#include <media/v4l2-common.h>
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
#include <linux/jiffies.h>
-#endif
#include <asm/io.h>
-static struct i2c_algo_bit_data bttv_i2c_algo_bit_template;
-static struct i2c_adapter bttv_i2c_adap_sw_template;
-static struct i2c_adapter bttv_i2c_adap_hw_template;
-static struct i2c_client bttv_i2c_client_template;
-
static int attach_inform(struct i2c_client *client);
static int i2c_debug;
@@ -106,7 +99,7 @@ static int bttv_bit_getsda(void *data)
return state;
}
-static struct i2c_algo_bit_data bttv_i2c_algo_bit_template = {
+static struct i2c_algo_bit_data __devinitdata bttv_i2c_algo_bit_template = {
.setsda = bttv_bit_setsda,
.setscl = bttv_bit_setscl,
.getsda = bttv_bit_getsda,
@@ -115,18 +108,6 @@ static struct i2c_algo_bit_data bttv_i2c_algo_bit_template = {
.timeout = 200,
};
-static struct i2c_adapter bttv_i2c_adap_sw_template = {
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
- .owner = THIS_MODULE,
-#endif
-#ifdef I2C_CLASS_TV_ANALOG
- .class = I2C_CLASS_TV_ANALOG,
-#endif
- .name = "bttv",
- .id = I2C_HW_B_BT848,
- .client_register = attach_inform,
-};
-
/* ----------------------------------------------------------------------- */
/* I2C functions - hardware i2c */
@@ -276,24 +257,11 @@ static int bttv_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int
return retval;
}
-static struct i2c_algorithm bttv_algo = {
+static const struct i2c_algorithm bttv_algo = {
.master_xfer = bttv_i2c_xfer,
.functionality = functionality,
};
-static struct i2c_adapter bttv_i2c_adap_hw_template = {
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
- .owner = THIS_MODULE,
-#endif
-#ifdef I2C_CLASS_TV_ANALOG
- .class = I2C_CLASS_TV_ANALOG,
-#endif
- .name = "bt878",
- .id = I2C_HW_B_BT848 /* FIXME */,
- .algo = &bttv_algo,
- .client_register = attach_inform,
-};
-
/* ----------------------------------------------------------------------- */
/* I2C functions - common stuff */
@@ -346,10 +314,6 @@ void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg)
i2c_clients_command(&btv->c.i2c_adap, cmd, arg);
}
-static struct i2c_client bttv_i2c_client_template = {
- .name = "bttv internal",
-};
-
/* read I2C */
int bttv_I2CRead(struct bttv *btv, unsigned char addr, char *probe_for)
@@ -431,33 +395,36 @@ static void do_i2c_scan(char *name, struct i2c_client *c)
/* init + register i2c algo-bit adapter */
int __devinit init_bttv_i2c(struct bttv *btv)
{
- memcpy(&btv->i2c_client, &bttv_i2c_client_template,
- sizeof(bttv_i2c_client_template));
+ strlcpy(btv->i2c_client.name, "bttv internal", I2C_NAME_SIZE);
if (i2c_hw)
btv->use_i2c_hw = 1;
if (btv->use_i2c_hw) {
/* bt878 */
- memcpy(&btv->c.i2c_adap, &bttv_i2c_adap_hw_template,
- sizeof(bttv_i2c_adap_hw_template));
+ strlcpy(btv->c.i2c_adap.name, "bt878",
+ sizeof(btv->c.i2c_adap.name));
+ btv->c.i2c_adap.id = I2C_HW_B_BT848; /* FIXME */
+ btv->c.i2c_adap.algo = &bttv_algo;
} else {
/* bt848 */
/* Prevents usage of invalid delay values */
if (i2c_udelay<5)
i2c_udelay=5;
- bttv_i2c_algo_bit_template.udelay=i2c_udelay;
- memcpy(&btv->c.i2c_adap, &bttv_i2c_adap_sw_template,
- sizeof(bttv_i2c_adap_sw_template));
+ strlcpy(btv->c.i2c_adap.name, "bttv",
+ sizeof(btv->c.i2c_adap.name));
+ btv->c.i2c_adap.id = I2C_HW_B_BT848;
memcpy(&btv->i2c_algo, &bttv_i2c_algo_bit_template,
sizeof(bttv_i2c_algo_bit_template));
+ btv->i2c_algo.udelay = i2c_udelay;
btv->i2c_algo.data = btv;
btv->c.i2c_adap.algo_data = &btv->i2c_algo;
}
+ btv->c.i2c_adap.owner = THIS_MODULE;
+ btv->c.i2c_adap.class = I2C_CLASS_TV_ANALOG;
+ btv->c.i2c_adap.client_register = attach_inform;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,66)
btv->c.i2c_adap.dev.parent = &btv->c.pci->dev;
-#endif
snprintf(btv->c.i2c_adap.name, sizeof(btv->c.i2c_adap.name),
"bt%d #%d [%s]", btv->id, btv->c.nr,
btv->use_i2c_hw ? "hw" : "sw");
@@ -465,12 +432,10 @@ int __devinit init_bttv_i2c(struct bttv *btv)
i2c_set_adapdata(&btv->c.i2c_adap, btv);
btv->i2c_client.adapter = &btv->c.i2c_adap;
-#ifdef I2C_CLASS_TV_ANALOG
if (bttv_tvcards[btv->c.type].no_video)
btv->c.i2c_adap.class &= ~I2C_CLASS_TV_ANALOG;
if (bttv_tvcards[btv->c.type].has_dvb)
btv->c.i2c_adap.class |= I2C_CLASS_TV_DIGITAL;
-#endif
if (btv->use_i2c_hw) {
btv->i2c_rc = i2c_add_adapter(&btv->c.i2c_adap);
diff --git a/linux/drivers/media/video/bt8xx/bttv-input.c b/linux/drivers/media/video/bt8xx/bttv-input.c
index f82213990..ada104826 100644
--- a/linux/drivers/media/video/bt8xx/bttv-input.c
+++ b/linux/drivers/media/video/bt8xx/bttv-input.c
@@ -313,7 +313,6 @@ int bttv_input_init(struct bttv *btv)
ir_input_init(input_dev, &ir->ir, ir_type, ir_codes);
input_dev->name = ir->name;
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
input_dev->phys = ir->phys;
input_dev->id.bustype = BUS_PCI;
input_dev->id.version = 1;
@@ -333,7 +332,6 @@ int bttv_input_init(struct bttv *btv)
input_dev->dev = &btv->c.pci->dev;
#endif
#endif
-#endif
btv->remote = ir;
bttv_ir_start(btv, ir);
diff --git a/linux/drivers/media/video/bt8xx/bttv-risc.c b/linux/drivers/media/video/bt8xx/bttv-risc.c
index a064f4ee9..a8c98e52c 100644
--- a/linux/drivers/media/video/bt8xx/bttv-risc.c
+++ b/linux/drivers/media/video/bt8xx/bttv-risc.c
@@ -48,7 +48,7 @@ bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
{
u32 instructions,line,todo;
struct scatterlist *sg;
- u32 *rp;
+ __le32 *rp;
int rc;
/* estimate risc mem: worst case is one write per page border +
@@ -128,7 +128,8 @@ bttv_risc_planar(struct bttv *btv, struct btcx_riscmem *risc,
unsigned int cpadding)
{
unsigned int instructions,line,todo,ylen,chroma;
- u32 *rp,ri;
+ __le32 *rp;
+ u32 ri;
struct scatterlist *ysg;
struct scatterlist *usg;
struct scatterlist *vsg;
@@ -244,7 +245,8 @@ bttv_risc_overlay(struct bttv *btv, struct btcx_riscmem *risc,
{
int dwords,rc,line,maxy,start,end,skip,nskips;
struct btcx_skiplist *skips;
- u32 *rp,ri,ra;
+ __le32 *rp;
+ u32 ri,ra;
u32 addr;
/* skip list for window clipping */
diff --git a/linux/drivers/media/video/bt8xx/bttv.h b/linux/drivers/media/video/bt8xx/bttv.h
index 4c73aacdb..dab61e62e 100644
--- a/linux/drivers/media/video/bt8xx/bttv.h
+++ b/linux/drivers/media/video/bt8xx/bttv.h
@@ -302,8 +302,6 @@ extern int bttv_write_gpio(unsigned int card,
/* ---------------------------------------------------------- */
/* sysfs/driver-moded based gpio access interface */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
-
struct bttv_sub_device {
struct device dev;
struct bttv_core *core;
@@ -335,14 +333,6 @@ void bttv_gpio_bits(struct bttv_core *core, u32 mask, u32 bits);
#define gpio_write(value) bttv_gpio_write(&btv->c, value)
#define gpio_bits(mask,bits) bttv_gpio_bits(&btv->c, mask, bits)
-#else
-
-#define gpio_inout(mask,bits) btaor((mask)&(bits),~(mask),BT848_GPIO_OUT_EN)
-#define gpio_read() btread(BT848_GPIO_DATA)
-#define gpio_write(value) btwrite((value),BT848_GPIO_DATA)
-#define gpio_bits(mask,bits) btaor((mask)&(bits),~(mask),BT848_GPIO_DATA)
-
-#endif
/* ---------------------------------------------------------- */
/* i2c */
diff --git a/linux/drivers/media/video/bt8xx/bttvp.h b/linux/drivers/media/video/bt8xx/bttvp.h
index 9fd8eeddf..c3d1703ac 100644
--- a/linux/drivers/media/video/bt8xx/bttvp.h
+++ b/linux/drivers/media/video/bt8xx/bttvp.h
@@ -42,13 +42,7 @@
#include <asm/io.h>
#include "compat.h"
#include <media/v4l2-common.h>
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-#include "i2c-compat.h"
-#define strlcpy(dest,src,len) strncpy(dest,src,(len)-1)
-#else
#include <linux/device.h>
-#endif
#include <media/videobuf-dma-sg.h>
#include <media/tveeprom.h>
#include <media/ir-common.h>
@@ -272,14 +266,10 @@ extern struct videobuf_queue_ops bttv_vbi_qops;
/* ---------------------------------------------------------- */
/* bttv-gpio.c */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
-
extern struct bus_type bttv_sub_bus_type;
int bttv_sub_add_device(struct bttv_core *core, char *name);
int bttv_sub_del_devices(struct bttv_core *core);
-#endif
-
/* ---------------------------------------------------------- */
/* bttv-driver.c */
@@ -318,9 +308,6 @@ struct bttv_input {
};
struct bttv_suspend_state {
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
- u32 pci_cfg[64 / sizeof(u32)];
-#endif
u32 gpio_enable;
u32 gpio_data;
int disabled;
diff --git a/linux/drivers/media/video/btcx-risc.c b/linux/drivers/media/video/btcx-risc.c
index 2d2ad58b4..e0e1158ce 100644
--- a/linux/drivers/media/video/btcx-risc.c
+++ b/linux/drivers/media/video/btcx-risc.c
@@ -64,7 +64,7 @@ int btcx_riscmem_alloc(struct pci_dev *pci,
struct btcx_riscmem *risc,
unsigned int size)
{
- u32 *cpu;
+ __le32 *cpu;
dma_addr_t dma;
if (NULL != risc->cpu && risc->size < size)
diff --git a/linux/drivers/media/video/btcx-risc.h b/linux/drivers/media/video/btcx-risc.h
index 503e6c6d7..861bc8112 100644
--- a/linux/drivers/media/video/btcx-risc.h
+++ b/linux/drivers/media/video/btcx-risc.h
@@ -2,8 +2,8 @@
*/
struct btcx_riscmem {
unsigned int size;
- u32 *cpu;
- u32 *jmp;
+ __le32 *cpu;
+ __le32 *jmp;
dma_addr_t dma;
};
diff --git a/linux/drivers/media/video/compat_ioctl32.c b/linux/drivers/media/video/compat_ioctl32.c
index 6b405e75c..017c2a8d4 100644
--- a/linux/drivers/media/video/compat_ioctl32.c
+++ b/linux/drivers/media/video/compat_ioctl32.c
@@ -12,7 +12,6 @@
* ioctls.
*/
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11)
#include <linux/compat.h>
#include <linux/videodev.h>
#include <linux/videodev2.h>
@@ -996,4 +995,3 @@ long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
EXPORT_SYMBOL_GPL(v4l_compat_ioctl32);
MODULE_LICENSE("GPL");
-#endif
diff --git a/linux/drivers/media/video/cs5345.c b/linux/drivers/media/video/cs5345.c
index d7bcb6d9e..e2f0b0278 100644
--- a/linux/drivers/media/video/cs5345.c
+++ b/linux/drivers/media/video/cs5345.c
@@ -34,21 +34,13 @@ MODULE_LICENSE("GPL");
static int debug;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
module_param(debug, bool, 0644);
-#else
-MODULE_PARM(debug, "i");
-#endif
MODULE_PARM_DESC(debug, "Debugging messages\n\t\t\t0=Off (default), 1=On");
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
static unsigned short normal_i2c[] = { 0x98 >> 1, I2C_CLIENT_END };
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 13)
-static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
-#endif
-
I2C_CLIENT_INSMOD;
#endif
@@ -174,13 +166,20 @@ static int cs5345_probe(struct i2c_client *client,
/* ----------------------------------------------------------------------- */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+static const struct i2c_device_id cs5345_id[] = {
+ { "cs5345", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, cs5345_id);
+
+#endif
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.name = "cs5345",
.driverid = I2C_DRIVERID_CS5345,
.command = cs5345_command,
.probe = cs5345_probe,
-};
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
-EXPORT_NO_SYMBOLS;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ .id_table = cs5345_id,
#endif
+};
diff --git a/linux/drivers/media/video/cs53l32a.c b/linux/drivers/media/video/cs53l32a.c
index e98574f42..bef0950e5 100644
--- a/linux/drivers/media/video/cs53l32a.c
+++ b/linux/drivers/media/video/cs53l32a.c
@@ -30,10 +30,6 @@
#include <media/v4l2-common.h>
#include <media/v4l2-chip-ident.h>
#include <media/v4l2-i2c-drv-legacy.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
-#include "i2c-compat.h"
-#include <linux/slab.h>
-#endif
#include "compat.h"
MODULE_DESCRIPTION("i2c device driver for cs53l32a Audio ADC");
@@ -42,20 +38,12 @@ MODULE_LICENSE("GPL");
static int debug;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
module_param(debug, bool, 0644);
-#else
-MODULE_PARM(debug, "i");
-#endif
MODULE_PARM_DESC(debug, "Debugging messages\n\t\t\t0=Off (default), 1=On");
static unsigned short normal_i2c[] = { 0x22 >> 1, I2C_CLIENT_END };
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 13)
-static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
-#endif
-
I2C_CLIENT_INSMOD;
/* ----------------------------------------------------------------------- */
@@ -156,7 +144,12 @@ static int cs53l32a_probe(struct i2c_client *client,
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -EIO;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
snprintf(client->name, sizeof(client->name) - 1, "cs53l32a");
+#else
+ if (!id)
+ strlcpy(client->name, "cs53l32a", sizeof(client->name));
+#endif
v4l_info(client, "chip found @ 0x%x (%s)\n",
client->addr << 1, client->adapter->name);
@@ -187,13 +180,20 @@ static int cs53l32a_probe(struct i2c_client *client,
return 0;
}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+static const struct i2c_device_id cs53l32a_id[] = {
+ { "cs53l32a", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, cs53l32a_id);
+
+#endif
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.name = "cs53l32a",
.driverid = I2C_DRIVERID_CS53L32A,
.command = cs53l32a_command,
.probe = cs53l32a_probe,
-};
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
-EXPORT_NO_SYMBOLS;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ .id_table = cs53l32a_id,
#endif
+};
diff --git a/linux/drivers/media/video/cx18/Kconfig b/linux/drivers/media/video/cx18/Kconfig
index 5f9426905..9aefdc5ea 100644
--- a/linux/drivers/media/video/cx18/Kconfig
+++ b/linux/drivers/media/video/cx18/Kconfig
@@ -10,8 +10,8 @@ config VIDEO_CX18
select VIDEO_TVEEPROM
select VIDEO_CX2341X
select VIDEO_CS5345
- select DVB_S5H1409
- select MEDIA_TUNER_MXL5005S
+ select DVB_S5H1409 if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_MXL5005S if !DVB_FE_CUSTOMISE
---help---
This is a video4linux driver for Conexant cx23418 based
PCI combo video recorder devices.
diff --git a/linux/drivers/media/video/cx18/cx18-audio.c b/linux/drivers/media/video/cx18/cx18-audio.c
index 1adc404d9..6d5b94fc7 100644
--- a/linux/drivers/media/video/cx18/cx18-audio.c
+++ b/linux/drivers/media/video/cx18/cx18-audio.c
@@ -26,13 +26,17 @@
#include "cx18-cards.h"
#include "cx18-audio.h"
+#define CX18_AUDIO_ENABLE 0xc72014
+
/* Selects the audio input and output according to the current
settings. */
int cx18_audio_set_io(struct cx18 *cx)
{
struct v4l2_routing route;
u32 audio_input;
+ u32 val;
int mux_input;
+ int err;
/* Determine which input to use */
if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) {
@@ -51,8 +55,17 @@ int cx18_audio_set_io(struct cx18 *cx)
cx18_i2c_hw(cx, cx->card->hw_muxer, VIDIOC_INT_S_AUDIO_ROUTING, &route);
route.input = audio_input;
- return cx18_i2c_hw(cx, cx->card->hw_audio_ctrl,
+ err = cx18_i2c_hw(cx, cx->card->hw_audio_ctrl,
VIDIOC_INT_S_AUDIO_ROUTING, &route);
+ if (err)
+ return err;
+
+ val = read_reg(CX18_AUDIO_ENABLE) & ~0x30;
+ val |= (audio_input > CX18_AV_AUDIO_SERIAL2) ? 0x20 :
+ (audio_input << 4);
+ write_reg(val | 0xb00, CX18_AUDIO_ENABLE);
+ cx18_vapi(cx, CX18_APU_RESETAI, 1, 0);
+ return 0;
}
void cx18_audio_set_route(struct cx18 *cx, struct v4l2_routing *route)
diff --git a/linux/drivers/media/video/cx18/cx18-av-audio.c b/linux/drivers/media/video/cx18/cx18-av-audio.c
index 2dc3a5dd1..c40a286de 100644
--- a/linux/drivers/media/video/cx18/cx18-av-audio.c
+++ b/linux/drivers/media/video/cx18/cx18-av-audio.c
@@ -34,7 +34,7 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq)
/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x10 */
cx18_av_write(cx, 0x127, 0x50);
- if (state->aud_input != CX18_AV_AUDIO_SERIAL) {
+ if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
switch (freq) {
case 32000:
/* VID_PLL and AUX_PLL */
@@ -148,7 +148,7 @@ void cx18_av_audio_set_path(struct cx18 *cx)
/* Mute everything to prevent the PFFT! */
cx18_av_write(cx, 0x8d3, 0x1f);
- if (state->aud_input == CX18_AV_AUDIO_SERIAL) {
+ if (state->aud_input <= CX18_AV_AUDIO_SERIAL2) {
/* Set Path1 to Serial Audio Input */
cx18_av_write4(cx, 0x8d0, 0x01011012);
@@ -165,7 +165,7 @@ void cx18_av_audio_set_path(struct cx18 *cx)
/* deassert soft reset */
cx18_av_and_or(cx, 0x810, ~0x1, 0x00);
- if (state->aud_input != CX18_AV_AUDIO_SERIAL) {
+ if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
/* When the microcontroller detects the
* audio format, it will unmute the lines */
cx18_av_and_or(cx, 0x803, ~0x10, 0x10);
@@ -271,7 +271,7 @@ static void set_mute(struct cx18 *cx, int mute)
{
struct cx18_av_state *state = &cx->av_state;
- if (state->aud_input != CX18_AV_AUDIO_SERIAL) {
+ if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
/* Must turn off microcontroller in order to mute sound.
* Not sure if this is the best method, but it does work.
* If the microcontroller is running, then it will undo any
@@ -298,14 +298,14 @@ int cx18_av_audio(struct cx18 *cx, unsigned int cmd, void *arg)
switch (cmd) {
case VIDIOC_INT_AUDIO_CLOCK_FREQ:
- if (state->aud_input != CX18_AV_AUDIO_SERIAL) {
+ if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
cx18_av_and_or(cx, 0x803, ~0x10, 0);
cx18_av_write(cx, 0x8d3, 0x1f);
}
cx18_av_and_or(cx, 0x810, ~0x1, 1);
retval = set_audclk_freq(cx, *(u32 *)arg);
cx18_av_and_or(cx, 0x810, ~0x1, 0);
- if (state->aud_input != CX18_AV_AUDIO_SERIAL)
+ if (state->aud_input > CX18_AV_AUDIO_SERIAL2)
cx18_av_and_or(cx, 0x803, ~0x10, 0x10);
return retval;
diff --git a/linux/drivers/media/video/cx18/cx18-av-core.c b/linux/drivers/media/video/cx18/cx18-av-core.c
index 9a2675161..3ccdf613b 100644
--- a/linux/drivers/media/video/cx18/cx18-av-core.c
+++ b/linux/drivers/media/video/cx18/cx18-av-core.c
@@ -169,12 +169,7 @@ static void input_change(struct cx18 *cx)
v4l2_std_id std = state->std;
/* Follow step 8c and 8d of section 3.16 in the cx18_av datasheet */
- if (std & V4L2_STD_SECAM)
- cx18_av_write(cx, 0x402, 0);
- else {
- cx18_av_write(cx, 0x402, 0x04);
- cx18_av_write(cx, 0x49f, (std & V4L2_STD_NTSC) ? 0x14 : 0x11);
- }
+ cx18_av_write(cx, 0x49f, (std & V4L2_STD_NTSC) ? 0x14 : 0x11);
cx18_av_and_or(cx, 0x401, ~0x60, 0);
cx18_av_and_or(cx, 0x401, ~0x60, 0x60);
@@ -228,7 +223,7 @@ static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input,
if ((vid_input & ~0xff0) ||
luma < CX18_AV_SVIDEO_LUMA1 ||
- luma > CX18_AV_SVIDEO_LUMA4 ||
+ luma > CX18_AV_SVIDEO_LUMA8 ||
chroma < CX18_AV_SVIDEO_CHROMA4 ||
chroma > CX18_AV_SVIDEO_CHROMA8) {
CX18_ERR("0x%04x is not a valid video input!\n",
@@ -246,7 +241,8 @@ static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input,
}
switch (aud_input) {
- case CX18_AV_AUDIO_SERIAL:
+ case CX18_AV_AUDIO_SERIAL1:
+ case CX18_AV_AUDIO_SERIAL2:
/* do nothing, use serial audio input */
break;
case CX18_AV_AUDIO4: reg &= ~0x30; break;
@@ -322,7 +318,7 @@ static int set_v4lstd(struct cx18 *cx)
/* Turn off LCOMB */
cx18_av_and_or(cx, 0x47b, ~6, 0);
}
- cx18_av_and_or(cx, 0x400, ~0xf, fmt);
+ cx18_av_and_or(cx, 0x400, ~0x2f, fmt | 0x20);
cx18_av_and_or(cx, 0x403, ~0x3, pal_m);
cx18_av_vbi_setup(cx);
input_change(cx);
diff --git a/linux/drivers/media/video/cx18/cx18-av-core.h b/linux/drivers/media/video/cx18/cx18-av-core.h
index 786901d72..b54239959 100644
--- a/linux/drivers/media/video/cx18/cx18-av-core.h
+++ b/linux/drivers/media/video/cx18/cx18-av-core.h
@@ -37,12 +37,16 @@ enum cx18_av_video_input {
CX18_AV_COMPOSITE7,
CX18_AV_COMPOSITE8,
- /* S-Video inputs consist of one luma input (In1-In4) ORed with one
+ /* S-Video inputs consist of one luma input (In1-In8) ORed with one
chroma input (In5-In8) */
CX18_AV_SVIDEO_LUMA1 = 0x10,
CX18_AV_SVIDEO_LUMA2 = 0x20,
CX18_AV_SVIDEO_LUMA3 = 0x30,
CX18_AV_SVIDEO_LUMA4 = 0x40,
+ CX18_AV_SVIDEO_LUMA5 = 0x50,
+ CX18_AV_SVIDEO_LUMA6 = 0x60,
+ CX18_AV_SVIDEO_LUMA7 = 0x70,
+ CX18_AV_SVIDEO_LUMA8 = 0x80,
CX18_AV_SVIDEO_CHROMA4 = 0x400,
CX18_AV_SVIDEO_CHROMA5 = 0x500,
CX18_AV_SVIDEO_CHROMA6 = 0x600,
@@ -58,7 +62,8 @@ enum cx18_av_video_input {
enum cx18_av_audio_input {
/* Audio inputs: serial or In4-In8 */
- CX18_AV_AUDIO_SERIAL,
+ CX18_AV_AUDIO_SERIAL1,
+ CX18_AV_AUDIO_SERIAL2,
CX18_AV_AUDIO4 = 4,
CX18_AV_AUDIO5,
CX18_AV_AUDIO6,
diff --git a/linux/drivers/media/video/cx18/cx18-av-firmware.c b/linux/drivers/media/video/cx18/cx18-av-firmware.c
index 526e14215..6fa3b01a1 100644
--- a/linux/drivers/media/video/cx18/cx18-av-firmware.c
+++ b/linux/drivers/media/video/cx18/cx18-av-firmware.c
@@ -22,6 +22,7 @@
#include "cx18-driver.h"
#include <linux/firmware.h>
+#define CX18_AUDIO_ENABLE 0xc72014
#define FWFILE "v4l-cx23418-dig.fw"
int cx18_av_loadfw(struct cx18 *cx)
@@ -31,40 +32,58 @@ int cx18_av_loadfw(struct cx18 *cx)
u32 v;
u8 *ptr;
int i;
+ int retries = 0;
if (request_firmware(&fw, FWFILE, &cx->dev->dev) != 0) {
CX18_ERR("unable to open firmware %s\n", FWFILE);
return -EINVAL;
}
- cx18_av_write4(cx, CXADEC_CHIP_CTRL, 0x00010000);
- cx18_av_write(cx, CXADEC_STD_DET_CTL, 0xf6); /* Byte 0 */
-
- /* Reset the Mako core (Register is undocumented.) */
- cx18_av_write4(cx, 0x8100, 0x00010000);
-
- /* Put the 8051 in reset and enable firmware upload */
- cx18_av_write4(cx, CXADEC_DL_CTL, 0x0F000000);
-
- ptr = fw->data;
- size = fw->size;
-
- for (i = 0; i < size; i++) {
- u32 dl_control = 0x0F000000 | ((u32)ptr[i] << 16);
- u32 value = 0;
- int retries;
-
- for (retries = 0; retries < 5; retries++) {
- cx18_av_write4(cx, CXADEC_DL_CTL, dl_control);
- value = cx18_av_read4(cx, CXADEC_DL_CTL);
- if ((value & 0x3F00) == (dl_control & 0x3F00))
+ /* The firmware load often has byte errors, so allow for several
+ retries, both at byte level and at the firmware load level. */
+ while (retries < 5) {
+ cx18_av_write4(cx, CXADEC_CHIP_CTRL, 0x00010000);
+ cx18_av_write(cx, CXADEC_STD_DET_CTL, 0xf6);
+
+ /* Reset the Mako core (Register is undocumented.) */
+ cx18_av_write4(cx, 0x8100, 0x00010000);
+
+ /* Put the 8051 in reset and enable firmware upload */
+ cx18_av_write4(cx, CXADEC_DL_CTL, 0x0F000000);
+
+ ptr = fw->data;
+ size = fw->size;
+
+ for (i = 0; i < size; i++) {
+ u32 dl_control = 0x0F000000 | i | ((u32)ptr[i] << 16);
+ u32 value = 0;
+ int retries;
+
+ for (retries = 0; retries < 5; retries++) {
+ cx18_av_write4(cx, CXADEC_DL_CTL, dl_control);
+ udelay(10);
+ value = cx18_av_read4(cx, CXADEC_DL_CTL);
+ if (value == dl_control)
+ break;
+ /* Check if we can correct the byte by changing
+ the address. We can only write the lower
+ address byte of the address. */
+ if ((value & 0x3F00) != (dl_control & 0x3F00)) {
+ retries = 5;
+ break;
+ }
+ }
+ if (retries >= 5)
break;
}
- if (retries >= 5) {
- CX18_ERR("unable to load firmware %s\n", FWFILE);
- release_firmware(fw);
- return -EIO;
- }
+ if (i == size)
+ break;
+ retries++;
+ }
+ if (retries >= 5) {
+ CX18_ERR("unable to load firmware %s\n", FWFILE);
+ release_firmware(fw);
+ return -EIO;
}
cx18_av_write4(cx, CXADEC_DL_CTL, 0x13000000 | fw->size);
@@ -100,7 +119,6 @@ int cx18_av_loadfw(struct cx18 *cx)
have a name in the spec. */
cx18_av_write4(cx, 0x09CC, 1);
-#define CX18_AUDIO_ENABLE 0xc72014
v = read_reg(CX18_AUDIO_ENABLE);
/* If bit 11 is 1 */
if (v & 0x800)
diff --git a/linux/drivers/media/video/cx18/cx18-av-vbi.c b/linux/drivers/media/video/cx18/cx18-av-vbi.c
index d09f1daf4..0c92f1236 100644
--- a/linux/drivers/media/video/cx18/cx18-av-vbi.c
+++ b/linux/drivers/media/video/cx18/cx18-av-vbi.c
@@ -108,18 +108,18 @@ void cx18_av_vbi_setup(struct cx18 *cx)
src_decimation = 0x21f;
luma_lpf = 2;
- if (std & V4L2_STD_SECAM) {
- uv_lpf = 0;
- comb = 0;
- sc = 0x0a425f;
- } else if (std == V4L2_STD_PAL_Nc) {
+ if (std & V4L2_STD_PAL) {
uv_lpf = 1;
comb = 0x20;
- sc = 556453;
- } else {
+ sc = 0x0a8263;
+ } else if (std == V4L2_STD_PAL_Nc) {
uv_lpf = 1;
comb = 0x20;
- sc = 0x0a8263;
+ sc = 0x087da5;
+ } else { /* SECAM */
+ uv_lpf = 0;
+ comb = 0;
+ sc = 0x0a425f;
}
} else {
hactive = 720;
@@ -127,25 +127,20 @@ void cx18_av_vbi_setup(struct cx18 *cx)
vactive = 487;
luma_lpf = 1;
uv_lpf = 1;
+ vblank = 26;
+ vblank656 = 26;
src_decimation = 0x21f;
if (std == V4L2_STD_PAL_60) {
- vblank = 26;
- vblank656 = 26;
burst = 0x5b;
luma_lpf = 2;
comb = 0x20;
sc = 0x0a8263;
} else if (std == V4L2_STD_PAL_M) {
- vblank = 20;
- vblank656 = 24;
burst = 0x61;
comb = 0x20;
-
sc = 555452;
} else {
- vblank = 26;
- vblank656 = 26;
burst = 0x5b;
comb = 0x66;
sc = 556063;
diff --git a/linux/drivers/media/video/cx18/cx18-cards.c b/linux/drivers/media/video/cx18/cx18-cards.c
index baccd0792..0caae1a5e 100644
--- a/linux/drivers/media/video/cx18/cx18-cards.c
+++ b/linux/drivers/media/video/cx18/cx18-cards.c
@@ -23,9 +23,12 @@
#include "cx18-driver.h"
#include "cx18-cards.h"
+#include "cx18-av-core.h"
#include "cx18-i2c.h"
#include <media/cs5345.h>
+#define V4L2_STD_PAL_SECAM (V4L2_STD_PAL|V4L2_STD_SECAM)
+
/********************** card configuration *******************************/
/* usual i2c tuner addresses to probe */
@@ -54,22 +57,22 @@ static const struct cx18_card cx18_card_hvr1600_esmt = {
.hw_all = CX18_HW_TVEEPROM | CX18_HW_TUNER |
CX18_HW_CS5345 | CX18_HW_DVB,
.video_inputs = {
- { CX18_CARD_INPUT_VID_TUNER, 0, CX23418_COMPOSITE7 },
- { CX18_CARD_INPUT_SVIDEO1, 1, CX23418_SVIDEO1 },
- { CX18_CARD_INPUT_COMPOSITE1, 1, CX23418_COMPOSITE3 },
- { CX18_CARD_INPUT_SVIDEO2, 2, CX23418_SVIDEO2 },
- { CX18_CARD_INPUT_COMPOSITE2, 2, CX23418_COMPOSITE4 },
+ { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE7 },
+ { CX18_CARD_INPUT_SVIDEO1, 1, CX18_AV_SVIDEO1 },
+ { CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE3 },
+ { CX18_CARD_INPUT_SVIDEO2, 2, CX18_AV_SVIDEO2 },
+ { CX18_CARD_INPUT_COMPOSITE2, 2, CX18_AV_COMPOSITE4 },
},
.audio_inputs = {
{ CX18_CARD_INPUT_AUD_TUNER,
- CX23418_AUDIO8, CS5345_IN_1 | CS5345_MCLK_1_5 },
+ CX18_AV_AUDIO8, CS5345_IN_1 | CS5345_MCLK_1_5 },
{ CX18_CARD_INPUT_LINE_IN1,
- CX23418_AUDIO_SERIAL, CS5345_IN_2 },
+ CX18_AV_AUDIO_SERIAL1, CS5345_IN_2 },
{ CX18_CARD_INPUT_LINE_IN2,
- CX23418_AUDIO_SERIAL, CS5345_IN_2 },
+ CX18_AV_AUDIO_SERIAL1, CS5345_IN_3 },
},
.radio_input = { CX18_CARD_INPUT_AUD_TUNER,
- CX23418_AUDIO_SERIAL, 0 },
+ CX18_AV_AUDIO_SERIAL1, CS5345_IN_4 },
.ddr = {
/* ESMT M13S128324A-5B memory */
.chip_config = 0x003,
@@ -81,6 +84,11 @@ static const struct cx18_card cx18_card_hvr1600_esmt = {
},
.gpio_init.initial_value = 0x3001,
.gpio_init.direction = 0x3001,
+ .gpio_i2c_slave_reset = {
+ .active_lo_mask = 0x3001,
+ .msecs_asserted = 10,
+ .msecs_recovery = 40,
+ },
.i2c = &cx18_i2c_std,
};
@@ -94,22 +102,22 @@ static const struct cx18_card cx18_card_hvr1600_samsung = {
.hw_all = CX18_HW_TVEEPROM | CX18_HW_TUNER |
CX18_HW_CS5345 | CX18_HW_DVB,
.video_inputs = {
- { CX18_CARD_INPUT_VID_TUNER, 0, CX23418_COMPOSITE7 },
- { CX18_CARD_INPUT_SVIDEO1, 1, CX23418_SVIDEO1 },
- { CX18_CARD_INPUT_COMPOSITE1, 1, CX23418_COMPOSITE3 },
- { CX18_CARD_INPUT_SVIDEO2, 2, CX23418_SVIDEO2 },
- { CX18_CARD_INPUT_COMPOSITE2, 2, CX23418_COMPOSITE4 },
+ { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE7 },
+ { CX18_CARD_INPUT_SVIDEO1, 1, CX18_AV_SVIDEO1 },
+ { CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE3 },
+ { CX18_CARD_INPUT_SVIDEO2, 2, CX18_AV_SVIDEO2 },
+ { CX18_CARD_INPUT_COMPOSITE2, 2, CX18_AV_COMPOSITE4 },
},
.audio_inputs = {
{ CX18_CARD_INPUT_AUD_TUNER,
- CX23418_AUDIO8, CS5345_IN_1 | CS5345_MCLK_1_5 },
+ CX18_AV_AUDIO8, CS5345_IN_1 | CS5345_MCLK_1_5 },
{ CX18_CARD_INPUT_LINE_IN1,
- CX23418_AUDIO_SERIAL, CS5345_IN_2 },
+ CX18_AV_AUDIO_SERIAL1, CS5345_IN_2 },
{ CX18_CARD_INPUT_LINE_IN2,
- CX23418_AUDIO_SERIAL, CS5345_IN_2 },
+ CX18_AV_AUDIO_SERIAL1, CS5345_IN_3 },
},
.radio_input = { CX18_CARD_INPUT_AUD_TUNER,
- CX23418_AUDIO_SERIAL, 0 },
+ CX18_AV_AUDIO_SERIAL1, CS5345_IN_4 },
.ddr = {
/* Samsung K4D263238G-VC33 memory */
.chip_config = 0x003,
@@ -121,6 +129,11 @@ static const struct cx18_card cx18_card_hvr1600_samsung = {
},
.gpio_init.initial_value = 0x3001,
.gpio_init.direction = 0x3001,
+ .gpio_i2c_slave_reset = {
+ .active_lo_mask = 0x3001,
+ .msecs_asserted = 10,
+ .msecs_recovery = 40,
+ },
.i2c = &cx18_i2c_std,
};
@@ -141,19 +154,19 @@ static const struct cx18_card cx18_card_h900 = {
.hw_audio_ctrl = CX18_HW_CX23418,
.hw_all = CX18_HW_TUNER,
.video_inputs = {
- { CX18_CARD_INPUT_VID_TUNER, 0, CX23418_COMPOSITE2 },
+ { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE2 },
{ CX18_CARD_INPUT_SVIDEO1, 1,
- CX23418_SVIDEO_LUMA3 | CX23418_SVIDEO_CHROMA4 },
- { CX18_CARD_INPUT_COMPOSITE1, 1, CX23418_COMPOSITE1 },
+ CX18_AV_SVIDEO_LUMA3 | CX18_AV_SVIDEO_CHROMA4 },
+ { CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE1 },
},
.audio_inputs = {
{ CX18_CARD_INPUT_AUD_TUNER,
- CX23418_AUDIO8, 0 },
+ CX18_AV_AUDIO8, 0 },
{ CX18_CARD_INPUT_LINE_IN1,
- CX23418_AUDIO_SERIAL, 0 },
+ CX18_AV_AUDIO_SERIAL1, 0 },
},
.radio_input = { CX18_CARD_INPUT_AUD_TUNER,
- CX23418_AUDIO_SERIAL, 0 },
+ CX18_AV_AUDIO_SERIAL1, 0 },
.tuners = {
{ .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
},
@@ -183,23 +196,26 @@ static const struct cx18_card_pci_info cx18_pci_mpc718[] = {
static const struct cx18_card cx18_card_mpc718 = {
.type = CX18_CARD_YUAN_MPC718,
.name = "Yuan MPC718",
- .comment = "Not yet supported!\n",
- .v4l2_capabilities = 0,
+ .comment = "Analog video capture works; some audio line in may not.\n",
+ .v4l2_capabilities = CX18_CAP_ENCODER,
.hw_audio_ctrl = CX18_HW_CX23418,
.hw_all = CX18_HW_TUNER,
.video_inputs = {
- { CX18_CARD_INPUT_VID_TUNER, 0, CX23418_COMPOSITE7 },
- { CX18_CARD_INPUT_SVIDEO1, 1, CX23418_SVIDEO1 },
- { CX18_CARD_INPUT_COMPOSITE1, 1, CX23418_COMPOSITE3 },
+ { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE2 },
+ { CX18_CARD_INPUT_SVIDEO1, 1,
+ CX18_AV_SVIDEO_LUMA3 | CX18_AV_SVIDEO_CHROMA4 },
+ { CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE1 },
+ { CX18_CARD_INPUT_SVIDEO2, 2,
+ CX18_AV_SVIDEO_LUMA7 | CX18_AV_SVIDEO_CHROMA8 },
+ { CX18_CARD_INPUT_COMPOSITE2, 2, CX18_AV_COMPOSITE6 },
+ { CX18_CARD_INPUT_COMPOSITE3, 2, CX18_AV_COMPOSITE3 },
},
.audio_inputs = {
- { CX18_CARD_INPUT_AUD_TUNER,
- CX23418_AUDIO8, 0 },
- { CX18_CARD_INPUT_LINE_IN1,
- CX23418_AUDIO_SERIAL, 0 },
+ { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 0 },
+ { CX18_CARD_INPUT_LINE_IN1, CX18_AV_AUDIO_SERIAL1, 0 },
+ { CX18_CARD_INPUT_LINE_IN2, CX18_AV_AUDIO_SERIAL1, 0 },
},
- .radio_input = { CX18_CARD_INPUT_AUD_TUNER,
- CX23418_AUDIO_SERIAL, 0 },
+ .radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO_SERIAL1, 0 },
.tuners = {
/* XC3028 tuner */
{ .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
@@ -213,16 +229,73 @@ static const struct cx18_card cx18_card_mpc718 = {
.tune_lane = 0,
.initial_emrs = 2,
},
- .xceive_pin = 15,
+ .xceive_pin = 0,
.pci_list = cx18_pci_mpc718,
.i2c = &cx18_i2c_std,
};
+/* ------------------------------------------------------------------------- */
+
+/* Conexant Raptor PAL/SECAM: note that this card is analog only! */
+
+static const struct cx18_card_pci_info cx18_pci_cnxt_raptor_pal[] = {
+ { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_CONEXANT, 0x0009 },
+ { 0, 0, 0 }
+};
+
+static const struct cx18_card cx18_card_cnxt_raptor_pal = {
+ .type = CX18_CARD_CNXT_RAPTOR_PAL,
+ .name = "Conexant Raptor PAL/SECAM",
+ .comment = "VBI is not yet supported\n",
+ .v4l2_capabilities = CX18_CAP_ENCODER,
+ .hw_audio_ctrl = CX18_HW_CX23418,
+ .hw_muxer = CX18_HW_GPIO,
+ .hw_all = CX18_HW_TUNER | CX18_HW_GPIO,
+ .video_inputs = {
+ { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE2 },
+ { CX18_CARD_INPUT_SVIDEO1, 1,
+ CX18_AV_SVIDEO_LUMA3 | CX18_AV_SVIDEO_CHROMA4 },
+ { CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE1 },
+ { CX18_CARD_INPUT_SVIDEO2, 2,
+ CX18_AV_SVIDEO_LUMA7 | CX18_AV_SVIDEO_CHROMA8 },
+ { CX18_CARD_INPUT_COMPOSITE2, 2, CX18_AV_COMPOSITE6 },
+ },
+ .audio_inputs = {
+ { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 0 },
+ { CX18_CARD_INPUT_LINE_IN1, CX18_AV_AUDIO_SERIAL1, 1 },
+ { CX18_CARD_INPUT_LINE_IN2, CX18_AV_AUDIO_SERIAL2, 1 },
+ },
+ .tuners = {
+ { .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
+ },
+ .radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO_SERIAL1, 2 },
+ .ddr = {
+ /* MT 46V16M16 memory */
+ .chip_config = 0x50306,
+ .refresh = 0x753,
+ .timing1 = 0x33220953,
+ .timing2 = 0x09,
+ .tune_lane = 0,
+ .initial_emrs = 0,
+ },
+ .gpio_init.initial_value = 0x1002,
+ .gpio_init.direction = 0xf002,
+ .gpio_audio_input = { .mask = 0xf002,
+ .tuner = 0x1002, /* LED D1 Tuner AF */
+ .linein = 0x2000, /* LED D2 Line In 1 */
+ .radio = 0x4002 }, /* LED D3 Tuner AF */
+ .pci_list = cx18_pci_cnxt_raptor_pal,
+ .i2c = &cx18_i2c_std,
+};
+
+/* ------------------------------------------------------------------------- */
+
static const struct cx18_card *cx18_card_list[] = {
&cx18_card_hvr1600_esmt,
&cx18_card_hvr1600_samsung,
&cx18_card_h900,
&cx18_card_mpc718,
+ &cx18_card_cnxt_raptor_pal,
};
const struct cx18_card *cx18_get_card(u16 index)
diff --git a/linux/drivers/media/video/cx18/cx18-cards.h b/linux/drivers/media/video/cx18/cx18-cards.h
index bccb67f0d..dc283d756 100644
--- a/linux/drivers/media/video/cx18/cx18-cards.h
+++ b/linux/drivers/media/video/cx18/cx18-cards.h
@@ -36,36 +36,6 @@
#define CX18_CARD_INPUT_COMPOSITE2 5
#define CX18_CARD_INPUT_COMPOSITE3 6
-enum cx34180_video_input {
- /* Composite video inputs In1-In8 */
- CX23418_COMPOSITE1 = 1,
- CX23418_COMPOSITE2,
- CX23418_COMPOSITE3,
- CX23418_COMPOSITE4,
- CX23418_COMPOSITE5,
- CX23418_COMPOSITE6,
- CX23418_COMPOSITE7,
- CX23418_COMPOSITE8,
-
- /* S-Video inputs consist of one luma input (In1-In4) ORed with one
- chroma input (In5-In8) */
- CX23418_SVIDEO_LUMA1 = 0x10,
- CX23418_SVIDEO_LUMA2 = 0x20,
- CX23418_SVIDEO_LUMA3 = 0x30,
- CX23418_SVIDEO_LUMA4 = 0x40,
- CX23418_SVIDEO_CHROMA4 = 0x400,
- CX23418_SVIDEO_CHROMA5 = 0x500,
- CX23418_SVIDEO_CHROMA6 = 0x600,
- CX23418_SVIDEO_CHROMA7 = 0x700,
- CX23418_SVIDEO_CHROMA8 = 0x800,
-
- /* S-Video aliases for common luma/chroma combinations */
- CX23418_SVIDEO1 = 0x510,
- CX23418_SVIDEO2 = 0x620,
- CX23418_SVIDEO3 = 0x730,
- CX23418_SVIDEO4 = 0x840,
-};
-
/* audio inputs */
#define CX18_CARD_INPUT_AUD_TUNER 1
#define CX18_CARD_INPUT_LINE_IN1 2
@@ -75,16 +45,6 @@ enum cx34180_video_input {
#define CX18_CARD_MAX_AUDIO_INPUTS 3
#define CX18_CARD_MAX_TUNERS 2
-enum cx23418_audio_input {
- /* Audio inputs: serial or In4-In8 */
- CX23418_AUDIO_SERIAL,
- CX23418_AUDIO4 = 4,
- CX23418_AUDIO5,
- CX23418_AUDIO6,
- CX23418_AUDIO7,
- CX23418_AUDIO8,
-};
-
/* V4L2 capability aliases */
#define CX18_CAP_ENCODER (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | \
V4L2_CAP_AUDIO | V4L2_CAP_READWRITE)
@@ -118,6 +78,20 @@ struct cx18_gpio_init { /* set initial GPIO DIR and OUT values */
u32 initial_value;
};
+struct cx18_gpio_i2c_slave_reset {
+ u32 active_lo_mask; /* GPIO outputs that reset i2c chips when low */
+ u32 active_hi_mask; /* GPIO outputs that reset i2c chips when high */
+ int msecs_asserted; /* time period reset must remain asserted */
+ int msecs_recovery; /* time after deassert for chips to be ready */
+};
+
+struct cx18_gpio_audio_input { /* select tuner/line in input */
+ u32 mask; /* leave to 0 if not supported */
+ u32 tuner;
+ u32 linein;
+ u32 radio;
+};
+
struct cx18_card_tuner {
v4l2_std_id std; /* standard for which the tuner is suitable */
int tuner; /* tuner ID (from tuner.h) */
@@ -154,7 +128,9 @@ struct cx18_card {
/* GPIO card-specific settings */
u8 xceive_pin; /* XCeive tuner GPIO reset pin */
- struct cx18_gpio_init gpio_init;
+ struct cx18_gpio_init gpio_init;
+ struct cx18_gpio_i2c_slave_reset gpio_i2c_slave_reset;
+ struct cx18_gpio_audio_input gpio_audio_input;
struct cx18_card_tuner tuners[CX18_CARD_MAX_TUNERS];
struct cx18_card_tuner_i2c *i2c;
diff --git a/linux/drivers/media/video/cx18/cx18-controls.c b/linux/drivers/media/video/cx18/cx18-controls.c
index 87cf41021..f46c7e5ed 100644
--- a/linux/drivers/media/video/cx18/cx18-controls.c
+++ b/linux/drivers/media/video/cx18/cx18-controls.c
@@ -51,12 +51,11 @@ static const u32 *ctrl_classes[] = {
NULL
};
-static int cx18_queryctrl(struct cx18 *cx, struct v4l2_queryctrl *qctrl)
+int cx18_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qctrl)
{
+ struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
const char *name;
- CX18_DEBUG_IOCTL("VIDIOC_QUERYCTRL(%08x)\n", qctrl->id);
-
qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
if (qctrl->id == 0)
return -EINVAL;
@@ -91,21 +90,35 @@ static int cx18_queryctrl(struct cx18 *cx, struct v4l2_queryctrl *qctrl)
return 0;
}
-static int cx18_querymenu(struct cx18 *cx, struct v4l2_querymenu *qmenu)
+int cx18_querymenu(struct file *file, void *fh, struct v4l2_querymenu *qmenu)
{
+ struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
struct v4l2_queryctrl qctrl;
qctrl.id = qmenu->id;
- cx18_queryctrl(cx, &qctrl);
- return v4l2_ctrl_query_menu(qmenu, &qctrl, cx2341x_ctrl_get_menu(qmenu->id));
+ cx18_queryctrl(file, fh, &qctrl);
+ return v4l2_ctrl_query_menu(qmenu, &qctrl,
+ cx2341x_ctrl_get_menu(&cx->params, qmenu->id));
}
-static int cx18_s_ctrl(struct cx18 *cx, struct v4l2_control *vctrl)
+static int cx18_try_ctrl(struct file *file, void *fh,
+ struct v4l2_ext_control *vctrl)
{
- s32 v = vctrl->value;
-
- CX18_DEBUG_IOCTL("VIDIOC_S_CTRL(%08x, %x)\n", vctrl->id, v);
+ struct v4l2_queryctrl qctrl;
+ const char **menu_items = NULL;
+ int err;
+
+ qctrl.id = vctrl->id;
+ err = cx18_queryctrl(file, fh, &qctrl);
+ if (err)
+ return err;
+ if (qctrl.type == V4L2_CTRL_TYPE_MENU)
+ menu_items = v4l2_ctrl_get_menu(qctrl.id);
+ return v4l2_ctrl_check(vctrl, &qctrl, menu_items);
+}
+static int cx18_s_ctrl(struct cx18 *cx, struct v4l2_control *vctrl)
+{
switch (vctrl->id) {
/* Standard V4L2 controls */
case V4L2_CID_BRIGHTNESS:
@@ -123,7 +136,7 @@ static int cx18_s_ctrl(struct cx18 *cx, struct v4l2_control *vctrl)
return cx18_i2c_hw(cx, cx->card->hw_audio_ctrl, VIDIOC_S_CTRL, vctrl);
default:
- CX18_DEBUG_IOCTL("invalid control %x\n", vctrl->id);
+ CX18_DEBUG_IOCTL("invalid control 0x%x\n", vctrl->id);
return -EINVAL;
}
return 0;
@@ -131,8 +144,6 @@ static int cx18_s_ctrl(struct cx18 *cx, struct v4l2_control *vctrl)
static int cx18_g_ctrl(struct cx18 *cx, struct v4l2_control *vctrl)
{
- CX18_DEBUG_IOCTL("VIDIOC_G_CTRL(%08x)\n", vctrl->id);
-
switch (vctrl->id) {
/* Standard V4L2 controls */
case V4L2_CID_BRIGHTNESS:
@@ -149,7 +160,7 @@ static int cx18_g_ctrl(struct cx18 *cx, struct v4l2_control *vctrl)
case V4L2_CID_AUDIO_LOUDNESS:
return cx18_i2c_hw(cx, cx->card->hw_audio_ctrl, VIDIOC_G_CTRL, vctrl);
default:
- CX18_DEBUG_IOCTL("invalid control %x\n", vctrl->id);
+ CX18_DEBUG_IOCTL("invalid control 0x%x\n", vctrl->id);
return -EINVAL;
}
return 0;
@@ -194,113 +205,110 @@ static int cx18_setup_vbi_fmt(struct cx18 *cx, enum v4l2_mpeg_stream_vbi_fmt fmt
return 0;
}
-int cx18_control_ioctls(struct cx18 *cx, unsigned int cmd, void *arg)
+int cx18_g_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
{
+ struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
struct v4l2_control ctrl;
- switch (cmd) {
- case VIDIOC_QUERYMENU:
- CX18_DEBUG_IOCTL("VIDIOC_QUERYMENU\n");
- return cx18_querymenu(cx, arg);
-
- case VIDIOC_QUERYCTRL:
- return cx18_queryctrl(cx, arg);
-
- case VIDIOC_S_CTRL:
- return cx18_s_ctrl(cx, arg);
-
- case VIDIOC_G_CTRL:
- return cx18_g_ctrl(cx, arg);
-
- case VIDIOC_S_EXT_CTRLS:
- {
- struct v4l2_ext_controls *c = arg;
-
- if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
- int i;
- int err = 0;
-
- for (i = 0; i < c->count; i++) {
- ctrl.id = c->controls[i].id;
- ctrl.value = c->controls[i].value;
- err = cx18_s_ctrl(cx, &ctrl);
- c->controls[i].value = ctrl.value;
- if (err) {
- c->error_idx = i;
- break;
- }
+ if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
+ int i;
+ int err = 0;
+
+ for (i = 0; i < c->count; i++) {
+ ctrl.id = c->controls[i].id;
+ ctrl.value = c->controls[i].value;
+ err = cx18_g_ctrl(cx, &ctrl);
+ c->controls[i].value = ctrl.value;
+ if (err) {
+ c->error_idx = i;
+ break;
}
- return err;
}
- CX18_DEBUG_IOCTL("VIDIOC_S_EXT_CTRLS\n");
- if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
- struct cx2341x_mpeg_params p = cx->params;
- int err = cx2341x_ext_ctrls(&p, atomic_read(&cx->ana_capturing), arg, cmd);
+ return err;
+ }
+ if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG)
+ return cx2341x_ext_ctrls(&cx->params, 0, c, VIDIOC_G_EXT_CTRLS);
+ return -EINVAL;
+}
- if (err)
- return err;
+int cx18_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
+{
+ struct cx18_open_id *id = fh;
+ struct cx18 *cx = id->cx;
+ int ret;
+ struct v4l2_control ctrl;
- if (p.video_encoding != cx->params.video_encoding) {
- int is_mpeg1 = p.video_encoding ==
- V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
- struct v4l2_format fmt;
+ ret = v4l2_prio_check(&cx->prio, &id->prio);
+ if (ret)
+ return ret;
- /* fix videodecoder resolution */
- fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- fmt.fmt.pix.width = cx->params.width / (is_mpeg1 ? 2 : 1);
- fmt.fmt.pix.height = cx->params.height;
- cx18_av_cmd(cx, VIDIOC_S_FMT, &fmt);
+ if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
+ int i;
+ int err = 0;
+
+ for (i = 0; i < c->count; i++) {
+ ctrl.id = c->controls[i].id;
+ ctrl.value = c->controls[i].value;
+ err = cx18_s_ctrl(cx, &ctrl);
+ c->controls[i].value = ctrl.value;
+ if (err) {
+ c->error_idx = i;
+ break;
}
- err = cx2341x_update(cx, cx18_api_func, &cx->params, &p);
- if (!err && cx->params.stream_vbi_fmt != p.stream_vbi_fmt)
- err = cx18_setup_vbi_fmt(cx, p.stream_vbi_fmt);
- cx->params = p;
- cx->dualwatch_stereo_mode = p.audio_properties & 0x0300;
- cx18_audio_set_audio_clock_freq(cx, p.audio_properties & 0x03);
- return err;
}
- return -EINVAL;
+ return err;
}
+ if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
+ struct cx2341x_mpeg_params p = cx->params;
+ int err = cx2341x_ext_ctrls(&p, atomic_read(&cx->ana_capturing),
+ c, VIDIOC_S_EXT_CTRLS);
- case VIDIOC_G_EXT_CTRLS:
- {
- struct v4l2_ext_controls *c = arg;
-
- if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
- int i;
- int err = 0;
-
- for (i = 0; i < c->count; i++) {
- ctrl.id = c->controls[i].id;
- ctrl.value = c->controls[i].value;
- err = cx18_g_ctrl(cx, &ctrl);
- c->controls[i].value = ctrl.value;
- if (err) {
- c->error_idx = i;
- break;
- }
- }
+ if (err)
return err;
+
+ if (p.video_encoding != cx->params.video_encoding) {
+ int is_mpeg1 = p.video_encoding ==
+ V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
+ struct v4l2_format fmt;
+
+ /* fix videodecoder resolution */
+ fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ fmt.fmt.pix.width = cx->params.width
+ / (is_mpeg1 ? 2 : 1);
+ fmt.fmt.pix.height = cx->params.height;
+ cx18_av_cmd(cx, VIDIOC_S_FMT, &fmt);
}
- CX18_DEBUG_IOCTL("VIDIOC_G_EXT_CTRLS\n");
- if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG)
- return cx2341x_ext_ctrls(&cx->params, 0, arg, cmd);
- return -EINVAL;
+ err = cx2341x_update(cx, cx18_api_func, &cx->params, &p);
+ if (!err && cx->params.stream_vbi_fmt != p.stream_vbi_fmt)
+ err = cx18_setup_vbi_fmt(cx, p.stream_vbi_fmt);
+ cx->params = p;
+ cx->dualwatch_stereo_mode = p.audio_properties & 0x0300;
+ cx18_audio_set_audio_clock_freq(cx, p.audio_properties & 0x03);
+ return err;
}
+ return -EINVAL;
+}
- case VIDIOC_TRY_EXT_CTRLS:
- {
- struct v4l2_ext_controls *c = arg;
+int cx18_try_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
+{
+ struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
- CX18_DEBUG_IOCTL("VIDIOC_TRY_EXT_CTRLS\n");
- if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG)
- return cx2341x_ext_ctrls(&cx->params,
- atomic_read(&cx->ana_capturing), arg, cmd);
- return -EINVAL;
- }
+ if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
+ int i;
+ int err = 0;
- default:
- return -EINVAL;
+ for (i = 0; i < c->count; i++) {
+ err = cx18_try_ctrl(file, fh, &c->controls[i]);
+ if (err) {
+ c->error_idx = i;
+ break;
+ }
+ }
+ return err;
}
- return 0;
+ if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG)
+ return cx2341x_ext_ctrls(&cx->params,
+ atomic_read(&cx->ana_capturing),
+ c, VIDIOC_TRY_EXT_CTRLS);
+ return -EINVAL;
}
diff --git a/linux/drivers/media/video/cx18/cx18-controls.h b/linux/drivers/media/video/cx18/cx18-controls.h
index 6e985cf42..e46323700 100644
--- a/linux/drivers/media/video/cx18/cx18-controls.h
+++ b/linux/drivers/media/video/cx18/cx18-controls.h
@@ -21,4 +21,9 @@
* 02111-1307 USA
*/
-int cx18_control_ioctls(struct cx18 *cx, unsigned int cmd, void *arg);
+int cx18_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *a);
+int cx18_g_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *a);
+int cx18_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *a);
+int cx18_try_ext_ctrls(struct file *file, void *fh,
+ struct v4l2_ext_controls *a);
+int cx18_querymenu(struct file *file, void *fh, struct v4l2_querymenu *a);
diff --git a/linux/drivers/media/video/cx18/cx18-driver.c b/linux/drivers/media/video/cx18/cx18-driver.c
index d654b1d6e..e73de6252 100644
--- a/linux/drivers/media/video/cx18/cx18-driver.c
+++ b/linux/drivers/media/video/cx18/cx18-driver.c
@@ -120,6 +120,7 @@ MODULE_PARM_DESC(cardtype,
"\t\t\t 2 = Hauppauge HVR 1600 (Samsung memory)\n"
"\t\t\t 3 = Compro VideoMate H900\n"
"\t\t\t 4 = Yuan MPC718\n"
+ "\t\t\t 5 = Conexant Raptor PAL/SECAM\n"
"\t\t\t 0 = Autodetect (default)\n"
"\t\t\t-1 = Ignore this card\n\t\t");
MODULE_PARM_DESC(pal, "Set PAL standard: B, G, H, D, K, I, M, N, Nc, 60");
@@ -435,7 +436,7 @@ static int __devinit cx18_init_struct1(struct cx18 *cx)
(cx->params.video_temporal_filter_mode << 1) |
(cx->params.video_median_filter_type << 2);
cx->params.port = CX2341X_PORT_MEMORY;
- cx->params.capabilities = CX2341X_CAP_HAS_SLICED_VBI;
+ cx->params.capabilities = CX2341X_CAP_HAS_TS;
init_waitqueue_head(&cx->cap_w);
init_waitqueue_head(&cx->mb_apu_waitq);
init_waitqueue_head(&cx->mb_cpu_waitq);
@@ -670,7 +671,7 @@ static int __devinit cx18_probe(struct pci_dev *dev,
cx18_init_power(cx, 1);
cx18_init_memory(cx);
- cx->scb = (struct cx18_scb *)(cx->enc_mem + SCB_OFFSET);
+ cx->scb = (struct cx18_scb __iomem *)(cx->enc_mem + SCB_OFFSET);
cx18_init_scb(cx);
cx18_gpio_init(cx);
@@ -721,6 +722,12 @@ static int __devinit cx18_probe(struct pci_dev *dev,
/* if no tuner was found, then pick the first tuner in the card list */
if (cx->options.tuner == -1 && cx->card->tuners[0].std) {
cx->std = cx->card->tuners[0].std;
+ if (cx->std & V4L2_STD_PAL)
+ cx->std = V4L2_STD_PAL_BG | V4L2_STD_PAL_H;
+ else if (cx->std & V4L2_STD_NTSC)
+ cx->std = V4L2_STD_NTSC_M;
+ else if (cx->std & V4L2_STD_SECAM)
+ cx->std = V4L2_STD_SECAM_L;
cx->options.tuner = cx->card->tuners[0].tuner;
}
if (cx->options.radio == -1)
@@ -751,17 +758,6 @@ static int __devinit cx18_probe(struct pci_dev *dev,
if (cx->options.radio > 0)
cx->v4l2_cap |= V4L2_CAP_RADIO;
- retval = cx18_streams_setup(cx);
- if (retval) {
- CX18_ERR("Error %d setting up streams\n", retval);
- goto free_irq;
- }
- retval = cx18_streams_register(cx);
- if (retval) {
- CX18_ERR("Error %d registering devices\n", retval);
- goto free_streams;
- }
-
if (cx->options.tuner > -1) {
struct tuner_setup setup;
@@ -788,7 +784,16 @@ static int __devinit cx18_probe(struct pci_dev *dev,
are not. */
cx->tuner_std = cx->std;
- cx18_init_on_first_open(cx);
+ retval = cx18_streams_setup(cx);
+ if (retval) {
+ CX18_ERR("Error %d setting up streams\n", retval);
+ goto free_irq;
+ }
+ retval = cx18_streams_register(cx);
+ if (retval) {
+ CX18_ERR("Error %d registering devices\n", retval);
+ goto free_streams;
+ }
CX18_INFO("Initialized card #%d: %s\n", cx->num, cx->card_name);
@@ -820,6 +825,9 @@ int cx18_init_on_first_open(struct cx18 *cx)
int video_input;
int fw_retry_count = 3;
struct v4l2_frequency vf;
+ struct cx18_open_id fh;
+
+ fh.cx = cx;
if (test_bit(CX18_F_I_FAILED, &cx->i_flags))
return -ENXIO;
@@ -871,13 +879,13 @@ int cx18_init_on_first_open(struct cx18 *cx)
video_input = cx->active_input;
cx->active_input++; /* Force update of input */
- cx18_v4l2_ioctls(cx, NULL, VIDIOC_S_INPUT, &video_input);
+ cx18_s_input(NULL, &fh, video_input);
/* Let the VIDIOC_S_STD ioctl do all the work, keeps the code
in one place. */
cx->std++; /* Force full standard initialization */
- cx18_v4l2_ioctls(cx, NULL, VIDIOC_S_STD, &cx->tuner_std);
- cx18_v4l2_ioctls(cx, NULL, VIDIOC_S_FREQUENCY, &vf);
+ cx18_s_std(NULL, &fh, &cx->tuner_std);
+ cx18_s_frequency(NULL, &fh, &vf);
return 0;
}
diff --git a/linux/drivers/media/video/cx18/cx18-driver.h b/linux/drivers/media/video/cx18/cx18-driver.h
index d2b563f98..e4f1accd2 100644
--- a/linux/drivers/media/video/cx18/cx18-driver.h
+++ b/linux/drivers/media/video/cx18/cx18-driver.h
@@ -77,7 +77,8 @@
#define CX18_CARD_HVR_1600_SAMSUNG 1 /* Hauppauge HVR 1600 (Samsung memory) */
#define CX18_CARD_COMPRO_H900 2 /* Compro VideoMate H900 */
#define CX18_CARD_YUAN_MPC718 3 /* Yuan MPC718 */
-#define CX18_CARD_LAST 3
+#define CX18_CARD_CNXT_RAPTOR_PAL 4 /* Conexant Raptor PAL */
+#define CX18_CARD_LAST 4
#define CX18_ENC_STREAM_TYPE_MPG 0
#define CX18_ENC_STREAM_TYPE_TS 1
@@ -96,6 +97,7 @@
#define CX18_PCI_ID_HAUPPAUGE 0x0070
#define CX18_PCI_ID_COMPRO 0x185b
#define CX18_PCI_ID_YUAN 0x12ab
+#define CX18_PCI_ID_CONEXANT 0x14f1
/* ======================================================================== */
/* ========================== START USER SETTABLE DMA VARIABLES =========== */
@@ -364,7 +366,7 @@ struct cx18 {
u32 v4l2_cap; /* V4L2 capabilities of card */
u32 hw_flags; /* Hardware description of the board */
unsigned mdl_offset;
- struct cx18_scb *scb; /* pointer to SCB */
+ struct cx18_scb __iomem *scb; /* pointer to SCB */
struct cx18_av_state av_state;
diff --git a/linux/drivers/media/video/cx18/cx18-dvb.c b/linux/drivers/media/video/cx18/cx18-dvb.c
index c9744173f..cae38985b 100644
--- a/linux/drivers/media/video/cx18/cx18-dvb.c
+++ b/linux/drivers/media/video/cx18/cx18-dvb.c
@@ -69,11 +69,21 @@ static int cx18_dvb_start_feed(struct dvb_demux_feed *feed)
struct dvb_demux *demux = feed->demux;
struct cx18_stream *stream = (struct cx18_stream *) demux->priv;
struct cx18 *cx = stream->cx;
- int ret = -EINVAL;
+ int ret;
u32 v;
CX18_DEBUG_INFO("Start feed: pid = 0x%x index = %d\n",
feed->pid, feed->index);
+
+ mutex_lock(&cx->serialize_lock);
+ ret = cx18_init_on_first_open(cx);
+ mutex_unlock(&cx->serialize_lock);
+ if (ret) {
+ CX18_ERR("Failed to initialize firmware starting DVB feed\n");
+ return ret;
+ }
+ ret = -EINVAL;
+
switch (cx->card->type) {
case CX18_CARD_HVR_1600_ESMT:
case CX18_CARD_HVR_1600_SAMSUNG:
@@ -101,6 +111,11 @@ static int cx18_dvb_start_feed(struct dvb_demux_feed *feed)
if (stream->dvb.feeding++ == 0) {
CX18_DEBUG_INFO("Starting Transport DMA\n");
ret = cx18_start_v4l2_encode_stream(stream);
+ if (ret < 0) {
+ CX18_DEBUG_INFO(
+ "Failed to start Transport DMA\n");
+ stream->dvb.feeding--;
+ }
} else
ret = 0;
mutex_unlock(&stream->dvb.feedlock);
diff --git a/linux/drivers/media/video/cx18/cx18-fileops.c b/linux/drivers/media/video/cx18/cx18-fileops.c
index f5f82c487..12f9de74d 100644
--- a/linux/drivers/media/video/cx18/cx18-fileops.c
+++ b/linux/drivers/media/video/cx18/cx18-fileops.c
@@ -396,7 +396,8 @@ static ssize_t cx18_read(struct cx18_stream *s, char __user *ubuf,
cx18_enqueue(s, buf, &s->q_free);
cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5,
s->handle,
- (void *)&cx->scb->cpu_mdl[buf->id] - cx->enc_mem,
+ (void __iomem *)&cx->scb->cpu_mdl[buf->id] -
+ cx->enc_mem,
1, buf->id, s->buf_size);
} else
cx18_enqueue(s, buf, &s->q_io);
diff --git a/linux/drivers/media/video/cx18/cx18-firmware.c b/linux/drivers/media/video/cx18/cx18-firmware.c
index 5e37427ec..2d630d9f7 100644
--- a/linux/drivers/media/video/cx18/cx18-firmware.c
+++ b/linux/drivers/media/video/cx18/cx18-firmware.c
@@ -41,9 +41,6 @@
#define CX18_REG_BUS_TIMEOUT_EN 0xc72024
-#define CX18_AUDIO_ENABLE 0xc72014
-#define CX18_REG_BUS_TIMEOUT_EN 0xc72024
-
#define CX18_FAST_CLOCK_PLL_INT 0xc78000
#define CX18_FAST_CLOCK_PLL_FRAC 0xc78004
#define CX18_FAST_CLOCK_PLL_POST 0xc78008
@@ -90,7 +87,7 @@
#define CX18_DSP0_INTERRUPT_MASK 0xd0004C
/* Encoder/decoder firmware sizes */
-#define CX18_FW_CPU_SIZE (174716)
+#define CX18_FW_CPU_SIZE (158332)
#define CX18_FW_APU_SIZE (141200)
#define APU_ROM_SYNC1 0x6D676553 /* "mgeS" */
@@ -344,13 +341,11 @@ int cx18_firmware_init(struct cx18 *cx)
if (read_reg(CX18_PROC_SOFT_RESET) & 8) {
int sz = load_apu_fw_direct("v4l-cx23418-apu.fw",
cx->enc_mem, cx, CX18_FW_APU_SIZE);
-#if 0
- /* this might be needed after all, check later */
+
write_enc(0xE51FF004, 0);
write_enc(0xa00000, 4); /* todo: not hardcoded */
write_reg(0x00010000, CX18_PROC_SOFT_RESET); /* Start APU */
cx18_msleep_timeout(500, 0);
-#endif
sz = sz <= 0 ? sz : load_cpu_fw_direct("v4l-cx23418-cpu.fw",
cx->enc_mem, cx, CX18_FW_CPU_SIZE);
diff --git a/linux/drivers/media/video/cx18/cx18-gpio.c b/linux/drivers/media/video/cx18/cx18-gpio.c
index 2f324b846..089bad6d8 100644
--- a/linux/drivers/media/video/cx18/cx18-gpio.c
+++ b/linux/drivers/media/video/cx18/cx18-gpio.c
@@ -53,16 +53,40 @@ static void gpio_write(struct cx18 *cx)
write_reg(((dir & 0xffff) << 16) | (val & 0xffff),
CX18_REG_GPIO_OUT1);
write_reg(dir & 0xffff0000, CX18_REG_GPIO_DIR2);
- write_reg((dir & 0xffff0000) | ((val & 0xffff0000) >> 16),
+ write_reg_sync((dir & 0xffff0000) | ((val & 0xffff0000) >> 16),
CX18_REG_GPIO_OUT2);
}
+void cx18_reset_i2c_slaves_gpio(struct cx18 *cx)
+{
+ const struct cx18_gpio_i2c_slave_reset *p;
+
+ p = &cx->card->gpio_i2c_slave_reset;
+
+ if ((p->active_lo_mask | p->active_hi_mask) == 0)
+ return;
+
+ /* Assuming that the masks are a subset of the bits in gpio_dir */
+
+ /* Assert */
+ cx->gpio_val =
+ (cx->gpio_val | p->active_hi_mask) & ~(p->active_lo_mask);
+ gpio_write(cx);
+ schedule_timeout_uninterruptible(msecs_to_jiffies(p->msecs_asserted));
+
+ /* Deassert */
+ cx->gpio_val =
+ (cx->gpio_val | p->active_lo_mask) & ~(p->active_hi_mask);
+ gpio_write(cx);
+ schedule_timeout_uninterruptible(msecs_to_jiffies(p->msecs_recovery));
+}
+
void cx18_gpio_init(struct cx18 *cx)
{
cx->gpio_dir = cx->card->gpio_init.direction;
cx->gpio_val = cx->card->gpio_init.initial_value;
- if (cx->card->xceive_pin) {
+ if (cx->card->tuners[0].tuner == TUNER_XC2028) {
cx->gpio_dir |= 1 << cx->card->xceive_pin;
cx->gpio_val |= 1 << cx->card->xceive_pin;
}
@@ -98,3 +122,37 @@ int cx18_reset_tuner_gpio(void *dev, int cmd, int value)
schedule_timeout_interruptible(msecs_to_jiffies(1));
return 0;
}
+
+int cx18_gpio(struct cx18 *cx, unsigned int command, void *arg)
+{
+ struct v4l2_routing *route = arg;
+ u32 mask, data;
+
+ switch (command) {
+ case VIDIOC_INT_S_AUDIO_ROUTING:
+ if (route->input > 2)
+ return -EINVAL;
+ mask = cx->card->gpio_audio_input.mask;
+ switch (route->input) {
+ case 0:
+ data = cx->card->gpio_audio_input.tuner;
+ break;
+ case 1:
+ data = cx->card->gpio_audio_input.linein;
+ break;
+ case 2:
+ default:
+ data = cx->card->gpio_audio_input.radio;
+ break;
+ }
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ if (mask) {
+ cx->gpio_val = (cx->gpio_val & ~mask) | (data & mask);
+ gpio_write(cx);
+ }
+ return 0;
+}
diff --git a/linux/drivers/media/video/cx18/cx18-gpio.h b/linux/drivers/media/video/cx18/cx18-gpio.h
index 41bac8856..7447fed35 100644
--- a/linux/drivers/media/video/cx18/cx18-gpio.h
+++ b/linux/drivers/media/video/cx18/cx18-gpio.h
@@ -21,4 +21,6 @@
*/
void cx18_gpio_init(struct cx18 *cx);
+void cx18_reset_i2c_slaves_gpio(struct cx18 *cx);
int cx18_reset_tuner_gpio(void *dev, int cmd, int value);
+int cx18_gpio(struct cx18 *cx, unsigned int command, void *arg);
diff --git a/linux/drivers/media/video/cx18/cx18-i2c.c b/linux/drivers/media/video/cx18/cx18-i2c.c
index 940e3718d..64a259405 100644
--- a/linux/drivers/media/video/cx18/cx18-i2c.c
+++ b/linux/drivers/media/video/cx18/cx18-i2c.c
@@ -39,10 +39,6 @@
#define GETSCL_BIT 0x0004
#define GETSDL_BIT 0x0008
-#ifndef I2C_ADAP_CLASS_TV_ANALOG
-#define I2C_ADAP_CLASS_TV_ANALOG I2C_CLASS_TV_ANALOG
-#endif
-
#define CX18_CS5345_I2C_ADDR 0x4c
/* This array should match the CX18_HW_ defines */
@@ -74,7 +70,7 @@ static const u8 hw_bus[] = {
};
/* This array should match the CX18_HW_ defines */
-static const char * const hw_drivernames[] = {
+static const char * const hw_devicenames[] = {
"tuner",
"tveeprom",
"cs5345",
@@ -96,8 +92,12 @@ int cx18_i2c_register(struct cx18 *cx, unsigned idx)
id = hw_driverids[idx];
bus = hw_bus[idx];
memset(&info, 0, sizeof(info));
- strlcpy(info.driver_name, hw_drivernames[idx],
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
+ strlcpy(info.driver_name, hw_devicenames[idx],
sizeof(info.driver_name));
+#else
+ strlcpy(info.type, hw_devicenames[idx], sizeof(info.type));
+#endif
info.addr = hw_addrs[idx];
for (i = 0; i < I2C_CLIENTS_MAX; i++)
if (cx->i2c_clients[i] == NULL)
@@ -230,9 +230,7 @@ static struct i2c_adapter cx18_i2c_adap_template = {
.client_unregister = detach_inform,
.owner = THIS_MODULE,
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
-#ifdef I2C_ADAP_CLASS_TV_ANALOG
- .class = I2C_ADAP_CLASS_TV_ANALOG,
-#endif
+ .class = I2C_CLASS_TV_ANALOG,
#endif
};
@@ -302,7 +300,7 @@ static const char *cx18_i2c_id_name(u32 id)
for (i = 0; i < ARRAY_SIZE(hw_driverids); i++)
if (hw_driverids[i] == id)
- return hw_drivernames[i];
+ return hw_devicenames[i];
return "unknown device";
}
@@ -313,7 +311,7 @@ static const char *cx18_i2c_hw_name(u32 hw)
for (i = 0; i < ARRAY_SIZE(hw_driverids); i++)
if (1 << i == hw)
- return hw_drivernames[i];
+ return hw_devicenames[i];
return "unknown device";
}
@@ -335,8 +333,12 @@ int cx18_i2c_hw(struct cx18 *cx, u32 hw, unsigned int cmd, void *arg)
{
int addr;
- if (hw == CX18_HW_GPIO || hw == 0)
+ if (hw == 0)
return 0;
+
+ if (hw == CX18_HW_GPIO)
+ return cx18_gpio(cx, cmd, arg);
+
if (hw == CX18_HW_CX23418)
return cx18_av_cmd(cx, cmd, arg);
@@ -374,6 +376,8 @@ void cx18_call_i2c_clients(struct cx18 *cx, unsigned int cmd, void *arg)
cx18_av_cmd(cx, cmd, arg);
i2c_clients_command(&cx->i2c_adap[0], cmd, arg);
i2c_clients_command(&cx->i2c_adap[1], cmd, arg);
+ if (cx->hw_flags & CX18_HW_GPIO)
+ cx18_gpio(cx, cmd, arg);
}
/* init + register i2c algo-bit adapter */
@@ -382,6 +386,18 @@ int init_cx18_i2c(struct cx18 *cx)
int i;
CX18_DEBUG_I2C("i2c init\n");
+ /* Sanity checks for the I2C hardware arrays. They must be the
+ * same size and GPIO/CX23418 must be the last entries.
+ */
+ if (ARRAY_SIZE(hw_driverids) != ARRAY_SIZE(hw_addrs) ||
+ ARRAY_SIZE(hw_devicenames) != ARRAY_SIZE(hw_addrs) ||
+ CX18_HW_GPIO != (1 << (ARRAY_SIZE(hw_addrs) - 2)) ||
+ CX18_HW_CX23418 != (1 << (ARRAY_SIZE(hw_addrs) - 1)) ||
+ hw_driverids[ARRAY_SIZE(hw_addrs) - 1]) {
+ CX18_ERR("Mismatched I2C hardware arrays\n");
+ return -ENODEV;
+ }
+
for (i = 0; i < 2; i++) {
memcpy(&cx->i2c_adap[i], &cx18_i2c_adap_template,
sizeof(struct i2c_adapter));
@@ -417,6 +433,7 @@ int init_cx18_i2c(struct cx18 *cx)
write_reg_sync(0x00c000c0, 0xc7001c);
mdelay(10);
write_reg_sync(0x00c00000, 0xc7001c);
+ mdelay(10);
write_reg_sync(0x00c00000, 0xc730c8); /* Set to edge-triggered intrs. */
write_reg_sync(0x00c00000, 0xc730c4); /* Clear any stale intrs */
@@ -431,6 +448,8 @@ int init_cx18_i2c(struct cx18 *cx)
cx18_setscl(&cx->i2c_algo_cb_data[1], 1);
cx18_setsda(&cx->i2c_algo_cb_data[1], 1);
+ cx18_reset_i2c_slaves_gpio(cx);
+
return i2c_bit_add_bus(&cx->i2c_adap[0]) ||
i2c_bit_add_bus(&cx->i2c_adap[1]);
}
diff --git a/linux/drivers/media/video/cx18/cx18-ioctl.c b/linux/drivers/media/video/cx18/cx18-ioctl.c
index f008604f9..b3d72d4a4 100644
--- a/linux/drivers/media/video/cx18/cx18-ioctl.c
+++ b/linux/drivers/media/video/cx18/cx18-ioctl.c
@@ -100,6 +100,7 @@ void cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
}
}
+#if 0
static int check_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
{
int f, l;
@@ -113,6 +114,7 @@ static int check_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
}
return set != 0;
}
+#endif
u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt)
{
@@ -126,740 +128,737 @@ u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt)
return set;
}
-static const struct {
- v4l2_std_id std;
- char *name;
-} enum_stds[] = {
- { V4L2_STD_PAL_BG | V4L2_STD_PAL_H, "PAL-BGH" },
- { V4L2_STD_PAL_DK, "PAL-DK" },
- { V4L2_STD_PAL_I, "PAL-I" },
- { V4L2_STD_PAL_M, "PAL-M" },
- { V4L2_STD_PAL_N, "PAL-N" },
- { V4L2_STD_PAL_Nc, "PAL-Nc" },
- { V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H, "SECAM-BGH" },
- { V4L2_STD_SECAM_DK, "SECAM-DK" },
- { V4L2_STD_SECAM_L, "SECAM-L" },
- { V4L2_STD_SECAM_LC, "SECAM-L'" },
- { V4L2_STD_NTSC_M, "NTSC-M" },
- { V4L2_STD_NTSC_M_JP, "NTSC-J" },
- { V4L2_STD_NTSC_M_KR, "NTSC-K" },
-};
-
-static const struct v4l2_standard cx18_std_60hz = {
- .frameperiod = {.numerator = 1001, .denominator = 30000},
- .framelines = 525,
-};
-
-static const struct v4l2_standard cx18_std_50hz = {
- .frameperiod = { .numerator = 1, .denominator = 25 },
- .framelines = 625,
-};
-
-static int cx18_cxc(struct cx18 *cx, unsigned int cmd, void *arg)
+static int cx18_g_fmt_vid_cap(struct file *file, void *fh,
+ struct v4l2_format *fmt)
{
- struct v4l2_register *regs = arg;
- unsigned long flags;
-
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- if (regs->reg >= CX18_MEM_OFFSET + CX18_MEM_SIZE)
- return -EINVAL;
-
- spin_lock_irqsave(&cx18_cards_lock, flags);
- if (cmd == VIDIOC_DBG_G_REGISTER)
- regs->val = read_enc(regs->reg);
- else
- write_enc(regs->val, regs->reg);
- spin_unlock_irqrestore(&cx18_cards_lock, flags);
+ struct cx18_open_id *id = fh;
+ struct cx18 *cx = id->cx;
+ struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
+
+ pixfmt->width = cx->params.width;
+ pixfmt->height = cx->params.height;
+ pixfmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
+ pixfmt->field = V4L2_FIELD_INTERLACED;
+ pixfmt->priv = 0;
+ if (id->type == CX18_ENC_STREAM_TYPE_YUV) {
+ pixfmt->pixelformat = V4L2_PIX_FMT_HM12;
+ /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */
+ pixfmt->sizeimage =
+ pixfmt->height * pixfmt->width +
+ pixfmt->height * (pixfmt->width / 2);
+ pixfmt->bytesperline = 720;
+ } else {
+ pixfmt->pixelformat = V4L2_PIX_FMT_MPEG;
+ pixfmt->sizeimage = 128 * 1024;
+ pixfmt->bytesperline = 0;
+ }
return 0;
}
-static int cx18_get_fmt(struct cx18 *cx, int streamtype, struct v4l2_format *fmt)
-{
- switch (fmt->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- fmt->fmt.pix.width = cx->params.width;
- fmt->fmt.pix.height = cx->params.height;
- fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
- fmt->fmt.pix.field = V4L2_FIELD_INTERLACED;
- if (streamtype == CX18_ENC_STREAM_TYPE_YUV) {
- fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12;
- /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */
- fmt->fmt.pix.sizeimage =
- fmt->fmt.pix.height * fmt->fmt.pix.width +
- fmt->fmt.pix.height * (fmt->fmt.pix.width / 2);
- } else {
- fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
- fmt->fmt.pix.sizeimage = 128 * 1024;
- }
- break;
-
- case V4L2_BUF_TYPE_VBI_CAPTURE:
- fmt->fmt.vbi.sampling_rate = 27000000;
- fmt->fmt.vbi.offset = 248;
- fmt->fmt.vbi.samples_per_line = cx->vbi.raw_decoder_line_size - 4;
- fmt->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
- fmt->fmt.vbi.start[0] = cx->vbi.start[0];
- fmt->fmt.vbi.start[1] = cx->vbi.start[1];
- fmt->fmt.vbi.count[0] = fmt->fmt.vbi.count[1] = cx->vbi.count;
- break;
+static int cx18_g_fmt_vbi_cap(struct file *file, void *fh,
+ struct v4l2_format *fmt)
+{
+ struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+ struct v4l2_vbi_format *vbifmt = &fmt->fmt.vbi;
+
+ vbifmt->sampling_rate = 27000000;
+ vbifmt->offset = 248;
+ vbifmt->samples_per_line = cx->vbi.raw_decoder_line_size - 4;
+ vbifmt->sample_format = V4L2_PIX_FMT_GREY;
+ vbifmt->start[0] = cx->vbi.start[0];
+ vbifmt->start[1] = cx->vbi.start[1];
+ vbifmt->count[0] = vbifmt->count[1] = cx->vbi.count;
+ vbifmt->flags = 0;
+ vbifmt->reserved[0] = 0;
+ vbifmt->reserved[1] = 0;
+ return 0;
+}
- case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
- {
- struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
+static int cx18_g_fmt_sliced_vbi_cap(struct file *file, void *fh,
+ struct v4l2_format *fmt)
+{
+#if 0
+ /* Supported by the cx23418 but not yet implemented. */
+ struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+ struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
- vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
- memset(vbifmt->reserved, 0, sizeof(vbifmt->reserved));
- memset(vbifmt->service_lines, 0, sizeof(vbifmt->service_lines));
+ vbifmt->reserved[0] = 0;
+ vbifmt->reserved[1] = 0;
+ vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
+ memset(vbifmt->service_lines, 0, sizeof(vbifmt->service_lines));
- cx18_av_cmd(cx, VIDIOC_G_FMT, fmt);
- vbifmt->service_set = cx18_get_service_set(vbifmt);
- break;
- }
- default:
- return -EINVAL;
- }
+ cx18_av_cmd(cx, VIDIOC_G_FMT, fmt);
+ vbifmt->service_set = cx18_get_service_set(vbifmt);
return 0;
+#else
+ return -EINVAL;
+#endif
}
-static int cx18_try_or_set_fmt(struct cx18 *cx, int streamtype,
- struct v4l2_format *fmt, int set_fmt)
+static int cx18_try_fmt_vid_cap(struct file *file, void *fh,
+ struct v4l2_format *fmt)
{
- struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
- u16 set;
-
- /* set window size */
- if (fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- int w = fmt->fmt.pix.width;
- int h = fmt->fmt.pix.height;
-
- if (w > 720)
- w = 720;
- else if (w < 1)
- w = 1;
- if (h > (cx->is_50hz ? 576 : 480))
- h = (cx->is_50hz ? 576 : 480);
- else if (h < 2)
- h = 2;
- cx18_get_fmt(cx, streamtype, fmt);
- fmt->fmt.pix.width = w;
- fmt->fmt.pix.height = h;
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18)
- if (cx->params.width != 720 || cx->params.height != (cx->is_50hz ? 576 : 480))
- cx->params.video_temporal_filter = 0;
- else
- cx->params.video_temporal_filter = 8;
-#endif
+ struct cx18_open_id *id = fh;
+ struct cx18 *cx = id->cx;
- if (!set_fmt || (cx->params.width == w && cx->params.height == h))
- return 0;
- if (atomic_read(&cx->ana_capturing) > 0)
- return -EBUSY;
-
- cx->params.width = w;
- cx->params.height = h;
- if (w != 720 || h != (cx->is_50hz ? 576 : 480))
- cx->params.video_temporal_filter = 0;
- else
- cx->params.video_temporal_filter = 8;
- cx18_av_cmd(cx, VIDIOC_S_FMT, fmt);
- return cx18_get_fmt(cx, streamtype, fmt);
- }
+ int w = fmt->fmt.pix.width;
+ int h = fmt->fmt.pix.height;
- /* set raw VBI format */
- if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
- if (set_fmt && streamtype == CX18_ENC_STREAM_TYPE_VBI &&
- cx->vbi.sliced_in->service_set &&
- atomic_read(&cx->ana_capturing) > 0)
- return -EBUSY;
- if (set_fmt) {
- cx->vbi.sliced_in->service_set = 0;
- cx18_av_cmd(cx, VIDIOC_S_FMT, &cx->vbi.in);
- }
- return cx18_get_fmt(cx, streamtype, fmt);
- }
+ w = min(w, 720);
+ w = max(w, 1);
+ h = min(h, cx->is_50hz ? 576 : 480);
+ h = max(h, 2);
+ cx18_g_fmt_vid_cap(file, fh, fmt);
+ fmt->fmt.pix.width = w;
+ fmt->fmt.pix.height = h;
+ return 0;
+}
- /* any else but sliced VBI capture is an error */
- if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
- return -EINVAL;
+static int cx18_try_fmt_vbi_cap(struct file *file, void *fh,
+ struct v4l2_format *fmt)
+{
+ return cx18_g_fmt_vbi_cap(file, fh, fmt);
+}
- /* TODO: implement sliced VBI, for now silently return 0 */
- return 0;
+static int cx18_try_fmt_sliced_vbi_cap(struct file *file, void *fh,
+ struct v4l2_format *fmt)
+{
+#if 0
+ /* Supported by the cx23418 but not yet implemented. */
+ struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+ struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
- /* set sliced VBI capture format */
vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
- memset(vbifmt->reserved, 0, sizeof(vbifmt->reserved));
+ vbifmt->reserved[0] = 0;
+ vbifmt->reserved[1] = 0;
if (vbifmt->service_set)
cx18_expand_service_set(vbifmt, cx->is_50hz);
- set = check_service_set(vbifmt, cx->is_50hz);
+ check_service_set(vbifmt, cx->is_50hz);
vbifmt->service_set = cx18_get_service_set(vbifmt);
+ return 0;
+#else
+ return -EINVAL;
+#endif
+}
+
+static int cx18_s_fmt_vid_cap(struct file *file, void *fh,
+ struct v4l2_format *fmt)
+{
+ struct cx18_open_id *id = fh;
+ struct cx18 *cx = id->cx;
+ int ret;
+ int w = fmt->fmt.pix.width;
+ int h = fmt->fmt.pix.height;
+
+ ret = v4l2_prio_check(&cx->prio, &id->prio);
+ if (ret)
+ return ret;
+
+ ret = cx18_try_fmt_vid_cap(file, fh, fmt);
+ if (ret)
+ return ret;
- if (!set_fmt)
+ if (cx->params.width == w && cx->params.height == h)
return 0;
- if (set == 0)
- return -EINVAL;
- if (atomic_read(&cx->ana_capturing) > 0 && cx->vbi.sliced_in->service_set == 0)
+
+ if (atomic_read(&cx->ana_capturing) > 0)
return -EBUSY;
+
+ cx->params.width = w;
+ cx->params.height = h;
cx18_av_cmd(cx, VIDIOC_S_FMT, fmt);
- memcpy(cx->vbi.sliced_in, vbifmt, sizeof(*cx->vbi.sliced_in));
- return 0;
+ return cx18_g_fmt_vid_cap(file, fh, fmt);
}
-static int cx18_debug_ioctls(struct file *filp, unsigned int cmd, void *arg)
+static int cx18_s_fmt_vbi_cap(struct file *file, void *fh,
+ struct v4l2_format *fmt)
{
- struct cx18_open_id *id = (struct cx18_open_id *)filp->private_data;
+ struct cx18_open_id *id = fh;
struct cx18 *cx = id->cx;
- struct v4l2_register *reg = arg;
+ int ret;
- switch (cmd) {
- /* ioctls to allow direct access to the encoder registers for testing */
- case VIDIOC_DBG_G_REGISTER:
- if (v4l2_chip_match_host(reg->match_type, reg->match_chip))
- return cx18_cxc(cx, cmd, arg);
- if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
- return cx18_i2c_id(cx, reg->match_chip, cmd, arg);
- return cx18_call_i2c_client(cx, reg->match_chip, cmd, arg);
-
- case VIDIOC_DBG_S_REGISTER:
- if (v4l2_chip_match_host(reg->match_type, reg->match_chip))
- return cx18_cxc(cx, cmd, arg);
- if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
- return cx18_i2c_id(cx, reg->match_chip, cmd, arg);
- return cx18_call_i2c_client(cx, reg->match_chip, cmd, arg);
-
- case VIDIOC_G_CHIP_IDENT: {
- struct v4l2_chip_ident *chip = arg;
-
- chip->ident = V4L2_IDENT_NONE;
- chip->revision = 0;
- if (reg->match_type == V4L2_CHIP_MATCH_HOST) {
- if (v4l2_chip_match_host(reg->match_type, reg->match_chip)) {
- struct v4l2_chip_ident *chip = arg;
-
- chip->ident = V4L2_IDENT_CX23418;
- }
- return 0;
- }
- if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
- return cx18_i2c_id(cx, reg->match_chip, cmd, arg);
- if (reg->match_type == V4L2_CHIP_MATCH_I2C_ADDR)
- return cx18_call_i2c_client(cx, reg->match_chip, cmd, arg);
+ ret = v4l2_prio_check(&cx->prio, &id->prio);
+ if (ret)
+ return ret;
+
+ if (id->type == CX18_ENC_STREAM_TYPE_VBI &&
+ cx->vbi.sliced_in->service_set &&
+ atomic_read(&cx->ana_capturing) > 0)
+ return -EBUSY;
+
+ cx->vbi.sliced_in->service_set = 0;
+ cx18_av_cmd(cx, VIDIOC_S_FMT, &cx->vbi.in);
+ return cx18_g_fmt_vbi_cap(file, fh, fmt);
+}
+
+static int cx18_s_fmt_sliced_vbi_cap(struct file *file, void *fh,
+ struct v4l2_format *fmt)
+{
+#if 0
+ /* Supported by the cx23418 but not yet implemented. */
+ struct cx18_open_id *id = fh;
+ struct cx18 *cx = id->cx;
+ int ret;
+ struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
+
+ ret = v4l2_prio_check(&cx->prio, &id->prio);
+ if (ret)
+ return ret;
+
+ ret = cx18_try_fmt_sliced_vbi_cap(file, fh, fmt);
+ if (ret)
+ return ret;
+
+ if (check_service_set(vbifmt, cx->is_50hz) == 0)
return -EINVAL;
- }
- case VIDIOC_INT_S_AUDIO_ROUTING: {
- struct v4l2_routing *route = arg;
+ if (atomic_read(&cx->ana_capturing) > 0 &&
+ cx->vbi.sliced_in->service_set == 0)
+ return -EBUSY;
+ cx18_av_cmd(cx, VIDIOC_S_FMT, fmt);
+ memcpy(cx->vbi.sliced_in, vbifmt, sizeof(*cx->vbi.sliced_in));
+ return 0;
+#else
+ return -EINVAL;
+#endif
+}
- cx18_audio_set_route(cx, route);
- break;
+static int cx18_g_chip_ident(struct file *file, void *fh,
+ struct v4l2_chip_ident *chip)
+{
+ struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+
+ chip->ident = V4L2_IDENT_NONE;
+ chip->revision = 0;
+ if (chip->match_type == V4L2_CHIP_MATCH_HOST) {
+ if (v4l2_chip_match_host(chip->match_type, chip->match_chip))
+ chip->ident = V4L2_IDENT_CX23418;
+ return 0;
}
+ if (chip->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
+ return cx18_i2c_id(cx, chip->match_chip, VIDIOC_G_CHIP_IDENT,
+ chip);
+ if (chip->match_type == V4L2_CHIP_MATCH_I2C_ADDR)
+ return cx18_call_i2c_client(cx, chip->match_chip,
+ VIDIOC_G_CHIP_IDENT, chip);
+ return -EINVAL;
+}
- default:
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int cx18_cxc(struct cx18 *cx, unsigned int cmd, void *arg)
+{
+ struct v4l2_register *regs = arg;
+ unsigned long flags;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ if (regs->reg >= CX18_MEM_OFFSET + CX18_MEM_SIZE)
return -EINVAL;
- }
+
+ spin_lock_irqsave(&cx18_cards_lock, flags);
+ if (cmd == VIDIOC_DBG_G_REGISTER)
+ regs->val = read_enc(regs->reg);
+ else
+ write_enc(regs->val, regs->reg);
+ spin_unlock_irqrestore(&cx18_cards_lock, flags);
return 0;
}
-int cx18_v4l2_ioctls(struct cx18 *cx, struct file *filp, unsigned cmd, void *arg)
+static int cx18_g_register(struct file *file, void *fh,
+ struct v4l2_register *reg)
{
- struct cx18_open_id *id = NULL;
+ struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+
+ if (v4l2_chip_match_host(reg->match_type, reg->match_chip))
+ return cx18_cxc(cx, VIDIOC_DBG_G_REGISTER, reg);
+ if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
+ return cx18_i2c_id(cx, reg->match_chip, VIDIOC_DBG_G_REGISTER,
+ reg);
+ return cx18_call_i2c_client(cx, reg->match_chip, VIDIOC_DBG_G_REGISTER,
+ reg);
+}
- if (filp)
- id = (struct cx18_open_id *)filp->private_data;
+static int cx18_s_register(struct file *file, void *fh,
+ struct v4l2_register *reg)
+{
+ struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+
+ if (v4l2_chip_match_host(reg->match_type, reg->match_chip))
+ return cx18_cxc(cx, VIDIOC_DBG_S_REGISTER, reg);
+ if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
+ return cx18_i2c_id(cx, reg->match_chip, VIDIOC_DBG_S_REGISTER,
+ reg);
+ return cx18_call_i2c_client(cx, reg->match_chip, VIDIOC_DBG_S_REGISTER,
+ reg);
+}
+#endif
- switch (cmd) {
- case VIDIOC_G_PRIORITY:
- {
- enum v4l2_priority *p = arg;
+static int cx18_g_priority(struct file *file, void *fh, enum v4l2_priority *p)
+{
+ struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
- *p = v4l2_prio_max(&cx->prio);
- break;
- }
+ *p = v4l2_prio_max(&cx->prio);
+ return 0;
+}
- case VIDIOC_S_PRIORITY:
- {
- enum v4l2_priority *prio = arg;
+static int cx18_s_priority(struct file *file, void *fh, enum v4l2_priority prio)
+{
+ struct cx18_open_id *id = fh;
+ struct cx18 *cx = id->cx;
- return v4l2_prio_change(&cx->prio, &id->prio, *prio);
- }
+ return v4l2_prio_change(&cx->prio, &id->prio, prio);
+}
- case VIDIOC_QUERYCAP:{
- struct v4l2_capability *vcap = arg;
+static int cx18_querycap(struct file *file, void *fh,
+ struct v4l2_capability *vcap)
+{
+ struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
- memset(vcap, 0, sizeof(*vcap));
- strlcpy(vcap->driver, CX18_DRIVER_NAME, sizeof(vcap->driver));
- strlcpy(vcap->card, cx->card_name, sizeof(vcap->card));
- strlcpy(vcap->bus_info, pci_name(cx->dev), sizeof(vcap->bus_info));
- vcap->version = CX18_DRIVER_VERSION; /* version */
- vcap->capabilities = cx->v4l2_cap; /* capabilities */
+ strlcpy(vcap->driver, CX18_DRIVER_NAME, sizeof(vcap->driver));
+ strlcpy(vcap->card, cx->card_name, sizeof(vcap->card));
+ strlcpy(vcap->bus_info, pci_name(cx->dev), sizeof(vcap->bus_info));
+ vcap->version = CX18_DRIVER_VERSION; /* version */
+ vcap->capabilities = cx->v4l2_cap; /* capabilities */
+ return 0;
+}
- /* reserved.. must set to 0! */
- vcap->reserved[0] = vcap->reserved[1] =
- vcap->reserved[2] = vcap->reserved[3] = 0;
- break;
- }
+static int cx18_enumaudio(struct file *file, void *fh, struct v4l2_audio *vin)
+{
+ struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
- case VIDIOC_ENUMAUDIO:{
- struct v4l2_audio *vin = arg;
+ return cx18_get_audio_input(cx, vin->index, vin);
+}
- return cx18_get_audio_input(cx, vin->index, vin);
- }
+static int cx18_g_audio(struct file *file, void *fh, struct v4l2_audio *vin)
+{
+ struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
- case VIDIOC_G_AUDIO:{
- struct v4l2_audio *vin = arg;
+ vin->index = cx->audio_input;
+ return cx18_get_audio_input(cx, vin->index, vin);
+}
- vin->index = cx->audio_input;
- return cx18_get_audio_input(cx, vin->index, vin);
- }
+static int cx18_s_audio(struct file *file, void *fh, struct v4l2_audio *vout)
+{
+ struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+
+ if (vout->index >= cx->nof_audio_inputs)
+ return -EINVAL;
+ cx->audio_input = vout->index;
+ cx18_audio_set_io(cx);
+ return 0;
+}
- case VIDIOC_S_AUDIO:{
- struct v4l2_audio *vout = arg;
+static int cx18_enum_input(struct file *file, void *fh, struct v4l2_input *vin)
+{
+ struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
- if (vout->index >= cx->nof_audio_inputs)
- return -EINVAL;
- cx->audio_input = vout->index;
- cx18_audio_set_io(cx);
- break;
- }
+ /* set it to defaults from our table */
+ return cx18_get_input(cx, vin->index, vin);
+}
- case VIDIOC_ENUMINPUT:{
- struct v4l2_input *vin = arg;
+static int cx18_cropcap(struct file *file, void *fh,
+ struct v4l2_cropcap *cropcap)
+{
+ struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
- /* set it to defaults from our table */
- return cx18_get_input(cx, vin->index, vin);
- }
+ if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ cropcap->bounds.top = cropcap->bounds.left = 0;
+ cropcap->bounds.width = 720;
+ cropcap->bounds.height = cx->is_50hz ? 576 : 480;
+ cropcap->pixelaspect.numerator = cx->is_50hz ? 59 : 10;
+ cropcap->pixelaspect.denominator = cx->is_50hz ? 54 : 11;
+ cropcap->defrect = cropcap->bounds;
+ return 0;
+}
- case VIDIOC_TRY_FMT:
- case VIDIOC_S_FMT: {
- struct v4l2_format *fmt = arg;
+static int cx18_s_crop(struct file *file, void *fh, struct v4l2_crop *crop)
+{
+ struct cx18_open_id *id = fh;
+ struct cx18 *cx = id->cx;
+ int ret;
- return cx18_try_or_set_fmt(cx, id->type, fmt, cmd == VIDIOC_S_FMT);
- }
+ ret = v4l2_prio_check(&cx->prio, &id->prio);
+ if (ret)
+ return ret;
- case VIDIOC_G_FMT: {
- struct v4l2_format *fmt = arg;
- int type = fmt->type;
+ if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ return cx18_av_cmd(cx, VIDIOC_S_CROP, crop);
+}
- memset(fmt, 0, sizeof(*fmt));
- fmt->type = type;
- return cx18_get_fmt(cx, id->type, fmt);
- }
+static int cx18_g_crop(struct file *file, void *fh, struct v4l2_crop *crop)
+{
+ struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
- case VIDIOC_CROPCAP: {
- struct v4l2_cropcap *cropcap = arg;
-
- if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- cropcap->bounds.top = cropcap->bounds.left = 0;
- cropcap->bounds.width = 720;
- cropcap->bounds.height = cx->is_50hz ? 576 : 480;
- cropcap->pixelaspect.numerator = cx->is_50hz ? 59 : 10;
- cropcap->pixelaspect.denominator = cx->is_50hz ? 54 : 11;
- cropcap->defrect = cropcap->bounds;
- return 0;
- }
+ if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ return cx18_av_cmd(cx, VIDIOC_G_CROP, crop);
+}
- case VIDIOC_S_CROP: {
- struct v4l2_crop *crop = arg;
+static int cx18_enum_fmt_vid_cap(struct file *file, void *fh,
+ struct v4l2_fmtdesc *fmt)
+{
+ static struct v4l2_fmtdesc formats[] = {
+ { 0, V4L2_BUF_TYPE_VIDEO_CAPTURE, 0,
+ "HM12 (YUV 4:1:1)", V4L2_PIX_FMT_HM12, { 0, 0, 0, 0 }
+ },
+ { 1, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FMT_FLAG_COMPRESSED,
+ "MPEG", V4L2_PIX_FMT_MPEG, { 0, 0, 0, 0 }
+ }
+ };
- if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- return cx18_av_cmd(cx, VIDIOC_S_CROP, arg);
- }
+ if (fmt->index > 1)
+ return -EINVAL;
+ *fmt = formats[fmt->index];
+ return 0;
+}
- case VIDIOC_G_CROP: {
- struct v4l2_crop *crop = arg;
+static int cx18_g_input(struct file *file, void *fh, unsigned int *i)
+{
+ struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
- if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- return cx18_av_cmd(cx, VIDIOC_G_CROP, arg);
- }
+ *i = cx->active_input;
+ return 0;
+}
- case VIDIOC_ENUM_FMT: {
- static struct v4l2_fmtdesc formats[] = {
- { 0, 0, 0,
- "HM12 (YUV 4:1:1)", V4L2_PIX_FMT_HM12,
- { 0, 0, 0, 0 }
- },
- { 1, 0, V4L2_FMT_FLAG_COMPRESSED,
- "MPEG", V4L2_PIX_FMT_MPEG,
- { 0, 0, 0, 0 }
- }
- };
- struct v4l2_fmtdesc *fmt = arg;
- enum v4l2_buf_type type = fmt->type;
-
- switch (type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- break;
- default:
- return -EINVAL;
- }
- if (fmt->index > 1)
- return -EINVAL;
- *fmt = formats[fmt->index];
- fmt->type = type;
+int cx18_s_input(struct file *file, void *fh, unsigned int inp)
+{
+ struct cx18_open_id *id = fh;
+ struct cx18 *cx = id->cx;
+ int ret;
+
+ ret = v4l2_prio_check(&cx->prio, &id->prio);
+ if (ret)
+ return ret;
+
+ if (inp < 0 || inp >= cx->nof_inputs)
+ return -EINVAL;
+
+ if (inp == cx->active_input) {
+ CX18_DEBUG_INFO("Input unchanged\n");
return 0;
}
- case VIDIOC_G_INPUT:{
- *(int *)arg = cx->active_input;
- break;
- }
+ CX18_DEBUG_INFO("Changing input from %d to %d\n",
+ cx->active_input, inp);
- case VIDIOC_S_INPUT:{
- int inp = *(int *)arg;
+ cx->active_input = inp;
+ /* Set the audio input to whatever is appropriate for the input type. */
+ cx->audio_input = cx->card->video_inputs[inp].audio_index;
- if (inp < 0 || inp >= cx->nof_inputs)
- return -EINVAL;
+ /* prevent others from messing with the streams until
+ we're finished changing inputs. */
+ cx18_mute(cx);
+ cx18_video_set_io(cx);
+ cx18_audio_set_io(cx);
+ cx18_unmute(cx);
+ return 0;
+}
- if (inp == cx->active_input) {
- CX18_DEBUG_INFO("Input unchanged\n");
- break;
- }
- CX18_DEBUG_INFO("Changing input from %d to %d\n",
- cx->active_input, inp);
+static int cx18_g_frequency(struct file *file, void *fh,
+ struct v4l2_frequency *vf)
+{
+ struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
- cx->active_input = inp;
- /* Set the audio input to whatever is appropriate for the
- input type. */
- cx->audio_input = cx->card->video_inputs[inp].audio_index;
+ if (vf->tuner != 0)
+ return -EINVAL;
- /* prevent others from messing with the streams until
- we're finished changing inputs. */
- cx18_mute(cx);
- cx18_video_set_io(cx);
- cx18_audio_set_io(cx);
- cx18_unmute(cx);
- break;
- }
+ cx18_call_i2c_clients(cx, VIDIOC_G_FREQUENCY, vf);
+ return 0;
+}
- case VIDIOC_G_FREQUENCY:{
- struct v4l2_frequency *vf = arg;
+int cx18_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf)
+{
+ struct cx18_open_id *id = fh;
+ struct cx18 *cx = id->cx;
+ int ret;
- if (vf->tuner != 0)
- return -EINVAL;
- cx18_call_i2c_clients(cx, cmd, arg);
- break;
- }
+ ret = v4l2_prio_check(&cx->prio, &id->prio);
+ if (ret)
+ return ret;
- case VIDIOC_S_FREQUENCY:{
- struct v4l2_frequency vf = *(struct v4l2_frequency *)arg;
+ if (vf->tuner != 0)
+ return -EINVAL;
- if (vf.tuner != 0)
- return -EINVAL;
+ cx18_mute(cx);
+ CX18_DEBUG_INFO("v4l2 ioctl: set frequency %d\n", vf->frequency);
+ cx18_call_i2c_clients(cx, VIDIOC_S_FREQUENCY, vf);
+ cx18_unmute(cx);
+ return 0;
+}
- cx18_mute(cx);
- CX18_DEBUG_INFO("v4l2 ioctl: set frequency %d\n", vf.frequency);
- cx18_call_i2c_clients(cx, cmd, &vf);
- cx18_unmute(cx);
- break;
- }
+static int cx18_g_std(struct file *file, void *fh, v4l2_std_id *std)
+{
+ struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
- case VIDIOC_ENUMSTD:{
- struct v4l2_standard *vs = arg;
- int idx = vs->index;
+ *std = cx->std;
+ return 0;
+}
- if (idx < 0 || idx >= ARRAY_SIZE(enum_stds))
- return -EINVAL;
+int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std)
+{
+ struct cx18_open_id *id = fh;
+ struct cx18 *cx = id->cx;
+ int ret;
- *vs = (enum_stds[idx].std & V4L2_STD_525_60) ?
- cx18_std_60hz : cx18_std_50hz;
- vs->index = idx;
- vs->id = enum_stds[idx].std;
- strlcpy(vs->name, enum_stds[idx].name, sizeof(vs->name));
- break;
- }
+ ret = v4l2_prio_check(&cx->prio, &id->prio);
+ if (ret)
+ return ret;
- case VIDIOC_G_STD:{
- *(v4l2_std_id *) arg = cx->std;
- break;
- }
+ if ((*std & V4L2_STD_ALL) == 0)
+ return -EINVAL;
- case VIDIOC_S_STD: {
- v4l2_std_id std = *(v4l2_std_id *) arg;
+ if (*std == cx->std)
+ return 0;
- if ((std & V4L2_STD_ALL) == 0)
- return -EINVAL;
+ if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ||
+ atomic_read(&cx->ana_capturing) > 0) {
+ /* Switching standard would turn off the radio or mess
+ with already running streams, prevent that by
+ returning EBUSY. */
+ return -EBUSY;
+ }
- if (std == cx->std)
- break;
+ cx->std = *std;
+ cx->is_60hz = (*std & V4L2_STD_525_60) ? 1 : 0;
+ cx->params.is_50hz = cx->is_50hz = !cx->is_60hz;
+ cx->params.width = 720;
+ cx->params.height = cx->is_50hz ? 576 : 480;
+ cx->vbi.count = cx->is_50hz ? 18 : 12;
+ cx->vbi.start[0] = cx->is_50hz ? 6 : 10;
+ cx->vbi.start[1] = cx->is_50hz ? 318 : 273;
+ cx->vbi.sliced_decoder_line_size = cx->is_60hz ? 272 : 284;
+ CX18_DEBUG_INFO("Switching standard to %llx.\n",
+ (unsigned long long) cx->std);
+
+ /* Tuner */
+ cx18_call_i2c_clients(cx, VIDIOC_S_STD, &cx->std);
+ return 0;
+}
- if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ||
- atomic_read(&cx->ana_capturing) > 0) {
- /* Switching standard would turn off the radio or mess
- with already running streams, prevent that by
- returning EBUSY. */
- return -EBUSY;
- }
+static int cx18_s_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
+{
+ struct cx18_open_id *id = fh;
+ struct cx18 *cx = id->cx;
+ int ret;
- cx->std = std;
- cx->is_60hz = (std & V4L2_STD_525_60) ? 1 : 0;
- cx->params.is_50hz = cx->is_50hz = !cx->is_60hz;
- cx->params.width = 720;
- cx->params.height = cx->is_50hz ? 576 : 480;
- cx->vbi.count = cx->is_50hz ? 18 : 12;
- cx->vbi.start[0] = cx->is_50hz ? 6 : 10;
- cx->vbi.start[1] = cx->is_50hz ? 318 : 273;
- cx->vbi.sliced_decoder_line_size = cx->is_60hz ? 272 : 284;
- CX18_DEBUG_INFO("Switching standard to %llx.\n", (unsigned long long)cx->std);
-
- /* Tuner */
- cx18_call_i2c_clients(cx, VIDIOC_S_STD, &cx->std);
- break;
- }
+ ret = v4l2_prio_check(&cx->prio, &id->prio);
+ if (ret)
+ return ret;
- case VIDIOC_S_TUNER: { /* Setting tuner can only set audio mode */
- struct v4l2_tuner *vt = arg;
+ if (vt->index != 0)
+ return -EINVAL;
- if (vt->index != 0)
- return -EINVAL;
+ /* Setting tuner can only set audio mode */
+ cx18_call_i2c_clients(cx, VIDIOC_S_TUNER, vt);
- cx18_call_i2c_clients(cx, VIDIOC_S_TUNER, vt);
- break;
- }
+ return 0;
+}
- case VIDIOC_G_TUNER: {
- struct v4l2_tuner *vt = arg;
+static int cx18_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
+{
+ struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
- if (vt->index != 0)
- return -EINVAL;
+ if (vt->index != 0)
+ return -EINVAL;
- memset(vt, 0, sizeof(*vt));
- cx18_call_i2c_clients(cx, VIDIOC_G_TUNER, vt);
+ cx18_call_i2c_clients(cx, VIDIOC_G_TUNER, vt);
- if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) {
- strlcpy(vt->name, "cx18 Radio Tuner", sizeof(vt->name));
- vt->type = V4L2_TUNER_RADIO;
- } else {
- strlcpy(vt->name, "cx18 TV Tuner", sizeof(vt->name));
- vt->type = V4L2_TUNER_ANALOG_TV;
- }
- break;
+ if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) {
+ strlcpy(vt->name, "cx18 Radio Tuner", sizeof(vt->name));
+ vt->type = V4L2_TUNER_RADIO;
+ } else {
+ strlcpy(vt->name, "cx18 TV Tuner", sizeof(vt->name));
+ vt->type = V4L2_TUNER_ANALOG_TV;
}
- case VIDIOC_G_SLICED_VBI_CAP: {
- struct v4l2_sliced_vbi_cap *cap = arg;
- int set = cx->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525;
- int f, l;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
- enum v4l2_buf_type type = cap->type;
-#else
- enum v4l2_buf_type type = VIDIOC_G_SLICED_VBI_CAP;
-#endif
+ return 0;
+}
- memset(cap, 0, sizeof(*cap));
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
- cap->type = type;
-#endif
- if (type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
- for (f = 0; f < 2; f++) {
- for (l = 0; l < 24; l++) {
- if (valid_service_line(f, l, cx->is_50hz))
- cap->service_lines[f][l] = set;
- }
+static int cx18_g_sliced_vbi_cap(struct file *file, void *fh,
+ struct v4l2_sliced_vbi_cap *cap)
+{
+#if 0
+ /* Supported by the cx23418 but not yet implemented. */
+ struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+ int set = cx->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525;
+ int f, l;
+
+ if (cap->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
+ for (f = 0; f < 2; f++) {
+ for (l = 0; l < 24; l++) {
+ if (valid_service_line(f, l, cx->is_50hz))
+ cap->service_lines[f][l] = set;
}
- return 0;
}
- return -EINVAL;
+ return 0;
}
+#endif
+ return -EINVAL;
+}
+static int cx18_g_enc_index(struct file *file, void *fh,
+ struct v4l2_enc_idx *idx)
+{
#if 0
- case VIDIOC_G_ENC_INDEX: {
- struct v4l2_enc_idx *idx = arg;
- int i;
-
- idx->entries = (cx->pgm_info_write_idx + CX18_MAX_PGM_INDEX - cx->pgm_info_read_idx) %
- CX18_MAX_PGM_INDEX;
- if (idx->entries > V4L2_ENC_IDX_ENTRIES)
- idx->entries = V4L2_ENC_IDX_ENTRIES;
- for (i = 0; i < idx->entries; i++)
- idx->entry[i] = cx->pgm_info[(cx->pgm_info_read_idx + i) % CX18_MAX_PGM_INDEX];
- cx->pgm_info_read_idx = (cx->pgm_info_read_idx + idx->entries) % CX18_MAX_PGM_INDEX;
- break;
- }
+ /* Supported by the cx23418 but not yet implemented. */
+ struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+ int i;
+
+ idx->entries = (cx->pgm_info_write_idx + CX18_MAX_PGM_INDEX
+ - cx->pgm_info_read_idx) % CX18_MAX_PGM_INDEX;
+ if (idx->entries > V4L2_ENC_IDX_ENTRIES)
+ idx->entries = V4L2_ENC_IDX_ENTRIES;
+ for (i = 0; i < idx->entries; i++)
+ idx->entry[i] = cx->pgm_info [(cx->pgm_info_read_idx + i)
+ % CX18_MAX_PGM_INDEX];
+ cx->pgm_info_read_idx =
+ (cx->pgm_info_read_idx + idx->entries) % CX18_MAX_PGM_INDEX;
+ return 0;
+#else
+ return -EINVAL;
#endif
- case VIDIOC_ENCODER_CMD:
- case VIDIOC_TRY_ENCODER_CMD: {
- struct v4l2_encoder_cmd *enc = arg;
- int try = cmd == VIDIOC_TRY_ENCODER_CMD;
-
- memset(&enc->raw, 0, sizeof(enc->raw));
- switch (enc->cmd) {
- case V4L2_ENC_CMD_START:
- enc->flags = 0;
- if (try)
- return 0;
- return cx18_start_capture(id);
-
- case V4L2_ENC_CMD_STOP:
- enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END;
- if (try)
- return 0;
- cx18_stop_capture(id, enc->flags & V4L2_ENC_CMD_STOP_AT_GOP_END);
+}
+
+static int cx18_encoder_cmd(struct file *file, void *fh,
+ struct v4l2_encoder_cmd *enc)
+{
+ struct cx18_open_id *id = fh;
+ struct cx18 *cx = id->cx;
+
+ switch (enc->cmd) {
+ case V4L2_ENC_CMD_START:
+ CX18_DEBUG_IOCTL("V4L2_ENC_CMD_START\n");
+ enc->flags = 0;
+ return cx18_start_capture(id);
+
+ case V4L2_ENC_CMD_STOP:
+ CX18_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n");
+ enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END;
+ cx18_stop_capture(id,
+ enc->flags & V4L2_ENC_CMD_STOP_AT_GOP_END);
+ break;
+
+ case V4L2_ENC_CMD_PAUSE:
+ CX18_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n");
+ enc->flags = 0;
+ if (!atomic_read(&cx->ana_capturing))
+ return -EPERM;
+ if (test_and_set_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags))
return 0;
+ cx18_mute(cx);
+ cx18_vapi(cx, CX18_CPU_CAPTURE_PAUSE, 1, cx18_find_handle(cx));
+ break;
- case V4L2_ENC_CMD_PAUSE:
- enc->flags = 0;
- if (try)
- return 0;
- if (!atomic_read(&cx->ana_capturing))
- return -EPERM;
- if (test_and_set_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags))
- return 0;
- cx18_mute(cx);
- cx18_vapi(cx, CX18_CPU_CAPTURE_PAUSE, 1, cx18_find_handle(cx));
- break;
-
- case V4L2_ENC_CMD_RESUME:
- enc->flags = 0;
- if (try)
- return 0;
- if (!atomic_read(&cx->ana_capturing))
- return -EPERM;
- if (!test_and_clear_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags))
- return 0;
- cx18_vapi(cx, CX18_CPU_CAPTURE_RESUME, 1, cx18_find_handle(cx));
- cx18_unmute(cx);
- break;
- default:
- return -EINVAL;
- }
+ case V4L2_ENC_CMD_RESUME:
+ CX18_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n");
+ enc->flags = 0;
+ if (!atomic_read(&cx->ana_capturing))
+ return -EPERM;
+ if (!test_and_clear_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags))
+ return 0;
+ cx18_vapi(cx, CX18_CPU_CAPTURE_RESUME, 1, cx18_find_handle(cx));
+ cx18_unmute(cx);
break;
+
+ default:
+ CX18_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd);
+ return -EINVAL;
}
+ return 0;
+}
- case VIDIOC_LOG_STATUS:
- {
- struct v4l2_input vidin;
- struct v4l2_audio audin;
- int i;
+static int cx18_try_encoder_cmd(struct file *file, void *fh,
+ struct v4l2_encoder_cmd *enc)
+{
+ struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
- CX18_INFO("================= START STATUS CARD #%d =================\n", cx->num);
- if (cx->hw_flags & CX18_HW_TVEEPROM) {
- struct tveeprom tv;
+ switch (enc->cmd) {
+ case V4L2_ENC_CMD_START:
+ CX18_DEBUG_IOCTL("V4L2_ENC_CMD_START\n");
+ enc->flags = 0;
+ break;
- cx18_read_eeprom(cx, &tv);
- }
- cx18_call_i2c_clients(cx, VIDIOC_LOG_STATUS, NULL);
- cx18_get_input(cx, cx->active_input, &vidin);
- cx18_get_audio_input(cx, cx->audio_input, &audin);
- CX18_INFO("Video Input: %s\n", vidin.name);
- CX18_INFO("Audio Input: %s\n", audin.name);
- CX18_INFO("Tuner: %s\n",
- test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ?
- "Radio" : "TV");
- cx2341x_log_status(&cx->params, cx->name);
- CX18_INFO("Status flags: 0x%08lx\n", cx->i_flags);
- for (i = 0; i < CX18_MAX_STREAMS; i++) {
- struct cx18_stream *s = &cx->streams[i];
-
- if (s->v4l2dev == NULL || s->buffers == 0)
- continue;
- CX18_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n",
- s->name, s->s_flags,
- (s->buffers - s->q_free.buffers) * 100 / s->buffers,
- (s->buffers * s->buf_size) / 1024, s->buffers);
- }
- CX18_INFO("Read MPEG/VBI: %lld/%lld bytes\n",
- (long long)cx->mpg_data_received,
- (long long)cx->vbi_data_inserted);
- CX18_INFO("================== END STATUS CARD #%d ==================\n", cx->num);
+ case V4L2_ENC_CMD_STOP:
+ CX18_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n");
+ enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END;
+ break;
+
+ case V4L2_ENC_CMD_PAUSE:
+ CX18_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n");
+ enc->flags = 0;
+ break;
+
+ case V4L2_ENC_CMD_RESUME:
+ CX18_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n");
+ enc->flags = 0;
break;
- }
default:
+ CX18_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd);
return -EINVAL;
}
return 0;
}
-static int cx18_v4l2_do_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, void *arg)
+static int cx18_log_status(struct file *file, void *fh)
{
- struct cx18_open_id *id = (struct cx18_open_id *)filp->private_data;
- struct cx18 *cx = id->cx;
- int ret;
+ struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+ struct v4l2_input vidin;
+ struct v4l2_audio audin;
+ int i;
- /* check priority */
- switch (cmd) {
- case VIDIOC_S_CTRL:
- case VIDIOC_S_STD:
- case VIDIOC_S_INPUT:
- case VIDIOC_S_TUNER:
- case VIDIOC_S_FREQUENCY:
- case VIDIOC_S_FMT:
- case VIDIOC_S_CROP:
- case VIDIOC_S_EXT_CTRLS:
- ret = v4l2_prio_check(&cx->prio, &id->prio);
- if (ret)
- return ret;
- }
+ CX18_INFO("================= START STATUS CARD #%d =================\n", cx->num);
+ if (cx->hw_flags & CX18_HW_TVEEPROM) {
+ struct tveeprom tv;
+
+ cx18_read_eeprom(cx, &tv);
+ }
+ cx18_call_i2c_clients(cx, VIDIOC_LOG_STATUS, NULL);
+ cx18_get_input(cx, cx->active_input, &vidin);
+ cx18_get_audio_input(cx, cx->audio_input, &audin);
+ CX18_INFO("Video Input: %s\n", vidin.name);
+ CX18_INFO("Audio Input: %s\n", audin.name);
+ CX18_INFO("GPIO: direction 0x%08x, value 0x%08x\n",
+ cx->gpio_dir, cx->gpio_val);
+ CX18_INFO("Tuner: %s\n",
+ test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ? "Radio" : "TV");
+ cx2341x_log_status(&cx->params, cx->name);
+ CX18_INFO("Status flags: 0x%08lx\n", cx->i_flags);
+ for (i = 0; i < CX18_MAX_STREAMS; i++) {
+ struct cx18_stream *s = &cx->streams[i];
+
+ if (s->v4l2dev == NULL || s->buffers == 0)
+ continue;
+ CX18_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n",
+ s->name, s->s_flags,
+ (s->buffers - s->q_free.buffers) * 100 / s->buffers,
+ (s->buffers * s->buf_size) / 1024, s->buffers);
+ }
+ CX18_INFO("Read MPEG/VBI: %lld/%lld bytes\n",
+ (long long)cx->mpg_data_received,
+ (long long)cx->vbi_data_inserted);
+ CX18_INFO("================== END STATUS CARD #%d ==================\n", cx->num);
+ return 0;
+}
+
+static int cx18_default(struct file *file, void *fh, int cmd, void *arg)
+{
+ struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
switch (cmd) {
- case VIDIOC_DBG_G_REGISTER:
- case VIDIOC_DBG_S_REGISTER:
- case VIDIOC_G_CHIP_IDENT:
- case VIDIOC_INT_S_AUDIO_ROUTING:
- case VIDIOC_INT_RESET:
- if (cx18_debug & CX18_DBGFLG_IOCTL) {
- printk(KERN_INFO "cx18%d ioctl: ", cx->num);
- v4l_printk_ioctl(cmd);
- }
- return cx18_debug_ioctls(filp, cmd, arg);
-
- case VIDIOC_G_PRIORITY:
- case VIDIOC_S_PRIORITY:
- case VIDIOC_QUERYCAP:
- case VIDIOC_ENUMINPUT:
- case VIDIOC_G_INPUT:
- case VIDIOC_S_INPUT:
- case VIDIOC_G_FMT:
- case VIDIOC_S_FMT:
- case VIDIOC_TRY_FMT:
- case VIDIOC_ENUM_FMT:
- case VIDIOC_CROPCAP:
- case VIDIOC_G_CROP:
- case VIDIOC_S_CROP:
- case VIDIOC_G_FREQUENCY:
- case VIDIOC_S_FREQUENCY:
- case VIDIOC_ENUMSTD:
- case VIDIOC_G_STD:
- case VIDIOC_S_STD:
- case VIDIOC_S_TUNER:
- case VIDIOC_G_TUNER:
- case VIDIOC_ENUMAUDIO:
- case VIDIOC_S_AUDIO:
- case VIDIOC_G_AUDIO:
- case VIDIOC_G_SLICED_VBI_CAP:
- case VIDIOC_LOG_STATUS:
- case VIDIOC_G_ENC_INDEX:
- case VIDIOC_ENCODER_CMD:
- case VIDIOC_TRY_ENCODER_CMD:
- if (cx18_debug & CX18_DBGFLG_IOCTL) {
- printk(KERN_INFO "cx18%d ioctl: ", cx->num);
- v4l_printk_ioctl(cmd);
- }
- return cx18_v4l2_ioctls(cx, filp, cmd, arg);
-
- case VIDIOC_QUERYMENU:
- case VIDIOC_QUERYCTRL:
- case VIDIOC_S_CTRL:
- case VIDIOC_G_CTRL:
- case VIDIOC_S_EXT_CTRLS:
- case VIDIOC_G_EXT_CTRLS:
- case VIDIOC_TRY_EXT_CTRLS:
- if (cx18_debug & CX18_DBGFLG_IOCTL) {
- printk(KERN_INFO "cx18%d ioctl: ", cx->num);
- v4l_printk_ioctl(cmd);
- }
- return cx18_control_ioctls(cx, cmd, arg);
+ case VIDIOC_INT_S_AUDIO_ROUTING: {
+ struct v4l2_routing *route = arg;
- case 0x00005401: /* Handle isatty() calls */
- return -EINVAL;
+ CX18_DEBUG_IOCTL("VIDIOC_INT_S_AUDIO_ROUTING(%d, %d)\n",
+ route->input, route->output);
+ cx18_audio_set_route(cx, route);
+ break;
+ }
default:
- return v4l_compat_translate_ioctl(inode, filp, cmd, arg,
- cx18_v4l2_do_ioctl);
+ return -EINVAL;
}
return 0;
}
@@ -867,12 +866,65 @@ static int cx18_v4l2_do_ioctl(struct inode *inode, struct file *filp,
int cx18_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
unsigned long arg)
{
+ struct video_device *vfd = video_devdata(filp);
struct cx18_open_id *id = (struct cx18_open_id *)filp->private_data;
struct cx18 *cx = id->cx;
int res;
mutex_lock(&cx->serialize_lock);
- res = video_usercopy(inode, filp, cmd, arg, cx18_v4l2_do_ioctl);
+
+ if (cx18_debug & CX18_DBGFLG_IOCTL)
+ vfd->debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG;
+ res = video_ioctl2(inode, filp, cmd, arg);
+ vfd->debug = 0;
mutex_unlock(&cx->serialize_lock);
return res;
}
+
+void cx18_set_funcs(struct video_device *vdev)
+{
+ vdev->vidioc_querycap = cx18_querycap;
+ vdev->vidioc_g_priority = cx18_g_priority;
+ vdev->vidioc_s_priority = cx18_s_priority;
+ vdev->vidioc_s_audio = cx18_s_audio;
+ vdev->vidioc_g_audio = cx18_g_audio;
+ vdev->vidioc_enumaudio = cx18_enumaudio;
+ vdev->vidioc_enum_input = cx18_enum_input;
+ vdev->vidioc_cropcap = cx18_cropcap;
+ vdev->vidioc_s_crop = cx18_s_crop;
+ vdev->vidioc_g_crop = cx18_g_crop;
+ vdev->vidioc_g_input = cx18_g_input;
+ vdev->vidioc_s_input = cx18_s_input;
+ vdev->vidioc_g_frequency = cx18_g_frequency;
+ vdev->vidioc_s_frequency = cx18_s_frequency;
+ vdev->vidioc_s_tuner = cx18_s_tuner;
+ vdev->vidioc_g_tuner = cx18_g_tuner;
+ vdev->vidioc_g_enc_index = cx18_g_enc_index;
+ vdev->vidioc_g_std = cx18_g_std;
+ vdev->vidioc_s_std = cx18_s_std;
+ vdev->vidioc_log_status = cx18_log_status;
+ vdev->vidioc_enum_fmt_vid_cap = cx18_enum_fmt_vid_cap;
+ vdev->vidioc_encoder_cmd = cx18_encoder_cmd;
+ vdev->vidioc_try_encoder_cmd = cx18_try_encoder_cmd;
+ vdev->vidioc_g_fmt_vid_cap = cx18_g_fmt_vid_cap;
+ vdev->vidioc_g_fmt_vbi_cap = cx18_g_fmt_vbi_cap;
+ vdev->vidioc_g_fmt_sliced_vbi_cap = cx18_g_fmt_sliced_vbi_cap;
+ vdev->vidioc_s_fmt_vid_cap = cx18_s_fmt_vid_cap;
+ vdev->vidioc_s_fmt_vbi_cap = cx18_s_fmt_vbi_cap;
+ vdev->vidioc_s_fmt_sliced_vbi_cap = cx18_s_fmt_sliced_vbi_cap;
+ vdev->vidioc_try_fmt_vid_cap = cx18_try_fmt_vid_cap;
+ vdev->vidioc_try_fmt_vbi_cap = cx18_try_fmt_vbi_cap;
+ vdev->vidioc_try_fmt_sliced_vbi_cap = cx18_try_fmt_sliced_vbi_cap;
+ vdev->vidioc_g_sliced_vbi_cap = cx18_g_sliced_vbi_cap;
+ vdev->vidioc_g_chip_ident = cx18_g_chip_ident;
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ vdev->vidioc_g_register = cx18_g_register;
+ vdev->vidioc_s_register = cx18_s_register;
+#endif
+ vdev->vidioc_default = cx18_default;
+ vdev->vidioc_queryctrl = cx18_queryctrl;
+ vdev->vidioc_querymenu = cx18_querymenu;
+ vdev->vidioc_g_ext_ctrls = cx18_g_ext_ctrls;
+ vdev->vidioc_s_ext_ctrls = cx18_s_ext_ctrls;
+ vdev->vidioc_try_ext_ctrls = cx18_try_ext_ctrls;
+}
diff --git a/linux/drivers/media/video/cx18/cx18-ioctl.h b/linux/drivers/media/video/cx18/cx18-ioctl.h
index 9f4c7eb28..2222f679d 100644
--- a/linux/drivers/media/video/cx18/cx18-ioctl.h
+++ b/linux/drivers/media/video/cx18/cx18-ioctl.h
@@ -24,7 +24,9 @@
u16 cx18_service2vbi(int type);
void cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal);
u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt);
+void cx18_set_funcs(struct video_device *vdev);
+int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std);
+int cx18_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf);
+int cx18_s_input(struct file *file, void *fh, unsigned int inp);
int cx18_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
unsigned long arg);
-int cx18_v4l2_ioctls(struct cx18 *cx, struct file *filp, unsigned cmd,
- void *arg);
diff --git a/linux/drivers/media/video/cx18/cx18-irq.c b/linux/drivers/media/video/cx18/cx18-irq.c
index 6e14f8bda..25114a5cb 100644
--- a/linux/drivers/media/video/cx18/cx18-irq.c
+++ b/linux/drivers/media/video/cx18/cx18-irq.c
@@ -75,7 +75,7 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_mailbox *mb)
cx18_buf_sync_for_device(s, buf);
cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle,
- (void *)&cx->scb->cpu_mdl[buf->id] - cx->enc_mem,
+ (void __iomem *)&cx->scb->cpu_mdl[buf->id] - cx->enc_mem,
1, buf->id, s->buf_size);
} else
set_bit(CX18_F_B_NEED_BUF_SWAP, &buf->b_flags);
@@ -161,13 +161,15 @@ irqreturn_t cx18_irq_handler(int irq, void *dev_id)
*/
if (sw2) {
- if (sw2 & (cx->scb->cpu2hpu_irq_ack | cx->scb->cpu2epu_irq_ack))
+ if (sw2 & (readl(&cx->scb->cpu2hpu_irq_ack) |
+ readl(&cx->scb->cpu2epu_irq_ack)))
wake_up(&cx->mb_cpu_waitq);
- if (sw2 & (cx->scb->apu2hpu_irq_ack | cx->scb->apu2epu_irq_ack))
+ if (sw2 & (readl(&cx->scb->apu2hpu_irq_ack) |
+ readl(&cx->scb->apu2epu_irq_ack)))
wake_up(&cx->mb_apu_waitq);
- if (sw2 & cx->scb->epu2hpu_irq_ack)
+ if (sw2 & readl(&cx->scb->epu2hpu_irq_ack))
wake_up(&cx->mb_epu_waitq);
- if (sw2 & cx->scb->hpu2epu_irq_ack)
+ if (sw2 & readl(&cx->scb->hpu2epu_irq_ack))
wake_up(&cx->mb_hpu_waitq);
}
diff --git a/linux/drivers/media/video/cx18/cx18-mailbox.c b/linux/drivers/media/video/cx18/cx18-mailbox.c
index 0c5f328bc..93177514e 100644
--- a/linux/drivers/media/video/cx18/cx18-mailbox.c
+++ b/linux/drivers/media/video/cx18/cx18-mailbox.c
@@ -81,6 +81,7 @@ static const struct cx18_api_info api_info[] = {
API_ENTRY(CPU, CX18_CPU_GET_ENC_PTS, 0),
API_ENTRY(CPU, CX18_CPU_DE_SET_MDL_ACK, 0),
API_ENTRY(CPU, CX18_CPU_DE_SET_MDL, API_FAST),
+ API_ENTRY(CPU, CX18_APU_RESETAI, API_FAST),
API_ENTRY(0, 0, 0),
};
@@ -94,10 +95,10 @@ static const struct cx18_api_info *find_api_info(u32 cmd)
return NULL;
}
-static struct cx18_mailbox *cx18_mb_is_complete(struct cx18 *cx, int rpu,
+static struct cx18_mailbox __iomem *cx18_mb_is_complete(struct cx18 *cx, int rpu,
u32 *state, u32 *irq, u32 *req)
{
- struct cx18_mailbox *mb = NULL;
+ struct cx18_mailbox __iomem *mb = NULL;
int wait_count = 0;
u32 ack;
@@ -142,7 +143,7 @@ static struct cx18_mailbox *cx18_mb_is_complete(struct cx18 *cx, int rpu,
long cx18_mb_ack(struct cx18 *cx, const struct cx18_mailbox *mb)
{
const struct cx18_api_info *info = find_api_info(mb->cmd);
- struct cx18_mailbox *ack_mb;
+ struct cx18_mailbox __iomem *ack_mb;
u32 ack_irq;
u8 rpu = CPU;
@@ -182,7 +183,7 @@ static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[])
{
const struct cx18_api_info *info = find_api_info(cmd);
u32 state = 0, irq = 0, req, oldreq, err;
- struct cx18_mailbox *mb;
+ struct cx18_mailbox __iomem *mb;
wait_queue_head_t *waitq;
int timeout = 100;
int cnt = 0;
diff --git a/linux/drivers/media/video/cx18/cx18-streams.c b/linux/drivers/media/video/cx18/cx18-streams.c
index 352ff698a..df99070e6 100644
--- a/linux/drivers/media/video/cx18/cx18-streams.c
+++ b/linux/drivers/media/video/cx18/cx18-streams.c
@@ -39,10 +39,9 @@ static struct file_operations cx18_v4l2_enc_fops = {
.owner = THIS_MODULE,
.read = cx18_v4l2_read,
.open = cx18_v4l2_open,
+ /* FIXME change to video_ioctl2 if serialization lock can be removed */
.ioctl = cx18_v4l2_ioctl,
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11)
.compat_ioctl = v4l_compat_ioctl32,
-#endif
.release = cx18_v4l2_close,
.poll = cx18_v4l2_enc_poll,
};
@@ -191,14 +190,15 @@ static int cx18_prep_dev(struct cx18 *cx, int type)
s->v4l2dev->type =
VID_TYPE_CAPTURE | VID_TYPE_TUNER | VID_TYPE_TELETEXT |
VID_TYPE_CLIPPING | VID_TYPE_SCALES | VID_TYPE_MPEG_ENCODER;
- snprintf(s->v4l2dev->name, sizeof(s->v4l2dev->name), "cx18%d %s",
- cx->num, s->name);
+ snprintf(s->v4l2dev->name, sizeof(s->v4l2dev->name), "cx18-%d",
+ cx->num);
s->v4l2dev->minor = minor;
s->v4l2dev->dev = &cx->dev->dev;
s->v4l2dev->fops = cx18_stream_info[type].fops;
s->v4l2dev->release = video_device_release;
-
+ s->v4l2dev->tvnorms = V4L2_STD_ALL;
+ cx18_set_funcs(s->v4l2dev);
return 0;
}
@@ -475,8 +475,8 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
}
cx18_vapi(cx, CX18_CPU_DE_SET_MDL_ACK, 3, s->handle,
- (void *)&cx->scb->cpu_mdl_ack[s->type][0] - cx->enc_mem,
- (void *)&cx->scb->cpu_mdl_ack[s->type][1] - cx->enc_mem);
+ (void __iomem *)&cx->scb->cpu_mdl_ack[s->type][0] - cx->enc_mem,
+ (void __iomem *)&cx->scb->cpu_mdl_ack[s->type][1] - cx->enc_mem);
list_for_each(p, &s->q_free.list) {
struct cx18_buffer *buf = list_entry(p, struct cx18_buffer, list);
@@ -484,8 +484,8 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
writel(buf->dma_handle, &cx->scb->cpu_mdl[buf->id].paddr);
writel(s->buf_size, &cx->scb->cpu_mdl[buf->id].length);
cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle,
- (void *)&cx->scb->cpu_mdl[buf->id] - cx->enc_mem, 1,
- buf->id, s->buf_size);
+ (void __iomem *)&cx->scb->cpu_mdl[buf->id] - cx->enc_mem,
+ 1, buf->id, s->buf_size);
}
/* begin_capture */
if (cx18_vapi(cx, CX18_CPU_CAPTURE_START, 1, s->handle)) {
diff --git a/linux/drivers/media/video/cx18/cx23418.h b/linux/drivers/media/video/cx18/cx23418.h
index 33f78da9d..e7ed05305 100644
--- a/linux/drivers/media/video/cx18/cx23418.h
+++ b/linux/drivers/media/video/cx18/cx23418.h
@@ -52,6 +52,11 @@
#define EPU_CMD_MASK_DEBUG (EPU_CMD_MASK | 0x000000)
#define EPU_CMD_MASK_DE (EPU_CMD_MASK | 0x040000)
+#define APU_CMD_MASK 0x10000000
+#define APU_CMD_MASK_ACK (APU_CMD_MASK | 0x80000000)
+
+#define CX18_APU_RESETAI (APU_CMD_MASK | 0x05)
+
/* Description: This command indicates that a Memory Descriptor List has been
filled with the requested channel type
IN[0] - Task handle. Handle of the task
diff --git a/linux/drivers/media/video/cx2341x.c b/linux/drivers/media/video/cx2341x.c
index 6acb47605..3f2191162 100644
--- a/linux/drivers/media/video/cx2341x.c
+++ b/linux/drivers/media/video/cx2341x.c
@@ -25,9 +25,6 @@
#include <linux/init.h>
#include <linux/types.h>
#include <linux/videodev2.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
-#include <linux/slab.h>
-#endif
#include <media/tuner.h>
#include <media/cx2341x.h>
@@ -84,7 +81,7 @@ EXPORT_SYMBOL(cx2341x_mpeg_ctrls);
/* Map the control ID to the correct field in the cx2341x_mpeg_params
struct. Return -EINVAL if the ID is unknown, else return 0. */
-static int cx2341x_get_ctrl(struct cx2341x_mpeg_params *params,
+static int cx2341x_get_ctrl(const struct cx2341x_mpeg_params *params,
struct v4l2_ext_control *ctrl)
{
switch (ctrl->id) {
@@ -424,7 +421,7 @@ static int cx2341x_ctrl_query_fill(struct v4l2_queryctrl *qctrl,
return 0;
}
-int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params,
+int cx2341x_ctrl_query(const struct cx2341x_mpeg_params *params,
struct v4l2_queryctrl *qctrl)
{
int err;
@@ -584,9 +581,9 @@ int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params,
}
EXPORT_SYMBOL(cx2341x_ctrl_query);
-const char **cx2341x_ctrl_get_menu(u32 id)
+const char **cx2341x_ctrl_get_menu(const struct cx2341x_mpeg_params *p, u32 id)
{
- static const char *mpeg_stream_type[] = {
+ static const char *mpeg_stream_type_without_ts[] = {
"MPEG-2 Program Stream",
"",
"MPEG-1 System Stream",
@@ -596,6 +593,16 @@ const char **cx2341x_ctrl_get_menu(u32 id)
NULL
};
+ static const char *mpeg_stream_type_with_ts[] = {
+ "MPEG-2 Program Stream",
+ "MPEG-2 Transport Stream",
+ "MPEG-1 System Stream",
+ "MPEG-2 DVD-compatible Stream",
+ "MPEG-1 VCD-compatible Stream",
+ "MPEG-2 SVCD-compatible Stream",
+ NULL
+ };
+
static const char *cx2341x_video_spatial_filter_mode_menu[] = {
"Manual",
"Auto",
@@ -634,7 +641,8 @@ const char **cx2341x_ctrl_get_menu(u32 id)
switch (id) {
case V4L2_CID_MPEG_STREAM_TYPE:
- return mpeg_stream_type;
+ return (p->capabilities & CX2341X_CAP_HAS_TS) ?
+ mpeg_stream_type_with_ts : mpeg_stream_type_without_ts;
case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
return NULL;
@@ -694,7 +702,7 @@ int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params, int busy,
if (err)
break;
if (qctrl.type == V4L2_CTRL_TYPE_MENU)
- menu_items = cx2341x_ctrl_get_menu(qctrl.id);
+ menu_items = cx2341x_ctrl_get_menu(params, qctrl.id);
err = v4l2_ctrl_check(ctrl, &qctrl, menu_items);
if (err)
break;
@@ -937,9 +945,9 @@ int cx2341x_update(void *priv, cx2341x_mbox_func func,
}
EXPORT_SYMBOL(cx2341x_update);
-static const char *cx2341x_menu_item(struct cx2341x_mpeg_params *p, u32 id)
+static const char *cx2341x_menu_item(const struct cx2341x_mpeg_params *p, u32 id)
{
- const char **menu = cx2341x_ctrl_get_menu(id);
+ const char **menu = cx2341x_ctrl_get_menu(p, id);
struct v4l2_ext_control ctrl;
if (menu == NULL)
@@ -956,7 +964,7 @@ invalid:
return "<invalid>";
}
-void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix)
+void cx2341x_log_status(const struct cx2341x_mpeg_params *p, const char *prefix)
{
int is_mpeg1 = p->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
int temporal = p->video_temporal_filter;
diff --git a/linux/drivers/media/video/cx23885/cx23885-417.c b/linux/drivers/media/video/cx23885/cx23885-417.c
index 1585db931..ff1abdb0f 100644
--- a/linux/drivers/media/video/cx23885/cx23885-417.c
+++ b/linux/drivers/media/video/cx23885/cx23885-417.c
@@ -1173,387 +1173,412 @@ static int cx23885_querymenu(struct cx23885_dev *dev,
qctrl.id = qmenu->id;
cx23885_queryctrl(dev, &qctrl);
return v4l2_ctrl_query_menu(qmenu, &qctrl,
- cx2341x_ctrl_get_menu(qmenu->id));
+ cx2341x_ctrl_get_menu(&dev->mpeg_params, qmenu->id));
}
-int cx23885_do_ioctl(struct inode *inode, struct file *file, int radio,
- struct cx23885_dev *dev, unsigned int cmd, void *arg,
- v4l2_kioctl driver_ioctl)
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id)
{
- int err;
-
- switch (cmd) {
- /* ---------- tv norms ---------- */
- case VIDIOC_ENUMSTD:
- {
- struct v4l2_standard *e = arg;
- unsigned int i;
-
- i = e->index;
- if (i >= ARRAY_SIZE(cx23885_tvnorms))
- return -EINVAL;
- err = v4l2_video_std_construct(e,
- cx23885_tvnorms[e->index].id,
- cx23885_tvnorms[e->index].name);
- e->index = i;
- if (err < 0)
- return err;
- return 0;
- }
- case VIDIOC_G_STD:
- {
- v4l2_std_id *id = arg;
+ struct cx23885_fh *fh = file->private_data;
+ struct cx23885_dev *dev = fh->dev;
+ unsigned int i;
- *id = dev->encodernorm.id;
- return 0;
- }
- case VIDIOC_S_STD:
- {
- v4l2_std_id *id = arg;
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(cx23885_tvnorms); i++)
- if (*id & cx23885_tvnorms[i].id)
- break;
- if (i == ARRAY_SIZE(cx23885_tvnorms))
- return -EINVAL;
- dev->encodernorm = cx23885_tvnorms[i];
+ for (i = 0; i < ARRAY_SIZE(cx23885_tvnorms); i++)
+ if (*id & cx23885_tvnorms[i].id)
+ break;
+ if (i == ARRAY_SIZE(cx23885_tvnorms))
+ return -EINVAL;
+ dev->encodernorm = cx23885_tvnorms[i];
#if 0
- /* Notify the video decoder and other i2c clients.
- * This will likely need to be enabled for non NTSC
- * formats.
- */
- cx23885_call_i2c_clients(&dev->i2c_bus[0], VIDIOC_S_STD, id);
- cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_S_STD, id);
+ /* Notify the video decoder and other i2c clients.
+ * This will likely need to be enabled for non NTSC
+ * formats.
+ */
+ cx23885_call_i2c_clients(&dev->i2c_bus[0], VIDIOC_S_STD, id);
+ cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_S_STD, id);
#endif
+ return 0;
+}
- return 0;
- }
+static int vidioc_enum_input(struct file *file, void *priv,
+ struct v4l2_input *i)
+{
+ struct cx23885_fh *fh = file->private_data;
+ struct cx23885_dev *dev = fh->dev;
+ struct cx23885_input *input;
+ unsigned int n;
- /* ------ input switching ---------- */
- case VIDIOC_ENUMINPUT:
- {
- struct cx23885_input *input;
- struct v4l2_input *i = arg;
- unsigned int n;
-
- n = i->index;
- if (n >= 4)
- return -EINVAL;
- input = &cx23885_boards[dev->board].input[n];
- if (input->type == 0)
- return -EINVAL;
- memset(i, 0, sizeof(*i));
- i->index = n;
- /* FIXME
- * strcpy(i->name, input->name); */
- strcpy(i->name, "unset");
- if (input->type == CX23885_VMUX_TELEVISION ||
- input->type == CX23885_VMUX_CABLE)
- i->type = V4L2_INPUT_TYPE_TUNER;
- else
- i->type = V4L2_INPUT_TYPE_CAMERA;
+ n = i->index;
- for (n = 0; n < ARRAY_SIZE(cx23885_tvnorms); n++)
- i->std |= cx23885_tvnorms[n].id;
- return 0;
- }
- case VIDIOC_G_INPUT:
- {
- unsigned int *i = arg;
+ if (n >= 4)
+ return -EINVAL;
- *i = dev->input;
- return 0;
- }
- case VIDIOC_S_INPUT:
- {
- unsigned int *i = arg;
+ input = &cx23885_boards[dev->board].input[n];
- if (*i >= 4)
- return -EINVAL;
+ if (input->type == 0)
+ return -EINVAL;
- return 0;
- }
+ memset(i, 0, sizeof(*i));
+ i->index = n;
- /* --- tuner ioctls ------------------------------------------ */
- case VIDIOC_G_TUNER:
- {
- struct v4l2_tuner *t = arg;
+ /* FIXME
+ * strcpy(i->name, input->name); */
+ strcpy(i->name, "unset");
- if (UNSET == dev->tuner_type)
- return -EINVAL;
- if (0 != t->index)
- return -EINVAL;
- memset(t, 0, sizeof(*t));
- strcpy(t->name, "Television");
- cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_G_TUNER, t);
- cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_G_TUNER, t);
+ if (input->type == CX23885_VMUX_TELEVISION ||
+ input->type == CX23885_VMUX_CABLE)
+ i->type = V4L2_INPUT_TYPE_TUNER;
+ else
+ i->type = V4L2_INPUT_TYPE_CAMERA;
- dprintk(1, "VIDIOC_G_TUNER: tuner type %d\n", t->type);
+ for (n = 0; n < ARRAY_SIZE(cx23885_tvnorms); n++)
+ i->std |= cx23885_tvnorms[n].id;
+ return 0;
+}
- return 0;
- }
- case VIDIOC_S_TUNER:
- {
- struct v4l2_tuner *t = arg;
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+{
+ struct cx23885_fh *fh = file->private_data;
+ struct cx23885_dev *dev = fh->dev;
- if (UNSET == dev->tuner_type)
- return -EINVAL;
+ *i = dev->input;
+ return 0;
+}
- /* Update the A/V core */
- cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_S_TUNER, t);
+static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
+{
+ if (i >= 4)
+ return -EINVAL;
- return 0;
- }
- case VIDIOC_G_FREQUENCY:
- {
- struct v4l2_frequency *f = arg;
+ return 0;
+}
- memset(f, 0, sizeof(*f));
- if (UNSET == dev->tuner_type)
- return -EINVAL;
- f->type = V4L2_TUNER_ANALOG_TV;
- f->frequency = dev->freq;
+static int vidioc_g_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *t)
+{
+ struct cx23885_fh *fh = file->private_data;
+ struct cx23885_dev *dev = fh->dev;
- /* Assumption that tuner is always on bus 1 */
- cx23885_call_i2c_clients(&dev->i2c_bus[1],
- VIDIOC_G_FREQUENCY, f);
+ if (UNSET == dev->tuner_type)
+ return -EINVAL;
+ if (0 != t->index)
+ return -EINVAL;
+ memset(t, 0, sizeof(*t));
+ strcpy(t->name, "Television");
+ cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_G_TUNER, t);
+ cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_G_TUNER, t);
- return 0;
- }
- case VIDIOC_S_FREQUENCY:
- {
- struct v4l2_frequency *f = arg;
-
- dprintk(1, "VIDIOC_S_FREQUENCY: dev type %d, f\n",
- dev->tuner_type);
- dprintk(1, "VIDIOC_S_FREQUENCY: f tuner %d, f type %d\n",
- f->tuner, f->type);
- if (UNSET == dev->tuner_type)
- return -EINVAL;
- if (f->tuner != 0)
- return -EINVAL;
- if (f->type != V4L2_TUNER_ANALOG_TV)
- return -EINVAL;
- dev->freq = f->frequency;
-
- /* Assumption that tuner is always on bus 1 */
- cx23885_call_i2c_clients(&dev->i2c_bus[1],
- VIDIOC_S_FREQUENCY, f);
- return 0;
- }
- case VIDIOC_S_CTRL:
- {
- /* Update the A/V core */
- cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_S_CTRL, arg);
- return 0;
- }
- default:
- /* Convert V4L ioctl to V4L2 and call mpeg_do_ioctl
- * (driver_ioctl) */
- return v4l_compat_translate_ioctl(inode, file, cmd, arg,
- driver_ioctl);
- }
+ dprintk(1, "VIDIOC_G_TUNER: tuner type %d\n", t->type);
+
+ return 0;
+}
+
+static int vidioc_s_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *t)
+{
+ struct cx23885_fh *fh = file->private_data;
+ struct cx23885_dev *dev = fh->dev;
+
+ if (UNSET == dev->tuner_type)
+ return -EINVAL;
+
+ /* Update the A/V core */
+ cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_S_TUNER, t);
return 0;
}
-static int mpeg_do_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, void *arg)
+static int vidioc_g_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+{
+ struct cx23885_fh *fh = file->private_data;
+ struct cx23885_dev *dev = fh->dev;
+
+ memset(f, 0, sizeof(*f));
+ if (UNSET == dev->tuner_type)
+ return -EINVAL;
+ f->type = V4L2_TUNER_ANALOG_TV;
+ f->frequency = dev->freq;
+
+ /* Assumption that tuner is always on bus 1 */
+ cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_G_FREQUENCY, f);
+
+ return 0;
+}
+
+static int vidioc_s_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+{
+ struct cx23885_fh *fh = file->private_data;
+ struct cx23885_dev *dev = fh->dev;
+
+ cx23885_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
+ CX23885_END_NOW, CX23885_MPEG_CAPTURE,
+ CX23885_RAW_BITS_NONE);
+
+ dprintk(1, "VIDIOC_S_FREQUENCY: dev type %d, f\n",
+ dev->tuner_type);
+ dprintk(1, "VIDIOC_S_FREQUENCY: f tuner %d, f type %d\n",
+ f->tuner, f->type);
+ if (UNSET == dev->tuner_type)
+ return -EINVAL;
+ if (f->tuner != 0)
+ return -EINVAL;
+ if (f->type != V4L2_TUNER_ANALOG_TV)
+ return -EINVAL;
+ dev->freq = f->frequency;
+
+ /* Assumption that tuner is always on bus 1 */
+ cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_S_FREQUENCY, f);
+
+ cx23885_initialize_codec(dev);
+
+ return 0;
+}
+
+static int vidioc_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctl)
+{
+ struct cx23885_fh *fh = file->private_data;
+ struct cx23885_dev *dev = fh->dev;
+
+ /* Update the A/V core */
+ cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_S_CTRL, ctl);
+ return 0;
+}
+
+static int vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
{
struct cx23885_fh *fh = file->private_data;
struct cx23885_dev *dev = fh->dev;
struct cx23885_tsport *tsport = &dev->ts1;
- if (v4l_debug > 1)
- v4l_print_ioctl(dev->name, cmd);
+ memset(cap, 0, sizeof(*cap));
+ strcpy(cap->driver, dev->name);
+ strlcpy(cap->card, cx23885_boards[tsport->dev->board].name,
+ sizeof(cap->card));
+ sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
+ cap->version = CX23885_VERSION_CODE;
+ cap->capabilities =
+ V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_READWRITE |
+ V4L2_CAP_STREAMING |
+ 0;
+ if (UNSET != dev->tuner_type)
+ cap->capabilities |= V4L2_CAP_TUNER;
- switch (cmd) {
+ return 0;
+}
- /* --- capabilities ------------------------------------------ */
- case VIDIOC_QUERYCAP:
- {
- struct v4l2_capability *cap = arg;
-
- memset(cap, 0, sizeof(*cap));
- strcpy(cap->driver, dev->name);
- strlcpy(cap->card, cx23885_boards[tsport->dev->board].name,
- sizeof(cap->card));
- sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
- cap->version = CX23885_VERSION_CODE;
- cap->capabilities =
- V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_READWRITE |
- V4L2_CAP_STREAMING |
- 0;
- if (UNSET != dev->tuner_type)
- cap->capabilities |= V4L2_CAP_TUNER;
-
- return 0;
- }
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ int index;
- /* --- capture ioctls ---------------------------------------- */
- case VIDIOC_ENUM_FMT:
- {
- struct v4l2_fmtdesc *f = arg;
- int index;
-
- index = f->index;
- if (index != 0)
- return -EINVAL;
-
- memset(f, 0, sizeof(*f));
- f->index = index;
- strlcpy(f->description, "MPEG", sizeof(f->description));
- f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- f->pixelformat = V4L2_PIX_FMT_MPEG;
- return 0;
- }
- case VIDIOC_G_FMT:
- {
- struct v4l2_format *f = arg;
-
- memset(f, 0, sizeof(*f));
- f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
- f->fmt.pix.bytesperline = 0;
- f->fmt.pix.sizeimage =
- dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
- f->fmt.pix.colorspace = 0;
- f->fmt.pix.width = dev->ts1.width;
- f->fmt.pix.height = dev->ts1.height;
- f->fmt.pix.field = fh->mpegq.field;
- dprintk(1, "VIDIOC_G_FMT: w: %d, h: %d, f: %d\n",
- dev->ts1.width, dev->ts1.height, fh->mpegq.field);
- return 0;
- }
- case VIDIOC_TRY_FMT:
- {
- struct v4l2_format *f = arg;
-
- f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
- f->fmt.pix.bytesperline = 0;
- f->fmt.pix.sizeimage =
- dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
- f->fmt.pix.sizeimage =
- f->fmt.pix.colorspace = 0;
- dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n",
- dev->ts1.width, dev->ts1.height, fh->mpegq.field);
- return 0;
- }
- case VIDIOC_S_FMT:
- {
- struct v4l2_format *f = arg;
-
- f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
- f->fmt.pix.bytesperline = 0;
- f->fmt.pix.sizeimage =
- dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
- f->fmt.pix.colorspace = 0;
- dprintk(1, "VIDIOC_S_FMT: w: %d, h: %d, f: %d\n",
- f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field);
- return 0;
- }
+ index = f->index;
+ if (index != 0)
+ return -EINVAL;
- /* --- streaming capture ------------------------------------- */
- case VIDIOC_REQBUFS:
- return videobuf_reqbufs(&fh->mpegq, arg);
+ memset(f, 0, sizeof(*f));
+ f->index = index;
+ strlcpy(f->description, "MPEG", sizeof(f->description));
+ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ f->pixelformat = V4L2_PIX_FMT_MPEG;
- case VIDIOC_QUERYBUF:
- return videobuf_querybuf(&fh->mpegq, arg);
+ return 0;
+}
- case VIDIOC_QBUF:
- return videobuf_qbuf(&fh->mpegq, arg);
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct cx23885_fh *fh = file->private_data;
+ struct cx23885_dev *dev = fh->dev;
- case VIDIOC_DQBUF:
- return videobuf_dqbuf(&fh->mpegq, arg,
- file->f_flags & O_NONBLOCK);
+ memset(f, 0, sizeof(*f));
+ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
+ f->fmt.pix.bytesperline = 0;
+ f->fmt.pix.sizeimage =
+ dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
+ f->fmt.pix.colorspace = 0;
+ f->fmt.pix.width = dev->ts1.width;
+ f->fmt.pix.height = dev->ts1.height;
+ f->fmt.pix.field = fh->mpegq.field;
+ dprintk(1, "VIDIOC_G_FMT: w: %d, h: %d, f: %d\n",
+ dev->ts1.width, dev->ts1.height, fh->mpegq.field);
+ return 0;
+}
- case VIDIOC_STREAMON:
- return videobuf_streamon(&fh->mpegq);
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct cx23885_fh *fh = file->private_data;
+ struct cx23885_dev *dev = fh->dev;
- case VIDIOC_STREAMOFF:
- return videobuf_streamoff(&fh->mpegq);
+ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
+ f->fmt.pix.bytesperline = 0;
+ f->fmt.pix.sizeimage =
+ dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
+ f->fmt.pix.sizeimage =
+ f->fmt.pix.colorspace = 0;
+ dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n",
+ dev->ts1.width, dev->ts1.height, fh->mpegq.field);
+ return 0;
+}
- case VIDIOC_G_EXT_CTRLS:
- {
- struct v4l2_ext_controls *f = arg;
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct cx23885_fh *fh = file->private_data;
+ struct cx23885_dev *dev = fh->dev;
- if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
- return -EINVAL;
- return cx2341x_ext_ctrls(&dev->mpeg_params, 0, f, cmd);
- }
- case VIDIOC_S_EXT_CTRLS:
- case VIDIOC_TRY_EXT_CTRLS:
- {
- struct v4l2_ext_controls *f = arg;
- struct cx2341x_mpeg_params p;
- int err;
-
- if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
- return -EINVAL;
- p = dev->mpeg_params;
- err = cx2341x_ext_ctrls(&p, 0, f, cmd);
- if (err == 0 && cmd == VIDIOC_S_EXT_CTRLS) {
- err = cx2341x_update(dev, cx23885_mbox_func,
- &dev->mpeg_params, &p);
- dev->mpeg_params = p;
- }
- return err;
- }
- case VIDIOC_S_FREQUENCY:
- {
- cx23885_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
- CX23885_END_NOW, CX23885_MPEG_CAPTURE,
- CX23885_RAW_BITS_NONE);
- cx23885_do_ioctl(inode, file, 0, dev, cmd, arg,
- mpeg_do_ioctl);
- cx23885_initialize_codec(dev);
-
- return 0;
- }
- case VIDIOC_LOG_STATUS:
- {
- char name[32 + 2];
-
- snprintf(name, sizeof(name), "%s/2", dev->name);
- printk(KERN_INFO
- "%s/2: ============ START LOG STATUS ============\n",
- dev->name);
- cx23885_call_i2c_clients(&dev->i2c_bus[0], VIDIOC_LOG_STATUS,
- NULL);
- cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_LOG_STATUS,
- NULL);
- cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_LOG_STATUS,
- NULL);
- cx2341x_log_status(&dev->mpeg_params, name);
- printk(KERN_INFO
- "%s/2: ============= END LOG STATUS =============\n",
- dev->name);
- return 0;
- }
- case VIDIOC_QUERYMENU:
- return cx23885_querymenu(dev, arg);
- case VIDIOC_QUERYCTRL:
- {
- struct v4l2_queryctrl *c = arg;
+ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
+ f->fmt.pix.bytesperline = 0;
+ f->fmt.pix.sizeimage =
+ dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
+ f->fmt.pix.colorspace = 0;
+ dprintk(1, "VIDIOC_S_FMT: w: %d, h: %d, f: %d\n",
+ f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field);
+ return 0;
+}
- return cx23885_queryctrl(dev, c);
- }
+static int vidioc_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *p)
+{
+ struct cx23885_fh *fh = file->private_data;
- default:
- return cx23885_do_ioctl(inode, file, 0, dev, cmd, arg,
- mpeg_do_ioctl);
+ return videobuf_reqbufs(&fh->mpegq, p);
+}
+
+static int vidioc_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *p)
+{
+ struct cx23885_fh *fh = file->private_data;
+
+ return videobuf_querybuf(&fh->mpegq, p);
+}
+
+static int vidioc_qbuf(struct file *file, void *priv,
+ struct v4l2_buffer *p)
+{
+ struct cx23885_fh *fh = file->private_data;
+
+ return videobuf_qbuf(&fh->mpegq, p);
+}
+
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+ struct cx23885_fh *fh = priv;
+
+ return videobuf_dqbuf(&fh->mpegq, b, file->f_flags & O_NONBLOCK);
+}
+
+
+static int vidioc_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type i)
+{
+ struct cx23885_fh *fh = file->private_data;
+
+ return videobuf_streamon(&fh->mpegq);
+}
+
+static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+ struct cx23885_fh *fh = file->private_data;
+
+ return videobuf_streamoff(&fh->mpegq);
+}
+
+static int vidioc_g_ext_ctrls(struct file *file, void *priv,
+ struct v4l2_ext_controls *f)
+{
+ struct cx23885_fh *fh = priv;
+ struct cx23885_dev *dev = fh->dev;
+
+ if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+ return -EINVAL;
+ return cx2341x_ext_ctrls(&dev->mpeg_params, 0, f, VIDIOC_G_EXT_CTRLS);
+}
+
+static int vidioc_s_ext_ctrls(struct file *file, void *priv,
+ struct v4l2_ext_controls *f)
+{
+ struct cx23885_fh *fh = priv;
+ struct cx23885_dev *dev = fh->dev;
+ struct cx2341x_mpeg_params p;
+ int err;
+
+ if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+ return -EINVAL;
+
+ p = dev->mpeg_params;
+ err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_S_EXT_CTRLS);
+
+ if (err == 0) {
+ err = cx2341x_update(dev, cx23885_mbox_func,
+ &dev->mpeg_params, &p);
+ dev->mpeg_params = p;
}
+ return err;
+}
+
+static int vidioc_try_ext_ctrls(struct file *file, void *priv,
+ struct v4l2_ext_controls *f)
+{
+ struct cx23885_fh *fh = priv;
+ struct cx23885_dev *dev = fh->dev;
+ struct cx2341x_mpeg_params p;
+ int err;
+
+ if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+ return -EINVAL;
+
+ p = dev->mpeg_params;
+ err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_TRY_EXT_CTRLS);
+ return err;
+}
+
+static int vidioc_log_status(struct file *file, void *priv)
+{
+ struct cx23885_fh *fh = priv;
+ struct cx23885_dev *dev = fh->dev;
+ char name[32 + 2];
+
+ snprintf(name, sizeof(name), "%s/2", dev->name);
+ printk(KERN_INFO
+ "%s/2: ============ START LOG STATUS ============\n",
+ dev->name);
+ cx23885_call_i2c_clients(&dev->i2c_bus[0], VIDIOC_LOG_STATUS,
+ NULL);
+ cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_LOG_STATUS,
+ NULL);
+ cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_LOG_STATUS,
+ NULL);
+ cx2341x_log_status(&dev->mpeg_params, name);
+ printk(KERN_INFO
+ "%s/2: ============= END LOG STATUS =============\n",
+ dev->name);
return 0;
}
-static int mpeg_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
+static int vidioc_querymenu(struct file *file, void *priv,
+ struct v4l2_querymenu *a)
+{
+ struct cx23885_fh *fh = priv;
+ struct cx23885_dev *dev = fh->dev;
+
+ return cx23885_querymenu(dev, a);
+}
+
+static int vidioc_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *c)
{
- return video_usercopy(inode, file, cmd, arg, mpeg_do_ioctl);
+ struct cx23885_fh *fh = priv;
+ struct cx23885_dev *dev = fh->dev;
+
+ return cx23885_queryctrl(dev, c);
}
static int mpeg_open(struct inode *inode, struct file *file)
@@ -1678,7 +1703,7 @@ static struct file_operations mpeg_fops = {
.read = mpeg_read,
.poll = mpeg_poll,
.mmap = mpeg_mmap,
- .ioctl = mpeg_ioctl,
+ .ioctl = video_ioctl2,
.llseek = no_llseek,
};
@@ -1690,6 +1715,32 @@ static struct video_device cx23885_mpeg_template = {
VID_TYPE_MPEG_ENCODER,
.fops = &mpeg_fops,
.minor = -1,
+ .vidioc_s_std = vidioc_s_std,
+ .vidioc_enum_input = vidioc_enum_input,
+ .vidioc_g_input = vidioc_g_input,
+ .vidioc_s_input = vidioc_s_input,
+ .vidioc_g_tuner = vidioc_g_tuner,
+ .vidioc_s_tuner = vidioc_s_tuner,
+ .vidioc_g_frequency = vidioc_g_frequency,
+ .vidioc_s_frequency = vidioc_s_frequency,
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ .vidioc_querycap = vidioc_querycap,
+ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+ .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_streamon = vidioc_streamon,
+ .vidioc_streamoff = vidioc_streamoff,
+ .vidioc_g_ext_ctrls = vidioc_g_ext_ctrls,
+ .vidioc_s_ext_ctrls = vidioc_s_ext_ctrls,
+ .vidioc_try_ext_ctrls = vidioc_try_ext_ctrls,
+ .vidioc_log_status = vidioc_log_status,
+ .vidioc_querymenu = vidioc_querymenu,
+ .vidioc_queryctrl = vidioc_queryctrl,
};
void cx23885_417_unregister(struct cx23885_dev *dev)
diff --git a/linux/drivers/media/video/cx23885/cx23885-core.c b/linux/drivers/media/video/cx23885/cx23885-core.c
index 49d8620a3..a1902d59e 100644
--- a/linux/drivers/media/video/cx23885/cx23885-core.c
+++ b/linux/drivers/media/video/cx23885/cx23885-core.c
@@ -292,9 +292,9 @@ int cx23885_sram_channel_setup(struct cx23885_dev *dev,
lines = 6;
BUG_ON(lines < 2);
- cx_write(8 + 0, cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC) );
- cx_write(8 + 4, cpu_to_le32(8) );
- cx_write(8 + 8, cpu_to_le32(0) );
+ cx_write(8 + 0, RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
+ cx_write(8 + 4, 8);
+ cx_write(8 + 8, 0);
/* write CDT */
for (i = 0; i < lines; i++) {
@@ -409,11 +409,11 @@ static void cx23885_risc_disasm(struct cx23885_tsport *port,
dev->name, risc->cpu, (unsigned long)risc->dma);
for (i = 0; i < (risc->size >> 2); i += n) {
printk("%s: %04d: ", dev->name, i);
- n = cx23885_risc_decode(risc->cpu[i]);
+ n = cx23885_risc_decode(le32_to_cpu(risc->cpu[i]));
for (j = 1; j < n; j++)
printk("%s: %04d: 0x%08x [ arg #%d ]\n",
dev->name, i + j, risc->cpu[i + j], j);
- if (risc->cpu[i] == RISC_JUMP)
+ if (risc->cpu[i] == cpu_to_le32(RISC_JUMP))
break;
}
}
@@ -824,7 +824,7 @@ static void cx23885_dev_unregister(struct cx23885_dev *dev)
iounmap(dev->lmmio);
}
-static u32* cx23885_risc_field(u32 *rp, struct scatterlist *sglist,
+static __le32* cx23885_risc_field(__le32 *rp, struct scatterlist *sglist,
unsigned int offset, u32 sync_line,
unsigned int bpl, unsigned int padding,
unsigned int lines)
@@ -884,7 +884,7 @@ int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
unsigned int padding, unsigned int lines)
{
u32 instructions, fields;
- u32 *rp;
+ __le32 *rp;
int rc;
fields = 0;
@@ -925,7 +925,7 @@ static int cx23885_risc_databuffer(struct pci_dev *pci,
unsigned int lines)
{
u32 instructions;
- u32 *rp;
+ __le32 *rp;
int rc;
/* estimate risc mem: worst case is one write per page border +
@@ -952,7 +952,7 @@ static int cx23885_risc_databuffer(struct pci_dev *pci,
int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
u32 reg, u32 mask, u32 value)
{
- u32 *rp;
+ __le32 *rp;
int rc;
if ((rc = btcx_riscmem_alloc(pci, risc, 4*16)) < 0)
diff --git a/linux/drivers/media/video/cx23885/cx23885-i2c.c b/linux/drivers/media/video/cx23885/cx23885-i2c.c
index ba8e27ca9..f0ee47256 100644
--- a/linux/drivers/media/video/cx23885/cx23885-i2c.c
+++ b/linux/drivers/media/video/cx23885/cx23885-i2c.c
@@ -359,9 +359,7 @@ static struct i2c_algorithm cx23885_i2c_algo_template = {
static struct i2c_adapter cx23885_i2c_adap_template = {
.name = "cx23885",
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
.owner = THIS_MODULE,
-#endif
.id = I2C_HW_B_CX23885,
.algo = &cx23885_i2c_algo_template,
.class = I2C_CLASS_TV_ANALOG,
diff --git a/linux/drivers/media/video/cx23885/cx23885-video.c b/linux/drivers/media/video/cx23885/cx23885-video.c
index fdbcd53ab..6d0345935 100644
--- a/linux/drivers/media/video/cx23885/cx23885-video.c
+++ b/linux/drivers/media/video/cx23885/cx23885-video.c
@@ -29,9 +29,7 @@
#include <linux/interrupt.h>
#include <linux/delay.h>
#include "compat.h"
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
#include <linux/kthread.h>
-#endif
#include <asm/div64.h>
#include "cx23885.h"
@@ -52,22 +50,9 @@ static unsigned int video_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET };
static unsigned int vbi_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET };
static unsigned int radio_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET };
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
-MODULE_PARM(video_nr, "1-" __stringify(CX23885_MAXBOARDS) "i");
-MODULE_PARM(vbi_nr, "1-" __stringify(CX23885_MAXBOARDS) "i");
-MODULE_PARM(radio_nr, "1-" __stringify(CX23885_MAXBOARDS) "i");
-#else
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 10)
-static unsigned int dummy;
-module_param_array(video_nr, int, dummy, 0444);
-module_param_array(vbi_nr, int, dummy, 0444);
-module_param_array(radio_nr, int, dummy, 0444);
-#else
module_param_array(video_nr, int, NULL, 0444);
module_param_array(vbi_nr, int, NULL, 0444);
module_param_array(radio_nr, int, NULL, 0444);
-#endif
-#endif
MODULE_PARM_DESC(video_nr, "video device numbers");
MODULE_PARM_DESC(vbi_nr, "vbi device numbers");
@@ -376,10 +361,8 @@ struct video_device *cx23885_vdev_init(struct cx23885_dev *dev,
return NULL;
*vfd = *template;
vfd->minor = -1;
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
vfd->dev = &pci->dev;
vfd->release = video_device_release;
-#endif
snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)",
dev->name, type, cx23885_boards[dev->board].name);
return vfd;
@@ -1654,9 +1637,7 @@ static const struct file_operations video_fops = {
.poll = video_poll,
.mmap = video_mmap,
.ioctl = video_ioctl2,
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11)
.compat_ioctl = v4l_compat_ioctl32,
-#endif
.llseek = no_llseek,
};
@@ -1707,9 +1688,7 @@ static const struct file_operations radio_fops = {
.open = video_open,
.release = video_release,
.ioctl = video_ioctl2,
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11)
.compat_ioctl = v4l_compat_ioctl32,
-#endif
.llseek = no_llseek,
};
diff --git a/linux/drivers/media/video/cx25840/cx25840-audio.c b/linux/drivers/media/video/cx25840/cx25840-audio.c
index eda48b596..8e134312c 100644
--- a/linux/drivers/media/video/cx25840/cx25840-audio.c
+++ b/linux/drivers/media/video/cx25840/cx25840-audio.c
@@ -21,9 +21,6 @@
#include <media/v4l2-common.h>
#include <media/cx25840.h>
#include "compat.h"
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-#include "i2c-compat.h"
-#endif
#include "cx25840-core.h"
diff --git a/linux/drivers/media/video/cx25840/cx25840-core.c b/linux/drivers/media/video/cx25840/cx25840-core.c
index e4a25d7cc..a43ed390a 100644
--- a/linux/drivers/media/video/cx25840/cx25840-core.c
+++ b/linux/drivers/media/video/cx25840/cx25840-core.c
@@ -42,9 +42,6 @@
#include <media/v4l2-i2c-drv-legacy.h>
#include <media/cx25840.h>
#include "compat.h"
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-#include "i2c-compat.h"
-#endif
#include "cx25840-core.h"
@@ -54,17 +51,9 @@ MODULE_LICENSE("GPL");
static unsigned short normal_i2c[] = { 0x88 >> 1, I2C_CLIENT_END };
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13)
-static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
-#endif
-
int cx25840_debug;
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
module_param_named(debug,cx25840_debug, int, 0644);
-#else
-MODULE_PARM(cx25840_debug, "i");
-#endif
MODULE_PARM_DESC(debug, "Debugging messages [0=Off (default) 1=On]");
@@ -462,7 +451,7 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
int chroma = vid_input & 0xf00;
if ((vid_input & ~0xff0) ||
- luma < CX25840_SVIDEO_LUMA1 || luma > CX25840_SVIDEO_LUMA4 ||
+ luma < CX25840_SVIDEO_LUMA1 || luma > CX25840_SVIDEO_LUMA8 ||
chroma < CX25840_SVIDEO_CHROMA4 || chroma > CX25840_SVIDEO_CHROMA8) {
v4l_err(client, "0x%04x is not a valid video input!\n",
vid_input);
@@ -1313,10 +1302,21 @@ static int cx25840_remove(struct i2c_client *client)
return 0;
}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+static const struct i2c_device_id cx25840_id[] = {
+ { "cx25840", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, cx25840_id);
+
+#endif
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.name = "cx25840",
.driverid = I2C_DRIVERID_CX25840,
.command = cx25840_command,
.probe = cx25840_probe,
.remove = cx25840_remove,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ .id_table = cx25840_id,
+#endif
};
diff --git a/linux/drivers/media/video/cx25840/cx25840-firmware.c b/linux/drivers/media/video/cx25840/cx25840-firmware.c
index d283ef2d1..95b84ce21 100644
--- a/linux/drivers/media/video/cx25840/cx25840-firmware.c
+++ b/linux/drivers/media/video/cx25840/cx25840-firmware.c
@@ -38,19 +38,11 @@
*/
#define FWSEND 48
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
#define FWDEV(x) &((x)->dev)
-#else
-#define FWDEV(x) (x)->name
-#endif
static char *firmware = FWFILE;
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
module_param(firmware, charp, 0444);
-#else
-MODULE_PARM(firmware, "s");
-#endif
MODULE_PARM_DESC(firmware, "Firmware image [default: " FWFILE "]");
diff --git a/linux/drivers/media/video/cx88/cx88-alsa.c b/linux/drivers/media/video/cx88/cx88-alsa.c
index 9e87bcb98..c675cbeae 100644
--- a/linux/drivers/media/video/cx88/cx88-alsa.c
+++ b/linux/drivers/media/video/cx88/cx88-alsa.c
@@ -98,10 +98,6 @@ struct cx88_audio_dev {
typedef struct cx88_audio_dev snd_cx88_card_t;
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,8)
-#define chip_t snd_cx88_card_t
-#endif
-
#ifdef COMPAT_SND_CTL_BOOLEAN_MONO
static int snd_ctl_boolean_mono_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
@@ -122,19 +118,10 @@ static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 1};
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
-static unsigned int dummy;
-module_param_array(enable, bool, dummy, 0444);
-#else
module_param_array(enable, bool, NULL, 0444);
-#endif
MODULE_PARM_DESC(enable, "Enable cx88x soundcard. default enabled.");
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
-module_param_array(index, int, dummy, 0444);
-#else
module_param_array(index, int, NULL, 0444);
-#endif
MODULE_PARM_DESC(index, "Index value for cx88x capture interface(s).");
@@ -385,6 +372,12 @@ static int snd_cx88_pcm_open(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime = substream->runtime;
int err;
+ if (!chip) {
+ printk(KERN_ERR "BUG: cx88 can't find device struct."
+ " Can't proceed with open\n");
+ return -ENODEV;
+ }
+
err = snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIODS);
if (err < 0)
goto _error;
diff --git a/linux/drivers/media/video/cx88/cx88-blackbird.c b/linux/drivers/media/video/cx88/cx88-blackbird.c
index 781beeb7f..83638557d 100644
--- a/linux/drivers/media/video/cx88/cx88-blackbird.c
+++ b/linux/drivers/media/video/cx88/cx88-blackbird.c
@@ -30,9 +30,7 @@
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/delay.h>
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
#include <linux/device.h>
-#endif
#include <linux/firmware.h>
#include <media/v4l2-common.h>
#include <media/cx2341x.h>
@@ -444,13 +442,8 @@ static int blackbird_load_firmware(struct cx8802_dev *dev)
if (retval < 0)
dprintk(0, "Error with register_write\n");
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
retval = request_firmware(&firmware, CX2341X_FIRM_ENC_FILENAME,
&dev->pci->dev);
-#else
- retval = request_firmware(&firmware, CX2341X_FIRM_ENC_FILENAME,
- pci_name(dev->pci));
-#endif
if (retval != 0) {
@@ -733,7 +726,8 @@ static int vidioc_querymenu (struct file *file, void *priv,
qctrl.id = qmenu->id;
blackbird_queryctrl(dev, &qctrl);
- return v4l2_ctrl_query_menu(qmenu, &qctrl, cx2341x_ctrl_get_menu(qmenu->id));
+ return v4l2_ctrl_query_menu(qmenu, &qctrl,
+ cx2341x_ctrl_get_menu(&dev->params, qmenu->id));
}
static int vidioc_querycap (struct file *file, void *priv,
diff --git a/linux/drivers/media/video/cx88/cx88-cards.c b/linux/drivers/media/video/cx88/cx88-cards.c
index fdcfb39ef..9329dbf6a 100644
--- a/linux/drivers/media/video/cx88/cx88-cards.c
+++ b/linux/drivers/media/video/cx88/cx88-cards.c
@@ -33,22 +33,9 @@ static unsigned int tuner[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
static unsigned int radio[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
static unsigned int card[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-MODULE_PARM(tuner,"1-" __stringify(CX88_MAXBOARDS) "i");
-MODULE_PARM(radiox,"1-" __stringify(CX88_MAXBOARDS) "i");
-MODULE_PARM(card,"1-" __stringify(CX88_MAXBOARDS) "i");
-#else
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
-static int dummy;
-module_param_array(tuner, int, dummy, 0444);
-module_param_array(radio, int, dummy, 0444);
-module_param_array(card, int, dummy, 0444);
-#else
module_param_array(tuner, int, NULL, 0444);
module_param_array(radio, int, NULL, 0444);
module_param_array(card, int, NULL, 0444);
-#endif
-#endif
MODULE_PARM_DESC(tuner,"tuner type");
MODULE_PARM_DESC(radio,"radio tuner type");
@@ -1543,10 +1530,16 @@ static const struct cx88_board cx88_boards[] = {
},
},
[CX88_BOARD_POWERCOLOR_REAL_ANGEL] = {
- .name = "PowerColor Real Angel 330",
+ .name = "PowerColor RA330", /* Long names may confuse LIRC. */
.tuner_type = TUNER_XC2028,
.tuner_addr = 0x61,
.input = { {
+ .type = CX88_VMUX_DEBUG,
+ .vmux = 3, /* Due to the way the cx88 driver is written, */
+ .gpio0 = 0x00ff, /* there is no way to deactivate audio pass- */
+ .gpio1 = 0xf39d, /* through without this entry. Furthermore, if */
+ .gpio3 = 0x0000, /* the TV mux entry is first, you get audio */
+ }, { /* from the tuner on boot for a little while. */
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
.gpio0 = 0x00ff,
@@ -2474,8 +2467,9 @@ void cx88_setup_xc3028(struct cx88_core *core, struct xc2028_ctrl *ctl)
switch (core->boardnr) {
case CX88_BOARD_POWERCOLOR_REAL_ANGEL:
- /* Doesn't work with firmware version 2.7 */
- ctl->fname = "xc3028-v25.fw";
+ /* Now works with firmware version 2.7 */
+ if (core->i2c_algo.udelay < 16)
+ core->i2c_algo.udelay = 16;
break;
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO:
ctl->scode_table = XC3028_FE_ZARLINK456;
diff --git a/linux/drivers/media/video/cx88/cx88-core.c b/linux/drivers/media/video/cx88/cx88-core.c
index 8655bb677..6efb1c61a 100644
--- a/linux/drivers/media/video/cx88/cx88-core.c
+++ b/linux/drivers/media/video/cx88/cx88-core.c
@@ -73,7 +73,7 @@ static DEFINE_MUTEX(devlist);
/* @lpi: lines per IRQ, or 0 to not generate irqs. Note: IRQ to be
generated _after_ lpi lines are transferred. */
-static u32* cx88_risc_field(u32 *rp, struct scatterlist *sglist,
+static __le32* cx88_risc_field(__le32 *rp, struct scatterlist *sglist,
unsigned int offset, u32 sync_line,
unsigned int bpl, unsigned int padding,
unsigned int lines, unsigned int lpi)
@@ -133,7 +133,7 @@ int cx88_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
unsigned int bpl, unsigned int padding, unsigned int lines)
{
u32 instructions,fields;
- u32 *rp;
+ __le32 *rp;
int rc;
fields = 0;
@@ -171,7 +171,7 @@ int cx88_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
unsigned int lines, unsigned int lpi)
{
u32 instructions;
- u32 *rp;
+ __le32 *rp;
int rc;
/* estimate risc mem: worst case is one write per page border +
@@ -196,7 +196,7 @@ int cx88_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
int cx88_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
u32 reg, u32 mask, u32 value)
{
- u32 *rp;
+ __le32 *rp;
int rc;
if ((rc = btcx_riscmem_alloc(pci, risc, 4*16)) < 0)
@@ -1037,10 +1037,8 @@ struct video_device *cx88_vdev_init(struct cx88_core *core,
return NULL;
*vfd = *template;
vfd->minor = -1;
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
vfd->dev = &pci->dev;
vfd->release = video_device_release;
-#endif
snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)",
core->name, type, core->board.name);
return vfd;
diff --git a/linux/drivers/media/video/cx88/cx88-i2c.c b/linux/drivers/media/video/cx88/cx88-i2c.c
index 800ea0d64..df615f19a 100644
--- a/linux/drivers/media/video/cx88/cx88-i2c.c
+++ b/linux/drivers/media/video/cx88/cx88-i2c.c
@@ -34,9 +34,6 @@
#include "cx88.h"
#include <media/v4l2-common.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-#include "i2c-compat.h"
-#endif
static unsigned int i2c_debug;
module_param(i2c_debug, int, 0644);
@@ -187,22 +184,14 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci)
memcpy(&core->i2c_algo, &cx8800_i2c_algo_template,
sizeof(core->i2c_algo));
-#ifdef I2C_CLASS_TV_ANALOG
if (core->board.tuner_type != TUNER_ABSENT)
core->i2c_adap.class |= I2C_CLASS_TV_ANALOG;
-#endif
-#ifdef I2C_CLASS_TV_DIGITAL
if (core->board.mpeg & CX88_MPEG_DVB)
core->i2c_adap.class |= I2C_CLASS_TV_DIGITAL;
-#endif
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,66)
core->i2c_adap.dev.parent = &pci->dev;
-#endif
strlcpy(core->i2c_adap.name,core->name,sizeof(core->i2c_adap.name));
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
core->i2c_adap.owner = THIS_MODULE;
-#endif
core->i2c_adap.id = I2C_HW_B_CX2388x;
core->i2c_adap.client_register = attach_inform;
core->i2c_adap.client_unregister = detach_inform;
diff --git a/linux/drivers/media/video/cx88/cx88-input.c b/linux/drivers/media/video/cx88/cx88-input.c
index e334bd20a..4796e3ba1 100644
--- a/linux/drivers/media/video/cx88/cx88-input.c
+++ b/linux/drivers/media/video/cx88/cx88-input.c
@@ -349,7 +349,6 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
ir_input_init(input_dev, &ir->ir, ir_type, ir_codes);
input_dev->name = ir->name;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
input_dev->phys = ir->phys;
input_dev->id.bustype = BUS_PCI;
input_dev->id.version = 1;
@@ -369,7 +368,6 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
input_dev->dev = &pci->dev;
#endif
#endif
-#endif
/* record handles to ourself */
ir->core = core;
core->ir = ir;
@@ -500,11 +498,9 @@ void cx88_ir_irq(struct cx88_core *core)
/* ---------------------------------------------------------------------- */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
MODULE_AUTHOR("Gerd Knorr, Pavel Machek, Chris Pascoe");
MODULE_DESCRIPTION("input driver for cx88 GPIO-based IR remote controls");
MODULE_LICENSE("GPL");
-#endif
/*
* Local variables:
* c-basic-offset: 8
diff --git a/linux/drivers/media/video/cx88/cx88-mpeg.c b/linux/drivers/media/video/cx88/cx88-mpeg.c
index c8dba3dfa..4af6604ec 100644
--- a/linux/drivers/media/video/cx88/cx88-mpeg.c
+++ b/linux/drivers/media/video/cx88/cx88-mpeg.c
@@ -24,9 +24,7 @@
#include <linux/module.h>
#include <linux/init.h>
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
#include <linux/device.h>
-#endif
#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
#include <asm/delay.h>
@@ -36,13 +34,9 @@
/* ------------------------------------------------------------------ */
MODULE_DESCRIPTION("mpeg driver for cx2388x based TV cards");
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
MODULE_AUTHOR("Jelle Foks <jelle@foks.8m.com>");
MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
-#else
-MODULE_AUTHOR("Jelle Foks <jelle@foks.8m.com>,Chris Pascoe <c.pascoe@itee.uq.edu.au>,Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
-#endif
MODULE_LICENSE("GPL");
static unsigned int debug;
@@ -72,9 +66,6 @@ static void request_module_async(struct work_struct *work)
request_module("cx88-blackbird");
}
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-#define request_modules(dev)
-#else
static void request_modules(struct cx8802_dev *dev)
{
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
@@ -84,7 +75,6 @@ static void request_modules(struct cx8802_dev *dev)
#endif
schedule_work(&dev->request_module_wk);
}
-#endif
#else
#define request_modules(dev)
#endif /* CONFIG_MODULES */
@@ -576,11 +566,7 @@ static int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state)
cx88_shutdown(dev->core);
#endif
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
- pci_save_state(pci_dev, dev->state.pci_cfg);
-#else
pci_save_state(pci_dev);
-#endif
if (0 != pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state))) {
pci_disable_device(pci_dev);
dev->state.disabled = 1;
@@ -612,11 +598,7 @@ static int cx8802_resume_common(struct pci_dev *pci_dev)
return err;
}
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
- pci_restore_state(pci_dev, dev->state.pci_cfg);
-#else
pci_restore_state(pci_dev);
-#endif
#if 1
/* FIXME: re-initialize hardware */
diff --git a/linux/drivers/media/video/cx88/cx88-tvaudio.c b/linux/drivers/media/video/cx88/cx88-tvaudio.c
index b4dab2647..5eb95dbbe 100644
--- a/linux/drivers/media/video/cx88/cx88-tvaudio.c
+++ b/linux/drivers/media/video/cx88/cx88-tvaudio.c
@@ -53,9 +53,7 @@
#include <linux/vmalloc.h>
#include <linux/init.h>
#include <linux/delay.h>
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
#include <linux/kthread.h>
-#endif
#include "cx88.h"
diff --git a/linux/drivers/media/video/cx88/cx88-video.c b/linux/drivers/media/video/cx88/cx88-video.c
index c9f7d0048..63521066d 100644
--- a/linux/drivers/media/video/cx88/cx88-video.c
+++ b/linux/drivers/media/video/cx88/cx88-video.c
@@ -35,9 +35,7 @@
#include <linux/dma-mapping.h>
#include <linux/delay.h>
#include "compat.h"
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
#include <linux/kthread.h>
-#endif
#include <asm/div64.h>
#include "cx88.h"
@@ -58,22 +56,9 @@ static unsigned int video_nr[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
static unsigned int vbi_nr[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
static unsigned int radio_nr[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-MODULE_PARM(video_nr,"1-" __stringify(CX88_MAXBOARDS) "i");
-MODULE_PARM(vbi_nr,"1-" __stringify(CX88_MAXBOARDS) "i");
-MODULE_PARM(radio_nr,"1-" __stringify(CX88_MAXBOARDS) "i");
-#else
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
-static unsigned int dummy;
-module_param_array(video_nr, int, dummy, 0444);
-module_param_array(vbi_nr, int, dummy, 0444);
-module_param_array(radio_nr, int, dummy, 0444);
-#else
module_param_array(video_nr, int, NULL, 0444);
module_param_array(vbi_nr, int, NULL, 0444);
module_param_array(radio_nr, int, NULL, 0444);
-#endif
-#endif
MODULE_PARM_DESC(video_nr,"video device numbers");
MODULE_PARM_DESC(vbi_nr,"vbi device numbers");
@@ -1963,9 +1948,7 @@ static const struct file_operations video_fops =
.poll = video_poll,
.mmap = video_mmap,
.ioctl = video_ioctl2,
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11)
.compat_ioctl = v4l_compat_ioctl32,
-#endif
.llseek = no_llseek,
};
@@ -2018,9 +2001,7 @@ static const struct file_operations radio_fops =
.open = video_open,
.release = video_release,
.ioctl = video_ioctl2,
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11)
.compat_ioctl = v4l_compat_ioctl32,
-#endif
.llseek = no_llseek,
};
@@ -2221,7 +2202,6 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
mutex_unlock(&core->lock);
/* start tvaudio thread */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
if (core->board.tuner_type != TUNER_ABSENT) {
core->kthread = kthread_run(cx88_audio_thread, core, "cx88 tvaudio");
if (IS_ERR(core->kthread)) {
@@ -2230,13 +2210,6 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
core->name, err);
}
}
-#else
- /*FIXME: Not sure if this will work */
- if (core->board.tuner_type != TUNER_ABSENT)
- kernel_thread (cx88_audio_thread, core, 0);
-
- core->kthread = NULL;
-#endif
return 0;
fail_unreg:
@@ -2306,11 +2279,7 @@ static int cx8800_suspend(struct pci_dev *pci_dev, pm_message_t state)
cx88_shutdown(core);
#endif
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
- pci_save_state(pci_dev, dev->state.pci_cfg);
-#else
pci_save_state(pci_dev);
-#endif
if (0 != pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state))) {
pci_disable_device(pci_dev);
dev->state.disabled = 1;
@@ -2342,11 +2311,7 @@ static int cx8800_resume(struct pci_dev *pci_dev)
return err;
}
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
- pci_restore_state(pci_dev, dev->state.pci_cfg);
-#else
pci_restore_state(pci_dev);
-#endif
#if 1
/* FIXME: re-initialize hardware */
diff --git a/linux/drivers/media/video/cx88/cx88-vp3054-i2c.c b/linux/drivers/media/video/cx88/cx88-vp3054-i2c.c
index 84bb59175..20800425c 100644
--- a/linux/drivers/media/video/cx88/cx88-vp3054-i2c.c
+++ b/linux/drivers/media/video/cx88/cx88-vp3054-i2c.c
@@ -30,10 +30,6 @@
#include "cx88.h"
#include "cx88-vp3054-i2c.h"
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-#include "i2c-compat.h"
-#endif
-
MODULE_DESCRIPTION("driver for cx2388x VP3054 design");
MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
MODULE_LICENSE("GPL");
@@ -124,18 +120,12 @@ int vp3054_i2c_probe(struct cx8802_dev *dev)
memcpy(&vp3054_i2c->algo, &vp3054_i2c_algo_template,
sizeof(vp3054_i2c->algo));
-#ifdef I2C_CLASS_TV_DIGITAL
vp3054_i2c->adap.class |= I2C_CLASS_TV_DIGITAL;
-#endif
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,66)
vp3054_i2c->adap.dev.parent = &dev->pci->dev;
-#endif
strlcpy(vp3054_i2c->adap.name, core->name,
sizeof(vp3054_i2c->adap.name));
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
vp3054_i2c->adap.owner = THIS_MODULE;
-#endif
vp3054_i2c->adap.id = I2C_HW_B_CX2388x;
vp3054_i2c->algo.data = dev;
i2c_set_adapdata(&vp3054_i2c->adap, dev);
diff --git a/linux/drivers/media/video/cx88/cx88.h b/linux/drivers/media/video/cx88/cx88.h
index 4222f919e..161b3cc13 100644
--- a/linux/drivers/media/video/cx88/cx88.h
+++ b/linux/drivers/media/video/cx88/cx88.h
@@ -386,9 +386,6 @@ struct cx8800_fh {
};
struct cx8800_suspend_state {
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
- u32 pci_cfg[64 / sizeof(u32)];
-#endif
int disabled;
};
@@ -445,9 +442,6 @@ struct cx8802_fh {
};
struct cx8802_suspend_state {
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
- u32 pci_cfg[64 / sizeof(u32)];
-#endif
int disabled;
};
diff --git a/linux/drivers/media/video/em28xx/em28xx-audio.c b/linux/drivers/media/video/em28xx/em28xx-audio.c
index 609e28e77..904973305 100644
--- a/linux/drivers/media/video/em28xx/em28xx-audio.c
+++ b/linux/drivers/media/video/em28xx/em28xx-audio.c
@@ -299,6 +299,12 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream)
dprintk("opening device and trying to acquire exclusive lock\n");
+ if (!dev) {
+ printk(KERN_ERR "BUG: em28xx can't find device struct."
+ " Can't proceed with open\n");
+ return -ENODEV;
+ }
+
/* Sets volume, mute, etc */
dev->mute = 0;
@@ -486,6 +492,12 @@ static int em28xx_audio_init(struct em28xx *dev)
static int devnr;
int ret, err;
+ if (dev->has_audio_class) {
+ /* This device does not support the extension (in this case
+ the device is expecting the snd-usb-audio module */
+ return 0;
+ }
+
printk(KERN_INFO "em28xx-audio.c: probing for em28x1 "
"non standard usbaudio\n");
printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus "
@@ -529,6 +541,12 @@ static int em28xx_audio_fini(struct em28xx *dev)
if (dev == NULL)
return 0;
+ if (dev->has_audio_class) {
+ /* This device does not support the extension (in this case
+ the device is expecting the snd-usb-audio module */
+ return 0;
+ }
+
if (dev->adev) {
snd_card_free(dev->adev->sndcard);
kfree(dev->adev);
diff --git a/linux/drivers/media/video/em28xx/em28xx-cards.c b/linux/drivers/media/video/em28xx/em28xx-cards.c
index a9b6a5ecd..871d81242 100644
--- a/linux/drivers/media/video/em28xx/em28xx-cards.c
+++ b/linux/drivers/media/video/em28xx/em28xx-cards.c
@@ -158,6 +158,28 @@ struct em28xx_board em28xx_boards[] = {
.tda9887_conf = TDA9887_PRESENT,
.tuner_type = TUNER_XC2028,
.mts_firmware = 1,
+ .has_dvb = 1,
+ .decoder = EM28XX_TVP5150,
+ .input = { {
+ .type = EM28XX_VMUX_TELEVISION,
+ .vmux = TVP5150_COMPOSITE0,
+ .amux = 0,
+ }, {
+ .type = EM28XX_VMUX_COMPOSITE1,
+ .vmux = TVP5150_COMPOSITE1,
+ .amux = 1,
+ }, {
+ .type = EM28XX_VMUX_SVIDEO,
+ .vmux = TVP5150_SVIDEO,
+ .amux = 1,
+ } },
+ },
+ [EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2] = {
+ .name = "Hauppauge WinTV HVR 900 (R2)",
+ .vchannels = 3,
+ .tda9887_conf = TDA9887_PRESENT,
+ .tuner_type = TUNER_XC2028,
+ .mts_firmware = 1,
.decoder = EM28XX_TVP5150,
.input = { {
.type = EM28XX_VMUX_TELEVISION,
@@ -196,6 +218,29 @@ struct em28xx_board em28xx_boards[] = {
.amux = 1,
} },
},
+ [EM2880_BOARD_PINNACLE_PCTV_HD_PRO] = {
+ .name = "Pinnacle PCTV HD Pro Stick",
+ .vchannels = 3,
+ .tda9887_conf = TDA9887_PRESENT,
+ .tuner_type = TUNER_XC2028,
+ .mts_firmware = 1,
+ .has_12mhz_i2s = 1,
+ .has_dvb = 1,
+ .decoder = EM28XX_TVP5150,
+ .input = { {
+ .type = EM28XX_VMUX_TELEVISION,
+ .vmux = TVP5150_COMPOSITE0,
+ .amux = 0,
+ }, {
+ .type = EM28XX_VMUX_COMPOSITE1,
+ .vmux = TVP5150_COMPOSITE1,
+ .amux = 1,
+ }, {
+ .type = EM28XX_VMUX_SVIDEO,
+ .vmux = TVP5150_SVIDEO,
+ .amux = 1,
+ } },
+ },
[EM2880_BOARD_TERRATEC_HYBRID_XS] = {
.name = "Terratec Hybrid XS",
.vchannels = 3,
@@ -382,6 +427,19 @@ struct em28xx_board em28xx_boards[] = {
.amux = EM28XX_AMUX_LINE_IN,
} },
},
+ [EM2860_BOARD_POINTNIX_INTRAORAL_CAMERA] = {
+ .name = "PointNix Intra-Oral Camera",
+ .has_snapshot_button = 1,
+ .vchannels = 1,
+ .tda9887_conf = TDA9887_PRESENT,
+ .tuner_type = TUNER_ABSENT,
+ .decoder = EM28XX_SAA7113,
+ .input = { {
+ .type = EM28XX_VMUX_SVIDEO,
+ .vmux = SAA7115_SVIDEO3,
+ .amux = 0,
+ } },
+ },
};
const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards);
@@ -417,10 +475,12 @@ struct usb_device_id em28xx_id_table [] = {
.driver_info = EM2820_BOARD_PINNACLE_DVC_90 },
{ USB_DEVICE(0x2304, 0x021a),
.driver_info = EM2820_BOARD_PINNACLE_DVC_90 },
+ { USB_DEVICE(0x2304, 0x0227),
+ .driver_info = EM2880_BOARD_PINNACLE_PCTV_HD_PRO },
{ USB_DEVICE(0x2040, 0x6500),
.driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 },
{ USB_DEVICE(0x2040, 0x6502),
- .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 },
+ .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2 },
{ USB_DEVICE(0x2040, 0x6513), /* HCW HVR-980 */
.driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950 },
{ USB_DEVICE(0x2040, 0x6517), /* HP HVR-950 */
@@ -476,6 +536,7 @@ static struct em28xx_hash_table em28xx_eeprom_hash [] = {
static struct em28xx_hash_table em28xx_i2c_hash[] = {
{0xb06a32c3, EM2800_BOARD_TERRATEC_CINERGY_200, TUNER_LG_PAL_NEW_TAPC},
{0xf51200e3, EM2800_BOARD_VGEAR_POCKETTV, TUNER_LG_PAL_NEW_TAPC},
+ {0x1ba50080, EM2860_BOARD_POINTNIX_INTRAORAL_CAMERA, TUNER_ABSENT},
};
int em28xx_tuner_callback(void *ptr, int command, int arg)
@@ -508,6 +569,7 @@ static void em28xx_set_model(struct em28xx *dev)
dev->has_12mhz_i2s = em28xx_boards[dev->model].has_12mhz_i2s;
dev->max_range_640_480 = em28xx_boards[dev->model].max_range_640_480;
dev->has_dvb = em28xx_boards[dev->model].has_dvb;
+ dev->has_snapshot_button = em28xx_boards[dev->model].has_snapshot_button;
}
/* Since em28xx_pre_card_setup() requires a proper dev->model,
@@ -525,6 +587,9 @@ void em28xx_pre_card_setup(struct em28xx *dev)
rc = em28xx_read_reg(dev, EM28XX_R0A_CHIPID);
if (rc > 0) {
switch (rc) {
+ case CHIP_ID_EM2860:
+ em28xx_info("chip ID is em2860\n");
+ break;
case CHIP_ID_EM2883:
em28xx_info("chip ID is em2882/em2883\n");
dev->wait_after_write = 0;
@@ -539,8 +604,10 @@ void em28xx_pre_card_setup(struct em28xx *dev)
switch (dev->model) {
case EM2880_BOARD_TERRATEC_PRODIGY_XS:
case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
+ case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2:
case EM2880_BOARD_TERRATEC_HYBRID_XS:
case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950:
+ case EM2880_BOARD_PINNACLE_PCTV_HD_PRO:
em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1);
em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1);
msleep(50);
@@ -573,7 +640,12 @@ static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl)
case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
ctl->demod = XC3028_FE_ZARLINK456;
break;
+ case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2:
+ /* djh - Not sure which demod we need here */
+ ctl->demod = XC3028_FE_DEFAULT;
+ break;
case EM2880_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;
@@ -751,6 +823,7 @@ void em28xx_card_setup(struct em28xx *dev)
switch (dev->model) {
case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2:
case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
+ case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2:
case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950:
{
struct tveeprom tv;
@@ -784,6 +857,9 @@ void em28xx_card_setup(struct em28xx *dev)
em28xx_set_model(dev);
}
+ if (dev->has_snapshot_button)
+ em28xx_register_snapshot_button(dev);
+
/* Allow override tuner type by a module parameter */
if (tuner >= 0)
dev->tuner_type = tuner;
diff --git a/linux/drivers/media/video/em28xx/em28xx-dvb.c b/linux/drivers/media/video/em28xx/em28xx-dvb.c
index a890b8a32..b8a5c61ce 100644
--- a/linux/drivers/media/video/em28xx/em28xx-dvb.c
+++ b/linux/drivers/media/video/em28xx/em28xx-dvb.c
@@ -5,6 +5,7 @@
(c) 2008 Devin Heitmueller <devin.heitmueller@gmail.com>
- Fixes for the driver to properly work with HVR-950
+ - Fixes for the driver to properly work with Pinnacle PCTV HD Pro Stick
(c) 2008 Aidan Thornton <makosoft@googlemail.com>
@@ -27,6 +28,9 @@
#include "lgdt330x.h"
#include "zl10353.h"
+#ifdef EM28XX_DRX397XD_SUPPORT
+#include "drx397xD.h"
+#endif
MODULE_DESCRIPTION("driver for em28xx based DVB cards");
MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
@@ -59,11 +63,7 @@ struct em28xx_dvb {
int nfeeds;
/* general boilerplate stuff */
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12))
struct dvb_adapter adapter;
-#else
- struct dvb_adapter *adapter;
-#endif
struct dvb_demux demux;
struct dmxdev dmxdev;
struct dmx_frontend fe_hw;
@@ -236,6 +236,13 @@ static struct zl10353_config em28xx_zl10353_with_xc3028 = {
.if2 = 45600,
};
+#ifdef EM28XX_DRX397XD_SUPPORT
+/* [TODO] djh - not sure yet what the device config needs to contain */
+static struct drx397xD_config em28xx_drx397xD_with_xc3028 = {
+ .demod_address = (0xe0 >> 1),
+};
+#endif
+
/* ------------------------------------------------------------------ */
static int attach_xc3028(u8 addr, struct em28xx *dev)
@@ -292,17 +299,10 @@ int register_dvb(struct em28xx_dvb *dvb,
/* Ensure all frontends negotiate bus access */
dvb->frontend->ops.ts_bus_ctrl = em28xx_dvb_bus_ctrl;
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12))
dvb->adapter.priv = dev;
/* register frontend */
result = dvb_register_frontend(&dvb->adapter, dvb->frontend);
-#else
- dvb->adapter->priv = dev;
-
- /* register frontend */
- result = dvb_register_frontend(dvb->adapter, dvb->frontend);
-#endif
if (result < 0) {
printk(KERN_WARNING "%s: dvb_register_frontend failed (errno = %d)\n",
dev->name, result);
@@ -329,11 +329,7 @@ int register_dvb(struct em28xx_dvb *dvb,
dvb->dmxdev.filternum = 256;
dvb->dmxdev.demux = &dvb->demux.dmx;
dvb->dmxdev.capabilities = 0;
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12))
result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter);
-#else
- result = dvb_dmxdev_init(&dvb->dmxdev, dvb->adapter);
-#endif
if (result < 0) {
printk(KERN_WARNING "%s: dvb_dmxdev_init failed (errno = %d)\n",
dev->name, result);
@@ -364,11 +360,7 @@ int register_dvb(struct em28xx_dvb *dvb,
}
/* register network adapter */
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12))
dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx);
-#else
- dvb_net_init(dvb->adapter, &dvb->net, &dvb->demux.dmx);
-#endif
return 0;
fail_fe_conn:
@@ -383,11 +375,7 @@ fail_dmx:
dvb_unregister_frontend(dvb->frontend);
fail_frontend:
dvb_frontend_detach(dvb->frontend);
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12))
dvb_unregister_adapter(&dvb->adapter);
-#else
- dvb_unregister_adapter(dvb->adapter);
-#endif
fail_adapter:
return result;
}
@@ -401,11 +389,7 @@ static void unregister_dvb(struct em28xx_dvb *dvb)
dvb_dmx_release(&dvb->demux);
dvb_unregister_frontend(dvb->frontend);
dvb_frontend_detach(dvb->frontend);
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12))
dvb_unregister_adapter(&dvb->adapter);
-#else
- dvb_unregister_adapter(dvb->adapter);
-#endif
}
@@ -414,6 +398,11 @@ static int dvb_init(struct em28xx *dev)
int result = 0;
struct em28xx_dvb *dvb;
+ if (!dev->has_dvb) {
+ /* This device does not support the extension */
+ return 0;
+ }
+
dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL);
if (dvb == NULL) {
@@ -426,6 +415,7 @@ static int dvb_init(struct em28xx *dev)
/* init frontend */
switch (dev->model) {
case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950:
+ case EM2880_BOARD_PINNACLE_PCTV_HD_PRO:
dvb->frontend = dvb_attach(lgdt330x_attach,
&em2880_lgdt3303_dev,
&dev->i2c_adap);
@@ -443,6 +433,19 @@ static int dvb_init(struct em28xx *dev)
goto out_free;
}
break;
+ case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2:
+#ifdef EM28XX_DRX397XD_SUPPORT
+ /* We don't have the config structure properly populated, so
+ this is commented out for now */
+ dvb->frontend = dvb_attach(drx397xD_attach,
+ &em28xx_drx397xD_with_xc3028,
+ &dev->i2c_adap);
+ if (attach_xc3028(0x61, dev) < 0) {
+ result = -EINVAL;
+ goto out_free;
+ }
+ break;
+#endif
default:
printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card"
" isn't supported yet\n",
@@ -476,6 +479,11 @@ out_free:
static int dvb_fini(struct em28xx *dev)
{
+ if (!dev->has_dvb) {
+ /* This device does not support the extension */
+ return 0;
+ }
+
if (dev->dvb) {
unregister_dvb(dev->dvb);
dev->dvb = NULL;
diff --git a/linux/drivers/media/video/em28xx/em28xx-i2c.c b/linux/drivers/media/video/em28xx/em28xx-i2c.c
index c22e73019..4d6f650da 100644
--- a/linux/drivers/media/video/em28xx/em28xx-i2c.c
+++ b/linux/drivers/media/video/em28xx/em28xx-i2c.c
@@ -432,18 +432,6 @@ static u32 functionality(struct i2c_adapter *adap)
return I2C_FUNC_SMBUS_EMUL;
}
-#ifndef I2C_PEC
-static void inc_use(struct i2c_adapter *adap)
-{
- MOD_INC_USE_COUNT;
-}
-
-static void dec_use(struct i2c_adapter *adap)
-{
- MOD_DEC_USE_COUNT;
-}
-#endif
-
/*
* attach_inform()
* gets called when a device attaches to the i2c bus
@@ -521,15 +509,8 @@ static struct i2c_algorithm em28xx_algo = {
};
static struct i2c_adapter em28xx_adap_template = {
-#ifdef I2C_PEC
.owner = THIS_MODULE,
-#else
- .inc_use = inc_use,
- .dec_use = dec_use,
-#endif
-#ifdef I2C_CLASS_TV_ANALOG
.class = I2C_CLASS_TV_ANALOG,
-#endif
.name = "em28xx",
.id = I2C_HW_B_EM28XX,
.algo = &em28xx_algo,
diff --git a/linux/drivers/media/video/em28xx/em28xx-input.c b/linux/drivers/media/video/em28xx/em28xx-input.c
index 49c40f083..e83e3bebd 100644
--- a/linux/drivers/media/video/em28xx/em28xx-input.c
+++ b/linux/drivers/media/video/em28xx/em28xx-input.c
@@ -31,6 +31,10 @@
#include "compat.h"
#include "em28xx.h"
+#define EM28XX_SNAPSHOT_KEY KEY_CAMERA
+#define EM28XX_SBUTTON_QUERY_INTERVAL 500
+#define EM28XX_R0C_USBSUSP_SNAPSHOT 0x20
+
static unsigned int ir_debug;
module_param(ir_debug, int, 0644);
MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]");
@@ -130,6 +134,109 @@ int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key,
return 1;
}
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+static void em28xx_query_sbutton(void *data)
+#else
+static void em28xx_query_sbutton(struct work_struct *work)
+#endif
+{
+ /* Poll the register and see if the button is depressed */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+ struct em28xx *dev = data;
+#else
+ struct em28xx *dev =
+ container_of(work, struct em28xx, sbutton_query_work.work);
+#endif
+ 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);
+ }
+
+ /* Schedule next poll */
+ schedule_delayed_work(&dev->sbutton_query_work,
+ msecs_to_jiffies(EM28XX_SBUTTON_QUERY_INTERVAL));
+}
+
+void 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;
+ }
+
+ 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));
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+ INIT_WORK(&dev->sbutton_query_work, em28xx_query_sbutton, dev);
+#else
+ INIT_DELAYED_WORK(&dev->sbutton_query_work, em28xx_query_sbutton);
+#endif
+
+ input_dev->name = "em28xx snapshot button";
+ input_dev->phys = dev->snapshot_button_path;
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
+ set_bit(EM28XX_SNAPSHOT_KEY, input_dev->keybit);
+ input_dev->keycodesize = 0;
+ input_dev->keycodemax = 0;
+ input_dev->id.bustype = BUS_USB;
+ input_dev->id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor);
+ input_dev->id.product = le16_to_cpu(dev->udev->descriptor.idProduct);
+ input_dev->id.version = 1;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
+ input_dev->dev.parent = &dev->udev->dev;
+#else
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 15)
+ input_dev->cdev.dev = &dev->udev->dev;
+#else
+ input_dev->dev = &dev->udev->dev;
+#endif
+#endif
+
+ err = input_register_device(input_dev);
+ if (err) {
+ em28xx_errdev("input_register_device failed\n");
+ input_free_device(input_dev);
+ return;
+ }
+
+ dev->sbutton_input_dev = input_dev;
+ schedule_delayed_work(&dev->sbutton_query_work,
+ msecs_to_jiffies(EM28XX_SBUTTON_QUERY_INTERVAL));
+ return;
+
+}
+
+void em28xx_deregister_snapshot_button(struct em28xx *dev)
+{
+ if (dev->sbutton_input_dev != NULL) {
+ em28xx_info("Deregistering snapshot button\n");
+ cancel_rearming_delayed_work(&dev->sbutton_query_work);
+ input_unregister_device(dev->sbutton_input_dev);
+ dev->sbutton_input_dev = NULL;
+ }
+ return;
+}
+
/* ----------------------------------------------------------------------
* Local variables:
* c-basic-offset: 8
diff --git a/linux/drivers/media/video/em28xx/em28xx-reg.h b/linux/drivers/media/video/em28xx/em28xx-reg.h
index 9058bed07..fac1ab23f 100644
--- a/linux/drivers/media/video/em28xx/em28xx-reg.h
+++ b/linux/drivers/media/video/em28xx/em28xx-reg.h
@@ -84,5 +84,6 @@
/* FIXME: Need to be populated with the other chip ID's */
enum em28xx_chip_id {
+ CHIP_ID_EM2860 = 34,
CHIP_ID_EM2883 = 36,
};
diff --git a/linux/drivers/media/video/em28xx/em28xx-video.c b/linux/drivers/media/video/em28xx/em28xx-video.c
index 9e7965a32..5929d0860 100644
--- a/linux/drivers/media/video/em28xx/em28xx-video.c
+++ b/linux/drivers/media/video/em28xx/em28xx-video.c
@@ -42,9 +42,6 @@
#include <media/v4l2-common.h>
#include <media/msp3400.h>
#include <media/tuner.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
-#include "i2c-compat.h"
-#endif
#define DRIVER_AUTHOR "Ludovico Cavedon <cavedon@sssup.it>, " \
"Markus Rechberger <mrechberger@gmail.com>, " \
@@ -83,25 +80,10 @@ static unsigned int video_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
static unsigned int vbi_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
static unsigned int radio_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
-MODULE_PARM(card, "1-" __stringify(EM28XX_MAXBOARDS) "i");
-MODULE_PARM(video_nr, "1-" __stringify(EM28XX_MAXBOARDS) "i");
-MODULE_PARM(vbi_nr, "1-" __stringify(EM28XX_MAXBOARDS) "i");
-MODULE_PARM(radio_nr, "1-" __stringify(EM28XX_MAXBOARDS) "i");
-#else
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 10)
-static int dummy;
-module_param_array(card, int, dummy, 0444);
-module_param_array(video_nr, int, dummy, 0444);
-module_param_array(vbi_nr, int, dummy, 0444);
-module_param_array(radio_nr, int, dummy, 0444);
-#else
module_param_array(card, int, NULL, 0444);
module_param_array(video_nr, int, NULL, 0444);
module_param_array(vbi_nr, int, NULL, 0444);
module_param_array(radio_nr, int, NULL, 0444);
-#endif
-#endif
MODULE_PARM_DESC(card, "card type");
MODULE_PARM_DESC(video_nr, "video device numbers");
MODULE_PARM_DESC(vbi_nr, "vbi device numbers");
@@ -1192,13 +1174,13 @@ static int vidioc_g_register(struct file *file, void *priv,
reg->val = ret;
} else {
- u64 val = 0;
+ __le64 val = 0;
ret = em28xx_read_reg_req_len(dev, USB_REQ_GET_STATUS,
reg->reg, (char *)&val, 2);
if (ret < 0)
return ret;
- reg->val = cpu_to_le64((__u64)val);
+ reg->val = le64_to_cpu(val);
}
return 0;
@@ -1209,9 +1191,9 @@ static int vidioc_s_register(struct file *file, void *priv,
{
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
- u64 buf;
+ __le64 buf;
- buf = le64_to_cpu((__u64)reg->val);
+ buf = cpu_to_le64(reg->val);
return em28xx_write_regs(dev, reg->reg, (char *)&buf,
em28xx_reg_len(reg->reg));
@@ -1667,6 +1649,8 @@ static void em28xx_release_resources(struct em28xx *dev)
dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN,
dev->vbi_dev->minor-MINOR_VFL_TYPE_VBI_MIN);
list_del(&dev->devlist);
+ if (dev->sbutton_input_dev)
+ em28xx_deregister_snapshot_button(dev);
if (dev->radio_dev) {
if (-1 != dev->radio_dev->minor)
video_unregister_device(dev->radio_dev);
@@ -1835,9 +1819,7 @@ static const struct file_operations em28xx_v4l_fops = {
.mmap = em28xx_v4l2_mmap,
.ioctl = video_ioctl2,
.llseek = no_llseek,
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11)
.compat_ioctl = v4l_compat_ioctl32,
-#endif
};
static const struct file_operations radio_fops = {
@@ -1845,9 +1827,7 @@ static const struct file_operations radio_fops = {
.open = em28xx_v4l2_open,
.release = em28xx_v4l2_close,
.ioctl = video_ioctl2,
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11)
.compat_ioctl = v4l_compat_ioctl32,
-#endif
.llseek = no_llseek,
};
@@ -1934,32 +1914,28 @@ static DEFINE_MUTEX(em28xx_extension_devlist_lock);
int em28xx_register_extension(struct em28xx_ops *ops)
{
- struct em28xx *h, *dev = NULL;
-
- list_for_each_entry(h, &em28xx_devlist, devlist)
- dev = h;
+ struct em28xx *dev = NULL;
mutex_lock(&em28xx_extension_devlist_lock);
list_add_tail(&ops->next, &em28xx_extension_devlist);
- if (dev)
- ops->init(dev);
-
+ list_for_each_entry(dev, &em28xx_devlist, devlist) {
+ if (dev)
+ ops->init(dev);
+ }
printk(KERN_INFO "Em28xx: Initialized (%s) extension\n", ops->name);
mutex_unlock(&em28xx_extension_devlist_lock);
-
return 0;
}
EXPORT_SYMBOL(em28xx_register_extension);
void em28xx_unregister_extension(struct em28xx_ops *ops)
{
- struct em28xx *h, *dev = NULL;
-
- list_for_each_entry(h, &em28xx_devlist, devlist)
- dev = h;
+ struct em28xx *dev = NULL;
- if (dev)
- ops->fini(dev);
+ list_for_each_entry(dev, &em28xx_devlist, devlist) {
+ if (dev)
+ ops->fini(dev);
+ }
mutex_lock(&em28xx_extension_devlist_lock);
printk(KERN_INFO "Em28xx: Removed (%s) extension\n", ops->name);
@@ -1980,10 +1956,8 @@ static struct video_device *em28xx_vdev_init(struct em28xx *dev,
return NULL;
*vfd = *template;
vfd->minor = -1;
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
vfd->dev = &dev->udev->dev;
vfd->release = video_device_release;
-#endif
vfd->type = type;
vfd->debug = video_debug;
@@ -2169,9 +2143,6 @@ static void request_module_async(struct work_struct *work)
request_module("em28xx-dvb");
}
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
-#define request_modules(dev)
-#else
static void request_modules(struct em28xx *dev)
{
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
@@ -2182,7 +2153,6 @@ static void request_modules(struct em28xx *dev)
#endif
schedule_work(&dev->request_module_wk);
}
-#endif
#else
#define request_modules(dev)
#endif /* CONFIG_MODULES */
diff --git a/linux/drivers/media/video/em28xx/em28xx.h b/linux/drivers/media/video/em28xx/em28xx.h
index d31d11a5e..18b3bc134 100644
--- a/linux/drivers/media/video/em28xx/em28xx.h
+++ b/linux/drivers/media/video/em28xx/em28xx.h
@@ -58,6 +58,9 @@
#define EM2820_BOARD_PROLINK_PLAYTV_USB2 14
#define EM2800_BOARD_VGEAR_POCKETTV 15
#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950 16
+#define EM2880_BOARD_PINNACLE_PCTV_HD_PRO 17
+#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2 18
+#define EM2860_BOARD_POINTNIX_INTRAORAL_CAMERA 19
/* Limits minimum and default number of buffers */
#define EM28XX_MIN_BUF 4
@@ -250,6 +253,7 @@ struct em28xx_board {
unsigned int has_12mhz_i2s:1;
unsigned int max_range_640_480:1;
unsigned int has_dvb:1;
+ unsigned int has_snapshot_button:1;
enum em28xx_decoder decoder;
@@ -337,6 +341,7 @@ struct em28xx {
unsigned int has_12mhz_i2s:1;
unsigned int max_range_640_480:1;
unsigned int has_dvb:1;
+ unsigned int has_snapshot_button:1;
/* Some older em28xx chips needs a waiting time after writing */
unsigned int wait_after_write;
@@ -431,6 +436,15 @@ struct em28xx {
/* Caches GPO and GPIO registers */
unsigned char reg_gpo, reg_gpio;
+ /* Snapshot button */
+ char snapshot_button_path[30]; /* path of the input dev */
+ struct input_dev *sbutton_input_dev;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+ struct work_struct sbutton_query_work;
+#else
+ struct delayed_work sbutton_query_work;
+#endif
+
struct em28xx_dvb *dvb;
};
@@ -496,6 +510,8 @@ int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw);
int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw);
int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key,
u32 *ir_raw);
+void em28xx_register_snapshot_button(struct em28xx *dev);
+void em28xx_deregister_snapshot_button(struct em28xx *dev);
/* printk macros */
diff --git a/linux/drivers/media/video/et61x251/et61x251_core.c b/linux/drivers/media/video/et61x251/et61x251_core.c
index 27e1da696..4d08f0225 100644
--- a/linux/drivers/media/video/et61x251/et61x251_core.c
+++ b/linux/drivers/media/video/et61x251/et61x251_core.c
@@ -34,7 +34,7 @@
#include <linux/mm.h>
#include <linux/vmalloc.h>
#include <linux/page-flags.h>
-#include <linux/byteorder/generic.h>
+#include <asm/byteorder.h>
#include <asm/page.h>
#include <asm/uaccess.h>
diff --git a/linux/drivers/media/video/gspca/Kconfig b/linux/drivers/media/video/gspca/Kconfig
new file mode 100644
index 000000000..42b90742b
--- /dev/null
+++ b/linux/drivers/media/video/gspca/Kconfig
@@ -0,0 +1,13 @@
+config USB_GSPCA
+ tristate "USB GSPCA driver"
+ depends on VIDEO_V4L2
+ ---help---
+ Say Y here if you want support for various USB webcams.
+
+ See <file:Documentation/video4linux/gspca.txt> for more info.
+
+ This driver uses the Video For Linux API. You must say Y or M to
+ "Video For Linux" to use this driver.
+
+ To compile this driver as modules, choose M here: the
+ modules will be called gspca_xxxx.
diff --git a/linux/drivers/media/video/gspca/Makefile b/linux/drivers/media/video/gspca/Makefile
new file mode 100644
index 000000000..e68a89652
--- /dev/null
+++ b/linux/drivers/media/video/gspca/Makefile
@@ -0,0 +1,29 @@
+obj-$(CONFIG_USB_GSPCA) += gspca_main.o \
+ gspca_conex.o gspca_etoms.o gspca_mars.o \
+ gspca_ov519.o gspca_pac207.o gspca_pac7311.o \
+ gspca_sonixb.o gspca_sonixj.o gspca_spca500.o gspca_spca501.o \
+ gspca_spca505.o gspca_spca506.o gspca_spca508.o gspca_spca561.o \
+ gspca_sunplus.o gspca_stk014.o gspca_t613.o gspca_tv8532.o \
+ gspca_vc032x.o gspca_zc3xx.o
+
+gspca_main-objs := gspca.o
+gspca_conex-objs := conex.o
+gspca_etoms-objs := etoms.o
+gspca_mars-objs := mars.o
+gspca_ov519-objs := ov519.o
+gspca_pac207-objs := pac207.o
+gspca_pac7311-objs := pac7311.o
+gspca_sonixb-objs := sonixb.o
+gspca_sonixj-objs := sonixj.o
+gspca_spca500-objs := spca500.o
+gspca_spca501-objs := spca501.o
+gspca_spca505-objs := spca505.o
+gspca_spca506-objs := spca506.o
+gspca_spca508-objs := spca508.o
+gspca_spca561-objs := spca561.o
+gspca_stk014-objs := stk014.o
+gspca_sunplus-objs := sunplus.o
+gspca_t613-objs := t613.o
+gspca_tv8532-objs := tv8532.o
+gspca_vc032x-objs := vc032x.o
+gspca_zc3xx-objs := zc3xx.o
diff --git a/linux/drivers/media/video/gspca/conex.c b/linux/drivers/media/video/gspca/conex.c
new file mode 100644
index 000000000..b5481017d
--- /dev/null
+++ b/linux/drivers/media/video/gspca/conex.c
@@ -0,0 +1,1084 @@
+/*
+ * Connexant Cx11646 library
+ * Copyright (C) 2004 Michel Xhaard mxhaard@magic.fr
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define MODULE_NAME "conex"
+
+#include "gspca.h"
+#define CONEX_CAM 1 /* special JPEG header */
+#include "jpeg.h"
+
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 5)
+static const char version[] = "2.1.5";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("GSPCA USB Conexant Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+
+ unsigned char brightness;
+ unsigned char contrast;
+ unsigned char colors;
+
+ unsigned char qindex;
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+ {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+#define BRIGHTNESS_DEF 0xd4
+ .default_value = BRIGHTNESS_DEF,
+ },
+ .set = sd_setbrightness,
+ .get = sd_getbrightness,
+ },
+ {
+ {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = 0x0a,
+ .maximum = 0x1f,
+ .step = 1,
+#define CONTRAST_DEF 0x0c
+ .default_value = CONTRAST_DEF,
+ },
+ .set = sd_setcontrast,
+ .get = sd_getcontrast,
+ },
+ {
+ {
+ .id = V4L2_CID_SATURATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Color",
+ .minimum = 0,
+ .maximum = 7,
+ .step = 1,
+#define COLOR_DEF 3
+ .default_value = COLOR_DEF,
+ },
+ .set = sd_setcolors,
+ .get = sd_getcolors,
+ },
+};
+
+static struct v4l2_pix_format vga_mode[] = {
+ {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 176,
+ .sizeimage = 176 * 144 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 3},
+ {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 2},
+ {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 352,
+ .sizeimage = 352 * 288 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 1},
+ {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 0},
+};
+
+static void reg_r(struct usb_device *dev,
+ __u16 index,
+ __u8 *buffer, __u16 length)
+{
+ usb_control_msg(dev,
+ usb_rcvctrlpipe(dev, 0),
+ 0,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0,
+ index, buffer, length,
+ 500);
+ PDEBUG(D_USBI, "reg read [%02x] -> %02x ..", index, *buffer);
+}
+
+static void reg_w(struct usb_device *dev,
+ __u16 index,
+ const __u8 *buffer, __u16 len)
+{
+ __u8 tmpbuf[8];
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ if (len > sizeof tmpbuf) {
+ PDEBUG(D_ERR|D_PACK, "reg_w: buffer overflow");
+ return;
+ }
+ PDEBUG(D_USBO, "reg write [%02x] = %02x..", index, *buffer);
+#endif
+ memcpy(tmpbuf, buffer, len);
+ usb_control_msg(dev,
+ usb_sndctrlpipe(dev, 0),
+ 0,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0,
+ index, tmpbuf, len, 500);
+}
+
+static const __u8 cx_sensor_init[][4] = {
+ {0x88, 0x11, 0x01, 0x01},
+ {0x88, 0x12, 0x70, 0x01},
+ {0x88, 0x0f, 0x00, 0x01},
+ {0x88, 0x05, 0x01, 0x01},
+ {}
+};
+
+static const __u8 cx11646_fw1[][3] = {
+ {0x00, 0x02, 0x00},
+ {0x01, 0x43, 0x00},
+ {0x02, 0xA7, 0x00},
+ {0x03, 0x8B, 0x01},
+ {0x04, 0xE9, 0x02},
+ {0x05, 0x08, 0x04},
+ {0x06, 0x08, 0x05},
+ {0x07, 0x07, 0x06},
+ {0x08, 0xE7, 0x06},
+ {0x09, 0xC6, 0x07},
+ {0x0A, 0x86, 0x08},
+ {0x0B, 0x46, 0x09},
+ {0x0C, 0x05, 0x0A},
+ {0x0D, 0xA5, 0x0A},
+ {0x0E, 0x45, 0x0B},
+ {0x0F, 0xE5, 0x0B},
+ {0x10, 0x85, 0x0C},
+ {0x11, 0x25, 0x0D},
+ {0x12, 0xC4, 0x0D},
+ {0x13, 0x45, 0x0E},
+ {0x14, 0xE4, 0x0E},
+ {0x15, 0x64, 0x0F},
+ {0x16, 0xE4, 0x0F},
+ {0x17, 0x64, 0x10},
+ {0x18, 0xE4, 0x10},
+ {0x19, 0x64, 0x11},
+ {0x1A, 0xE4, 0x11},
+ {0x1B, 0x64, 0x12},
+ {0x1C, 0xE3, 0x12},
+ {0x1D, 0x44, 0x13},
+ {0x1E, 0xC3, 0x13},
+ {0x1F, 0x24, 0x14},
+ {0x20, 0xA3, 0x14},
+ {0x21, 0x04, 0x15},
+ {0x22, 0x83, 0x15},
+ {0x23, 0xE3, 0x15},
+ {0x24, 0x43, 0x16},
+ {0x25, 0xA4, 0x16},
+ {0x26, 0x23, 0x17},
+ {0x27, 0x83, 0x17},
+ {0x28, 0xE3, 0x17},
+ {0x29, 0x43, 0x18},
+ {0x2A, 0xA3, 0x18},
+ {0x2B, 0x03, 0x19},
+ {0x2C, 0x63, 0x19},
+ {0x2D, 0xC3, 0x19},
+ {0x2E, 0x22, 0x1A},
+ {0x2F, 0x63, 0x1A},
+ {0x30, 0xC3, 0x1A},
+ {0x31, 0x23, 0x1B},
+ {0x32, 0x83, 0x1B},
+ {0x33, 0xE2, 0x1B},
+ {0x34, 0x23, 0x1C},
+ {0x35, 0x83, 0x1C},
+ {0x36, 0xE2, 0x1C},
+ {0x37, 0x23, 0x1D},
+ {0x38, 0x83, 0x1D},
+ {0x39, 0xE2, 0x1D},
+ {0x3A, 0x23, 0x1E},
+ {0x3B, 0x82, 0x1E},
+ {0x3C, 0xC3, 0x1E},
+ {0x3D, 0x22, 0x1F},
+ {0x3E, 0x63, 0x1F},
+ {0x3F, 0xC1, 0x1F},
+ {}
+};
+static void cx11646_fw(struct gspca_dev*gspca_dev)
+{
+ __u8 val;
+ int i = 0;
+
+ val = 0x02;
+ reg_w(gspca_dev->dev, 0x006a, &val, 1);
+ while (cx11646_fw1[i][1]) {
+ reg_w(gspca_dev->dev, 0x006b, cx11646_fw1[i], 3);
+ i++;
+ }
+ val = 0x00;
+ reg_w(gspca_dev->dev, 0x006a, &val, 1);
+}
+
+static const __u8 cxsensor[] = {
+ 0x88, 0x12, 0x70, 0x01,
+ 0x88, 0x0d, 0x02, 0x01,
+ 0x88, 0x0f, 0x00, 0x01,
+ 0x88, 0x03, 0x71, 0x01, 0x88, 0x04, 0x00, 0x01, /* 3 */
+ 0x88, 0x02, 0x10, 0x01,
+ 0x88, 0x00, 0xD4, 0x01, 0x88, 0x01, 0x01, 0x01, /* 5 */
+ 0x88, 0x0B, 0x00, 0x01,
+ 0x88, 0x0A, 0x0A, 0x01,
+ 0x88, 0x00, 0x08, 0x01, 0x88, 0x01, 0x00, 0x01, /* 8 */
+ 0x88, 0x05, 0x01, 0x01,
+ 0xA1, 0x18, 0x00, 0x01,
+ 0x00
+};
+
+static const __u8 reg20[] = { 0x10, 0x42, 0x81, 0x19, 0xd3, 0xff, 0xa7, 0xff };
+static const __u8 reg28[] = { 0x87, 0x00, 0x87, 0x00, 0x8f, 0xff, 0xea, 0xff };
+static const __u8 reg10[] = { 0xb1, 0xb1 };
+static const __u8 reg71a[] = { 0x08, 0x18, 0x0a, 0x1e }; /* 640 */
+static const __u8 reg71b[] = { 0x04, 0x0c, 0x05, 0x0f };
+ /* 352{0x04,0x0a,0x06,0x12}; //352{0x05,0x0e,0x06,0x11}; //352 */
+static const __u8 reg71c[] = { 0x02, 0x07, 0x03, 0x09 };
+ /* 320{0x04,0x0c,0x05,0x0f}; //320 */
+static const __u8 reg71d[] = { 0x02, 0x07, 0x03, 0x09 }; /* 176 */
+static const __u8 reg7b[] = { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff };
+
+static void cx_sensor(struct gspca_dev*gspca_dev)
+{
+ __u8 val;
+ int i = 0;
+ __u8 bufread[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+ int length;
+ const __u8 *ptsensor = cxsensor;
+
+ reg_w(gspca_dev->dev, 0x0020, reg20, 8);
+ reg_w(gspca_dev->dev, 0x0028, reg28, 8);
+ reg_w(gspca_dev->dev, 0x0010, reg10, 8);
+ val = 0x03;
+ reg_w(gspca_dev->dev, 0x0092, &val, 1);
+
+ switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
+ case 0:
+ reg_w(gspca_dev->dev, 0x0071, reg71a, 4);
+ break;
+ case 1:
+ reg_w(gspca_dev->dev, 0x0071, reg71b, 4);
+ break;
+ default:
+/* case 2: */
+ reg_w(gspca_dev->dev, 0x0071, reg71c, 4);
+ break;
+ case 3:
+ reg_w(gspca_dev->dev, 0x0071, reg71d, 4);
+ break;
+ }
+ reg_w(gspca_dev->dev, 0x007b, reg7b, 6);
+ val = 0x00;
+ reg_w(gspca_dev->dev, 0x00f8, &val, 1);
+ reg_w(gspca_dev->dev, 0x0010, reg10, 8);
+ val = 0x41;
+ reg_w(gspca_dev->dev, 0x0098, &val, 1);
+ for (i = 0; i < 11; i++) {
+ if (i == 3 || i == 5 || i == 8)
+ length = 8;
+ else
+ length = 4;
+ reg_w(gspca_dev->dev, 0x00e5, ptsensor, length);
+ if (length == 4)
+ reg_r(gspca_dev->dev, 0x00e8, &val, 1);
+ else
+ reg_r(gspca_dev->dev, 0x00e8, bufread, length);
+ ptsensor += length;
+ }
+ reg_r(gspca_dev->dev, 0x00e7, bufread, 8);
+}
+
+static const __u8 cx_inits_176[] = {
+ 0x33, 0x81, 0xB0, 0x00, 0x90, 0x00, 0x0A, 0x03, /* 176x144 */
+ 0x00, 0x03, 0x03, 0x03, 0x1B, 0x05, 0x30, 0x03,
+ 0x65, 0x15, 0x18, 0x25, 0x03, 0x25, 0x08, 0x30,
+ 0x3B, 0x25, 0x10, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0xDC, 0xFF, 0xEE, 0xFF, 0xC5, 0xFF, 0xBF, 0xFF,
+ 0xF7, 0xFF, 0x88, 0xFF, 0x66, 0x02, 0x28, 0x02,
+ 0x1E, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+static const __u8 cx_inits_320[] = {
+ 0x7f, 0x7f, 0x40, 0x01, 0xf0, 0x00, 0x02, 0x01,
+ 0x00, 0x01, 0x01, 0x01, 0x10, 0x00, 0x02, 0x01,
+ 0x65, 0x45, 0xfa, 0x4c, 0x2c, 0xdf, 0xb9, 0x81,
+ 0x30, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0xe2, 0xff, 0xf1, 0xff, 0xc2, 0xff, 0xbc, 0xff,
+ 0xf5, 0xff, 0x6d, 0xff, 0xf6, 0x01, 0x43, 0x02,
+ 0xd3, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+static const __u8 cx_inits_352[] = {
+ 0x2e, 0x7c, 0x60, 0x01, 0x20, 0x01, 0x05, 0x03,
+ 0x00, 0x06, 0x03, 0x06, 0x1b, 0x10, 0x05, 0x3b,
+ 0x30, 0x25, 0x18, 0x25, 0x08, 0x30, 0x03, 0x25,
+ 0x3b, 0x30, 0x25, 0x1b, 0x10, 0x05, 0x00, 0x00,
+ 0xe3, 0xff, 0xf1, 0xff, 0xc2, 0xff, 0xbc, 0xff,
+ 0xf5, 0xff, 0x6b, 0xff, 0xee, 0x01, 0x43, 0x02,
+ 0xe4, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+static const __u8 cx_inits_640[] = {
+ 0x7e, 0x7e, 0x80, 0x02, 0xe0, 0x01, 0x01, 0x01,
+ 0x00, 0x02, 0x01, 0x02, 0x10, 0x30, 0x01, 0x01,
+ 0x65, 0x45, 0xf7, 0x52, 0x2c, 0xdf, 0xb9, 0x81,
+ 0x30, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0xe2, 0xff, 0xf1, 0xff, 0xc2, 0xff, 0xbc, 0xff,
+ 0xf6, 0xff, 0x7b, 0xff, 0x01, 0x02, 0x43, 0x02,
+ 0x77, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static int cx11646_initsize(struct gspca_dev *gspca_dev)
+{
+ const __u8 *cxinit;
+ __u8 val;
+ static const __u8 reg12[] = { 0x08, 0x05, 0x07, 0x04, 0x24 };
+ static const __u8 reg17[] =
+ { 0x0a, 0x00, 0xf2, 0x01, 0x0f, 0x00, 0x97, 0x02 };
+
+ switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
+ case 0:
+ cxinit = cx_inits_640;
+ break;
+ case 1:
+ cxinit = cx_inits_352;
+ break;
+ default:
+/* case 2: */
+ cxinit = cx_inits_320;
+ break;
+ case 3:
+ cxinit = cx_inits_176;
+ break;
+ }
+ val = 0x01;
+ reg_w(gspca_dev->dev, 0x009a, &val, 1);
+ val = 0x10;
+ reg_w(gspca_dev->dev, 0x0010, &val, 1);
+ reg_w(gspca_dev->dev, 0x0012, reg12, 5);
+ reg_w(gspca_dev->dev, 0x0017, reg17, 8);
+ val = 0x00;
+ reg_w(gspca_dev->dev, 0x00c0, &val, 1);
+ val = 0x04;
+ reg_w(gspca_dev->dev, 0x00c1, &val, 1);
+ val = 0x04;
+ reg_w(gspca_dev->dev, 0x00c2, &val, 1);
+
+ reg_w(gspca_dev->dev, 0x0061, cxinit, 8);
+ cxinit += 8;
+ reg_w(gspca_dev->dev, 0x00ca, cxinit, 8);
+ cxinit += 8;
+ reg_w(gspca_dev->dev, 0x00d2, cxinit, 8);
+ cxinit += 8;
+ reg_w(gspca_dev->dev, 0x00da, cxinit, 6);
+ cxinit += 8;
+ reg_w(gspca_dev->dev, 0x0041, cxinit, 8);
+ cxinit += 8;
+ reg_w(gspca_dev->dev, 0x0049, cxinit, 8);
+ cxinit += 8;
+ reg_w(gspca_dev->dev, 0x0051, cxinit, 2);
+
+ reg_r(gspca_dev->dev, 0x0010, &val, 1);
+ return val;
+}
+
+static const __u8 cx_jpeg_init[][8] = {
+ {0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x15}, /* 1 */
+ {0x0f, 0x10, 0x12, 0x10, 0x0d, 0x15, 0x12, 0x11},
+ {0x12, 0x18, 0x16, 0x15, 0x19, 0x20, 0x35, 0x22},
+ {0x20, 0x1d, 0x1d, 0x20, 0x41, 0x2e, 0x31, 0x26},
+ {0x35, 0x4d, 0x43, 0x51, 0x4f, 0x4b, 0x43, 0x4a},
+ {0x49, 0x55, 0x5F, 0x79, 0x67, 0x55, 0x5A, 0x73},
+ {0x5B, 0x49, 0x4A, 0x6A, 0x90, 0x6B, 0x73, 0x7D},
+ {0x81, 0x88, 0x89, 0x88, 0x52, 0x66, 0x95, 0xA0},
+ {0x94, 0x84, 0x9E, 0x79, 0x85, 0x88, 0x83, 0x01},
+ {0x15, 0x0F, 0x10, 0x12, 0x10, 0x0D, 0x15, 0x12},
+ {0x11, 0x12, 0x18, 0x16, 0x15, 0x19, 0x20, 0x35},
+ {0x22, 0x20, 0x1D, 0x1D, 0x20, 0x41, 0x2E, 0x31},
+ {0x26, 0x35, 0x4D, 0x43, 0x51, 0x4F, 0x4B, 0x43},
+ {0x4A, 0x49, 0x55, 0x5F, 0x79, 0x67, 0x55, 0x5A},
+ {0x73, 0x5B, 0x49, 0x4A, 0x6A, 0x90, 0x6B, 0x73},
+ {0x7D, 0x81, 0x88, 0x89, 0x88, 0x52, 0x66, 0x95},
+ {0xA0, 0x94, 0x84, 0x9E, 0x79, 0x85, 0x88, 0x83},
+ {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, 0x20, 0x00, 0x1F},
+ {0x02, 0x0C, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x11, 0x00, 0x11, 0x22, 0x00, 0x22},
+ {0x22, 0x11, 0x22, 0x22, 0x11, 0x33, 0x33, 0x11},
+ {0x44, 0x66, 0x22, 0x55, 0x66, 0xFF, 0xDD, 0x00},
+ {0x04, 0x00, 0x14, 0xFF, 0xC0, 0x00, 0x11, 0x08},
+ {0x00, 0xF0, 0x01, 0x40, 0x03, 0x00, 0x21, 0x00},
+ {0x01, 0x11, 0x01, 0x02, 0x11, 0x01, 0xFF, 0xDA},
+ {0x00, 0x0C, 0x03, 0x00, 0x00, 0x01, 0x11, 0x02},
+ {0x11, 0x00, 0x3F, 0x00, 0xFF, 0xD9, 0x00, 0x00} /* 79 */
+};
+
+
+static const __u8 cxjpeg_640[][8] = {
+ {0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x10}, /* 1 */
+ {0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e, 0x0d},
+ {0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28, 0x1a},
+ {0x18, 0x16, 0x16, 0x18, 0x31, 0x23, 0x25, 0x1d},
+ {0x28, 0x3a, 0x33, 0x3D, 0x3C, 0x39, 0x33, 0x38},
+ {0x37, 0x40, 0x48, 0x5C, 0x4E, 0x40, 0x44, 0x57},
+ {0x45, 0x37, 0x38, 0x50, 0x6D, 0x51, 0x57, 0x5F},
+ {0x62, 0x67, 0x68, 0x67, 0x3E, 0x4D, 0x71, 0x79},
+ {0x70, 0x64, 0x78, 0x5C, 0x65, 0x67, 0x63, 0x01},
+ {0x10, 0x0B, 0x0C, 0x0E, 0x0C, 0x0A, 0x10, 0x0E},
+ {0x0D, 0x0E, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28},
+ {0x1A, 0x18, 0x16, 0x16, 0x18, 0x31, 0x23, 0x25},
+ {0x1D, 0x28, 0x3A, 0x33, 0x3D, 0x3C, 0x39, 0x33},
+ {0x38, 0x37, 0x40, 0x48, 0x5C, 0x4E, 0x40, 0x44},
+ {0x57, 0x45, 0x37, 0x38, 0x50, 0x6D, 0x51, 0x57},
+ {0x5F, 0x62, 0x67, 0x68, 0x67, 0x3E, 0x4D, 0x71},
+ {0x79, 0x70, 0x64, 0x78, 0x5C, 0x65, 0x67, 0x63},
+ {0xFF, 0x20, 0x00, 0x1F, 0x00, 0x83, 0x00, 0x00},
+ {0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00},
+ {0x11, 0x22, 0x00, 0x22, 0x22, 0x11, 0x22, 0x22},
+ {0x11, 0x33, 0x33, 0x11, 0x44, 0x66, 0x22, 0x55},
+ {0x66, 0xFF, 0xDD, 0x00, 0x04, 0x00, 0x28, 0xFF},
+ {0xC0, 0x00, 0x11, 0x08, 0x01, 0xE0, 0x02, 0x80},
+ {0x03, 0x00, 0x21, 0x00, 0x01, 0x11, 0x01, 0x02},
+ {0x11, 0x01, 0xFF, 0xDA, 0x00, 0x0C, 0x03, 0x00},
+ {0x00, 0x01, 0x11, 0x02, 0x11, 0x00, 0x3F, 0x00},
+ {0xFF, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} /* 27 */
+};
+static const __u8 cxjpeg_352[][8] = {
+ {0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x0d},
+ {0x09, 0x09, 0x0b, 0x09, 0x08, 0x0D, 0x0b, 0x0a},
+ {0x0b, 0x0e, 0x0d, 0x0d, 0x0f, 0x13, 0x1f, 0x14},
+ {0x13, 0x11, 0x11, 0x13, 0x26, 0x1b, 0x1d, 0x17},
+ {0x1F, 0x2D, 0x28, 0x30, 0x2F, 0x2D, 0x28, 0x2C},
+ {0x2B, 0x32, 0x38, 0x48, 0x3D, 0x32, 0x35, 0x44},
+ {0x36, 0x2B, 0x2C, 0x3F, 0x55, 0x3F, 0x44, 0x4A},
+ {0x4D, 0x50, 0x51, 0x50, 0x30, 0x3C, 0x58, 0x5F},
+ {0x58, 0x4E, 0x5E, 0x48, 0x4F, 0x50, 0x4D, 0x01},
+ {0x0D, 0x09, 0x09, 0x0B, 0x09, 0x08, 0x0D, 0x0B},
+ {0x0A, 0x0B, 0x0E, 0x0D, 0x0D, 0x0F, 0x13, 0x1F},
+ {0x14, 0x13, 0x11, 0x11, 0x13, 0x26, 0x1B, 0x1D},
+ {0x17, 0x1F, 0x2D, 0x28, 0x30, 0x2F, 0x2D, 0x28},
+ {0x2C, 0x2B, 0x32, 0x38, 0x48, 0x3D, 0x32, 0x35},
+ {0x44, 0x36, 0x2B, 0x2C, 0x3F, 0x55, 0x3F, 0x44},
+ {0x4A, 0x4D, 0x50, 0x51, 0x50, 0x30, 0x3C, 0x58},
+ {0x5F, 0x58, 0x4E, 0x5E, 0x48, 0x4F, 0x50, 0x4D},
+ {0xFF, 0x20, 0x00, 0x1F, 0x01, 0x83, 0x00, 0x00},
+ {0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00},
+ {0x11, 0x22, 0x00, 0x22, 0x22, 0x11, 0x22, 0x22},
+ {0x11, 0x33, 0x33, 0x11, 0x44, 0x66, 0x22, 0x55},
+ {0x66, 0xFF, 0xDD, 0x00, 0x04, 0x00, 0x16, 0xFF},
+ {0xC0, 0x00, 0x11, 0x08, 0x01, 0x20, 0x01, 0x60},
+ {0x03, 0x00, 0x21, 0x00, 0x01, 0x11, 0x01, 0x02},
+ {0x11, 0x01, 0xFF, 0xDA, 0x00, 0x0C, 0x03, 0x00},
+ {0x00, 0x01, 0x11, 0x02, 0x11, 0x00, 0x3F, 0x00},
+ {0xFF, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+};
+static const __u8 cxjpeg_320[][8] = {
+ {0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x05},
+ {0x03, 0x04, 0x04, 0x04, 0x03, 0x05, 0x04, 0x04},
+ {0x04, 0x05, 0x05, 0x05, 0x06, 0x07, 0x0c, 0x08},
+ {0x07, 0x07, 0x07, 0x07, 0x0f, 0x0b, 0x0b, 0x09},
+ {0x0C, 0x11, 0x0F, 0x12, 0x12, 0x11, 0x0f, 0x11},
+ {0x11, 0x13, 0x16, 0x1C, 0x17, 0x13, 0x14, 0x1A},
+ {0x15, 0x11, 0x11, 0x18, 0x21, 0x18, 0x1A, 0x1D},
+ {0x1D, 0x1F, 0x1F, 0x1F, 0x13, 0x17, 0x22, 0x24},
+ {0x22, 0x1E, 0x24, 0x1C, 0x1E, 0x1F, 0x1E, 0x01},
+ {0x05, 0x03, 0x04, 0x04, 0x04, 0x03, 0x05, 0x04},
+ {0x04, 0x04, 0x05, 0x05, 0x05, 0x06, 0x07, 0x0C},
+ {0x08, 0x07, 0x07, 0x07, 0x07, 0x0F, 0x0B, 0x0B},
+ {0x09, 0x0C, 0x11, 0x0F, 0x12, 0x12, 0x11, 0x0F},
+ {0x11, 0x11, 0x13, 0x16, 0x1C, 0x17, 0x13, 0x14},
+ {0x1A, 0x15, 0x11, 0x11, 0x18, 0x21, 0x18, 0x1A},
+ {0x1D, 0x1D, 0x1F, 0x1F, 0x1F, 0x13, 0x17, 0x22},
+ {0x24, 0x22, 0x1E, 0x24, 0x1C, 0x1E, 0x1F, 0x1E},
+ {0xFF, 0x20, 0x00, 0x1F, 0x02, 0x0C, 0x00, 0x00},
+ {0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00},
+ {0x11, 0x22, 0x00, 0x22, 0x22, 0x11, 0x22, 0x22},
+ {0x11, 0x33, 0x33, 0x11, 0x44, 0x66, 0x22, 0x55},
+ {0x66, 0xFF, 0xDD, 0x00, 0x04, 0x00, 0x14, 0xFF},
+ {0xC0, 0x00, 0x11, 0x08, 0x00, 0xF0, 0x01, 0x40},
+ {0x03, 0x00, 0x21, 0x00, 0x01, 0x11, 0x01, 0x02},
+ {0x11, 0x01, 0xFF, 0xDA, 0x00, 0x0C, 0x03, 0x00},
+ {0x00, 0x01, 0x11, 0x02, 0x11, 0x00, 0x3F, 0x00},
+ {0xFF, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} /* 27 */
+};
+static const __u8 cxjpeg_176[][8] = {
+ {0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x0d},
+ {0x09, 0x09, 0x0B, 0x09, 0x08, 0x0D, 0x0B, 0x0A},
+ {0x0B, 0x0E, 0x0D, 0x0D, 0x0F, 0x13, 0x1F, 0x14},
+ {0x13, 0x11, 0x11, 0x13, 0x26, 0x1B, 0x1D, 0x17},
+ {0x1F, 0x2D, 0x28, 0x30, 0x2F, 0x2D, 0x28, 0x2C},
+ {0x2B, 0x32, 0x38, 0x48, 0x3D, 0x32, 0x35, 0x44},
+ {0x36, 0x2B, 0x2C, 0x3F, 0x55, 0x3F, 0x44, 0x4A},
+ {0x4D, 0x50, 0x51, 0x50, 0x30, 0x3C, 0x58, 0x5F},
+ {0x58, 0x4E, 0x5E, 0x48, 0x4F, 0x50, 0x4D, 0x01},
+ {0x0D, 0x09, 0x09, 0x0B, 0x09, 0x08, 0x0D, 0x0B},
+ {0x0A, 0x0B, 0x0E, 0x0D, 0x0D, 0x0F, 0x13, 0x1F},
+ {0x14, 0x13, 0x11, 0x11, 0x13, 0x26, 0x1B, 0x1D},
+ {0x17, 0x1F, 0x2D, 0x28, 0x30, 0x2F, 0x2D, 0x28},
+ {0x2C, 0x2B, 0x32, 0x38, 0x48, 0x3D, 0x32, 0x35},
+ {0x44, 0x36, 0x2B, 0x2C, 0x3F, 0x55, 0x3F, 0x44},
+ {0x4A, 0x4D, 0x50, 0x51, 0x50, 0x30, 0x3C, 0x58},
+ {0x5F, 0x58, 0x4E, 0x5E, 0x48, 0x4F, 0x50, 0x4D},
+ {0xFF, 0x20, 0x00, 0x1F, 0x03, 0xA1, 0x00, 0x00},
+ {0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00},
+ {0x11, 0x22, 0x00, 0x22, 0x22, 0x11, 0x22, 0x22},
+ {0x11, 0x33, 0x33, 0x11, 0x44, 0x66, 0x22, 0x55},
+ {0x66, 0xFF, 0xDD, 0x00, 0x04, 0x00, 0x0B, 0xFF},
+ {0xC0, 0x00, 0x11, 0x08, 0x00, 0x90, 0x00, 0xB0},
+ {0x03, 0x00, 0x21, 0x00, 0x01, 0x11, 0x01, 0x02},
+ {0x11, 0x01, 0xFF, 0xDA, 0x00, 0x0C, 0x03, 0x00},
+ {0x00, 0x01, 0x11, 0x02, 0x11, 0x00, 0x3F, 0x00},
+ {0xFF, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+};
+/* 640 take with the zcx30x part */
+static const __u8 cxjpeg_qtable[][8] = {
+ {0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x08},
+ {0x06, 0x06, 0x07, 0x06, 0x05, 0x08, 0x07, 0x07},
+ {0x07, 0x09, 0x09, 0x08, 0x0a, 0x0c, 0x14, 0x0a},
+ {0x0c, 0x0b, 0x0b, 0x0c, 0x19, 0x12, 0x13, 0x0f},
+ {0x14, 0x1d, 0x1a, 0x1f, 0x1e, 0x1d, 0x1a, 0x1c},
+ {0x1c, 0x20, 0x24, 0x2e, 0x27, 0x20, 0x22, 0x2c},
+ {0x23, 0x1c, 0x1c, 0x28, 0x37, 0x29, 0x2c, 0x30},
+ {0x31, 0x34, 0x34, 0x34, 0x1f, 0x27, 0x39, 0x3d},
+ {0x38, 0x32, 0x3c, 0x2e, 0x33, 0x34, 0x32, 0x01},
+ {0x09, 0x09, 0x09, 0x0c, 0x0b, 0x0c, 0x18, 0x0a},
+ {0x0a, 0x18, 0x32, 0x21, 0x1c, 0x21, 0x32, 0x32},
+ {0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32},
+ {0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32},
+ {0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32},
+ {0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32},
+ {0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32},
+ {0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32},
+ {0xFF, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} /* 18 */
+};
+
+
+static void cx11646_jpegInit(struct gspca_dev*gspca_dev)
+{
+ __u8 val;
+ int i;
+ int length;
+
+ val = 0x01;
+ reg_w(gspca_dev->dev, 0x00c0, &val, 1);
+ val = 0x00;
+ reg_w(gspca_dev->dev, 0x00c3, &val, 1);
+ val = 0x00;
+ reg_w(gspca_dev->dev, 0x00c0, &val, 1);
+ reg_r(gspca_dev->dev, 0x0001, &val, 1);
+ length = 8;
+ for (i = 0; i < 79; i++) {
+ if (i == 78)
+ length = 6;
+ reg_w(gspca_dev->dev, 0x0008, cx_jpeg_init[i], length);
+ }
+ reg_r(gspca_dev->dev, 0x0002, &val, 1);
+ val = 0x14;
+ reg_w(gspca_dev->dev, 0x0055, &val, 1);
+}
+
+static const __u8 reg12[] = { 0x0a, 0x05, 0x07, 0x04, 0x19 };
+static const __u8 regE5_8[] =
+ { 0x88, 0x00, 0xd4, 0x01, 0x88, 0x01, 0x01, 0x01 };
+static const __u8 regE5a[] = { 0x88, 0x0a, 0x0c, 0x01 };
+static const __u8 regE5b[] = { 0x88, 0x0b, 0x12, 0x01 };
+static const __u8 regE5c[] = { 0x88, 0x05, 0x01, 0x01 };
+static const __u8 reg51[] = { 0x77, 0x03 };
+static const __u8 reg70 = 0x03;
+
+static void cx11646_jpeg(struct gspca_dev*gspca_dev)
+{
+ __u8 val;
+ int i;
+ int length;
+ __u8 Reg55;
+ __u8 bufread[8];
+ int retry;
+
+ val = 0x01;
+ reg_w(gspca_dev->dev, 0x00c0, &val, 1);
+ val = 0x00;
+ reg_w(gspca_dev->dev, 0x00c3, &val, 1);
+ val = 0x00;
+ reg_w(gspca_dev->dev, 0x00c0, &val, 1);
+ reg_r(gspca_dev->dev, 0x0001, &val, 1);
+ length = 8;
+ switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
+ case 0:
+ for (i = 0; i < 27; i++) {
+ if (i == 26)
+ length = 2;
+ reg_w(gspca_dev->dev, 0x0008, cxjpeg_640[i], length);
+ }
+ Reg55 = 0x28;
+ break;
+ case 1:
+ for (i = 0; i < 27; i++) {
+ if (i == 26)
+ length = 2;
+ reg_w(gspca_dev->dev, 0x0008, cxjpeg_352[i], length);
+ }
+ Reg55 = 0x16;
+ break;
+ default:
+/* case 2: */
+ for (i = 0; i < 27; i++) {
+ if (i == 26)
+ length = 2;
+ reg_w(gspca_dev->dev, 0x0008, cxjpeg_320[i], length);
+ }
+ Reg55 = 0x14;
+ break;
+ case 3:
+ for (i = 0; i < 27; i++) {
+ if (i == 26)
+ length = 2;
+ reg_w(gspca_dev->dev, 0x0008, cxjpeg_176[i], length);
+ }
+ Reg55 = 0x0B;
+ break;
+ }
+
+ reg_r(gspca_dev->dev, 0x0002, &val, 1);
+ val = Reg55;
+ reg_w(gspca_dev->dev, 0x0055, &val, 1);
+ reg_r(gspca_dev->dev, 0x0002, &val, 1);
+ reg_w(gspca_dev->dev, 0x0010, reg10, 2);
+ val = 0x02;
+ reg_w(gspca_dev->dev, 0x0054, &val, 1);
+ val = 0x01;
+ reg_w(gspca_dev->dev, 0x0054, &val, 1);
+ val = 0x94;
+ reg_w(gspca_dev->dev, 0x0000, &val, 1);
+ val = 0xc0;
+ reg_w(gspca_dev->dev, 0x0053, &val, 1);
+ val = 0xe1;
+ reg_w(gspca_dev->dev, 0x00fc, &val, 1);
+ val = 0x00;
+ reg_w(gspca_dev->dev, 0x0000, &val, 1);
+ /* wait for completion */
+ retry = 50;
+ while (retry--) {
+ reg_r(gspca_dev->dev, 0x0002, &val, 1);
+ /* 0x07 until 0x00 */
+ if (val == 0x00)
+ break;
+ val = 0x00;
+ reg_w(gspca_dev->dev, 0x0053, &val, 1);
+ }
+ if (retry == 0)
+ PDEBUG(D_ERR, "Damned Errors sending jpeg Table");
+ /* send the qtable now */
+ reg_r(gspca_dev->dev, 0x0001, &val, 1); /* -> 0x18 */
+ length = 8;
+ for (i = 0; i < 18; i++) {
+ if (i == 17)
+ length = 2;
+ reg_w(gspca_dev->dev, 0x0008, cxjpeg_qtable[i], length);
+
+ }
+ reg_r(gspca_dev->dev, 0x0002, &val, 1); /* 0x00 */
+ reg_r(gspca_dev->dev, 0x0053, &val, 1); /* 0x00 */
+ val = 0x02;
+ reg_w(gspca_dev->dev, 0x0054, &val, 1);
+ val = 0x01;
+ reg_w(gspca_dev->dev, 0x0054, &val, 1);
+ val = 0x94;
+ reg_w(gspca_dev->dev, 0x0000, &val, 1);
+ val = 0xc0;
+ reg_w(gspca_dev->dev, 0x0053, &val, 1);
+
+ reg_r(gspca_dev->dev, 0x0038, &val, 1); /* 0x40 */
+ reg_r(gspca_dev->dev, 0x0038, &val, 1); /* 0x40 */
+ reg_r(gspca_dev->dev, 0x001f, &val, 1); /* 0x38 */
+ reg_w(gspca_dev->dev, 0x0012, reg12, 5);
+ reg_w(gspca_dev->dev, 0x00e5, regE5_8, 8);
+ reg_r(gspca_dev->dev, 0x00e8, bufread, 8);
+ reg_w(gspca_dev->dev, 0x00e5, regE5a, 4);
+ reg_r(gspca_dev->dev, 0x00e8, &val, 1); /* 0x00 */
+ val = 0x01;
+ reg_w(gspca_dev->dev, 0x009a, &val, 1);
+ reg_w(gspca_dev->dev, 0x00e5, regE5b, 4);
+ reg_r(gspca_dev->dev, 0x00e8, &val, 1); /* 0x00 */
+ reg_w(gspca_dev->dev, 0x00e5, regE5c, 4);
+ reg_r(gspca_dev->dev, 0x00e8, &val, 1); /* 0x00 */
+
+ reg_w(gspca_dev->dev, 0x0051, reg51, 2);
+ reg_w(gspca_dev->dev, 0x0010, reg10, 2);
+ reg_w(gspca_dev->dev, 0x0070, &reg70, 1);
+}
+
+static void cx11646_init1(struct gspca_dev *gspca_dev)
+{
+ __u8 val;
+ int i = 0;
+
+ val = 0;
+ reg_w(gspca_dev->dev, 0x0010, &val, 1);
+ reg_w(gspca_dev->dev, 0x0053, &val, 1);
+ reg_w(gspca_dev->dev, 0x0052, &val, 1);
+ val = 0x2f;
+ reg_w(gspca_dev->dev, 0x009b, &val, 1);
+ val = 0x10;
+ reg_w(gspca_dev->dev, 0x009c, &val, 1);
+ reg_r(gspca_dev->dev, 0x0098, &val, 1);
+ val = 0x40;
+ reg_w(gspca_dev->dev, 0x0098, &val, 1);
+ reg_r(gspca_dev->dev, 0x0099, &val, 1);
+ val = 0x07;
+ reg_w(gspca_dev->dev, 0x0099, &val, 1);
+ val = 0x40;
+ reg_w(gspca_dev->dev, 0x0039, &val, 1);
+ val = 0xff;
+ reg_w(gspca_dev->dev, 0x003c, &val, 1);
+ val = 0x1f;
+ reg_w(gspca_dev->dev, 0x003f, &val, 1);
+ val = 0x40;
+ reg_w(gspca_dev->dev, 0x003d, &val, 1);
+/* val= 0x60; */
+/* reg_w(gspca_dev->dev, 0x00, 0x00, 0x003d, &val, 1); */
+ reg_r(gspca_dev->dev, 0x0099, &val, 1); /* ->0x07 */
+
+ while (cx_sensor_init[i][0]) {
+ reg_w(gspca_dev->dev, 0x00e5, cx_sensor_init[i], 1);
+ reg_r(gspca_dev->dev, 0x00e8, &val, 1); /* -> 0x00 */
+ if (i == 1) {
+ val = 1;
+ reg_w(gspca_dev->dev, 0x00ed, &val, 1);
+ reg_r(gspca_dev->dev, 0x00ed, &val, 1); /* -> 0x01 */
+ }
+ i++;
+ }
+ val = 0x00;
+ reg_w(gspca_dev->dev, 0x00c3, &val, 1);
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+ const struct usb_device_id *id)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct cam *cam;
+
+ cam = &gspca_dev->cam;
+ cam->dev_name = (char *) id->driver_info;
+ cam->epaddr = 0x01;
+ cam->cam_mode = vga_mode;
+ cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+
+ sd->qindex = 0; /* set the quantization */
+ sd->brightness = BRIGHTNESS_DEF;
+ sd->contrast = CONTRAST_DEF;
+ sd->colors = COLOR_DEF;
+ return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+ cx11646_init1(gspca_dev);
+ cx11646_initsize(gspca_dev);
+ cx11646_fw(gspca_dev);
+ cx_sensor(gspca_dev);
+ cx11646_jpegInit(gspca_dev);
+ return 0;
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+ cx11646_initsize(gspca_dev);
+ cx11646_fw(gspca_dev);
+ cx_sensor(gspca_dev);
+ cx11646_jpeg(gspca_dev);
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+ int retry = 50;
+ __u8 val;
+
+ val = 0;
+ reg_w(gspca_dev->dev, 0x0000, &val, 1);
+ reg_r(gspca_dev->dev, 0x0002, &val, 1);
+ val = 0;
+ reg_w(gspca_dev->dev, 0x0053, &val, 1);
+
+ while (retry--) {
+/* reg_r(gspca_dev->dev, 0x0002, &val, 1);*/
+ reg_r(gspca_dev->dev, 0x0053, &val, 1);
+ if (val == 0)
+ break;
+ }
+ val = 0;
+ reg_w(gspca_dev->dev, 0x0000, &val, 1);
+ reg_r(gspca_dev->dev, 0x0002, &val, 1);
+
+ val = 0;
+ reg_w(gspca_dev->dev, 0x0010, &val, 1);
+ reg_r(gspca_dev->dev, 0x0033, &val, 1);
+ val = 0xe0;
+ reg_w(gspca_dev->dev, 0x00fc, &val, 1);
+}
+
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ struct gspca_frame *frame, /* target */
+ __u8 *data, /* isoc packet */
+ int len) /* iso packet length */
+{
+ if (data[0] == 0xff && data[1] == 0xd8) {
+
+ /* start of frame */
+ frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+ data, 0);
+
+ /* put the JPEG header in the new frame */
+ jpeg_put_header(gspca_dev, frame,
+ ((struct sd *) gspca_dev)->qindex,
+ 0x22);
+ data += 2;
+ len -= 2;
+ }
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+}
+
+static void setbrightness(struct gspca_dev*gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ __u8 regE5cbx[] = { 0x88, 0x00, 0xd4, 0x01, 0x88, 0x01, 0x01, 0x01 };
+ __u8 reg51c[2];
+ __u8 bright;
+ __u8 colors;
+ __u8 val;
+ __u8 bufread[8];
+
+ bright = sd->brightness;
+ regE5cbx[2] = bright;
+ reg_w(gspca_dev->dev, 0x00e5, regE5cbx, 8);
+ reg_r(gspca_dev->dev, 0x00e8, bufread, 8);
+ reg_w(gspca_dev->dev, 0x00e5, regE5c, 4);
+ reg_r(gspca_dev->dev, 0x00e8, &val, 1); /* 0x00 */
+
+ colors = sd->colors;
+ reg51c[0] = 0x77;
+ reg51c[1] = colors;
+ reg_w(gspca_dev->dev, 0x0051, reg51c, 2);
+ reg_w(gspca_dev->dev, 0x0010, reg10, 2);
+ reg_w(gspca_dev->dev, 0x0070, &reg70, 1);
+}
+
+static void setcontrast(struct gspca_dev*gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ __u8 regE5acx[] = { 0x88, 0x0a, 0x0c, 0x01 }; /* seem MSB */
+/* __u8 regE5bcx[] = { 0x88, 0x0b, 0x12, 0x01}; * LSB */
+ __u8 reg51c[2];
+ __u8 val;
+
+ regE5acx[2] = sd->contrast;
+ reg_w(gspca_dev->dev, 0x00e5, regE5acx, 4);
+ reg_r(gspca_dev->dev, 0x00e8, &val, 1); /* 0x00 */
+ reg51c[0] = 0x77;
+ reg51c[1] = sd->colors;
+ reg_w(gspca_dev->dev, 0x0051, reg51c, 2);
+ reg_w(gspca_dev->dev, 0x0010, reg10, 2);
+ reg_w(gspca_dev->dev, 0x0070, &reg70, 1);
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->brightness = val;
+ if (gspca_dev->streaming)
+ setbrightness(gspca_dev);
+ return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->brightness;
+ return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->contrast = val;
+ if (gspca_dev->streaming)
+ setcontrast(gspca_dev);
+ return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->contrast;
+ return 0;
+}
+
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->colors = val;
+ if (gspca_dev->streaming) {
+ setbrightness(gspca_dev);
+ setcontrast(gspca_dev);
+ }
+ return 0;
+}
+
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->colors;
+ return 0;
+}
+
+/* sub-driver description */
+static struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .ctrls = sd_ctrls,
+ .nctrls = ARRAY_SIZE(sd_ctrls),
+ .config = sd_config,
+ .open = sd_open,
+ .start = sd_start,
+ .stopN = sd_stopN,
+ .stop0 = sd_stop0,
+ .close = sd_close,
+ .pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static __devinitdata struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x0572, 0x0041), DVNM("Creative Notebook cx11646")},
+ {}
+};
+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,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+ if (usb_register(&sd_driver) < 0)
+ return -1;
+ PDEBUG(D_PROBE, "v%s registered", version);
+ return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+ usb_deregister(&sd_driver);
+ PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/linux/drivers/media/video/gspca/etoms.c b/linux/drivers/media/video/gspca/etoms.c
new file mode 100644
index 000000000..25d59ae1f
--- /dev/null
+++ b/linux/drivers/media/video/gspca/etoms.c
@@ -0,0 +1,961 @@
+/*
+ * Etoms Et61x151 GPL Linux driver by Michel Xhaard (09/09/2004)
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define MODULE_NAME "etoms"
+
+#include "gspca.h"
+
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 5)
+static const char version[] = "2.1.5";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("Etoms USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+
+ unsigned char brightness;
+ unsigned char contrast;
+ unsigned char colors;
+ unsigned char autogain;
+
+ char sensor;
+#define SENSOR_PAS106 0
+#define SENSOR_TAS5130CXX 1
+ signed char ag_cnt;
+#define AG_CNT_START 13
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+ {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 1,
+ .maximum = 127,
+ .step = 1,
+#define BRIGHTNESS_DEF 63
+ .default_value = BRIGHTNESS_DEF,
+ },
+ .set = sd_setbrightness,
+ .get = sd_getbrightness,
+ },
+ {
+ {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+#define CONTRAST_DEF 127
+ .default_value = CONTRAST_DEF,
+ },
+ .set = sd_setcontrast,
+ .get = sd_getcontrast,
+ },
+ {
+ {
+ .id = V4L2_CID_SATURATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Color",
+ .minimum = 0,
+ .maximum = 15,
+ .step = 1,
+#define COLOR_DEF 7
+ .default_value = COLOR_DEF,
+ },
+ .set = sd_setcolors,
+ .get = sd_getcolors,
+ },
+ {
+ {
+ .id = V4L2_CID_AUTOGAIN,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Auto Gain",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+#define AUTOGAIN_DEF 1
+ .default_value = AUTOGAIN_DEF,
+ },
+ .set = sd_setautogain,
+ .get = sd_getautogain,
+ },
+};
+
+static struct v4l2_pix_format vga_mode[] = {
+ {320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 1},
+/* {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0}, */
+};
+
+static struct v4l2_pix_format sif_mode[] = {
+ {176, 144, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+ .bytesperline = 176,
+ .sizeimage = 176 * 144,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 1},
+ {352, 288, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+ .bytesperline = 352,
+ .sizeimage = 352 * 288,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0},
+};
+
+#define ETOMS_ALT_SIZE_1000 12
+
+#define ET_GPIO_DIR_CTRL 0x04 /* Control IO bit[0..5] (0 in 1 out) */
+#define ET_GPIO_OUT 0x05 /* Only IO data */
+#define ET_GPIO_IN 0x06 /* Read Only IO data */
+#define ET_RESET_ALL 0x03
+#define ET_ClCK 0x01
+#define ET_CTRL 0x02 /* enable i2c OutClck Powerdown mode */
+
+#define ET_COMP 0x12 /* Compression register */
+#define ET_MAXQt 0x13
+#define ET_MINQt 0x14
+#define ET_COMP_VAL0 0x02
+#define ET_COMP_VAL1 0x03
+
+#define ET_REG1d 0x1d
+#define ET_REG1e 0x1e
+#define ET_REG1f 0x1f
+#define ET_REG20 0x20
+#define ET_REG21 0x21
+#define ET_REG22 0x22
+#define ET_REG23 0x23
+#define ET_REG24 0x24
+#define ET_REG25 0x25
+/* base registers for luma calculation */
+#define ET_LUMA_CENTER 0x39
+
+#define ET_G_RED 0x4d
+#define ET_G_GREEN1 0x4e
+#define ET_G_BLUE 0x4f
+#define ET_G_GREEN2 0x50
+#define ET_G_GR_H 0x51
+#define ET_G_GB_H 0x52
+
+#define ET_O_RED 0x34
+#define ET_O_GREEN1 0x35
+#define ET_O_BLUE 0x36
+#define ET_O_GREEN2 0x37
+
+#define ET_SYNCHRO 0x68
+#define ET_STARTX 0x69
+#define ET_STARTY 0x6a
+#define ET_WIDTH_LOW 0x6b
+#define ET_HEIGTH_LOW 0x6c
+#define ET_W_H_HEIGTH 0x6d
+
+#define ET_REG6e 0x6e /* OBW */
+#define ET_REG6f 0x6f /* OBW */
+#define ET_REG70 0x70 /* OBW_AWB */
+#define ET_REG71 0x71 /* OBW_AWB */
+#define ET_REG72 0x72 /* OBW_AWB */
+#define ET_REG73 0x73 /* Clkdelay ns */
+#define ET_REG74 0x74 /* test pattern */
+#define ET_REG75 0x75 /* test pattern */
+
+#define ET_I2C_CLK 0x8c
+#define ET_PXL_CLK 0x60
+
+#define ET_I2C_BASE 0x89
+#define ET_I2C_COUNT 0x8a
+#define ET_I2C_PREFETCH 0x8b
+#define ET_I2C_REG 0x88
+#define ET_I2C_DATA7 0x87
+#define ET_I2C_DATA6 0x86
+#define ET_I2C_DATA5 0x85
+#define ET_I2C_DATA4 0x84
+#define ET_I2C_DATA3 0x83
+#define ET_I2C_DATA2 0x82
+#define ET_I2C_DATA1 0x81
+#define ET_I2C_DATA0 0x80
+
+#define PAS106_REG2 0x02 /* pxlClk = systemClk/(reg2) */
+#define PAS106_REG3 0x03 /* line/frame H [11..4] */
+#define PAS106_REG4 0x04 /* line/frame L [3..0] */
+#define PAS106_REG5 0x05 /* exposure time line offset(default 5) */
+#define PAS106_REG6 0x06 /* exposure time pixel offset(default 6) */
+#define PAS106_REG7 0x07 /* signbit Dac (default 0) */
+#define PAS106_REG9 0x09
+#define PAS106_REG0e 0x0e /* global gain [4..0](default 0x0e) */
+#define PAS106_REG13 0x13 /* end i2c write */
+
+static const __u8 GainRGBG[] = { 0x80, 0x80, 0x80, 0x80, 0x00, 0x00 };
+
+static const __u8 I2c2[] = { 0x08, 0x08, 0x08, 0x08, 0x0d };
+
+static const __u8 I2c3[] = { 0x12, 0x05 };
+
+static const __u8 I2c4[] = { 0x41, 0x08 };
+
+static void reg_r(struct usb_device *dev,
+ __u16 index, __u8 *buffer, int len)
+{
+ usb_control_msg(dev,
+ usb_rcvctrlpipe(dev, 0),
+ 0,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+ 0, index, buffer, len, 500);
+}
+
+static void reg_w_val(struct usb_device *dev,
+ __u16 index, __u8 val)
+{
+ __u8 data;
+
+ data = val;
+ usb_control_msg(dev,
+ usb_sndctrlpipe(dev, 0),
+ 0,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+ 0, index, &data, 1, 500);
+}
+
+static void reg_w(struct usb_device *dev,
+ __u16 index, const __u8 *buffer, __u16 len)
+{
+ __u8 tmpbuf[8];
+
+ memcpy(tmpbuf, buffer, len);
+ usb_control_msg(dev,
+ usb_sndctrlpipe(dev, 0),
+ 0,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+ 0, index, tmpbuf, len, 500);
+}
+
+static int Et_i2cwrite(struct usb_device *dev, __u8 reg,
+ const __u8 *buffer,
+ __u16 len, __u8 mode)
+{
+ /* buffer should be [D0..D7] */
+ __u8 ptchcount;
+
+ /* set the base address */
+ reg_w_val(dev, ET_I2C_BASE, 0x40); /* sensor base for the pas106 */
+ /* set count and prefetch */
+ ptchcount = ((len & 0x07) << 4) | (mode & 0x03);
+ reg_w_val(dev, ET_I2C_COUNT, ptchcount);
+ /* set the register base */
+ reg_w_val(dev, ET_I2C_REG, reg);
+ while (--len >= 0)
+ reg_w_val(dev, ET_I2C_DATA0 + len, buffer[len]);
+ return 0;
+}
+
+static int Et_i2cread(struct usb_device *dev, __u8 reg,
+ __u8 *buffer,
+ __u16 length, __u8 mode)
+{
+ /* buffer should be [D0..D7] */
+ int i, j;
+ __u8 ptchcount;
+
+ /* set the base address */
+ reg_w_val(dev, ET_I2C_BASE, 0x40); /* sensor base for the pas106 */
+ /* set count and prefetch */
+ ptchcount = ((length & 0x07) << 4) | (mode & 0x03);
+ reg_w_val(dev, ET_I2C_COUNT, ptchcount);
+ /* set the register base */
+ reg_w_val(dev, ET_I2C_REG, reg);
+ reg_w_val(dev, ET_I2C_PREFETCH, 0x02); /* prefetch */
+ reg_w_val(dev, ET_I2C_PREFETCH, 0);
+ j = length - 1;
+ for (i = 0; i < length; i++) {
+ reg_r(dev, (ET_I2C_DATA0 + j), &buffer[j], 1);
+ j--;
+ }
+ return 0;
+}
+
+static int Et_WaitStatus(struct usb_device *dev)
+{
+ __u8 bytereceived;
+ int retry = 10;
+
+ while (retry--) {
+ reg_r(dev, ET_ClCK, &bytereceived, 1);
+ if (bytereceived != 0)
+ return 1;
+ }
+ return 0;
+}
+
+static int et_video(struct usb_device *dev, int on)
+{
+ int err;
+
+ reg_w_val(dev, ET_GPIO_OUT, on
+ ? 0x10 /* startvideo - set Bit5 */
+ : 0); /* stopvideo */
+ err = Et_WaitStatus(dev);
+ if (!err)
+ PDEBUG(D_ERR, "timeout video on/off");
+ return err;
+}
+
+static void Et_init2(struct gspca_dev *gspca_dev)
+{
+ struct usb_device *dev = gspca_dev->dev;
+ __u8 value;
+ __u8 received;
+ static const __u8 FormLine[] = { 0x84, 0x03, 0x14, 0xf4, 0x01, 0x05 };
+
+ PDEBUG(D_STREAM, "Open Init2 ET");
+ reg_w_val(dev, ET_GPIO_DIR_CTRL, 0x2f);
+ reg_w_val(dev, ET_GPIO_OUT, 0x10);
+ reg_r(dev, ET_GPIO_IN, &received, 1);
+ reg_w_val(dev, ET_ClCK, 0x14); /* 0x14 // 0x16 enabled pattern */
+ reg_w_val(dev, ET_CTRL, 0x1b);
+
+ /* compression et subsampling */
+ if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv)
+ value = ET_COMP_VAL1; /* 320 */
+ else
+ value = ET_COMP_VAL0; /* 640 */
+ reg_w_val(dev, ET_COMP, value);
+ reg_w_val(dev, ET_MAXQt, 0x1f);
+ reg_w_val(dev, ET_MINQt, 0x04);
+ /* undocumented registers */
+ reg_w_val(dev, ET_REG1d, 0xff);
+ reg_w_val(dev, ET_REG1e, 0xff);
+ reg_w_val(dev, ET_REG1f, 0xff);
+ reg_w_val(dev, ET_REG20, 0x35);
+ reg_w_val(dev, ET_REG21, 0x01);
+ reg_w_val(dev, ET_REG22, 0x00);
+ reg_w_val(dev, ET_REG23, 0xff);
+ reg_w_val(dev, ET_REG24, 0xff);
+ reg_w_val(dev, ET_REG25, 0x0f);
+ /* colors setting */
+ reg_w_val(dev, 0x30, 0x11); /* 0x30 */
+ reg_w_val(dev, 0x31, 0x40);
+ reg_w_val(dev, 0x32, 0x00);
+ reg_w_val(dev, ET_O_RED, 0x00); /* 0x34 */
+ reg_w_val(dev, ET_O_GREEN1, 0x00);
+ reg_w_val(dev, ET_O_BLUE, 0x00);
+ reg_w_val(dev, ET_O_GREEN2, 0x00);
+ /*************/
+ reg_w_val(dev, ET_G_RED, 0x80); /* 0x4d */
+ reg_w_val(dev, ET_G_GREEN1, 0x80);
+ reg_w_val(dev, ET_G_BLUE, 0x80);
+ reg_w_val(dev, ET_G_GREEN2, 0x80);
+ reg_w_val(dev, ET_G_GR_H, 0x00);
+ reg_w_val(dev, ET_G_GB_H, 0x00); /* 0x52 */
+ /* Window control registers */
+ reg_w_val(dev, 0x61, 0x80); /* use cmc_out */
+ reg_w_val(dev, 0x62, 0x02);
+ reg_w_val(dev, 0x63, 0x03);
+ reg_w_val(dev, 0x64, 0x14);
+ reg_w_val(dev, 0x65, 0x0e);
+ reg_w_val(dev, 0x66, 0x02);
+ reg_w_val(dev, 0x67, 0x02);
+
+ /**************************************/
+ reg_w_val(dev, ET_SYNCHRO, 0x8f); /* 0x68 */
+ reg_w_val(dev, ET_STARTX, 0x69); /* 0x6a //0x69 */
+ reg_w_val(dev, ET_STARTY, 0x0d); /* 0x0d //0x0c */
+ reg_w_val(dev, ET_WIDTH_LOW, 0x80);
+ reg_w_val(dev, ET_HEIGTH_LOW, 0xe0);
+ reg_w_val(dev, ET_W_H_HEIGTH, 0x60); /* 6d */
+ reg_w_val(dev, ET_REG6e, 0x86);
+ reg_w_val(dev, ET_REG6f, 0x01);
+ reg_w_val(dev, ET_REG70, 0x26);
+ reg_w_val(dev, ET_REG71, 0x7a);
+ reg_w_val(dev, ET_REG72, 0x01);
+ /* Clock Pattern registers ***************** */
+ reg_w_val(dev, ET_REG73, 0x00);
+ reg_w_val(dev, ET_REG74, 0x18); /* 0x28 */
+ reg_w_val(dev, ET_REG75, 0x0f); /* 0x01 */
+ /**********************************************/
+ reg_w_val(dev, 0x8a, 0x20);
+ reg_w_val(dev, 0x8d, 0x0f);
+ reg_w_val(dev, 0x8e, 0x08);
+ /**************************************/
+ reg_w_val(dev, 0x03, 0x08);
+ reg_w_val(dev, ET_PXL_CLK, 0x03);
+ reg_w_val(dev, 0x81, 0xff);
+ reg_w_val(dev, 0x80, 0x00);
+ reg_w_val(dev, 0x81, 0xff);
+ reg_w_val(dev, 0x80, 0x20);
+ reg_w_val(dev, 0x03, 0x01);
+ reg_w_val(dev, 0x03, 0x00);
+ reg_w_val(dev, 0x03, 0x08);
+ /********************************************/
+
+/* reg_r(dev, ET_I2C_BASE, &received, 1);
+ always 0x40 as the pas106 ??? */
+ /* set the sensor */
+ if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv)
+ value = 0x04; /* 320 */
+ else /* 640 */
+ value = 0x1e; /* 0x17 * setting PixelClock
+ * 0x03 mean 24/(3+1) = 6 Mhz
+ * 0x05 -> 24/(5+1) = 4 Mhz
+ * 0x0b -> 24/(11+1) = 2 Mhz
+ * 0x17 -> 24/(23+1) = 1 Mhz
+ */
+ reg_w_val(dev, ET_PXL_CLK, value);
+ /* now set by fifo the FormatLine setting */
+ reg_w(dev, 0x62, FormLine, 6);
+
+ /* set exposure times [ 0..0x78] 0->longvalue 0x78->shortvalue */
+ reg_w_val(dev, 0x81, 0x47); /* 0x47; */
+ reg_w_val(dev, 0x80, 0x40); /* 0x40; */
+ /* Pedro change */
+ /* Brightness change Brith+ decrease value */
+ /* Brigth- increase value */
+ /* original value = 0x70; */
+ reg_w_val(dev, 0x81, 0x30); /* 0x20; - set brightness */
+ reg_w_val(dev, 0x80, 0x20); /* 0x20; */
+}
+
+static void setcolors(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+ __u8 I2cc[] = { 0x05, 0x02, 0x02, 0x05, 0x0d };
+ __u8 i2cflags = 0x01;
+ /* __u8 green = 0; */
+ __u8 colors = sd->colors;
+
+ I2cc[3] = colors; /* red */
+ I2cc[0] = 15 - colors; /* blue */
+ /* green = 15 - ((((7*I2cc[0]) >> 2 ) + I2cc[3]) >> 1); */
+ /* I2cc[1] = I2cc[2] = green; */
+ if (sd->sensor == SENSOR_PAS106) {
+ Et_i2cwrite(dev, PAS106_REG13, &i2cflags, 1, 3);
+ Et_i2cwrite(dev, PAS106_REG9, I2cc, sizeof I2cc, 1);
+ }
+/* PDEBUG(D_CONF , "Etoms red %d blue %d green %d",
+ I2cc[3], I2cc[0], green); */
+}
+
+static void getcolors(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+/* __u8 valblue; */
+ __u8 valred;
+
+ if (sd->sensor == SENSOR_PAS106) {
+/* Et_i2cread(gspca_dev->dev, PAS106_REG9, &valblue, 1, 1); */
+ Et_i2cread(gspca_dev->dev, PAS106_REG9 + 3, &valred, 1, 1);
+ sd->colors = valred & 0x0f;
+ }
+}
+
+static void Et_init1(struct gspca_dev *gspca_dev)
+{
+ struct usb_device *dev = gspca_dev->dev;
+ __u8 value;
+ __u8 received;
+/* __u8 I2c0 [] = {0x0a, 0x12, 0x05, 0x22, 0xac, 0x00, 0x01, 0x00}; */
+ __u8 I2c0[] = { 0x0a, 0x12, 0x05, 0x6d, 0xcd, 0x00, 0x01, 0x00 };
+ /* try 1/120 0x6d 0xcd 0x40 */
+/* __u8 I2c0 [] = {0x0a, 0x12, 0x05, 0xfe, 0xfe, 0xc0, 0x01, 0x00};
+ * 1/60000 hmm ?? */
+
+ PDEBUG(D_STREAM, "Open Init1 ET");
+ reg_w_val(dev, ET_GPIO_DIR_CTRL, 7);
+ reg_r(dev, ET_GPIO_IN, &received, 1);
+ reg_w_val(dev, ET_RESET_ALL, 1);
+ reg_w_val(dev, ET_RESET_ALL, 0);
+ reg_w_val(dev, ET_ClCK, 0x10);
+ reg_w_val(dev, ET_CTRL, 0x19);
+ /* compression et subsampling */
+ if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv)
+ value = ET_COMP_VAL1;
+ else
+ value = ET_COMP_VAL0;
+ PDEBUG(D_STREAM, "Open mode %d Compression %d",
+ gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv,
+ value);
+ reg_w_val(dev, ET_COMP, value);
+ reg_w_val(dev, ET_MAXQt, 0x1d);
+ reg_w_val(dev, ET_MINQt, 0x02);
+ /* undocumented registers */
+ reg_w_val(dev, ET_REG1d, 0xff);
+ reg_w_val(dev, ET_REG1e, 0xff);
+ reg_w_val(dev, ET_REG1f, 0xff);
+ reg_w_val(dev, ET_REG20, 0x35);
+ reg_w_val(dev, ET_REG21, 0x01);
+ reg_w_val(dev, ET_REG22, 0x00);
+ reg_w_val(dev, ET_REG23, 0xf7);
+ reg_w_val(dev, ET_REG24, 0xff);
+ reg_w_val(dev, ET_REG25, 0x07);
+ /* colors setting */
+ reg_w_val(dev, ET_G_RED, 0x80);
+ reg_w_val(dev, ET_G_GREEN1, 0x80);
+ reg_w_val(dev, ET_G_BLUE, 0x80);
+ reg_w_val(dev, ET_G_GREEN2, 0x80);
+ reg_w_val(dev, ET_G_GR_H, 0x00);
+ reg_w_val(dev, ET_G_GB_H, 0x00);
+ /* Window control registers */
+ reg_w_val(dev, ET_SYNCHRO, 0xf0);
+ reg_w_val(dev, ET_STARTX, 0x56); /* 0x56 */
+ reg_w_val(dev, ET_STARTY, 0x05); /* 0x04 */
+ reg_w_val(dev, ET_WIDTH_LOW, 0x60);
+ reg_w_val(dev, ET_HEIGTH_LOW, 0x20);
+ reg_w_val(dev, ET_W_H_HEIGTH, 0x50);
+ reg_w_val(dev, ET_REG6e, 0x86);
+ reg_w_val(dev, ET_REG6f, 0x01);
+ reg_w_val(dev, ET_REG70, 0x86);
+ reg_w_val(dev, ET_REG71, 0x14);
+ reg_w_val(dev, ET_REG72, 0x00);
+ /* Clock Pattern registers */
+ reg_w_val(dev, ET_REG73, 0x00);
+ reg_w_val(dev, ET_REG74, 0x00);
+ reg_w_val(dev, ET_REG75, 0x0a);
+ reg_w_val(dev, ET_I2C_CLK, 0x04);
+ reg_w_val(dev, ET_PXL_CLK, 0x01);
+ /* set the sensor */
+ if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
+ I2c0[0] = 0x06;
+ Et_i2cwrite(dev, PAS106_REG2, I2c0, sizeof I2c0, 1);
+ Et_i2cwrite(dev, PAS106_REG9, I2c2, sizeof I2c2, 1);
+ value = 0x06;
+ Et_i2cwrite(dev, PAS106_REG2, &value, 1, 1);
+ Et_i2cwrite(dev, PAS106_REG3, I2c3, sizeof I2c3, 1);
+ /* value = 0x1f; */
+ value = 0x04;
+ Et_i2cwrite(dev, PAS106_REG0e, &value, 1, 1);
+ } else {
+ I2c0[0] = 0x0a;
+
+ Et_i2cwrite(dev, PAS106_REG2, I2c0, sizeof I2c0, 1);
+ Et_i2cwrite(dev, PAS106_REG9, I2c2, sizeof I2c2, 1);
+ value = 0x0a;
+
+ Et_i2cwrite(dev, PAS106_REG2, &value, 1, 1);
+ Et_i2cwrite(dev, PAS106_REG3, I2c3, sizeof I2c3, 1);
+ value = 0x04;
+ /* value = 0x10; */
+ Et_i2cwrite(dev, PAS106_REG0e, &value, 1, 1);
+ /* bit 2 enable bit 1:2 select 0 1 2 3
+ value = 0x07; * curve 0 *
+ Et_i2cwrite(dev,PAS106_REG0f,&value,1,1);
+ */
+ }
+
+/* value = 0x01; */
+/* value = 0x22; */
+/* Et_i2cwrite(dev, PAS106_REG5, &value, 1, 1); */
+ /* magnetude and sign bit for DAC */
+ Et_i2cwrite(dev, PAS106_REG7, I2c4, sizeof I2c4, 1);
+ /* now set by fifo the whole colors setting */
+ reg_w(dev, ET_G_RED, GainRGBG, 6);
+ getcolors(gspca_dev);
+ setcolors(gspca_dev);
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+ const struct usb_device_id *id)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct cam *cam;
+ __u16 vendor;
+ __u16 product;
+
+ vendor = id->idVendor;
+ product = id->idProduct;
+/* switch (vendor) { */
+/* case 0x102c: * Etoms */
+ switch (product) {
+ case 0x6151:
+ sd->sensor = SENSOR_PAS106; /* Etoms61x151 */
+ break;
+ case 0x6251:
+ sd->sensor = SENSOR_TAS5130CXX; /* Etoms61x251 */
+ break;
+/* } */
+/* break; */
+ }
+ cam = &gspca_dev->cam;
+ cam->dev_name = (char *) id->driver_info;
+ cam->epaddr = 1;
+ if (sd->sensor == SENSOR_PAS106) {
+ cam->cam_mode = sif_mode;
+ cam->nmodes = sizeof sif_mode / sizeof sif_mode[0];
+ } else {
+ cam->cam_mode = vga_mode;
+ cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+ }
+ sd->brightness = BRIGHTNESS_DEF;
+ sd->contrast = CONTRAST_DEF;
+ sd->colors = COLOR_DEF;
+ sd->autogain = AUTOGAIN_DEF;
+ return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+
+ if (sd->sensor == SENSOR_PAS106)
+ Et_init1(gspca_dev);
+ else
+ Et_init2(gspca_dev);
+ reg_w_val(dev, ET_RESET_ALL, 0x08);
+ et_video(dev, 0); /* video off */
+ return 0;
+}
+
+/* -- start the camera -- */
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+
+ if (sd->sensor == SENSOR_PAS106)
+ Et_init1(gspca_dev);
+ else
+ Et_init2(gspca_dev);
+
+ reg_w_val(dev, ET_RESET_ALL, 0x08);
+ et_video(dev, 1); /* video on */
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+ et_video(gspca_dev->dev, 0); /* video off */
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int i;
+ __u8 brightness = sd->brightness;
+
+ for (i = 0; i < 4; i++)
+ reg_w_val(gspca_dev->dev, (ET_O_RED + i), brightness);
+}
+
+static void getbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int i;
+ int brightness = 0;
+ __u8 value;
+
+ for (i = 0; i < 4; i++) {
+ reg_r(gspca_dev->dev, (ET_O_RED + i), &value, 1);
+ brightness += value;
+ }
+ sd->brightness = brightness >> 3;
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ __u8 RGBG[] = { 0x80, 0x80, 0x80, 0x80, 0x00, 0x00 };
+ __u8 contrast = sd->contrast;
+
+ memset(RGBG, contrast, sizeof RGBG - 2);
+ reg_w(gspca_dev->dev, ET_G_RED, RGBG, 6);
+}
+
+static void getcontrast(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int i;
+ int contrast = 0;
+ __u8 value = 0;
+
+ for (i = 0; i < 4; i++) {
+ reg_r(gspca_dev->dev, (ET_G_RED + i), &value, 1);
+ contrast += value;
+ }
+ sd->contrast = contrast >> 2;
+}
+
+static __u8 Et_getgainG(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ __u8 value = 0;
+
+ if (sd->sensor == SENSOR_PAS106) {
+ Et_i2cread(gspca_dev->dev, PAS106_REG0e, &value, 1, 1);
+ PDEBUG(D_CONF, "Etoms gain G %d", value);
+ return value;
+ }
+ return 0x1f;
+}
+
+static void Et_setgainG(struct gspca_dev *gspca_dev, __u8 gain)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+ __u8 i2cflags = 0x01;
+
+ if (sd->sensor == SENSOR_PAS106) {
+ Et_i2cwrite(dev, PAS106_REG13, &i2cflags, 1, 3);
+ Et_i2cwrite(dev, PAS106_REG0e, &gain, 1, 1);
+#if 0
+ Et_i2cwrite(dev, 0x09, &gain, 1, 1);
+ Et_i2cwrite(dev, 0x0a, &gain, 1, 1);
+ Et_i2cwrite(dev, 0x0b, &gain, 1, 1);
+ Et_i2cwrite(dev, 0x0c, &gain, 1, 1);
+#endif
+ }
+}
+
+#define BLIMIT(bright) \
+ (__u8)((bright > 0x1f)?0x1f:((bright < 4)?3:bright))
+#define LIMIT(color) \
+ (unsigned char)((color > 0xff)?0xff:((color < 0)?0:color))
+
+static void setautogain(struct gspca_dev *gspca_dev)
+{
+ struct usb_device *dev = gspca_dev->dev;
+ __u8 GRBG[] = { 0, 0, 0, 0 };
+ __u8 luma = 0;
+ __u8 luma_mean = 128;
+ __u8 luma_delta = 20;
+ __u8 spring = 4;
+ int Gbright = 0;
+ __u8 r, g, b;
+
+ Gbright = Et_getgainG(gspca_dev);
+ reg_r(dev, ET_LUMA_CENTER, GRBG, 4);
+ g = (GRBG[0] + GRBG[3]) >> 1;
+ r = GRBG[1];
+ b = GRBG[2];
+ r = ((r << 8) - (r << 4) - (r << 3)) >> 10;
+ b = ((b << 7) >> 10);
+ g = ((g << 9) + (g << 7) + (g << 5)) >> 10;
+ luma = LIMIT(r + g + b);
+ PDEBUG(D_FRAM, "Etoms luma G %d", luma);
+ if (luma < luma_mean - luma_delta || luma > luma_mean + luma_delta) {
+ Gbright += (luma_mean - luma) >> spring;
+ Gbright = BLIMIT(Gbright);
+ PDEBUG(D_FRAM, "Etoms Gbright %d", Gbright);
+ Et_setgainG(gspca_dev, (__u8) Gbright);
+ }
+}
+
+#undef BLIMIT
+#undef LIMIT
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ struct gspca_frame *frame, /* target */
+ __u8 *data, /* isoc packet */
+ int len) /* iso packet length */
+{
+ struct sd *sd;
+ int seqframe;
+
+ seqframe = data[0] & 0x3f;
+ len = (int) (((data[0] & 0xc0) << 2) | data[1]);
+ if (seqframe == 0x3f) {
+ PDEBUG(D_FRAM,
+ "header packet found datalength %d !!", len);
+ PDEBUG(D_FRAM, "G %d R %d G %d B %d",
+ data[2], data[3], data[4], data[5]);
+ data += 30;
+ /* don't change datalength as the chips provided it */
+ frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+ data, 0);
+ gspca_frame_add(gspca_dev, FIRST_PACKET, frame, data, len);
+ sd = (struct sd *) gspca_dev;
+ if (sd->ag_cnt >= 0) {
+ if (--sd->ag_cnt < 0) {
+ sd->ag_cnt = AG_CNT_START;
+ setautogain(gspca_dev);
+ }
+ }
+ return;
+ }
+ if (len) {
+ data += 8;
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+ } else { /* Drop Packet */
+ gspca_dev->last_packet_type = DISCARD_PACKET;
+ }
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->brightness = val;
+ if (gspca_dev->streaming)
+ setbrightness(gspca_dev);
+ return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ getbrightness(gspca_dev);
+ *val = sd->brightness;
+ return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->contrast = val;
+ if (gspca_dev->streaming)
+ setcontrast(gspca_dev);
+ return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ getcontrast(gspca_dev);
+ *val = sd->contrast;
+ return 0;
+}
+
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->colors = val;
+ if (gspca_dev->streaming)
+ setcolors(gspca_dev);
+ return 0;
+}
+
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ getcolors(gspca_dev);
+ *val = sd->colors;
+ return 0;
+}
+
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->autogain = val;
+ if (val)
+ sd->ag_cnt = AG_CNT_START;
+ else
+ sd->ag_cnt = -1;
+ return 0;
+}
+
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->autogain;
+ return 0;
+}
+
+/* sub-driver description */
+static struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .ctrls = sd_ctrls,
+ .nctrls = ARRAY_SIZE(sd_ctrls),
+ .config = sd_config,
+ .open = sd_open,
+ .start = sd_start,
+ .stopN = sd_stopN,
+ .stop0 = sd_stop0,
+ .close = sd_close,
+ .pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static __devinitdata struct usb_device_id device_table[] = {
+#ifndef CONFIG_USB_ET61X251
+ {USB_DEVICE(0x102c, 0x6151), DVNM("Qcam Sangha CIF")},
+#endif
+ {USB_DEVICE(0x102c, 0x6251), DVNM("Qcam xxxxxx VGA")},
+ {}
+};
+
+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,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+ if (usb_register(&sd_driver) < 0)
+ return -1;
+ PDEBUG(D_PROBE, "v%s registered", version);
+ return 0;
+}
+
+static void __exit sd_mod_exit(void)
+{
+ usb_deregister(&sd_driver);
+ PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/linux/drivers/media/video/gspca/gspca.c b/linux/drivers/media/video/gspca/gspca.c
new file mode 100644
index 000000000..55d4af21e
--- /dev/null
+++ b/linux/drivers/media/video/gspca/gspca.c
@@ -0,0 +1,1816 @@
+/*
+ * Main USB camera driver
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * 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.
+ */
+
+#define MODULE_NAME "gspca"
+
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/vmalloc.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/pagemap.h>
+#include <linux/io.h>
+#include <asm/page.h>
+#include <linux/uaccess.h>
+#include <linux/jiffies.h>
+
+#include "gspca.h"
+
+/* global values */
+#define DEF_NURBS 2 /* default number of URBs */
+
+MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>");
+MODULE_DESCRIPTION("GSPCA USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 6)
+static const char version[] = "2.1.6";
+
+static int video_nr = -1;
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+int gspca_debug = D_ERR | D_PROBE;
+EXPORT_SYMBOL(gspca_debug);
+
+static void PDEBUG_MODE(char *txt, __u32 pixfmt, int w, int h)
+{
+ if ((pixfmt >> 24) >= '0' && (pixfmt >> 24) <= 'z') {
+ PDEBUG(D_CONF|D_STREAM, "%s %c%c%c%c %dx%d",
+ txt,
+ pixfmt & 0xff,
+ (pixfmt >> 8) & 0xff,
+ (pixfmt >> 16) & 0xff,
+ pixfmt >> 24,
+ w, h);
+ } else {
+ PDEBUG(D_CONF|D_STREAM, "%s 0x%08x %dx%d",
+ txt,
+ pixfmt,
+ w, h);
+ }
+}
+#else
+#define PDEBUG_MODE(txt, pixfmt, w, h)
+#endif
+
+/* specific memory types - !! should different from V4L2_MEMORY_xxx */
+#define GSPCA_MEMORY_NO 0 /* V4L2_MEMORY_xxx starts from 1 */
+#define GSPCA_MEMORY_READ 7
+
+#define BUF_ALL_FLAGS (V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE)
+
+/*
+ * VMA operations.
+ */
+static void gspca_vm_open(struct vm_area_struct *vma)
+{
+ struct gspca_frame *frame = vma->vm_private_data;
+
+ frame->vma_use_count++;
+ frame->v4l2_buf.flags |= V4L2_BUF_FLAG_MAPPED;
+}
+
+static void gspca_vm_close(struct vm_area_struct *vma)
+{
+ struct gspca_frame *frame = vma->vm_private_data;
+
+ if (--frame->vma_use_count <= 0)
+ frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_MAPPED;
+}
+
+static struct vm_operations_struct gspca_vm_ops = {
+ .open = gspca_vm_open,
+ .close = gspca_vm_close,
+};
+
+/*
+ * fill a video frame from an URB and resubmit
+ */
+static void fill_frame(struct gspca_dev *gspca_dev,
+ struct urb *urb)
+{
+ struct gspca_frame *frame;
+ __u8 *data; /* address of data in the iso message */
+ int i, j, len, st;
+ cam_pkt_op pkt_scan;
+
+ if (urb->status != 0) {
+ PDEBUG(D_ERR|D_PACK, "urb status: %d", urb->status);
+ return; /* disconnection ? */
+ }
+ pkt_scan = gspca_dev->sd_desc->pkt_scan;
+ for (i = 0; i < urb->number_of_packets; i++) {
+
+ /* check the availability of the frame buffer */
+ j = gspca_dev->fr_i;
+ j = gspca_dev->fr_queue[j];
+ frame = &gspca_dev->frame[j];
+ if ((frame->v4l2_buf.flags & BUF_ALL_FLAGS)
+ != V4L2_BUF_FLAG_QUEUED) {
+ gspca_dev->last_packet_type = DISCARD_PACKET;
+ break;
+ }
+
+ /* check the packet status and length */
+ len = urb->iso_frame_desc[i].actual_length;
+ if (len == 0)
+ continue;
+ st = urb->iso_frame_desc[i].status;
+ if (st) {
+ PDEBUG(D_ERR,
+ "ISOC data error: [%d] len=%d, status=%d",
+ i, len, st);
+ gspca_dev->last_packet_type = DISCARD_PACKET;
+ continue;
+ }
+
+ /* let the packet be analyzed by the subdriver */
+ PDEBUG(D_PACK, "packet [%d] o:%d l:%d",
+ i, urb->iso_frame_desc[i].offset, len);
+ data = (__u8 *) urb->transfer_buffer
+ + urb->iso_frame_desc[i].offset;
+ pkt_scan(gspca_dev, frame, data, len);
+ }
+
+ /* resubmit the URB */
+ urb->status = 0;
+ st = usb_submit_urb(urb, GFP_ATOMIC);
+ if (st < 0)
+ PDEBUG(D_ERR|D_PACK, "usb_submit_urb() ret %d", st);
+}
+
+/*
+ * ISOC message interrupt from the USB device
+ *
+ * Analyse each packet and call the subdriver for copy to the frame buffer.
+ */
+static void isoc_irq(struct urb *urb
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
+ , struct pt_regs *regs
+#endif
+)
+{
+ struct gspca_dev *gspca_dev = (struct gspca_dev *) urb->context;
+
+ PDEBUG(D_PACK, "isoc irq mmap");
+ if (!gspca_dev->streaming)
+ return;
+ fill_frame(gspca_dev, urb);
+}
+
+/*
+ * add data to the current frame
+ *
+ * This function is called by the subdrivers at interrupt level.
+ *
+ * To build a frame, these ones must add
+ * - one FIRST_PACKET
+ * - 0 or many INTER_PACKETs
+ * - one LAST_PACKET
+ * DISCARD_PACKET invalidates the whole frame.
+ * On LAST_PACKET, a new frame is returned.
+ */
+struct gspca_frame *gspca_frame_add(struct gspca_dev *gspca_dev,
+ int packet_type,
+ struct gspca_frame *frame,
+ const __u8 *data,
+ int len)
+{
+ int i, j;
+
+ PDEBUG(D_PACK, "add t:%d l:%d", packet_type, len);
+
+ /* when start of a new frame, if the current frame buffer
+ * is not queued, discard the whole frame */
+ if (packet_type == FIRST_PACKET) {
+ if ((frame->v4l2_buf.flags & BUF_ALL_FLAGS)
+ != V4L2_BUF_FLAG_QUEUED) {
+ gspca_dev->last_packet_type = DISCARD_PACKET;
+ return frame;
+ }
+ frame->data_end = frame->data;
+ jiffies_to_timeval(get_jiffies_64(),
+ &frame->v4l2_buf.timestamp);
+ frame->v4l2_buf.sequence = ++gspca_dev->sequence;
+ } else if (gspca_dev->last_packet_type == DISCARD_PACKET) {
+ return frame;
+ }
+
+ /* append the packet to the frame buffer */
+ if (len > 0) {
+ if (frame->data_end - frame->data + len
+ > frame->v4l2_buf.length) {
+ PDEBUG(D_ERR|D_PACK, "frame overflow %d > %d",
+ frame->data_end - frame->data + len,
+ frame->v4l2_buf.length);
+ packet_type = DISCARD_PACKET;
+ } else {
+ memcpy(frame->data_end, data, len);
+ frame->data_end += len;
+ }
+ }
+ gspca_dev->last_packet_type = packet_type;
+
+ /* if last packet, wake the application and advance in the queue */
+ if (packet_type == LAST_PACKET) {
+ frame->v4l2_buf.bytesused = frame->data_end - frame->data;
+ frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_QUEUED;
+ frame->v4l2_buf.flags |= V4L2_BUF_FLAG_DONE;
+ atomic_inc(&gspca_dev->nevent);
+ wake_up_interruptible(&gspca_dev->wq); /* event = new frame */
+ i = (gspca_dev->fr_i + 1) % gspca_dev->nframes;
+ gspca_dev->fr_i = i;
+ PDEBUG(D_FRAM, "frame complete len:%d q:%d i:%d o:%d",
+ frame->v4l2_buf.bytesused,
+ gspca_dev->fr_q,
+ i,
+ gspca_dev->fr_o);
+ j = gspca_dev->fr_queue[i];
+ frame = &gspca_dev->frame[j];
+ }
+ return frame;
+}
+EXPORT_SYMBOL(gspca_frame_add);
+
+static int gspca_is_compressed(__u32 format)
+{
+ switch (format) {
+ case V4L2_PIX_FMT_MJPEG:
+ case V4L2_PIX_FMT_JPEG:
+ case V4L2_PIX_FMT_SPCA561:
+ case V4L2_PIX_FMT_PAC207:
+ return 1;
+ }
+ return 0;
+}
+
+static void *rvmalloc(unsigned long size)
+{
+ void *mem;
+ unsigned long adr;
+
+/* size = PAGE_ALIGN(size); (already done) */
+ mem = vmalloc_32(size);
+ if (mem != NULL) {
+ adr = (unsigned long) mem;
+ while ((long) size > 0) {
+ SetPageReserved(vmalloc_to_page((void *) adr));
+ adr += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
+ }
+ return mem;
+}
+
+static void rvfree(void *mem, long size)
+{
+ unsigned long adr;
+
+ adr = (unsigned long) mem;
+ while (size > 0) {
+ ClearPageReserved(vmalloc_to_page((void *) adr));
+ adr += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
+ vfree(mem);
+}
+
+static int frame_alloc(struct gspca_dev *gspca_dev,
+ unsigned int count)
+{
+ struct gspca_frame *frame;
+ unsigned int frsz;
+ int i;
+
+ i = gspca_dev->curr_mode;
+ frsz = gspca_dev->cam.cam_mode[i].sizeimage;
+ PDEBUG(D_STREAM, "frame alloc frsz: %d", frsz);
+ frsz = PAGE_ALIGN(frsz);
+ gspca_dev->frsz = frsz;
+ if (count > GSPCA_MAX_FRAMES)
+ count = GSPCA_MAX_FRAMES;
+ gspca_dev->frbuf = rvmalloc(frsz * count);
+ if (!gspca_dev->frbuf) {
+ err("frame alloc failed");
+ return -ENOMEM;
+ }
+ gspca_dev->nframes = count;
+ for (i = 0; i < count; i++) {
+ frame = &gspca_dev->frame[i];
+ frame->v4l2_buf.index = i;
+ frame->v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ frame->v4l2_buf.flags = 0;
+ frame->v4l2_buf.field = V4L2_FIELD_NONE;
+ frame->v4l2_buf.length = frsz;
+ frame->v4l2_buf.memory = gspca_dev->memory;
+ frame->v4l2_buf.sequence = 0;
+ frame->data = frame->data_end =
+ gspca_dev->frbuf + i * frsz;
+ frame->v4l2_buf.m.offset = i * frsz;
+ }
+ gspca_dev->fr_i = gspca_dev->fr_o = gspca_dev->fr_q = 0;
+ gspca_dev->last_packet_type = DISCARD_PACKET;
+ gspca_dev->sequence = 0;
+ atomic_set(&gspca_dev->nevent, 0);
+ return 0;
+}
+
+static void frame_free(struct gspca_dev *gspca_dev)
+{
+ int i;
+
+ PDEBUG(D_STREAM, "frame free");
+ if (gspca_dev->frbuf != NULL) {
+ rvfree(gspca_dev->frbuf,
+ gspca_dev->nframes * gspca_dev->frsz);
+ gspca_dev->frbuf = NULL;
+ for (i = 0; i < gspca_dev->nframes; i++)
+ gspca_dev->frame[i].data = NULL;
+ }
+ gspca_dev->nframes = 0;
+}
+
+static void destroy_urbs(struct gspca_dev *gspca_dev)
+{
+ struct urb *urb;
+ unsigned int i;
+
+ PDEBUG(D_STREAM, "kill transfer");
+ for (i = 0; i < MAX_NURBS; ++i) {
+ urb = gspca_dev->urb[i];
+ if (urb == NULL)
+ break;
+
+ gspca_dev->urb[i] = NULL;
+ usb_kill_urb(urb);
+ if (urb->transfer_buffer != NULL)
+ usb_buffer_free(gspca_dev->dev,
+ urb->transfer_buffer_length,
+ urb->transfer_buffer,
+ urb->transfer_dma);
+ usb_free_urb(urb);
+ }
+}
+
+/*
+ * search an input isochronous endpoint in an alternate setting
+ */
+static struct usb_host_endpoint *alt_isoc(struct usb_host_interface *alt,
+ __u8 epaddr)
+{
+ struct usb_host_endpoint *ep;
+ int i, attr;
+
+ epaddr |= USB_DIR_IN;
+ for (i = 0; i < alt->desc.bNumEndpoints; i++) {
+ ep = &alt->endpoint[i];
+ if (ep->desc.bEndpointAddress == epaddr) {
+ attr = ep->desc.bmAttributes
+ & USB_ENDPOINT_XFERTYPE_MASK;
+ if (attr == USB_ENDPOINT_XFER_ISOC)
+ return ep;
+ break;
+ }
+ }
+ return NULL;
+}
+
+/*
+ * search an input isochronous endpoint
+ *
+ * The endpoint is defined by the subdriver.
+ * Use only the first isoc (some Zoran - 0x0572:0x0001 - have two such ep).
+ * This routine may be called many times when the bandwidth is too small
+ * (the bandwidth is checked on urb submit).
+ */
+struct usb_host_endpoint *get_isoc_ep(struct gspca_dev *gspca_dev)
+{
+ struct usb_interface *intf;
+ struct usb_host_endpoint *ep;
+ int i, ret;
+
+ intf = usb_ifnum_to_if(gspca_dev->dev, gspca_dev->iface);
+ ep = NULL;
+ i = gspca_dev->alt; /* previous alt setting */
+ while (--i > 0) { /* alt 0 is unusable */
+ ep = alt_isoc(&intf->altsetting[i], gspca_dev->cam.epaddr);
+ if (ep)
+ break;
+ }
+ if (ep == NULL) {
+ err("no ISOC endpoint found");
+ return NULL;
+ }
+ PDEBUG(D_STREAM, "use ISOC alt %d ep 0x%02x",
+ i, ep->desc.bEndpointAddress);
+ ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, i);
+ if (ret < 0) {
+ err("set interface err %d", ret);
+ return NULL;
+ }
+ gspca_dev->alt = i; /* memorize the current alt setting */
+ return ep;
+}
+
+/*
+ * create the isochronous URBs
+ */
+static int create_urbs(struct gspca_dev *gspca_dev,
+ struct usb_host_endpoint *ep)
+{
+ struct urb *urb;
+ int n, nurbs, i, psize, npkt, bsize;
+
+ /* calculate the packet size and the number of packets */
+ psize = le16_to_cpu(ep->desc.wMaxPacketSize);
+
+ /* See paragraph 5.9 / table 5-11 of the usb 2.0 spec. */
+ psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
+ npkt = ISO_MAX_SIZE / psize;
+ if (npkt > ISO_MAX_PKT)
+ npkt = ISO_MAX_PKT;
+ bsize = psize * npkt;
+ PDEBUG(D_STREAM,
+ "isoc %d pkts size %d (bsize:%d)", npkt, psize, bsize);
+ nurbs = DEF_NURBS;
+ gspca_dev->nurbs = nurbs;
+ for (n = 0; n < nurbs; n++) {
+ urb = usb_alloc_urb(npkt, GFP_KERNEL);
+ if (!urb) {
+ err("usb_alloc_urb failed");
+ return -ENOMEM;
+ }
+ urb->transfer_buffer = usb_buffer_alloc(gspca_dev->dev,
+ bsize,
+ GFP_KERNEL,
+ &urb->transfer_dma);
+
+ if (urb->transfer_buffer == NULL) {
+ usb_free_urb(urb);
+ destroy_urbs(gspca_dev);
+ err("usb_buffer_urb failed");
+ return -ENOMEM;
+ }
+ gspca_dev->urb[n] = urb;
+ urb->dev = gspca_dev->dev;
+ urb->context = gspca_dev;
+ urb->pipe = usb_rcvisocpipe(gspca_dev->dev,
+ ep->desc.bEndpointAddress);
+ urb->transfer_flags = URB_ISO_ASAP
+ | URB_NO_TRANSFER_DMA_MAP;
+ urb->interval = ep->desc.bInterval;
+ urb->complete = isoc_irq;
+ urb->number_of_packets = npkt;
+ urb->transfer_buffer_length = bsize;
+ for (i = 0; i < npkt; i++) {
+ urb->iso_frame_desc[i].length = psize;
+ urb->iso_frame_desc[i].offset = psize * i;
+ }
+ }
+ return 0;
+}
+
+/*
+ * start the USB transfer
+ */
+static int gspca_init_transfer(struct gspca_dev *gspca_dev)
+{
+ struct usb_host_endpoint *ep;
+ int n, ret;
+
+ if (mutex_lock_interruptible(&gspca_dev->usb_lock))
+ return -ERESTARTSYS;
+
+ /* set the higher alternate setting and
+ * loop until urb submit succeeds */
+ gspca_dev->alt = gspca_dev->nbalt;
+ for (;;) {
+ PDEBUG(D_STREAM, "init transfer alt %d", gspca_dev->alt);
+ ep = get_isoc_ep(gspca_dev);
+ if (ep == NULL) {
+ ret = -EIO;
+ goto out;
+ }
+ ret = create_urbs(gspca_dev, ep);
+ if (ret < 0)
+ goto out;
+
+ /* start the cam */
+ gspca_dev->sd_desc->start(gspca_dev);
+ gspca_dev->streaming = 1;
+ atomic_set(&gspca_dev->nevent, 0);
+
+ /* submit the URBs */
+ for (n = 0; n < gspca_dev->nurbs; n++) {
+ ret = usb_submit_urb(gspca_dev->urb[n], GFP_KERNEL);
+ if (ret < 0) {
+ PDEBUG(D_ERR|D_STREAM,
+ "usb_submit_urb [%d] err %d", n, ret);
+ gspca_dev->streaming = 0;
+ destroy_urbs(gspca_dev);
+ if (ret == -ENOSPC)
+ break; /* try the previous alt */
+ goto out;
+ }
+ }
+ if (ret >= 0)
+ break;
+ }
+out:
+ mutex_unlock(&gspca_dev->usb_lock);
+ return ret;
+}
+
+static int gspca_set_alt0(struct gspca_dev *gspca_dev)
+{
+ int ret;
+
+ ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, 0);
+ if (ret < 0)
+ PDEBUG(D_ERR|D_STREAM, "set interface 0 err %d", ret);
+ return ret;
+}
+
+/* Note both the queue and the usb lock should be hold when calling this */
+static void gspca_stream_off(struct gspca_dev *gspca_dev)
+{
+ gspca_dev->streaming = 0;
+ atomic_set(&gspca_dev->nevent, 0);
+ if (gspca_dev->present) {
+ gspca_dev->sd_desc->stopN(gspca_dev);
+ destroy_urbs(gspca_dev);
+ gspca_set_alt0(gspca_dev);
+ gspca_dev->sd_desc->stop0(gspca_dev);
+ PDEBUG(D_STREAM, "stream off OK");
+ } else {
+ destroy_urbs(gspca_dev);
+ atomic_inc(&gspca_dev->nevent);
+ wake_up_interruptible(&gspca_dev->wq);
+ PDEBUG(D_ERR|D_STREAM, "stream off no device ??");
+ }
+}
+
+static void gspca_set_default_mode(struct gspca_dev *gspca_dev)
+{
+ int i;
+
+ 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;
+}
+
+static int wxh_to_mode(struct gspca_dev *gspca_dev,
+ int width, int height)
+{
+ int i;
+
+ for (i = gspca_dev->cam.nmodes; --i > 0; ) {
+ if (width >= gspca_dev->cam.cam_mode[i].width
+ && height >= gspca_dev->cam.cam_mode[i].height)
+ break;
+ }
+ return i;
+}
+
+/*
+ * search a mode with the right pixel format
+ */
+static int gspca_get_mode(struct gspca_dev *gspca_dev,
+ int mode,
+ int pixfmt)
+{
+ int modeU, modeD;
+
+ modeU = modeD = mode;
+ while ((modeU < gspca_dev->cam.nmodes) || modeD >= 0) {
+ if (--modeD >= 0) {
+ if (gspca_dev->cam.cam_mode[modeD].pixelformat
+ == pixfmt)
+ return modeD;
+ }
+ if (++modeU < gspca_dev->cam.nmodes) {
+ if (gspca_dev->cam.cam_mode[modeU].pixelformat
+ == pixfmt)
+ return modeU;
+ }
+ }
+ return -EINVAL;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *fmtdesc)
+{
+ struct gspca_dev *gspca_dev = priv;
+ int i, j, index;
+ __u32 fmt_tb[8];
+
+ /* give an index to each format */
+ index = 0;
+ j = 0;
+ for (i = gspca_dev->cam.nmodes; --i >= 0; ) {
+ fmt_tb[index] = gspca_dev->cam.cam_mode[i].pixelformat;
+ j = 0;
+ for (;;) {
+ if (fmt_tb[j] == fmt_tb[index])
+ break;
+ j++;
+ }
+ if (j == index) {
+ if (fmtdesc->index == index)
+ break; /* new format */
+ index++;
+ if (index >= sizeof fmt_tb / sizeof fmt_tb[0])
+ return -EINVAL;
+ }
+ }
+ if (i < 0)
+ return -EINVAL; /* no more format */
+
+ fmtdesc->pixelformat = fmt_tb[index];
+ if (gspca_is_compressed(fmt_tb[index]))
+ fmtdesc->flags = V4L2_FMT_FLAG_COMPRESSED;
+ fmtdesc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ fmtdesc->description[0] = fmtdesc->pixelformat & 0xff;
+ fmtdesc->description[1] = (fmtdesc->pixelformat >> 8) & 0xff;
+ fmtdesc->description[2] = (fmtdesc->pixelformat >> 16) & 0xff;
+ fmtdesc->description[3] = fmtdesc->pixelformat >> 24;
+ fmtdesc->description[4] = '\0';
+ return 0;
+}
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *fmt)
+{
+ struct gspca_dev *gspca_dev = priv;
+ int mode;
+
+ if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ mode = gspca_dev->curr_mode;
+ memcpy(&fmt->fmt.pix, &gspca_dev->cam.cam_mode[mode],
+ sizeof fmt->fmt.pix);
+ return 0;
+}
+
+static int try_fmt_vid_cap(struct gspca_dev *gspca_dev,
+ struct v4l2_format *fmt)
+{
+ int w, h, mode, mode2;
+
+ if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ w = fmt->fmt.pix.width;
+ h = fmt->fmt.pix.height;
+
+ /* (luvcview problem) */
+ if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG)
+ fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_JPEG;
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ if (gspca_debug & D_CONF)
+ PDEBUG_MODE("try fmt cap", fmt->fmt.pix.pixelformat, w, h);
+#endif
+ /* search the closest mode for width and height */
+ mode = wxh_to_mode(gspca_dev, w, h);
+
+ /* OK if right palette */
+ if (gspca_dev->cam.cam_mode[mode].pixelformat
+ != fmt->fmt.pix.pixelformat) {
+
+ /* else, search the closest mode with the same pixel format */
+ mode2 = gspca_get_mode(gspca_dev, mode,
+ fmt->fmt.pix.pixelformat);
+ if (mode2 >= 0)
+ mode = mode2;
+/* else
+ ; * no chance, return this mode */
+ }
+ memcpy(&fmt->fmt.pix, &gspca_dev->cam.cam_mode[mode],
+ sizeof fmt->fmt.pix);
+ return mode; /* used when s_fmt */
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file,
+ void *priv,
+ struct v4l2_format *fmt)
+{
+ struct gspca_dev *gspca_dev = priv;
+ int ret;
+
+ ret = try_fmt_vid_cap(gspca_dev, fmt);
+ if (ret < 0)
+ return ret;
+ return 0;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *fmt)
+{
+ struct gspca_dev *gspca_dev = priv;
+ int ret;
+
+ if (mutex_lock_interruptible(&gspca_dev->queue_lock))
+ return -ERESTARTSYS;
+
+ ret = try_fmt_vid_cap(gspca_dev, fmt);
+ if (ret < 0)
+ goto out;
+
+ if (gspca_dev->nframes != 0
+ && fmt->fmt.pix.sizeimage > gspca_dev->frsz) {
+ ret = -EINVAL;
+ 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;
+
+ ret = 0;
+out:
+ mutex_unlock(&gspca_dev->queue_lock);
+ return ret;
+}
+
+static int dev_open(struct inode *inode, struct file *file)
+{
+ struct gspca_dev *gspca_dev;
+ int ret;
+
+ PDEBUG(D_STREAM, "%s open", current->comm);
+ gspca_dev = (struct gspca_dev *) video_devdata(file);
+ if (mutex_lock_interruptible(&gspca_dev->queue_lock))
+ return -ERESTARTSYS;
+ if (!gspca_dev->present) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ /* if not done yet, initialize the sensor */
+ if (gspca_dev->users == 0) {
+ if (mutex_lock_interruptible(&gspca_dev->usb_lock)) {
+ ret = -ERESTARTSYS;
+ goto out;
+ }
+ ret = gspca_dev->sd_desc->open(gspca_dev);
+ mutex_unlock(&gspca_dev->usb_lock);
+ if (ret != 0) {
+ PDEBUG(D_ERR|D_CONF, "init device failed %d", ret);
+ goto out;
+ }
+ } else if (gspca_dev->users > 4) { /* (arbitrary value) */
+ ret = -EBUSY;
+ goto out;
+ }
+ gspca_dev->users++;
+ file->private_data = gspca_dev;
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ /* activate the v4l2 debug */
+ if (gspca_debug & D_V4L2)
+ gspca_dev->vdev.debug |= 3;
+ else
+ gspca_dev->vdev.debug &= ~3;
+#endif
+out:
+ mutex_unlock(&gspca_dev->queue_lock);
+ if (ret != 0)
+ PDEBUG(D_ERR|D_STREAM, "open failed err %d", ret);
+ else
+ PDEBUG(D_STREAM, "open done");
+ return ret;
+}
+
+static int dev_close(struct inode *inode, struct file *file)
+{
+ struct gspca_dev *gspca_dev = file->private_data;
+
+ PDEBUG(D_STREAM, "%s close", current->comm);
+ if (mutex_lock_interruptible(&gspca_dev->queue_lock))
+ return -ERESTARTSYS;
+ gspca_dev->users--;
+
+ /* if the file did capture, free the streaming resources */
+ if (gspca_dev->capt_file == file) {
+ mutex_lock(&gspca_dev->usb_lock);
+ if (gspca_dev->streaming)
+ gspca_stream_off(gspca_dev);
+ gspca_dev->sd_desc->close(gspca_dev);
+ mutex_unlock(&gspca_dev->usb_lock);
+ frame_free(gspca_dev);
+ gspca_dev->capt_file = NULL;
+ gspca_dev->memory = GSPCA_MEMORY_NO;
+ }
+ file->private_data = NULL;
+ mutex_unlock(&gspca_dev->queue_lock);
+ PDEBUG(D_STREAM, "close done");
+ return 0;
+}
+
+static int vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct gspca_dev *gspca_dev = priv;
+
+ memset(cap, 0, sizeof *cap);
+ strncpy(cap->driver, gspca_dev->sd_desc->name, sizeof cap->driver);
+ strncpy(cap->card, gspca_dev->cam.dev_name, sizeof cap->card);
+ strncpy(cap->bus_info, gspca_dev->dev->bus->bus_name,
+ sizeof cap->bus_info);
+ cap->version = DRIVER_VERSION_NUMBER;
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE
+ | V4L2_CAP_STREAMING
+ | V4L2_CAP_READWRITE;
+ return 0;
+}
+
+/* the use of V4L2_CTRL_FLAG_NEXT_CTRL asks for the controls to be sorted */
+static int vidioc_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *q_ctrl)
+{
+ struct gspca_dev *gspca_dev = priv;
+ int i;
+ u32 id;
+
+ id = q_ctrl->id;
+ if (id & V4L2_CTRL_FLAG_NEXT_CTRL) {
+ id &= V4L2_CTRL_ID_MASK;
+ id++;
+ for (i = 0; i < gspca_dev->sd_desc->nctrls; i++) {
+ if (id >= gspca_dev->sd_desc->ctrls[i].qctrl.id) {
+ memcpy(q_ctrl,
+ &gspca_dev->sd_desc->ctrls[i].qctrl,
+ sizeof *q_ctrl);
+ return 0;
+ }
+ }
+ return -EINVAL;
+ }
+ for (i = 0; i < gspca_dev->sd_desc->nctrls; i++) {
+ if (id == gspca_dev->sd_desc->ctrls[i].qctrl.id) {
+ memcpy(q_ctrl,
+ &gspca_dev->sd_desc->ctrls[i].qctrl,
+ sizeof *q_ctrl);
+ return 0;
+ }
+ }
+ if (id >= V4L2_CID_BASE
+ && id <= V4L2_CID_LASTP1) {
+ q_ctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static int vidioc_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct gspca_dev *gspca_dev = priv;
+ const struct ctrl *ctrls;
+ int i, ret;
+
+ for (i = 0, ctrls = gspca_dev->sd_desc->ctrls;
+ i < gspca_dev->sd_desc->nctrls;
+ i++, ctrls++) {
+ if (ctrl->id != ctrls->qctrl.id)
+ continue;
+ if (ctrl->value < ctrls->qctrl.minimum
+ && ctrl->value > ctrls->qctrl.maximum)
+ return -ERANGE;
+ PDEBUG(D_CONF, "set ctrl [%08x] = %d", ctrl->id, ctrl->value);
+ if (mutex_lock_interruptible(&gspca_dev->usb_lock))
+ return -ERESTARTSYS;
+ ret = ctrls->set(gspca_dev, ctrl->value);
+ mutex_unlock(&gspca_dev->usb_lock);
+ return ret;
+ }
+ return -EINVAL;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct gspca_dev *gspca_dev = priv;
+
+ const struct ctrl *ctrls;
+ int i, ret;
+
+ for (i = 0, ctrls = gspca_dev->sd_desc->ctrls;
+ i < gspca_dev->sd_desc->nctrls;
+ i++, ctrls++) {
+ if (ctrl->id != ctrls->qctrl.id)
+ continue;
+ if (mutex_lock_interruptible(&gspca_dev->usb_lock))
+ return -ERESTARTSYS;
+ ret = ctrls->get(gspca_dev, &ctrl->value);
+ mutex_unlock(&gspca_dev->usb_lock);
+ return ret;
+ }
+ return -EINVAL;
+}
+
+static int vidioc_querymenu(struct file *file, void *priv,
+ struct v4l2_querymenu *qmenu)
+{
+ struct gspca_dev *gspca_dev = priv;
+
+ if (!gspca_dev->sd_desc->querymenu)
+ return -EINVAL;
+ return gspca_dev->sd_desc->querymenu(gspca_dev, qmenu);
+}
+
+static int vidioc_enum_input(struct file *file, void *priv,
+ struct v4l2_input *input)
+{
+ struct gspca_dev *gspca_dev = priv;
+
+ if (input->index != 0)
+ return -EINVAL;
+ memset(input, 0, sizeof *input);
+ input->type = V4L2_INPUT_TYPE_CAMERA;
+ strncpy(input->name, gspca_dev->sd_desc->name,
+ sizeof input->name);
+ return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+{
+ *i = 0;
+ return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
+{
+ if (i > 0)
+ return -EINVAL;
+ return (0);
+}
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *rb)
+{
+ struct gspca_dev *gspca_dev = priv;
+ int i, ret = 0;
+
+ if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ switch (rb->memory) {
+ case GSPCA_MEMORY_READ:
+ case V4L2_MEMORY_MMAP:
+ case V4L2_MEMORY_USERPTR:
+ break;
+ default:
+ return -EINVAL;
+ }
+ if (mutex_lock_interruptible(&gspca_dev->queue_lock))
+ return -ERESTARTSYS;
+
+ /* only one file may do capture */
+ if ((gspca_dev->capt_file != NULL && gspca_dev->capt_file != file)
+ || gspca_dev->streaming) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ if (rb->count == 0) { /* unrequest */
+ for (i = 0; i < gspca_dev->nframes; i++) {
+ if (gspca_dev->frame[i].vma_use_count) {
+ ret = -EBUSY;
+ goto out;
+ }
+ }
+ frame_free(gspca_dev);
+ gspca_dev->capt_file = NULL;
+ } else {
+ if (gspca_dev->nframes != 0) {
+ ret = -EBUSY;
+ goto out;
+ }
+ gspca_dev->memory = rb->memory;
+ ret = frame_alloc(gspca_dev, rb->count);
+ if (ret == 0) {
+ rb->count = gspca_dev->nframes;
+ gspca_dev->capt_file = file;
+ }
+ }
+out:
+ mutex_unlock(&gspca_dev->queue_lock);
+ PDEBUG(D_STREAM, "reqbufs st:%d c:%d", ret, rb->count);
+ return ret;
+}
+
+static int vidioc_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *v4l2_buf)
+{
+ struct gspca_dev *gspca_dev = priv;
+ struct gspca_frame *frame;
+
+ if (v4l2_buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE
+ || v4l2_buf->index < 0
+ || v4l2_buf->index >= gspca_dev->nframes)
+ return -EINVAL;
+
+ frame = &gspca_dev->frame[v4l2_buf->index];
+ memcpy(v4l2_buf, &frame->v4l2_buf, sizeof *v4l2_buf);
+ return 0;
+}
+
+static int vidioc_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type buf_type)
+{
+ struct gspca_dev *gspca_dev = priv;
+ int ret;
+
+ if (buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ if (mutex_lock_interruptible(&gspca_dev->queue_lock))
+ return -ERESTARTSYS;
+ if (!gspca_dev->present) {
+ ret = -ENODEV;
+ goto out;
+ }
+ if (gspca_dev->nframes == 0) {
+ ret = -EINVAL;
+ goto out;
+ }
+ if (gspca_dev->capt_file != file) {
+ ret = -EINVAL;
+ goto out;
+ }
+ if (!gspca_dev->streaming) {
+ ret = gspca_init_transfer(gspca_dev);
+ if (ret < 0)
+ goto out;
+ }
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ if (gspca_debug & D_STREAM) {
+ PDEBUG_MODE("stream on OK",
+ gspca_dev->pixfmt,
+ gspca_dev->width,
+ gspca_dev->height);
+ }
+#endif
+ ret = 0;
+out:
+ mutex_unlock(&gspca_dev->queue_lock);
+ return ret;
+}
+
+static int vidioc_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type buf_type)
+{
+ struct gspca_dev *gspca_dev = priv;
+ int ret;
+
+ if (buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ if (!gspca_dev->streaming)
+ return 0;
+ if (mutex_lock_interruptible(&gspca_dev->queue_lock))
+ return -ERESTARTSYS;
+ if (mutex_lock_interruptible(&gspca_dev->usb_lock)) {
+ ret = -ERESTARTSYS;
+ goto out;
+ }
+ if (gspca_dev->capt_file != file) {
+ ret = -EINVAL;
+ goto out2;
+ }
+ gspca_stream_off(gspca_dev);
+ ret = 0;
+out2:
+ mutex_unlock(&gspca_dev->usb_lock);
+out:
+ mutex_unlock(&gspca_dev->queue_lock);
+ return ret;
+}
+
+static int vidioc_g_jpegcomp(struct file *file, void *priv,
+ struct v4l2_jpegcompression *jpegcomp)
+{
+ struct gspca_dev *gspca_dev = priv;
+ int ret;
+
+ if (!gspca_dev->sd_desc->get_jcomp)
+ return -EINVAL;
+ if (mutex_lock_interruptible(&gspca_dev->usb_lock))
+ return -ERESTARTSYS;
+ ret = gspca_dev->sd_desc->get_jcomp(gspca_dev, jpegcomp);
+ mutex_unlock(&gspca_dev->usb_lock);
+ return ret;
+}
+
+static int vidioc_s_jpegcomp(struct file *file, void *priv,
+ struct v4l2_jpegcompression *jpegcomp)
+{
+ struct gspca_dev *gspca_dev = priv;
+ int ret;
+
+ if (mutex_lock_interruptible(&gspca_dev->usb_lock))
+ return -ERESTARTSYS;
+ if (!gspca_dev->sd_desc->set_jcomp)
+ return -EINVAL;
+ ret = gspca_dev->sd_desc->set_jcomp(gspca_dev, jpegcomp);
+ mutex_unlock(&gspca_dev->usb_lock);
+ return ret;
+}
+
+static int vidioc_g_parm(struct file *filp, void *priv,
+ struct v4l2_streamparm *parm)
+{
+ struct gspca_dev *gspca_dev = priv;
+
+ memset(parm, 0, sizeof *parm);
+ parm->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ parm->parm.capture.readbuffers = gspca_dev->nbufread;
+ return 0;
+}
+
+static int vidioc_s_parm(struct file *filp, void *priv,
+ struct v4l2_streamparm *parm)
+{
+ struct gspca_dev *gspca_dev = priv;
+ int n;
+
+ n = parm->parm.capture.readbuffers;
+ if (n == 0 || n > GSPCA_MAX_FRAMES)
+ parm->parm.capture.readbuffers = gspca_dev->nbufread;
+ else
+ gspca_dev->nbufread = n;
+ return 0;
+}
+
+static int vidioc_s_std(struct file *filp, void *priv,
+ v4l2_std_id *parm)
+{
+ return 0;
+}
+
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+static int vidiocgmbuf(struct file *file, void *priv,
+ struct video_mbuf *mbuf)
+{
+ struct gspca_dev *gspca_dev = file->private_data;
+ int i;
+
+ PDEBUG(D_STREAM, "cgmbuf");
+ if (gspca_dev->nframes == 0) {
+ int ret;
+
+ {
+ struct v4l2_format fmt;
+
+ memset(&fmt, 0, sizeof fmt);
+ fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ i = gspca_dev->cam.nmodes - 1; /* highest mode */
+ fmt.fmt.pix.width = gspca_dev->cam.cam_mode[i].width;
+ fmt.fmt.pix.height = gspca_dev->cam.cam_mode[i].height;
+ fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_BGR24;
+ ret = vidioc_s_fmt_vid_cap(file, priv, &fmt);
+ if (ret != 0)
+ return ret;
+ }
+ {
+ struct v4l2_requestbuffers rb;
+
+ memset(&rb, 0, sizeof rb);
+ rb.count = 4;
+ rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ rb.memory = V4L2_MEMORY_MMAP;
+ ret = vidioc_reqbufs(file, priv, &rb);
+ if (ret != 0)
+ return ret;
+ }
+ }
+ mbuf->frames = gspca_dev->nframes;
+ mbuf->size = gspca_dev->frsz * gspca_dev->nframes;
+ for (i = 0; i < mbuf->frames; i++)
+ mbuf->offsets[i] = gspca_dev->frame[i].v4l2_buf.m.offset;
+ return 0;
+}
+#endif
+
+static int dev_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct gspca_dev *gspca_dev = file->private_data;
+ struct gspca_frame *frame;
+ struct page *page;
+ unsigned long addr, start, size;
+ int i, ret;
+
+ start = vma->vm_start;
+ size = vma->vm_end - vma->vm_start;
+ PDEBUG(D_STREAM, "mmap start:%08x size:%d", (int) start, (int) size);
+
+ if (mutex_lock_interruptible(&gspca_dev->queue_lock))
+ return -ERESTARTSYS;
+ if (!gspca_dev->present) {
+ ret = -ENODEV;
+ goto out;
+ }
+ if (gspca_dev->capt_file != file) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ frame = NULL;
+ for (i = 0; i < gspca_dev->nframes; ++i) {
+ if (gspca_dev->frame[i].v4l2_buf.memory != V4L2_MEMORY_MMAP) {
+ PDEBUG(D_STREAM, "mmap bad memory type");
+ break;
+ }
+ if ((gspca_dev->frame[i].v4l2_buf.m.offset >> PAGE_SHIFT)
+ == vma->vm_pgoff) {
+ frame = &gspca_dev->frame[i];
+ break;
+ }
+ }
+ if (frame == NULL) {
+ PDEBUG(D_STREAM, "mmap no frame buffer found");
+ ret = -EINVAL;
+ goto out;
+ }
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+ /* v4l1 maps all the buffers */
+ if (i != 0
+ || size != frame->v4l2_buf.length * gspca_dev->nframes)
+#endif
+ if (size != frame->v4l2_buf.length) {
+ PDEBUG(D_STREAM, "mmap bad size");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /*
+ * - VM_IO marks the area as being a mmaped region for I/O to a
+ * device. It also prevents the region from being core dumped.
+ */
+ vma->vm_flags |= VM_IO;
+
+ addr = (unsigned long) frame->data;
+ while (size > 0) {
+ page = vmalloc_to_page((void *) addr);
+ ret = vm_insert_page(vma, start, page);
+ if (ret < 0)
+ goto out;
+ start += PAGE_SIZE;
+ addr += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
+
+ vma->vm_ops = &gspca_vm_ops;
+ vma->vm_private_data = frame;
+ gspca_vm_open(vma);
+ ret = 0;
+out:
+ mutex_unlock(&gspca_dev->queue_lock);
+ return ret;
+}
+
+/*
+ * wait for a video frame
+ *
+ * If a frame is ready, its index is returned.
+ */
+static int frame_wait(struct gspca_dev *gspca_dev,
+ int nonblock_ing)
+{
+ struct gspca_frame *frame;
+ int i, j, ret;
+
+ /* check if a frame is ready */
+ i = gspca_dev->fr_o;
+ j = gspca_dev->fr_queue[i];
+ frame = &gspca_dev->frame[j];
+ if (frame->v4l2_buf.flags & V4L2_BUF_FLAG_DONE) {
+ atomic_dec(&gspca_dev->nevent);
+ goto ok;
+ }
+ if (nonblock_ing) /* no frame yet */
+ return -EAGAIN;
+
+ /* wait till a frame is ready */
+ for (;;) {
+ ret = wait_event_interruptible_timeout(gspca_dev->wq,
+ atomic_read(&gspca_dev->nevent) > 0,
+ msecs_to_jiffies(3000));
+ if (ret <= 0) {
+ if (ret < 0)
+ return ret; /* interrupt */
+ return -EIO; /* timeout */
+ }
+ atomic_dec(&gspca_dev->nevent);
+ if (!gspca_dev->streaming || !gspca_dev->present)
+ return -EIO;
+ i = gspca_dev->fr_o;
+ j = gspca_dev->fr_queue[i];
+ frame = &gspca_dev->frame[j];
+ if (frame->v4l2_buf.flags & V4L2_BUF_FLAG_DONE)
+ break;
+ }
+ok:
+ gspca_dev->fr_o = (i + 1) % gspca_dev->nframes;
+ PDEBUG(D_FRAM, "frame wait q:%d i:%d o:%d",
+ gspca_dev->fr_q,
+ gspca_dev->fr_i,
+ gspca_dev->fr_o);
+
+ if (gspca_dev->sd_desc->dq_callback)
+ gspca_dev->sd_desc->dq_callback(gspca_dev);
+
+ return j;
+}
+
+/*
+ * dequeue a video buffer
+ *
+ * If nonblock_ing is false, block until a buffer is available.
+ */
+static int vidioc_dqbuf(struct file *file, void *priv,
+ struct v4l2_buffer *v4l2_buf)
+{
+ struct gspca_dev *gspca_dev = priv;
+ struct gspca_frame *frame;
+ int i, ret;
+
+ PDEBUG(D_FRAM, "dqbuf");
+ if (v4l2_buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ if (v4l2_buf->memory != gspca_dev->memory)
+ return -EINVAL;
+ if (!gspca_dev->streaming)
+ return -EINVAL;
+ if (gspca_dev->capt_file != file) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* only one read */
+ if (mutex_lock_interruptible(&gspca_dev->read_lock))
+ return -ERESTARTSYS;
+
+ ret = frame_wait(gspca_dev, file->f_flags & O_NONBLOCK);
+ if (ret < 0)
+ goto out;
+ i = ret; /* frame index */
+ frame = &gspca_dev->frame[i];
+ if (gspca_dev->memory == V4L2_MEMORY_USERPTR) {
+ if (copy_to_user((__u8 *) frame->v4l2_buf.m.userptr,
+ frame->data,
+ frame->v4l2_buf.bytesused)) {
+ PDEBUG(D_ERR|D_STREAM,
+ "dqbuf cp to user failed");
+ ret = -EFAULT;
+ goto out;
+ }
+ }
+ frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_DONE;
+ memcpy(v4l2_buf, &frame->v4l2_buf, sizeof *v4l2_buf);
+ PDEBUG(D_FRAM, "dqbuf %d", i);
+ ret = 0;
+out:
+ mutex_unlock(&gspca_dev->read_lock);
+ return ret;
+}
+
+/*
+ * queue a video buffer
+ *
+ * Attempting to queue a buffer that has already been
+ * queued will return -EINVAL.
+ */
+static int vidioc_qbuf(struct file *file, void *priv,
+ struct v4l2_buffer *v4l2_buf)
+{
+ struct gspca_dev *gspca_dev = priv;
+ struct gspca_frame *frame;
+ int i, index, ret;
+
+ PDEBUG(D_FRAM, "qbuf %d", v4l2_buf->index);
+ if (v4l2_buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ index = v4l2_buf->index;
+ if ((unsigned) index >= gspca_dev->nframes) {
+ PDEBUG(D_FRAM,
+ "qbuf idx %d >= %d", index, gspca_dev->nframes);
+ return -EINVAL;
+ }
+ frame = &gspca_dev->frame[index];
+
+ if (v4l2_buf->memory != frame->v4l2_buf.memory) {
+ PDEBUG(D_FRAM, "qbuf bad memory type");
+ return -EINVAL;
+ }
+ if (gspca_dev->capt_file != file)
+ return -EINVAL;
+
+ if (mutex_lock_interruptible(&gspca_dev->queue_lock))
+ return -ERESTARTSYS;
+
+ if (frame->v4l2_buf.flags & BUF_ALL_FLAGS) {
+ PDEBUG(D_FRAM, "qbuf bad state");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ frame->v4l2_buf.flags |= V4L2_BUF_FLAG_QUEUED;
+/* frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_DONE; */
+
+ if (frame->v4l2_buf.memory == V4L2_MEMORY_USERPTR) {
+ frame->v4l2_buf.m.userptr = v4l2_buf->m.userptr;
+ frame->v4l2_buf.length = v4l2_buf->length;
+ }
+
+ /* put the buffer in the 'queued' queue */
+ i = gspca_dev->fr_q;
+ gspca_dev->fr_queue[i] = index;
+ gspca_dev->fr_q = (i + 1) % gspca_dev->nframes;
+ PDEBUG(D_FRAM, "qbuf q:%d i:%d o:%d",
+ gspca_dev->fr_q,
+ gspca_dev->fr_i,
+ gspca_dev->fr_o);
+
+ v4l2_buf->flags |= V4L2_BUF_FLAG_QUEUED;
+ v4l2_buf->flags &= ~V4L2_BUF_FLAG_DONE;
+ ret = 0;
+out:
+ mutex_unlock(&gspca_dev->queue_lock);
+ return ret;
+}
+
+/*
+ * allocate the resources for read()
+ */
+static int read_alloc(struct gspca_dev *gspca_dev,
+ struct file *file)
+{
+ struct v4l2_buffer v4l2_buf;
+ int i, ret;
+
+ PDEBUG(D_STREAM, "read alloc");
+ if (gspca_dev->nframes == 0) {
+ struct v4l2_requestbuffers rb;
+
+ memset(&rb, 0, sizeof rb);
+ rb.count = gspca_dev->nbufread;
+ rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ rb.memory = GSPCA_MEMORY_READ;
+ ret = vidioc_reqbufs(file, gspca_dev, &rb);
+ if (ret != 0) {
+ PDEBUG(D_STREAM, "read reqbuf err %d", ret);
+ return ret;
+ }
+ memset(&v4l2_buf, 0, sizeof v4l2_buf);
+ v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ v4l2_buf.memory = GSPCA_MEMORY_READ;
+ for (i = 0; i < gspca_dev->nbufread; i++) {
+ v4l2_buf.index = i;
+/*fixme: ugly!*/
+ gspca_dev->frame[i].v4l2_buf.flags |=
+ V4L2_BUF_FLAG_MAPPED;
+ ret = vidioc_qbuf(file, gspca_dev, &v4l2_buf);
+ if (ret != 0) {
+ PDEBUG(D_STREAM, "read qbuf err: %d", ret);
+ return ret;
+ }
+ }
+ gspca_dev->memory = GSPCA_MEMORY_READ;
+ }
+
+ /* start streaming */
+ ret = vidioc_streamon(file, gspca_dev, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+ if (ret != 0)
+ PDEBUG(D_STREAM, "read streamon err %d", ret);
+ return ret;
+}
+
+static unsigned int dev_poll(struct file *file, poll_table *wait)
+{
+ struct gspca_dev *gspca_dev = file->private_data;
+ int i, ret;
+
+ PDEBUG(D_FRAM, "poll");
+
+ poll_wait(file, &gspca_dev->wq, wait);
+ if (!gspca_dev->present)
+ return POLLERR;
+
+ /* if not streaming, the user would use read() */
+ if (!gspca_dev->streaming) {
+ if (gspca_dev->memory != GSPCA_MEMORY_NO) {
+ ret = POLLERR; /* not the 1st time */
+ goto out;
+ }
+ ret = read_alloc(gspca_dev, file);
+ if (ret != 0) {
+ ret = POLLERR;
+ goto out;
+ }
+ }
+
+ if (mutex_lock_interruptible(&gspca_dev->queue_lock) != 0)
+ return POLLERR;
+ if (!gspca_dev->present) {
+ ret = POLLERR;
+ goto out;
+ }
+
+ i = gspca_dev->fr_o;
+ i = gspca_dev->fr_queue[i];
+ if (gspca_dev->frame[i].v4l2_buf.flags & V4L2_BUF_FLAG_DONE)
+ ret = POLLIN | POLLRDNORM; /* something to read */
+ else
+ ret = 0;
+out:
+ mutex_unlock(&gspca_dev->queue_lock);
+ return ret;
+}
+
+static ssize_t dev_read(struct file *file, char __user *data,
+ size_t count, loff_t *ppos)
+{
+ struct gspca_dev *gspca_dev = file->private_data;
+ struct gspca_frame *frame;
+ struct v4l2_buffer v4l2_buf;
+ struct timeval timestamp;
+ int n, ret, ret2;
+
+ PDEBUG(D_FRAM, "read (%d)", count);
+ if (!gspca_dev->present)
+ return -ENODEV;
+ switch (gspca_dev->memory) {
+ case GSPCA_MEMORY_NO: /* first time */
+ ret = read_alloc(gspca_dev, file);
+ if (ret != 0)
+ return ret;
+ break;
+ case GSPCA_MEMORY_READ:
+ if (gspca_dev->capt_file == file)
+ break;
+ /* fall thru */
+ default:
+ return -EINVAL;
+ }
+
+ /* get a frame */
+ jiffies_to_timeval(get_jiffies_64(), &timestamp);
+ timestamp.tv_sec--;
+ n = 2;
+ for (;;) {
+ memset(&v4l2_buf, 0, sizeof v4l2_buf);
+ v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ v4l2_buf.memory = GSPCA_MEMORY_READ;
+ ret = vidioc_dqbuf(file, gspca_dev, &v4l2_buf);
+ if (ret != 0) {
+ PDEBUG(D_STREAM, "read dqbuf err %d", ret);
+ return ret;
+ }
+
+ /* if the process slept for more than 1 second,
+ * get anewer frame */
+ frame = &gspca_dev->frame[v4l2_buf.index];
+ if (--n < 0)
+ break; /* avoid infinite loop */
+ if (frame->v4l2_buf.timestamp.tv_sec >= timestamp.tv_sec)
+ break;
+ ret = vidioc_qbuf(file, gspca_dev, &v4l2_buf);
+ if (ret != 0) {
+ PDEBUG(D_STREAM, "read qbuf err %d", ret);
+ return ret;
+ }
+ }
+
+ /* copy the frame */
+ if (count > frame->v4l2_buf.bytesused)
+ count = frame->v4l2_buf.bytesused;
+ ret = copy_to_user(data, frame->data, count);
+ if (ret != 0) {
+ PDEBUG(D_ERR|D_STREAM,
+ "read cp to user lack %d / %d", ret, count);
+ ret = -EFAULT;
+ goto out;
+ }
+ ret = count;
+out:
+ /* in each case, requeue the buffer */
+ ret2 = vidioc_qbuf(file, gspca_dev, &v4l2_buf);
+ if (ret2 != 0)
+ return ret2;
+ return ret;
+}
+
+static void dev_release(struct video_device *vfd)
+{
+ /* nothing */
+}
+
+static struct file_operations dev_fops = {
+ .owner = THIS_MODULE,
+ .open = dev_open,
+ .release = dev_close,
+ .read = dev_read,
+ .mmap = dev_mmap,
+ .ioctl = video_ioctl2,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = v4l_compat_ioctl32,
+#endif
+ .llseek = no_llseek,
+ .poll = dev_poll,
+};
+
+static struct video_device gspca_template = {
+ .name = "gspca main driver",
+ .type = VID_TYPE_CAPTURE,
+ .fops = &dev_fops,
+ .release = dev_release, /* mandatory */
+ .minor = -1,
+ .vidioc_querycap = vidioc_querycap,
+ .vidioc_dqbuf = vidioc_dqbuf,
+ .vidioc_qbuf = vidioc_qbuf,
+ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
+ .vidioc_streamon = vidioc_streamon,
+ .vidioc_queryctrl = vidioc_queryctrl,
+ .vidioc_g_ctrl = vidioc_g_ctrl,
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ .vidioc_querymenu = vidioc_querymenu,
+ .vidioc_enum_input = vidioc_enum_input,
+ .vidioc_g_input = vidioc_g_input,
+ .vidioc_s_input = vidioc_s_input,
+ .vidioc_reqbufs = vidioc_reqbufs,
+ .vidioc_querybuf = vidioc_querybuf,
+ .vidioc_streamoff = vidioc_streamoff,
+ .vidioc_g_jpegcomp = vidioc_g_jpegcomp,
+ .vidioc_s_jpegcomp = vidioc_s_jpegcomp,
+ .vidioc_g_parm = vidioc_g_parm,
+ .vidioc_s_parm = vidioc_s_parm,
+ .vidioc_s_std = vidioc_s_std,
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+ .vidiocgmbuf = vidiocgmbuf,
+#endif
+};
+
+/*
+ * probe and create a new gspca device
+ *
+ * This function must be called by the sub-driver when it is
+ * called for probing a new device.
+ */
+int gspca_dev_probe(struct usb_interface *intf,
+ const struct usb_device_id *id,
+ const struct sd_desc *sd_desc,
+ int dev_size,
+ struct module *module)
+{
+ struct usb_interface_descriptor *interface;
+ struct gspca_dev *gspca_dev;
+ struct usb_device *dev = interface_to_usbdev(intf);
+ int ret;
+
+ PDEBUG(D_PROBE, "probing %04x:%04x", id->idVendor, id->idProduct);
+
+ /* we don't handle multi-config cameras */
+ if (dev->descriptor.bNumConfigurations != 1)
+ return -ENODEV;
+ interface = &intf->cur_altsetting->desc;
+ if (interface->bInterfaceNumber > 0)
+ return -ENODEV;
+
+ /* create the device */
+ if (dev_size < sizeof *gspca_dev)
+ dev_size = sizeof *gspca_dev;
+ gspca_dev = kzalloc(dev_size, GFP_KERNEL);
+ if (gspca_dev == NULL) {
+ err("couldn't kzalloc gspca struct");
+ return -EIO;
+ }
+ gspca_dev->dev = dev;
+ gspca_dev->iface = interface->bInterfaceNumber;
+ gspca_dev->nbalt = intf->num_altsetting;
+ gspca_dev->sd_desc = sd_desc;
+/* gspca_dev->users = 0; (done by kzalloc) */
+ gspca_dev->nbufread = 2;
+
+ /* configure the subdriver */
+ ret = gspca_dev->sd_desc->config(gspca_dev, id);
+ if (ret < 0)
+ goto out;
+ ret = gspca_set_alt0(gspca_dev);
+ if (ret < 0)
+ goto out;
+ gspca_set_default_mode(gspca_dev);
+
+ mutex_init(&gspca_dev->usb_lock);
+ mutex_init(&gspca_dev->read_lock);
+ mutex_init(&gspca_dev->queue_lock);
+ init_waitqueue_head(&gspca_dev->wq);
+
+ /* init video stuff */
+ memcpy(&gspca_dev->vdev, &gspca_template, sizeof gspca_template);
+ gspca_dev->vdev.dev = &dev->dev;
+ memcpy(&gspca_dev->fops, &dev_fops, sizeof gspca_dev->fops);
+ gspca_dev->vdev.fops = &gspca_dev->fops;
+ gspca_dev->fops.owner = module; /* module protection */
+ ret = video_register_device(&gspca_dev->vdev,
+ VFL_TYPE_GRABBER,
+ video_nr);
+ if (ret < 0) {
+ err("video_register_device err %d", ret);
+ goto out;
+ }
+
+ gspca_dev->present = 1;
+ usb_set_intfdata(intf, gspca_dev);
+ PDEBUG(D_PROBE, "probe ok");
+ return 0;
+out:
+ kfree(gspca_dev);
+ return ret;
+}
+EXPORT_SYMBOL(gspca_dev_probe);
+
+/*
+ * USB disconnection
+ *
+ * This function must be called by the sub-driver
+ * when the device disconnects, after the specific resources are freed.
+ */
+void gspca_disconnect(struct usb_interface *intf)
+{
+ struct gspca_dev *gspca_dev = usb_get_intfdata(intf);
+
+ if (!gspca_dev)
+ return;
+ gspca_dev->present = 0;
+ mutex_lock(&gspca_dev->queue_lock);
+ mutex_lock(&gspca_dev->usb_lock);
+ gspca_dev->streaming = 0;
+ destroy_urbs(gspca_dev);
+ mutex_unlock(&gspca_dev->usb_lock);
+ mutex_unlock(&gspca_dev->queue_lock);
+ while (gspca_dev->users != 0) { /* wait until fully closed */
+ atomic_inc(&gspca_dev->nevent);
+ wake_up_interruptible(&gspca_dev->wq); /* wake processes */
+ schedule();
+ }
+/* We don't want people trying to open up the device */
+ video_unregister_device(&gspca_dev->vdev);
+/* Free the memory */
+ kfree(gspca_dev);
+ PDEBUG(D_PROBE, "disconnect complete");
+}
+EXPORT_SYMBOL(gspca_disconnect);
+
+/* -- module insert / remove -- */
+static int __init gspca_init(void)
+{
+ info("main v%s registered", version);
+ return 0;
+}
+static void __exit gspca_exit(void)
+{
+ info("main deregistered");
+}
+
+module_init(gspca_init);
+module_exit(gspca_exit);
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+module_param_named(debug, gspca_debug, int, 0644);
+MODULE_PARM_DESC(debug,
+ "Debug (bit) 0x01:error 0x02:probe 0x04:config"
+ " 0x08:stream 0x10:frame 0x20:packet 0x40:USBin 0x80:USBout"
+ " 0x0100: v4l2");
+#endif
diff --git a/linux/drivers/media/video/gspca/gspca.h b/linux/drivers/media/video/gspca/gspca.h
new file mode 100644
index 000000000..9b645af81
--- /dev/null
+++ b/linux/drivers/media/video/gspca/gspca.h
@@ -0,0 +1,173 @@
+#ifndef GSPCAV2_H
+#define GSPCAV2_H
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/usb.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <linux/mutex.h>
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+/* GSPCA our debug messages */
+extern int gspca_debug;
+#define PDEBUG(level, fmt, args...) \
+ do {\
+ if (gspca_debug & (level)) \
+ printk(KERN_INFO MODULE_NAME ": " fmt "\n", ## args); \
+ } while (0)
+#define D_ERR 0x01
+#define D_PROBE 0x02
+#define D_CONF 0x04
+#define D_STREAM 0x08
+#define D_FRAM 0x10
+#define D_PACK 0x20
+#define D_USBI 0x40
+#define D_USBO 0x80
+#define D_V4L2 0x0100
+#else
+#define PDEBUG(level, fmt, args...)
+#endif
+#undef err
+#define err(fmt, args...) \
+ do {\
+ printk(KERN_ERR MODULE_NAME ": " fmt "\n", ## args); \
+ } while (0)
+#undef info
+#define info(fmt, args...) \
+ do {\
+ printk(KERN_INFO MODULE_NAME ": " fmt "\n", ## args); \
+ } while (0)
+#undef warn
+#define warn(fmt, args...) \
+ do {\
+ printk(KERN_WARNING MODULE_NAME ": " fmt "\n", ## args); \
+ } while (0)
+
+#define GSPCA_MAX_FRAMES 16 /* maximum number of video frame buffers */
+/* ISOC transfers */
+#define MAX_NURBS 16 /* max number of URBs */
+#define ISO_MAX_PKT 32 /* max number of packets in an ISOC transfer */
+#define ISO_MAX_SIZE 0x8000 /* max size of one URB buffer (32 Kb) */
+
+/* device information - set at probe time */
+struct cam {
+ char *dev_name;
+ struct v4l2_pix_format *cam_mode; /* size nmodes */
+ char nmodes;
+ __u8 epaddr;
+};
+
+struct gspca_dev;
+struct gspca_frame;
+
+/* subdriver operations */
+typedef int (*cam_op) (struct gspca_dev *);
+typedef void (*cam_v_op) (struct gspca_dev *);
+typedef int (*cam_cf_op) (struct gspca_dev *, const struct usb_device_id *);
+typedef int (*cam_jpg_op) (struct gspca_dev *,
+ struct v4l2_jpegcompression *);
+typedef int (*cam_qmnu_op) (struct gspca_dev *,
+ struct v4l2_querymenu *);
+typedef void (*cam_pkt_op) (struct gspca_dev *gspca_dev,
+ struct gspca_frame *frame,
+ __u8 *data,
+ int len);
+
+struct ctrl {
+ struct v4l2_queryctrl qctrl;
+ int (*set)(struct gspca_dev *, __s32);
+ int (*get)(struct gspca_dev *, __s32 *);
+};
+
+/* subdriver description */
+struct sd_desc {
+/* information */
+ const char *name; /* sub-driver name */
+/* controls */
+ const struct ctrl *ctrls;
+ int nctrls;
+/* operations */
+ cam_cf_op config; /* called on probe */
+ cam_op open; /* called on open */
+ cam_v_op start; /* called on stream on */
+ cam_v_op stopN; /* called on stream off - main alt */
+ cam_v_op stop0; /* called on stream off - alt 0 */
+ cam_v_op close; /* called on close */
+ cam_pkt_op pkt_scan;
+/* optional operations */
+ cam_v_op dq_callback; /* called when a frame has been dequeued */
+ cam_jpg_op get_jcomp;
+ cam_jpg_op set_jcomp;
+ cam_qmnu_op querymenu;
+};
+
+/* packet types when moving from iso buf to frame buf */
+#define DISCARD_PACKET 0
+#define FIRST_PACKET 1
+#define INTER_PACKET 2
+#define LAST_PACKET 3
+
+struct gspca_frame {
+ __u8 *data; /* frame buffer */
+ __u8 *data_end; /* end of frame while filling */
+ int vma_use_count;
+ struct v4l2_buffer v4l2_buf;
+};
+
+struct gspca_dev {
+ struct video_device vdev; /* !! must be the first item */
+ struct file_operations fops;
+ struct usb_device *dev;
+ struct file *capt_file; /* file doing video capture */
+
+ struct cam cam; /* device information */
+ const struct sd_desc *sd_desc; /* subdriver description */
+
+ struct urb *urb[MAX_NURBS];
+
+ __u8 *frbuf; /* buffer for nframes */
+ struct gspca_frame frame[GSPCA_MAX_FRAMES];
+ __u32 frsz; /* frame size */
+ char nframes; /* number of frames */
+ char fr_i; /* frame being filled */
+ char fr_q; /* next frame to queue */
+ char fr_o; /* next frame to dequeue */
+ signed char fr_queue[GSPCA_MAX_FRAMES]; /* frame queue */
+ char last_packet_type;
+
+ __u8 iface; /* USB interface number */
+ __u8 alt; /* USB alternate setting */
+ __u8 curr_mode; /* current camera mode */
+ __u32 pixfmt; /* current mode parameters */
+ __u16 width;
+ __u16 height;
+
+ atomic_t nevent; /* number of frames done */
+ wait_queue_head_t wq; /* wait queue */
+ struct mutex usb_lock; /* usb exchange protection */
+ struct mutex read_lock; /* read protection */
+ struct mutex queue_lock; /* ISOC queue protection */
+ __u32 sequence; /* frame sequence number */
+ char streaming;
+ char users; /* number of opens */
+ char present; /* device connected */
+ char nbufread; /* number of buffers for read() */
+ char nurbs; /* number of allocated URBs */
+ char memory; /* memory type (V4L2_MEMORY_xxx) */
+ __u8 nbalt; /* number of USB alternate settings */
+};
+
+int gspca_dev_probe(struct usb_interface *intf,
+ const struct usb_device_id *id,
+ const struct sd_desc *sd_desc,
+ int dev_size,
+ struct module *module);
+void gspca_disconnect(struct usb_interface *intf);
+struct gspca_frame *gspca_frame_add(struct gspca_dev *gspca_dev,
+ int packet_type,
+ struct gspca_frame *frame,
+ const __u8 *data,
+ int len);
+#endif /* GSPCAV2_H */
diff --git a/linux/drivers/media/video/gspca/jpeg.h b/linux/drivers/media/video/gspca/jpeg.h
new file mode 100644
index 000000000..d823b47bd
--- /dev/null
+++ b/linux/drivers/media/video/gspca/jpeg.h
@@ -0,0 +1,301 @@
+#ifndef JPEG_H
+#define JPEG_H 1
+/*
+ * Insert a JPEG header at start of frame
+ *
+ * This module is used by the gspca subdrivers.
+ * A special case is done for Conexant webcams.
+ *
+ * Copyright (C) Jean-Francois Moine (http://moinejf.free.fr)
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/* start of jpeg frame + quantization table */
+static const unsigned char quant[][0x88] = {
+/* index 0 - Q40*/
+ {
+ 0xff, 0xd8, /* jpeg */
+ 0xff, 0xdb, 0x00, 0x84, /* DQT */
+0, /* quantization table part 1 */
+ 20, 14, 15, 18, 15, 13, 20, 18, 16, 18, 23, 21, 20, 24, 30, 50,
+ 33, 30, 28, 28, 30, 61, 44, 46, 36, 50, 73, 64, 76, 75, 71, 64,
+ 70, 69, 80, 90, 115, 98, 80, 85, 109, 86, 69, 70, 100, 136, 101,
+ 109,
+ 119, 123, 129, 130, 129, 78, 96, 141, 151, 140, 125, 150, 115,
+ 126, 129, 124,
+1, /* quantization table part 2 */
+ 21, 23, 23, 30, 26, 30, 59, 33, 33, 59, 124, 83, 70, 83, 124, 124,
+ 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124,
+ 124, 124, 124,
+ 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124,
+ 124, 124, 124,
+ 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124,
+ 124, 124, 124},
+/* index 1 - Q50 */
+ {
+ 0xff, 0xd8,
+ 0xff, 0xdb, 0x00, 0x84, /* DQT */
+0,
+ 16, 11, 12, 14, 12, 10, 16, 14, 13, 14, 18, 17, 16, 19, 24, 40,
+ 26, 24, 22, 22, 24, 49, 35, 37, 29, 40, 58, 51, 61, 60, 57, 51,
+ 56, 55, 64, 72, 92, 78, 64, 68, 87, 69, 55, 56, 80, 109, 81, 87,
+ 95, 98, 103, 104, 103, 62, 77, 113, 121, 112, 100, 120, 92, 101,
+ 103, 99,
+1,
+ 17, 18, 18, 24, 21, 24, 47, 26, 26, 47, 99, 66, 56, 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, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99},
+/* index 2 Q60 */
+ {
+ 0xff, 0xd8,
+ 0xff, 0xdb, 0x00, 0x84, /* DQT */
+0,
+ 13, 9, 10, 11, 10, 8, 13, 11, 10, 11, 14, 14, 13, 15, 19, 32,
+ 21, 19, 18, 18, 19, 39, 28, 30, 23, 32, 46, 41, 49, 48, 46, 41,
+ 45, 44, 51, 58, 74, 62, 51, 54, 70, 55, 44, 45, 64, 87, 65, 70,
+ 76, 78, 82, 83, 82, 50, 62, 90, 97, 90, 80, 96, 74, 81, 82, 79,
+1,
+ 14, 14, 14, 19, 17, 19, 38, 21, 21, 38, 79, 53, 45, 53, 79, 79,
+ 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79,
+ 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79,
+ 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79},
+/* index 3 - Q70 */
+ {
+ 0xff, 0xd8,
+ 0xff, 0xdb, 0x00, 0x84, /* DQT */
+0,
+ 10, 7, 7, 8, 7, 6, 10, 8, 8, 8, 11, 10, 10, 11, 14, 24,
+ 16, 14, 13, 13, 14, 29, 21, 22, 17, 24, 35, 31, 37, 36, 34, 31,
+ 34, 33, 38, 43, 55, 47, 38, 41, 52, 41, 33, 34, 48, 65, 49, 52,
+ 57, 59, 62, 62, 62, 37, 46, 68, 73, 67, 60, 72, 55, 61, 62, 59,
+1,
+ 10, 11, 11, 14, 13, 14, 28, 16, 16, 28, 59, 40, 34, 40, 59, 59,
+ 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+ 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+ 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59},
+/* index 4 - Q80 */
+ {
+ 0xff, 0xd8,
+ 0xff, 0xdb, 0x00, 0x84, /* DQT */
+0,
+ 6, 4, 5, 6, 5, 4, 6, 6, 5, 6, 7, 7, 6, 8, 10, 16,
+ 10, 10, 9, 9, 10, 20, 14, 15, 12, 16, 23, 20, 24, 24, 23, 20,
+ 22, 22, 26, 29, 37, 31, 26, 27, 35, 28, 22, 22, 32, 44, 32, 35,
+ 38, 39, 41, 42, 41, 25, 31, 45, 48, 45, 40, 48, 37, 40, 41, 40,
+1,
+ 7, 7, 7, 10, 8, 10, 19, 10, 10, 19, 40, 26, 22, 26, 40, 40,
+ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40},
+/* index 5 - Q85 */
+ {
+ 0xff, 0xd8,
+ 0xff, 0xdb, 0x00, 0x84, /* DQT */
+0,
+ 5, 3, 4, 4, 4, 3, 5, 4, 4, 4, 5, 5, 5, 6, 7, 12,
+ 8, 7, 7, 7, 7, 15, 11, 11, 9, 12, 17, 15, 18, 18, 17, 15,
+ 17, 17, 19, 22, 28, 23, 19, 20, 26, 21, 17, 17, 24, 33, 24, 26,
+ 29, 29, 31, 31, 31, 19, 23, 34, 36, 34, 30, 36, 28, 30, 31, 30,
+1,
+ 5, 5, 5, 7, 6, 7, 14, 8, 8, 14, 30, 20, 17, 20, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30},
+/* index 6 - 86 */
+{
+ 0xff, 0xd8,
+ 0xff, 0xdb, 0x00, 0x84, /* DQT */
+0,
+ 0x04, 0x03, 0x03, 0x04, 0x03, 0x03, 0x04, 0x04,
+ 0x04, 0x04, 0x05, 0x05, 0x04, 0x05, 0x07, 0x0B,
+ 0x07, 0x07, 0x06, 0x06, 0x07, 0x0E, 0x0A, 0x0A,
+ 0x08, 0x0B, 0x10, 0x0E, 0x11, 0x11, 0x10, 0x0E,
+ 0x10, 0x0F, 0x12, 0x14, 0x1A, 0x16, 0x12, 0x13,
+ 0x18, 0x13, 0x0F, 0x10, 0x16, 0x1F, 0x17, 0x18,
+ 0x1B, 0x1B, 0x1D, 0x1D, 0x1D, 0x11, 0x16, 0x20,
+ 0x22, 0x1F, 0x1C, 0x22, 0x1A, 0x1C, 0x1D, 0x1C,
+1,
+ 0x05, 0x05, 0x05, 0x07, 0x06, 0x07, 0x0D, 0x07,
+ 0x07, 0x0D, 0x1C, 0x12, 0x10, 0x12, 0x1C, 0x1C,
+ 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
+ 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
+ 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
+ 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
+ 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
+ 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
+ },
+/* index 7 - 88 */
+{
+ 0xff, 0xd8,
+ 0xff, 0xdb, 0x00, 0x84, /* DQT */
+0,
+ 0x04, 0x03, 0x03, 0x03, 0x03, 0x02, 0x04, 0x03,
+ 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, 0x06, 0x0A,
+ 0x06, 0x06, 0x05, 0x05, 0x06, 0x0C, 0x08, 0x09,
+ 0x07, 0x0A, 0x0E, 0x0C, 0x0F, 0x0E, 0x0E, 0x0C,
+ 0x0D, 0x0D, 0x0F, 0x11, 0x16, 0x13, 0x0F, 0x10,
+ 0x15, 0x11, 0x0D, 0x0D, 0x13, 0x1A, 0x13, 0x15,
+ 0x17, 0x18, 0x19, 0x19, 0x19, 0x0F, 0x12, 0x1B,
+ 0x1D, 0x1B, 0x18, 0x1D, 0x16, 0x18, 0x19, 0x18,
+1,
+ 0x04, 0x04, 0x04, 0x06, 0x05, 0x06, 0x0B, 0x06,
+ 0x06, 0x0B, 0x18, 0x10, 0x0D, 0x10, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+},
+/* index 8 - ?? */
+{
+ 0xff, 0xd8,
+ 0xff, 0xdb, 0x00, 0x84, /* DQT */
+0,
+ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x05,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x06, 0x04, 0x05,
+ 0x04, 0x05, 0x07, 0x06, 0x08, 0x08, 0x07, 0x06,
+ 0x07, 0x07, 0x08, 0x09, 0x0C, 0x0A, 0x08, 0x09,
+ 0x0B, 0x09, 0x07, 0x07, 0x0A, 0x0E, 0x0A, 0x0B,
+ 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x08, 0x0A, 0x0E,
+ 0x0F, 0x0E, 0x0D, 0x0F, 0x0C, 0x0D, 0x0D, 0x0C,
+1,
+ 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x06, 0x03,
+ 0x03, 0x06, 0x0C, 0x08, 0x07, 0x08, 0x0C, 0x0C,
+ 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
+ 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
+ 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
+ 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
+ 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
+ 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C
+}
+};
+
+/* huffman table + start of SOF0 */
+static unsigned char huffman[] = {
+ 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,
+#ifdef CONEX_CAM
+/* the Conexant frames start with SOF0 */
+#else
+ 0xff, 0xc0, 0x00, 0x11, /* SOF0 (start of frame 0 */
+ 0x08, /* data precision */
+#endif
+};
+
+#ifndef CONEX_CAM
+/* variable part:
+ * 0x01, 0xe0, height
+ * 0x02, 0x80, width
+ * 0x03, component number
+ * 0x01,
+ * 0x21, samples Y
+ */
+
+/* end of header */
+static unsigned char eoh[] = {
+ 0x00, /* quant Y */
+ 0x02, 0x11, 0x01, /* samples CbCr - quant CbCr */
+ 0x03, 0x11, 0x01,
+
+ 0xff, 0xda, 0x00, 0x0c, /* SOS (start of scan) */
+ 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00
+};
+#endif
+
+/* -- output the JPEG header -- */
+static void jpeg_put_header(struct gspca_dev *gspca_dev,
+ struct gspca_frame *frame,
+ int qindex,
+ int samplesY)
+{
+#ifndef CONEX_CAM
+ unsigned char tmpbuf[8];
+#endif
+
+ gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+ (unsigned char *) quant[qindex], sizeof quant[0]);
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+ (unsigned char *) huffman, sizeof huffman);
+#ifndef CONEX_CAM
+ tmpbuf[0] = gspca_dev->height >> 8;
+ tmpbuf[1] = gspca_dev->height & 0xff;
+ tmpbuf[2] = gspca_dev->width >> 8;
+ tmpbuf[3] = gspca_dev->width & 0xff;
+ tmpbuf[4] = 0x03; /* component number */
+ tmpbuf[5] = 0x01; /* first component */
+ tmpbuf[6] = samplesY;
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+ tmpbuf, 7);
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+ eoh, sizeof eoh);
+#endif
+}
+#endif
diff --git a/linux/drivers/media/video/gspca/mars.c b/linux/drivers/media/video/gspca/mars.c
new file mode 100644
index 000000000..23f3dba80
--- /dev/null
+++ b/linux/drivers/media/video/gspca/mars.c
@@ -0,0 +1,452 @@
+/*
+ * Mars-Semi MR97311A library
+ * Copyright (C) 2005 <bradlch@hotmail.com>
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define MODULE_NAME "mars"
+
+#include "gspca.h"
+#include "jpeg.h"
+
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 5)
+static const char version[] = "2.1.5";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("GSPCA/Mars USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+
+ char qindex;
+};
+
+/* V4L2 controls supported by the driver */
+static struct ctrl sd_ctrls[] = {
+};
+
+static struct v4l2_pix_format vga_mode[] = {
+ {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240 * 3 / 8 + 589,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 2},
+ {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 1},
+};
+
+/* MI Register table //elvis */
+enum {
+ REG_HW_MI_0,
+ REG_HW_MI_1,
+ REG_HW_MI_2,
+ REG_HW_MI_3,
+ REG_HW_MI_4,
+ REG_HW_MI_5,
+ REG_HW_MI_6,
+ REG_HW_MI_7,
+ REG_HW_MI_9 = 0x09,
+ REG_HW_MI_B = 0x0B,
+ REG_HW_MI_C,
+ REG_HW_MI_D,
+ REG_HW_MI_1E = 0x1E,
+ REG_HW_MI_20 = 0x20,
+ REG_HW_MI_2B = 0x2B,
+ REG_HW_MI_2C,
+ REG_HW_MI_2D,
+ REG_HW_MI_2E,
+ REG_HW_MI_35 = 0x35,
+ REG_HW_MI_5F = 0x5f,
+ REG_HW_MI_60,
+ REG_HW_MI_61,
+ REG_HW_MI_62,
+ REG_HW_MI_63,
+ REG_HW_MI_64,
+ REG_HW_MI_F1 = 0xf1,
+ ATTR_TOTAL_MI_REG = 242
+};
+
+static int pcam_reg_write(struct usb_device *dev,
+ __u16 index, __u8 *value, int len)
+{
+ int rc;
+
+ rc = usb_control_msg(dev,
+ usb_sndbulkpipe(dev, 4),
+ 0x12,
+/* ?? 0xc8 = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_??? !? */
+ 0xc8,
+ 0, /* value */
+ index, value, len, 500);
+ if (rc < 0)
+ PDEBUG(D_ERR, "reg write [%02x] error %d", index, rc);
+ return rc;
+}
+
+static void MISensor_BulkWrite(struct usb_device *dev,
+ unsigned short *pch,
+ char Address)
+{
+ __u8 data[6];
+
+ data[0] = 0x1f;
+ data[1] = 0; /* control byte */
+ data[2] = Address;
+ data[3] = *pch >> 8; /* high byte */
+ data[4] = *pch; /* low byte */
+
+ pcam_reg_write(dev, Address, data, 5);
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+ const struct usb_device_id *id)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct cam *cam;
+
+ cam = &gspca_dev->cam;
+ cam->dev_name = (char *) id->driver_info;
+ cam->epaddr = 0x01;
+ cam->cam_mode = vga_mode;
+ cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+ sd->qindex = 1; /* set the quantization table */
+ return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+ return 0;
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+ struct usb_device *dev = gspca_dev->dev;
+ int err_code;
+ __u8 data[12];
+ __u16 MI_buf[242];
+ int h_size, v_size;
+ int intpipe;
+/* struct usb_device *dev = pcam->dev; */
+
+ memset(data, 0, sizeof data);
+ memset(MI_buf, 0, sizeof MI_buf);
+
+ PDEBUG(D_STREAM, "camera start, iface %d, alt 8", gspca_dev->iface);
+ if (usb_set_interface(dev, gspca_dev->iface, 8) < 0) {
+ PDEBUG(D_ERR|D_STREAM, "Set packet size: set interface error");
+ return;
+ }
+
+ data[0] = 0x01; /* address */
+ data[1] = 0x01;
+
+ err_code = pcam_reg_write(dev, data[0], data, 2);
+ if (err_code < 0)
+ return;
+
+ /*
+ Initialize the MR97113 chip register
+ */
+ data[0] = 0x00; /* address */
+ data[1] = 0x0c | 0x01; /* reg 0 */
+ data[2] = 0x01; /* reg 1 */
+ h_size = gspca_dev->width;
+ v_size = gspca_dev->height;
+ data[3] = h_size / 8; /* h_size , reg 2 */
+ data[4] = v_size / 8; /* v_size , reg 3 */
+ data[5] = 0x30; /* reg 4, MI, PAS5101 :
+ * 0x30 for 24mhz , 0x28 for 12mhz */
+ data[6] = 4; /* reg 5, H start */
+ data[7] = 0xc0; /* reg 6, gamma 1.5 */
+ data[8] = 3; /* reg 7, V start */
+/* if(h_size == 320 ) */
+/* data[9]= 0x56; * reg 8, 24MHz, 2:1 scale down */
+/* else */
+ data[9] = 0x52; /* reg 8, 24MHz, no scale down */
+ data[10] = 0x5d; /* reg 9, I2C device address
+ * [for PAS5101 (0x40)] [for MI (0x5d)] */
+
+ err_code = pcam_reg_write(dev, data[0], data, 11);
+ if (err_code < 0)
+ return;
+
+ data[0] = 0x23; /* address */
+ data[1] = 0x09; /* reg 35, append frame header */
+
+ err_code = pcam_reg_write(dev, data[0], data, 2);
+ if (err_code < 0) {
+ PDEBUG(D_ERR, "Register write failed");
+ return;
+ }
+
+ data[0] = 0x3C; /* address */
+/* if (pcam->width == 1280) */
+/* data[1] = 200; * reg 60, pc-cam frame size
+ * (unit: 4KB) 800KB */
+/* else */
+ data[1] = 50; /* 50 reg 60, pc-cam frame size
+ * (unit: 4KB) 200KB */
+ err_code = pcam_reg_write(dev, data[0], data, 2);
+ if (err_code < 0)
+ return;
+
+ if (0) { /* fixed dark-gain */
+ data[1] = 0; /* reg 94, Y Gain (1.75) */
+ data[2] = 0; /* reg 95, UV Gain (1.75) */
+ data[3] = 0x3f; /* reg 96, Y Gain/UV Gain/disable
+ * auto dark-gain */
+ data[4] = 0; /* reg 97, set fixed dark level */
+ data[5] = 0; /* reg 98, don't care */
+ } else { /* auto dark-gain */
+ data[1] = 0; /* reg 94, Y Gain (auto) */
+ data[2] = 0; /* reg 95, UV Gain (1.75) */
+ data[3] = 0x78; /* reg 96, Y Gain/UV Gain/disable
+ * auto dark-gain */
+ switch (gspca_dev->width) {
+/* case 1280: */
+/* data[4] = 154;
+ * reg 97, %3 shadow point (unit: 256 pixel) */
+/* data[5] = 51;
+ * reg 98, %1 highlight point
+ * (uint: 256 pixel) */
+/* break; */
+ default:
+/* case 640: */
+ data[4] = 36; /* reg 97, %3 shadow point
+ * (unit: 256 pixel) */
+ data[5] = 12; /* reg 98, %1 highlight point
+ * (uint: 256 pixel) */
+ break;
+ case 320:
+ data[4] = 9; /* reg 97, %3 shadow point
+ * (unit: 256 pixel) */
+ data[5] = 3; /* reg 98, %1 highlight point
+ * (uint: 256 pixel) */
+ break;
+ }
+ }
+ /* auto dark-gain */
+ data[0] = 0x5e; /* address */
+
+ err_code = pcam_reg_write(dev, data[0], data, 6);
+ if (err_code < 0)
+ return;
+
+ data[0] = 0x67;
+ data[1] = 0x13; /* reg 103, first pixel B, disable sharpness */
+ err_code = pcam_reg_write(dev, data[0], data, 2);
+ if (err_code < 0)
+ return;
+
+ /*
+ * initialize the value of MI sensor...
+ */
+ MI_buf[REG_HW_MI_1] = 0x000a;
+ MI_buf[REG_HW_MI_2] = 0x000c;
+ MI_buf[REG_HW_MI_3] = 0x0405;
+ MI_buf[REG_HW_MI_4] = 0x0507;
+ /* mi_Attr_Reg_[REG_HW_MI_5] = 0x01ff;//13 */
+ MI_buf[REG_HW_MI_5] = 0x0013; /* 13 */
+ MI_buf[REG_HW_MI_6] = 0x001f; /* vertical blanking */
+ /* mi_Attr_Reg_[REG_HW_MI_6] = 0x0400; // vertical blanking */
+ MI_buf[REG_HW_MI_7] = 0x0002;
+ /* mi_Attr_Reg_[REG_HW_MI_9] = 0x015f; */
+ /* mi_Attr_Reg_[REG_HW_MI_9] = 0x030f; */
+ MI_buf[REG_HW_MI_9] = 0x0374;
+ MI_buf[REG_HW_MI_B] = 0x0000;
+ MI_buf[REG_HW_MI_C] = 0x0000;
+ MI_buf[REG_HW_MI_D] = 0x0000;
+ MI_buf[REG_HW_MI_1E] = 0x8000;
+/* mi_Attr_Reg_[REG_HW_MI_20] = 0x1104; */
+ MI_buf[REG_HW_MI_20] = 0x1104; /* 0x111c; */
+ MI_buf[REG_HW_MI_2B] = 0x0008;
+/* mi_Attr_Reg_[REG_HW_MI_2C] = 0x000f; */
+ MI_buf[REG_HW_MI_2C] = 0x001f; /* lita suggest */
+ MI_buf[REG_HW_MI_2D] = 0x0008;
+ MI_buf[REG_HW_MI_2E] = 0x0008;
+ MI_buf[REG_HW_MI_35] = 0x0051;
+ MI_buf[REG_HW_MI_5F] = 0x0904; /* fail to write */
+ MI_buf[REG_HW_MI_60] = 0x0000;
+ MI_buf[REG_HW_MI_61] = 0x0000;
+ MI_buf[REG_HW_MI_62] = 0x0498;
+ MI_buf[REG_HW_MI_63] = 0x0000;
+ MI_buf[REG_HW_MI_64] = 0x0000;
+ MI_buf[REG_HW_MI_F1] = 0x0001;
+ /* changing while setting up the different value of dx/dy */
+
+ if (gspca_dev->width != 1280) {
+ MI_buf[0x01] = 0x010a;
+ MI_buf[0x02] = 0x014c;
+ MI_buf[0x03] = 0x01e5;
+ MI_buf[0x04] = 0x0287;
+ }
+ MI_buf[0x20] = 0x1104;
+
+ MISensor_BulkWrite(dev, MI_buf + 1, 1);
+ MISensor_BulkWrite(dev, MI_buf + 2, 2);
+ MISensor_BulkWrite(dev, MI_buf + 3, 3);
+ MISensor_BulkWrite(dev, MI_buf + 4, 4);
+ MISensor_BulkWrite(dev, MI_buf + 5, 5);
+ MISensor_BulkWrite(dev, MI_buf + 6, 6);
+ MISensor_BulkWrite(dev, MI_buf + 7, 7);
+ MISensor_BulkWrite(dev, MI_buf + 9, 9);
+ MISensor_BulkWrite(dev, MI_buf + 0x0b, 0x0b);
+ MISensor_BulkWrite(dev, MI_buf + 0x0c, 0x0c);
+ MISensor_BulkWrite(dev, MI_buf + 0x0d, 0x0d);
+ MISensor_BulkWrite(dev, MI_buf + 0x1e, 0x1e);
+ MISensor_BulkWrite(dev, MI_buf + 0x20, 0x20);
+ MISensor_BulkWrite(dev, MI_buf + 0x2b, 0x2b);
+ MISensor_BulkWrite(dev, MI_buf + 0x2c, 0x2c);
+ MISensor_BulkWrite(dev, MI_buf + 0x2d, 0x2d);
+ MISensor_BulkWrite(dev, MI_buf + 0x2e, 0x2e);
+ MISensor_BulkWrite(dev, MI_buf + 0x35, 0x35);
+ MISensor_BulkWrite(dev, MI_buf + 0x5f, 0x5f);
+ MISensor_BulkWrite(dev, MI_buf + 0x60, 0x60);
+ MISensor_BulkWrite(dev, MI_buf + 0x61, 0x61);
+ MISensor_BulkWrite(dev, MI_buf + 0x62, 0x62);
+ MISensor_BulkWrite(dev, MI_buf + 0x63, 0x63);
+ MISensor_BulkWrite(dev, MI_buf + 0x64, 0x64);
+ MISensor_BulkWrite(dev, MI_buf + 0xf1, 0xf1);
+
+ intpipe = usb_sndintpipe(dev, 0);
+ err_code = usb_clear_halt(dev, intpipe);
+
+ data[0] = 0x00;
+ data[1] = 0x4d; /* ISOC transfering enable... */
+ pcam_reg_write(dev, data[0], data, 2);
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+ int result;
+ __u8 data[2];
+
+ data[0] = 1;
+ data[1] = 0;
+ result = pcam_reg_write(gspca_dev->dev, data[0], data, 2);
+ if (result < 0)
+ PDEBUG(D_ERR, "Camera Stop failed");
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ struct gspca_frame *frame, /* target */
+ __u8 *data, /* isoc packet */
+ int len) /* iso packet length */
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int p;
+
+ if (len < 6) {
+/* gspca_dev->last_packet_type = DISCARD_PACKET; */
+ return;
+ }
+ for (p = 0; p < len - 6; p++) {
+ if (data[0 + p] == 0xff
+ && data[1 + p] == 0xff
+ && data[2 + p] == 0x00
+ && data[3 + p] == 0xff
+ && data[4 + p] == 0x96) {
+ if (data[5 + p] == 0x64
+ || data[5 + p] == 0x65
+ || data[5 + p] == 0x66
+ || data[5 + p] == 0x67) {
+ PDEBUG(D_PACK, "sof offset: %d leng: %d",
+ p, len);
+ frame = gspca_frame_add(gspca_dev, LAST_PACKET,
+ frame, data, 0);
+
+ /* put the JPEG header */
+ jpeg_put_header(gspca_dev, frame,
+ sd->qindex, 0x21);
+ data += 16;
+ len -= 16;
+ break;
+ }
+ }
+ }
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .ctrls = sd_ctrls,
+ .nctrls = ARRAY_SIZE(sd_ctrls),
+ .config = sd_config,
+ .open = sd_open,
+ .start = sd_start,
+ .stopN = sd_stopN,
+ .stop0 = sd_stop0,
+ .close = sd_close,
+ .pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static const __devinitdata struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x093a, 0x050f), DVNM("Mars-Semi Pc-Camera")},
+ {}
+};
+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,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+ if (usb_register(&sd_driver) < 0)
+ return -1;
+ PDEBUG(D_PROBE, "v%s registered", version);
+ return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+ usb_deregister(&sd_driver);
+ PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/linux/drivers/media/video/gspca/ov519.c b/linux/drivers/media/video/gspca/ov519.c
new file mode 100644
index 000000000..402b3ed12
--- /dev/null
+++ b/linux/drivers/media/video/gspca/ov519.c
@@ -0,0 +1,2242 @@
+/**
+ * OV519 driver
+ *
+ * Copyright (C) 2008 Jean-Francois Moine (http://moinejf.free.fr)
+ *
+ * (This module is adapted from the ov51x-jpeg package)
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#define MODULE_NAME "ov519"
+
+#include "gspca.h"
+
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 5)
+static const char version[] = "2.1.5";
+
+MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>");
+MODULE_DESCRIPTION("OV519 USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* global parameters */
+static int frame_rate;
+
+/* Number of times to retry a failed I2C transaction. Increase this if you
+ * are getting "Failed to read sensor ID..." */
+static int i2c_detect_tries = 10;
+
+/* ov519 device descriptor */
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+
+ /* Determined by sensor type */
+ short maxwidth;
+ short maxheight;
+
+ unsigned char primary_i2c_slave; /* I2C write id of sensor */
+
+ unsigned char brightness;
+ unsigned char contrast;
+ unsigned char colors;
+
+ char compress; /* Should the next frame be compressed? */
+ char compress_inited; /* Are compression params uploaded? */
+ char stopped; /* Streaming is temporarily paused */
+
+ char frame_rate; /* current Framerate (OV519 only) */
+ char clockdiv; /* clockdiv override for OV519 only */
+
+ char sensor; /* Type of image sensor chip (SEN_*) */
+#define SEN_UNKNOWN 0
+#define SEN_OV6620 1
+#define SEN_OV6630 2
+#define SEN_OV7610 3
+#define SEN_OV7620 4
+#define SEN_OV7630 5
+#define SEN_OV7640 6
+#define SEN_OV7670 7
+#define SEN_OV76BE 8
+#define SEN_OV8610 9
+
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+#define SD_BRIGHTNESS 0
+ {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+ .default_value = 127,
+ },
+ .set = sd_setbrightness,
+ .get = sd_getbrightness,
+ },
+#define SD_CONTRAST 1
+ {
+ {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+ .default_value = 127,
+ },
+ .set = sd_setcontrast,
+ .get = sd_getcontrast,
+ },
+#define SD_COLOR 2
+ {
+ {
+ .id = V4L2_CID_SATURATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Saturation",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+ .default_value = 127,
+ },
+ .set = sd_setcolors,
+ .get = sd_getcolors,
+ },
+};
+
+static struct v4l2_pix_format vga_mode[] = {
+ {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240 * 3 / 8 + 589,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 1},
+ {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 0},
+};
+static struct v4l2_pix_format sif_mode[] = {
+ {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 176,
+ .sizeimage = 176 * 144 * 3 / 8 + 589,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 1},
+ {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 352,
+ .sizeimage = 352 * 288 * 3 / 8 + 589,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 0},
+};
+
+/* OV519 Camera interface register numbers */
+#define OV519_CAM_H_SIZE 0x10
+#define OV519_CAM_V_SIZE 0x11
+#define OV519_CAM_X_OFFSETL 0x12
+#define OV519_CAM_X_OFFSETH 0x13
+#define OV519_CAM_Y_OFFSETL 0x14
+#define OV519_CAM_Y_OFFSETH 0x15
+#define OV519_CAM_DIVIDER 0x16
+#define OV519_CAM_DFR 0x20
+#define OV519_CAM_FORMAT 0x25
+
+/* OV519 System Controller register numbers */
+#define OV519_SYS_RESET1 0x51
+#define OV519_SYS_EN_CLK1 0x54
+
+#define OV519_GPIO_DATA_OUT0 0x71
+#define OV519_GPIO_IO_CTRL0 0x72
+
+#define OV511_ENDPOINT_ADDRESS 1 /* Isoc endpoint number */
+
+/* I2C registers */
+#define R51x_I2C_W_SID 0x41
+#define R51x_I2C_SADDR_3 0x42
+#define R51x_I2C_SADDR_2 0x43
+#define R51x_I2C_R_SID 0x44
+#define R51x_I2C_DATA 0x45
+#define R518_I2C_CTL 0x47 /* OV518(+) only */
+
+/* I2C ADDRESSES */
+#define OV7xx0_SID 0x42
+#define OV8xx0_SID 0xa0
+#define OV6xx0_SID 0xc0
+
+/* OV7610 registers */
+#define OV7610_REG_GAIN 0x00 /* gain setting (5:0) */
+#define OV7610_REG_SAT 0x03 /* saturation */
+#define OV8610_REG_HUE 0x04 /* 04 reserved */
+#define OV7610_REG_CNT 0x05 /* Y contrast */
+#define OV7610_REG_BRT 0x06 /* Y brightness */
+#define OV7610_REG_COM_C 0x14 /* misc common regs */
+#define OV7610_REG_ID_HIGH 0x1c /* manufacturer ID MSB */
+#define OV7610_REG_ID_LOW 0x1d /* manufacturer ID LSB */
+#define OV7610_REG_COM_I 0x29 /* misc settings */
+
+/* OV7670 registers */
+#define OV7670_REG_GAIN 0x00 /* Gain lower 8 bits (rest in vref) */
+#define OV7670_REG_BLUE 0x01 /* blue gain */
+#define OV7670_REG_RED 0x02 /* red gain */
+#define OV7670_REG_VREF 0x03 /* Pieces of GAIN, VSTART, VSTOP */
+#define OV7670_REG_COM1 0x04 /* Control 1 */
+#define OV7670_REG_AECHH 0x07 /* AEC MS 5 bits */
+#define OV7670_REG_COM3 0x0c /* Control 3 */
+#define OV7670_REG_COM4 0x0d /* Control 4 */
+#define OV7670_REG_COM5 0x0e /* All "reserved" */
+#define OV7670_REG_COM6 0x0f /* Control 6 */
+#define OV7670_REG_AECH 0x10 /* More bits of AEC value */
+#define OV7670_REG_CLKRC 0x11 /* Clock control */
+#define OV7670_REG_COM7 0x12 /* Control 7 */
+#define OV7670_COM7_FMT_VGA 0x00
+#define OV7670_COM7_YUV 0x00 /* YUV */
+#define OV7670_COM7_FMT_QVGA 0x10 /* QVGA format */
+#define OV7670_COM7_FMT_MASK 0x38
+#define OV7670_COM7_RESET 0x80 /* Register reset */
+#define OV7670_REG_COM8 0x13 /* Control 8 */
+#define OV7670_COM8_AEC 0x01 /* Auto exposure enable */
+#define OV7670_COM8_AWB 0x02 /* White balance enable */
+#define OV7670_COM8_AGC 0x04 /* Auto gain enable */
+#define OV7670_COM8_BFILT 0x20 /* Band filter enable */
+#define OV7670_COM8_AECSTEP 0x40 /* Unlimited AEC step size */
+#define OV7670_COM8_FASTAEC 0x80 /* Enable fast AGC/AEC */
+#define OV7670_REG_COM9 0x14 /* Control 9 - gain ceiling */
+#define OV7670_REG_COM10 0x15 /* Control 10 */
+#define OV7670_REG_HSTART 0x17 /* Horiz start high bits */
+#define OV7670_REG_HSTOP 0x18 /* Horiz stop high bits */
+#define OV7670_REG_VSTART 0x19 /* Vert start high bits */
+#define OV7670_REG_VSTOP 0x1a /* Vert stop high bits */
+#define OV7670_REG_MVFP 0x1e /* Mirror / vflip */
+#define OV7670_MVFP_MIRROR 0x20 /* Mirror image */
+#define OV7670_REG_AEW 0x24 /* AGC upper limit */
+#define OV7670_REG_AEB 0x25 /* AGC lower limit */
+#define OV7670_REG_VPT 0x26 /* AGC/AEC fast mode op region */
+#define OV7670_REG_HREF 0x32 /* HREF pieces */
+#define OV7670_REG_TSLB 0x3a /* lots of stuff */
+#define OV7670_REG_COM11 0x3b /* Control 11 */
+#define OV7670_COM11_EXP 0x02
+#define OV7670_COM11_HZAUTO 0x10 /* Auto detect 50/60 Hz */
+#define OV7670_REG_COM12 0x3c /* Control 12 */
+#define OV7670_REG_COM13 0x3d /* Control 13 */
+#define OV7670_COM13_GAMMA 0x80 /* Gamma enable */
+#define OV7670_COM13_UVSAT 0x40 /* UV saturation auto adjustment */
+#define OV7670_REG_COM14 0x3e /* Control 14 */
+#define OV7670_REG_EDGE 0x3f /* Edge enhancement factor */
+#define OV7670_REG_COM15 0x40 /* Control 15 */
+#define OV7670_COM15_R00FF 0xc0 /* 00 to FF */
+#define OV7670_REG_COM16 0x41 /* Control 16 */
+#define OV7670_COM16_AWBGAIN 0x08 /* AWB gain enable */
+#define OV7670_REG_BRIGHT 0x55 /* Brightness */
+#define OV7670_REG_CONTRAS 0x56 /* Contrast control */
+#define OV7670_REG_GFIX 0x69 /* Fix gain control */
+#define OV7670_REG_RGB444 0x8c /* RGB 444 control */
+#define OV7670_REG_HAECC1 0x9f /* Hist AEC/AGC control 1 */
+#define OV7670_REG_HAECC2 0xa0 /* Hist AEC/AGC control 2 */
+#define OV7670_REG_BD50MAX 0xa5 /* 50hz banding step limit */
+#define OV7670_REG_HAECC3 0xa6 /* Hist AEC/AGC control 3 */
+#define OV7670_REG_HAECC4 0xa7 /* Hist AEC/AGC control 4 */
+#define OV7670_REG_HAECC5 0xa8 /* Hist AEC/AGC control 5 */
+#define OV7670_REG_HAECC6 0xa9 /* Hist AEC/AGC control 6 */
+#define OV7670_REG_HAECC7 0xaa /* Hist AEC/AGC control 7 */
+#define OV7670_REG_BD60MAX 0xab /* 60hz banding step limit */
+
+struct ovsensor_window {
+ short x;
+ short y;
+ short width;
+ short height;
+/* int format; */
+ short quarter; /* Scale width and height down 2x */
+ short clockdiv; /* Clock divisor setting */
+};
+
+static unsigned char ov7670_abs_to_sm(unsigned char v)
+{
+ if (v > 127)
+ return v & 0x7f;
+ return (128 - v) | 0x80;
+}
+
+/* Write a OV519 register */
+static int reg_w(struct sd *sd, __u16 index, __u8 value)
+{
+ int ret;
+ __u8 data;
+
+ data = value;
+ ret = usb_control_msg(sd->gspca_dev.dev,
+ usb_sndctrlpipe(sd->gspca_dev.dev, 0),
+ 1, /* REQ_IO (ov518/519) */
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, index,
+ &data, 1, 500);
+ if (ret < 0)
+ PDEBUG(D_ERR, "Write reg [%02x] %02x failed", index, value);
+ return ret;
+}
+
+/* Read from a OV519 register */
+/* returns: negative is error, pos or zero is data */
+static int reg_r(struct sd *sd, __u16 index)
+{
+ int ret;
+ __u8 data;
+
+ ret = usb_control_msg(sd->gspca_dev.dev,
+ usb_rcvctrlpipe(sd->gspca_dev.dev, 0),
+ 1, /* REQ_IO */
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, index, &data, 1, 500);
+
+ if (ret >= 0)
+ ret = data;
+ else
+ PDEBUG(D_ERR, "Read reg [0x%02x] failed", index);
+ return ret;
+}
+
+/* Read 8 values from a OV519 register */
+static int reg_r8(struct sd *sd,
+ __u16 index)
+{
+ int ret;
+ __u8 buf[8];
+
+ ret = usb_control_msg(sd->gspca_dev.dev,
+ usb_rcvctrlpipe(sd->gspca_dev.dev, 0),
+ 1, /* REQ_IO */
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, index, &buf[0], 8, 500);
+
+ if (ret >= 0)
+ ret = buf[0];
+ else
+ PDEBUG(D_ERR, "Read reg 8 [0x%02x] failed", index);
+ return ret;
+}
+
+/*
+ * Writes bits at positions specified by mask to an OV51x reg. Bits that are in
+ * the same position as 1's in "mask" are cleared and set to "value". Bits
+ * that are in the same position as 0's in "mask" are preserved, regardless
+ * of their respective state in "value".
+ */
+static int reg_w_mask(struct sd *sd,
+ __u16 index,
+ __u8 value,
+ __u8 mask)
+{
+ int ret;
+ __u8 oldval;
+
+ if (mask != 0xff) {
+ value &= mask; /* Enforce mask on value */
+ ret = reg_r(sd, index);
+ if (ret < 0)
+ return ret;
+
+ oldval = ret & ~mask; /* Clear the masked bits */
+ value |= oldval; /* Set the desired bits */
+ }
+ return reg_w(sd, index, value);
+}
+
+/*
+ * The OV518 I2C I/O procedure is different, hence, this function.
+ * This is normally only called from i2c_w(). Note that this function
+ * always succeeds regardless of whether the sensor is present and working.
+ */
+static int i2c_w(struct sd *sd,
+ __u8 reg,
+ __u8 value)
+{
+ int rc;
+
+ PDEBUG(D_USBO, "i2c 0x%02x -> [0x%02x]", value, reg);
+
+ /* Select camera register */
+ rc = reg_w(sd, R51x_I2C_SADDR_3, reg);
+ if (rc < 0)
+ return rc;
+
+ /* Write "value" to I2C data port of OV511 */
+ rc = reg_w(sd, R51x_I2C_DATA, value);
+ if (rc < 0)
+ return rc;
+
+ /* Initiate 3-byte write cycle */
+ rc = reg_w(sd, R518_I2C_CTL, 0x01);
+
+ /* wait for write complete */
+ msleep(4);
+ if (rc < 0)
+ return rc;
+ return reg_r8(sd, R518_I2C_CTL);
+}
+
+/*
+ * returns: negative is error, pos or zero is data
+ *
+ * The OV518 I2C I/O procedure is different, hence, this function.
+ * This is normally only called from i2c_r(). Note that this function
+ * always succeeds regardless of whether the sensor is present and working.
+ */
+static int i2c_r(struct sd *sd, __u8 reg)
+{
+ int rc, value;
+
+ /* Select camera register */
+ rc = reg_w(sd, R51x_I2C_SADDR_2, reg);
+ if (rc < 0)
+ return rc;
+
+ /* Initiate 2-byte write cycle */
+ rc = reg_w(sd, R518_I2C_CTL, 0x03);
+ if (rc < 0)
+ return rc;
+
+ /* Initiate 2-byte read cycle */
+ rc = reg_w(sd, R518_I2C_CTL, 0x05);
+ if (rc < 0)
+ return rc;
+ value = reg_r(sd, R51x_I2C_DATA);
+ PDEBUG(D_USBI, "i2c [0x%02X] -> 0x%02X", reg, value);
+ return value;
+}
+
+/* Writes bits at positions specified by mask to an I2C reg. Bits that are in
+ * the same position as 1's in "mask" are cleared and set to "value". Bits
+ * that are in the same position as 0's in "mask" are preserved, regardless
+ * of their respective state in "value".
+ */
+static int i2c_w_mask(struct sd *sd,
+ __u8 reg,
+ __u8 value,
+ __u8 mask)
+{
+ int rc;
+ __u8 oldval;
+
+ value &= mask; /* Enforce mask on value */
+ rc = i2c_r(sd, reg);
+ if (rc < 0)
+ return rc;
+ oldval = rc & ~mask; /* Clear the masked bits */
+ value |= oldval; /* Set the desired bits */
+ return i2c_w(sd, reg, value);
+}
+
+/* Temporarily stops OV511 from functioning. Must do this before changing
+ * registers while the camera is streaming */
+static inline int ov51x_stop(struct sd *sd)
+{
+ PDEBUG(D_STREAM, "stopping");
+ sd->stopped = 1;
+ return reg_w(sd, OV519_SYS_RESET1, 0x0f);
+}
+
+/* Restarts OV511 after ov511_stop() is called. Has no effect if it is not
+ * actually stopped (for performance). */
+static inline int ov51x_restart(struct sd *sd)
+{
+ PDEBUG(D_STREAM, "restarting");
+ if (!sd->stopped)
+ return 0;
+ sd->stopped = 0;
+
+ /* Reinitialize the stream */
+ return reg_w(sd, OV519_SYS_RESET1, 0x00);
+}
+
+/* This does an initial reset of an OmniVision sensor and ensures that I2C
+ * is synchronized. Returns <0 on failure.
+ */
+static int init_ov_sensor(struct sd *sd)
+{
+ int i, success;
+
+ /* Reset the sensor */
+ if (i2c_w(sd, 0x12, 0x80) < 0)
+ return -EIO;
+
+ /* Wait for it to initialize */
+ msleep(150);
+
+ for (i = 0, success = 0; i < i2c_detect_tries && !success; i++) {
+ if (i2c_r(sd, OV7610_REG_ID_HIGH) == 0x7f &&
+ i2c_r(sd, OV7610_REG_ID_LOW) == 0xa2) {
+ success = 1;
+ continue;
+ }
+
+ /* Reset the sensor */
+ if (i2c_w(sd, 0x12, 0x80) < 0)
+ return -EIO;
+ /* Wait for it to initialize */
+ msleep(150);
+ /* Dummy read to sync I2C */
+ if (i2c_r(sd, 0x00) < 0)
+ return -EIO;
+ }
+ if (!success)
+ return -EIO;
+ PDEBUG(D_PROBE, "I2C synced in %d attempt(s)", i);
+ return 0;
+}
+
+/* Switch on standard JPEG compression. Returns 0 for success. */
+static int ov519_init_compression(struct sd *sd)
+{
+ if (!sd->compress_inited) {
+ if (reg_w_mask(sd, OV519_SYS_EN_CLK1, 1 << 2, 1 << 2) < 0) {
+ PDEBUG(D_ERR, "Error switching to compressed mode");
+ return -EIO;
+ }
+ sd->compress_inited = 1;
+ }
+ return 0;
+}
+
+/* Set the read and write slave IDs. The "slave" argument is the write slave,
+ * and the read slave will be set to (slave + 1).
+ * This should not be called from outside the i2c I/O functions.
+ * Sets I2C read and write slave IDs. Returns <0 for error
+ */
+static int ov51x_set_slave_ids(struct sd *sd,
+ __u8 slave)
+{
+ int rc;
+
+ rc = reg_w(sd, R51x_I2C_W_SID, slave);
+ if (rc < 0)
+ return rc;
+ return reg_w(sd, R51x_I2C_R_SID, slave + 1);
+}
+
+struct ov_regvals {
+ __u8 reg;
+ __u8 val;
+};
+struct ov_i2c_regvals {
+ __u8 reg;
+ __u8 val;
+};
+
+static int write_regvals(struct sd *sd,
+ const struct ov_regvals *regvals,
+ int n)
+{
+ int rc;
+
+ while (--n >= 0) {
+ rc = reg_w(sd, regvals->reg, regvals->val);
+ if (rc < 0)
+ return rc;
+ regvals++;
+ }
+ return 0;
+}
+
+static int write_i2c_regvals(struct sd *sd,
+ const struct ov_i2c_regvals *regvals,
+ int n)
+{
+ int rc;
+
+ while (--n >= 0) {
+ rc = i2c_w(sd, regvals->reg, regvals->val);
+ if (rc < 0)
+ return rc;
+ regvals++;
+ }
+ return 0;
+}
+
+/****************************************************************************
+ *
+ * OV511 and sensor configuration
+ *
+ ***************************************************************************/
+
+/* This initializes the OV8110, OV8610 sensor. The OV8110 uses
+ * the same register settings as the OV8610, since they are very similar.
+ */
+static int ov8xx0_configure(struct sd *sd)
+{
+ int rc;
+ static const struct ov_i2c_regvals norm_8610[] = {
+ { 0x12, 0x80 },
+ { 0x00, 0x00 },
+ { 0x01, 0x80 },
+ { 0x02, 0x80 },
+ { 0x03, 0xc0 },
+ { 0x04, 0x30 },
+ { 0x05, 0x30 }, /* was 0x10, new from windrv 090403 */
+ { 0x06, 0x70 }, /* was 0x80, new from windrv 090403 */
+ { 0x0a, 0x86 },
+ { 0x0b, 0xb0 },
+ { 0x0c, 0x20 },
+ { 0x0d, 0x20 },
+ { 0x11, 0x01 },
+ { 0x12, 0x25 },
+ { 0x13, 0x01 },
+ { 0x14, 0x04 },
+ { 0x15, 0x01 }, /* Lin and Win think different about UV order */
+ { 0x16, 0x03 },
+ { 0x17, 0x38 }, /* was 0x2f, new from windrv 090403 */
+ { 0x18, 0xea }, /* was 0xcf, new from windrv 090403 */
+ { 0x19, 0x02 }, /* was 0x06, new from windrv 090403 */
+ { 0x1a, 0xf5 },
+ { 0x1b, 0x00 },
+ { 0x20, 0xd0 }, /* was 0x90, new from windrv 090403 */
+ { 0x23, 0xc0 }, /* was 0x00, new from windrv 090403 */
+ { 0x24, 0x30 }, /* was 0x1d, new from windrv 090403 */
+ { 0x25, 0x50 }, /* was 0x57, new from windrv 090403 */
+ { 0x26, 0xa2 },
+ { 0x27, 0xea },
+ { 0x28, 0x00 },
+ { 0x29, 0x00 },
+ { 0x2a, 0x80 },
+ { 0x2b, 0xc8 }, /* was 0xcc, new from windrv 090403 */
+ { 0x2c, 0xac },
+ { 0x2d, 0x45 }, /* was 0xd5, new from windrv 090403 */
+ { 0x2e, 0x80 },
+ { 0x2f, 0x14 }, /* was 0x01, new from windrv 090403 */
+ { 0x4c, 0x00 },
+ { 0x4d, 0x30 }, /* was 0x10, new from windrv 090403 */
+ { 0x60, 0x02 }, /* was 0x01, new from windrv 090403 */
+ { 0x61, 0x00 }, /* was 0x09, new from windrv 090403 */
+ { 0x62, 0x5f }, /* was 0xd7, new from windrv 090403 */
+ { 0x63, 0xff },
+ { 0x64, 0x53 }, /* new windrv 090403 says 0x57,
+ * maybe thats wrong */
+ { 0x65, 0x00 },
+ { 0x66, 0x55 },
+ { 0x67, 0xb0 },
+ { 0x68, 0xc0 }, /* was 0xaf, new from windrv 090403 */
+ { 0x69, 0x02 },
+ { 0x6a, 0x22 },
+ { 0x6b, 0x00 },
+ { 0x6c, 0x99 }, /* was 0x80, old windrv says 0x00, but
+ deleting bit7 colors the first images red */
+ { 0x6d, 0x11 }, /* was 0x00, new from windrv 090403 */
+ { 0x6e, 0x11 }, /* was 0x00, new from windrv 090403 */
+ { 0x6f, 0x01 },
+ { 0x70, 0x8b },
+ { 0x71, 0x00 },
+ { 0x72, 0x14 },
+ { 0x73, 0x54 },
+ { 0x74, 0x00 },/* 0x60? - was 0x00, new from windrv 090403 */
+ { 0x75, 0x0e },
+ { 0x76, 0x02 }, /* was 0x02, new from windrv 090403 */
+ { 0x77, 0xff },
+ { 0x78, 0x80 },
+ { 0x79, 0x80 },
+ { 0x7a, 0x80 },
+ { 0x7b, 0x10 }, /* was 0x13, new from windrv 090403 */
+ { 0x7c, 0x00 },
+ { 0x7d, 0x08 }, /* was 0x09, new from windrv 090403 */
+ { 0x7e, 0x08 }, /* was 0xc0, new from windrv 090403 */
+ { 0x7f, 0xfb },
+ { 0x80, 0x28 },
+ { 0x81, 0x00 },
+ { 0x82, 0x23 },
+ { 0x83, 0x0b },
+ { 0x84, 0x00 },
+ { 0x85, 0x62 }, /* was 0x61, new from windrv 090403 */
+ { 0x86, 0xc9 },
+ { 0x87, 0x00 },
+ { 0x88, 0x00 },
+ { 0x89, 0x01 },
+ { 0x12, 0x20 },
+ { 0x12, 0x25 }, /* was 0x24, new from windrv 090403 */
+ };
+
+ PDEBUG(D_PROBE, "starting ov8xx0 configuration");
+
+ if (init_ov_sensor(sd) < 0)
+ PDEBUG(D_ERR|D_PROBE, "Failed to read sensor ID");
+ else
+ PDEBUG(D_PROBE, "OV86x0 initialized");
+
+ /* Detect sensor (sub)type */
+ rc = i2c_r(sd, OV7610_REG_COM_I);
+ if (rc < 0) {
+ PDEBUG(D_ERR, "Error detecting sensor type");
+ return -1;
+ }
+ if ((rc & 3) == 1) {
+ PDEBUG(D_PROBE, "Sensor is an OV8610");
+ sd->sensor = SEN_OV8610;
+ } else {
+ PDEBUG(D_ERR, "Unknown image sensor version: %d", rc & 3);
+ return -1;
+ }
+ PDEBUG(D_PROBE, "Writing 8610 registers");
+ if (write_i2c_regvals(sd,
+ norm_8610,
+ sizeof norm_8610 / sizeof norm_8610[0]))
+ return -1;
+
+ /* Set sensor-specific vars */
+ sd->maxwidth = 640;
+ sd->maxheight = 480;
+ return 0;
+}
+
+/* This initializes the OV7610, OV7620, or OV76BE sensor. The OV76BE uses
+ * the same register settings as the OV7610, since they are very similar.
+ */
+static int ov7xx0_configure(struct sd *sd)
+{
+ int rc, high, low;
+
+ /* Lawrence Glaister <lg@jfm.bc.ca> reports:
+ *
+ * Register 0x0f in the 7610 has the following effects:
+ *
+ * 0x85 (AEC method 1): Best overall, good contrast range
+ * 0x45 (AEC method 2): Very overexposed
+ * 0xa5 (spec sheet default): Ok, but the black level is
+ * shifted resulting in loss of contrast
+ * 0x05 (old driver setting): very overexposed, too much
+ * contrast
+ */
+ static const struct ov_i2c_regvals norm_7610[] = {
+ { 0x10, 0xff },
+ { 0x16, 0x06 },
+ { 0x28, 0x24 },
+ { 0x2b, 0xac },
+ { 0x12, 0x00 },
+ { 0x38, 0x81 },
+ { 0x28, 0x24 }, /* 0c */
+ { 0x0f, 0x85 }, /* lg's setting */
+ { 0x15, 0x01 },
+ { 0x20, 0x1c },
+ { 0x23, 0x2a },
+ { 0x24, 0x10 },
+ { 0x25, 0x8a },
+ { 0x26, 0xa2 },
+ { 0x27, 0xc2 },
+ { 0x2a, 0x04 },
+ { 0x2c, 0xfe },
+ { 0x2d, 0x93 },
+ { 0x30, 0x71 },
+ { 0x31, 0x60 },
+ { 0x32, 0x26 },
+ { 0x33, 0x20 },
+ { 0x34, 0x48 },
+ { 0x12, 0x24 },
+ { 0x11, 0x01 },
+ { 0x0c, 0x24 },
+ { 0x0d, 0x24 },
+ };
+
+ static const struct ov_i2c_regvals norm_7620[] = {
+ { 0x00, 0x00 }, /* gain */
+ { 0x01, 0x80 }, /* blue gain */
+ { 0x02, 0x80 }, /* red gain */
+ { 0x03, 0xc0 }, /* OV7670_REG_VREF */
+ { 0x06, 0x60 },
+ { 0x07, 0x00 },
+ { 0x0c, 0x24 },
+ { 0x0c, 0x24 },
+ { 0x0d, 0x24 },
+ { 0x11, 0x01 },
+ { 0x12, 0x24 },
+ { 0x13, 0x01 },
+ { 0x14, 0x84 },
+ { 0x15, 0x01 },
+ { 0x16, 0x03 },
+ { 0x17, 0x2f },
+ { 0x18, 0xcf },
+ { 0x19, 0x06 },
+ { 0x1a, 0xf5 },
+ { 0x1b, 0x00 },
+ { 0x20, 0x18 },
+ { 0x21, 0x80 },
+ { 0x22, 0x80 },
+ { 0x23, 0x00 },
+ { 0x26, 0xa2 },
+ { 0x27, 0xea },
+ { 0x28, 0x20 },
+ { 0x29, 0x00 },
+ { 0x2a, 0x10 },
+ { 0x2b, 0x00 },
+ { 0x2c, 0x88 },
+ { 0x2d, 0x91 },
+ { 0x2e, 0x80 },
+ { 0x2f, 0x44 },
+ { 0x60, 0x27 },
+ { 0x61, 0x02 },
+ { 0x62, 0x5f },
+ { 0x63, 0xd5 },
+ { 0x64, 0x57 },
+ { 0x65, 0x83 },
+ { 0x66, 0x55 },
+ { 0x67, 0x92 },
+ { 0x68, 0xcf },
+ { 0x69, 0x76 },
+ { 0x6a, 0x22 },
+ { 0x6b, 0x00 },
+ { 0x6c, 0x02 },
+ { 0x6d, 0x44 },
+ { 0x6e, 0x80 },
+ { 0x6f, 0x1d },
+ { 0x70, 0x8b },
+ { 0x71, 0x00 },
+ { 0x72, 0x14 },
+ { 0x73, 0x54 },
+ { 0x74, 0x00 },
+ { 0x75, 0x8e },
+ { 0x76, 0x00 },
+ { 0x77, 0xff },
+ { 0x78, 0x80 },
+ { 0x79, 0x80 },
+ { 0x7a, 0x80 },
+ { 0x7b, 0xe2 },
+ { 0x7c, 0x00 },
+ };
+
+ /* 7640 and 7648. The defaults should be OK for most registers. */
+ static const struct ov_i2c_regvals norm_7640[] = {
+ { 0x12, 0x80 },
+ { 0x12, 0x14 },
+ };
+
+ /* 7670. Defaults taken from OmniVision provided data,
+ * as provided by Jonathan Corbet of OLPC */
+ static const struct ov_i2c_regvals norm_7670[] = {
+ { OV7670_REG_COM7, OV7670_COM7_RESET },
+ { OV7670_REG_TSLB, 0x04 }, /* OV */
+ { OV7670_REG_COM7, OV7670_COM7_FMT_VGA }, /* VGA */
+ { OV7670_REG_CLKRC, 0x1 },
+ /*
+ * Set the hardware window. These values from OV don't entirely
+ * make sense - hstop is less than hstart. But they work...
+ */
+ { OV7670_REG_HSTART, 0x13 }, { OV7670_REG_HSTOP, 0x01 },
+ { OV7670_REG_HREF, 0xb6 }, { OV7670_REG_VSTART, 0x02 },
+ { OV7670_REG_VSTOP, 0x7a }, { OV7670_REG_VREF, 0x0a },
+
+ { OV7670_REG_COM3, 0 }, { OV7670_REG_COM14, 0 },
+ /* Mystery scaling numbers */
+ { 0x70, 0x3a }, { 0x71, 0x35 },
+ { 0x72, 0x11 }, { 0x73, 0xf0 },
+ { 0xa2, 0x02 },
+/* jfm */
+/* { OV7670_REG_COM10, 0x0 }, */
+
+ /* Gamma curve values */
+ { 0x7a, 0x20 },
+/* jfm:win 7b=1c */
+ { 0x7b, 0x10 },
+/* jfm:win 7c=28 */
+ { 0x7c, 0x1e },
+/* jfm:win 7d=3c */
+ { 0x7d, 0x35 },
+ { 0x7e, 0x5a }, { 0x7f, 0x69 },
+ { 0x80, 0x76 }, { 0x81, 0x80 },
+ { 0x82, 0x88 }, { 0x83, 0x8f },
+ { 0x84, 0x96 }, { 0x85, 0xa3 },
+ { 0x86, 0xaf }, { 0x87, 0xc4 },
+ { 0x88, 0xd7 }, { 0x89, 0xe8 },
+
+ /* AGC and AEC parameters. Note we start by disabling those features,
+ then turn them only after tweaking the values. */
+ { OV7670_REG_COM8, OV7670_COM8_FASTAEC
+ | OV7670_COM8_AECSTEP
+ | OV7670_COM8_BFILT },
+ { OV7670_REG_GAIN, 0 }, { OV7670_REG_AECH, 0 },
+ { OV7670_REG_COM4, 0x40 }, /* magic reserved bit */
+/* jfm:win 14=38 */
+ { OV7670_REG_COM9, 0x18 }, /* 4x gain + magic rsvd bit */
+ { OV7670_REG_BD50MAX, 0x05 }, { OV7670_REG_BD60MAX, 0x07 },
+ { OV7670_REG_AEW, 0x95 }, { OV7670_REG_AEB, 0x33 },
+ { OV7670_REG_VPT, 0xe3 }, { OV7670_REG_HAECC1, 0x78 },
+ { OV7670_REG_HAECC2, 0x68 },
+/* jfm:win a1=0b */
+ { 0xa1, 0x03 }, /* magic */
+ { OV7670_REG_HAECC3, 0xd8 }, { OV7670_REG_HAECC4, 0xd8 },
+ { OV7670_REG_HAECC5, 0xf0 }, { OV7670_REG_HAECC6, 0x90 },
+ { OV7670_REG_HAECC7, 0x94 },
+ { OV7670_REG_COM8, OV7670_COM8_FASTAEC
+ | OV7670_COM8_AECSTEP
+ | OV7670_COM8_BFILT
+ | OV7670_COM8_AGC
+ | OV7670_COM8_AEC },
+
+ /* Almost all of these are magic "reserved" values. */
+ { OV7670_REG_COM5, 0x61 }, { OV7670_REG_COM6, 0x4b },
+ { 0x16, 0x02 },
+/* jfm */
+/* { OV7670_REG_MVFP, 0x07|OV7670_MVFP_MIRROR }, */
+ { OV7670_REG_MVFP, 0x07 },
+ { 0x21, 0x02 }, { 0x22, 0x91 },
+ { 0x29, 0x07 }, { 0x33, 0x0b },
+ { 0x35, 0x0b }, { 0x37, 0x1d },
+ { 0x38, 0x71 }, { 0x39, 0x2a },
+ { OV7670_REG_COM12, 0x78 }, { 0x4d, 0x40 },
+ { 0x4e, 0x20 }, { OV7670_REG_GFIX, 0 },
+ { 0x6b, 0x4a }, { 0x74, 0x10 },
+ { 0x8d, 0x4f }, { 0x8e, 0 },
+ { 0x8f, 0 }, { 0x90, 0 },
+ { 0x91, 0 }, { 0x96, 0 },
+ { 0x9a, 0 }, { 0xb0, 0x84 },
+ { 0xb1, 0x0c }, { 0xb2, 0x0e },
+ { 0xb3, 0x82 }, { 0xb8, 0x0a },
+
+ /* More reserved magic, some of which tweaks white balance */
+ { 0x43, 0x0a }, { 0x44, 0xf0 },
+ { 0x45, 0x34 }, { 0x46, 0x58 },
+ { 0x47, 0x28 }, { 0x48, 0x3a },
+ { 0x59, 0x88 }, { 0x5a, 0x88 },
+ { 0x5b, 0x44 }, { 0x5c, 0x67 },
+ { 0x5d, 0x49 }, { 0x5e, 0x0e },
+ { 0x6c, 0x0a }, { 0x6d, 0x55 },
+ { 0x6e, 0x11 }, { 0x6f, 0x9f },
+ /* "9e for advance AWB" */
+ { 0x6a, 0x40 }, { OV7670_REG_BLUE, 0x40 },
+ { OV7670_REG_RED, 0x60 },
+ { OV7670_REG_COM8, OV7670_COM8_FASTAEC
+ | OV7670_COM8_AECSTEP
+ | OV7670_COM8_BFILT
+ | OV7670_COM8_AGC
+ | OV7670_COM8_AEC
+ | OV7670_COM8_AWB },
+
+ /* Matrix coefficients */
+ { 0x4f, 0x80 }, { 0x50, 0x80 },
+ { 0x51, 0 }, { 0x52, 0x22 },
+ { 0x53, 0x5e }, { 0x54, 0x80 },
+ { 0x58, 0x9e },
+
+ { OV7670_REG_COM16, OV7670_COM16_AWBGAIN },
+ { OV7670_REG_EDGE, 0 },
+ { 0x75, 0x05 }, { 0x76, 0xe1 },
+ { 0x4c, 0 }, { 0x77, 0x01 },
+ { OV7670_REG_COM13, 0xc3 }, { 0x4b, 0x09 },
+ { 0xc9, 0x60 }, { OV7670_REG_COM16, 0x38 },
+ { 0x56, 0x40 },
+
+ { 0x34, 0x11 },
+ { OV7670_REG_COM11, OV7670_COM11_EXP|OV7670_COM11_HZAUTO },
+ { 0xa4, 0x88 }, { 0x96, 0 },
+ { 0x97, 0x30 }, { 0x98, 0x20 },
+ { 0x99, 0x30 }, { 0x9a, 0x84 },
+ { 0x9b, 0x29 }, { 0x9c, 0x03 },
+ { 0x9d, 0x4c }, { 0x9e, 0x3f },
+ { 0x78, 0x04 },
+
+ /* Extra-weird stuff. Some sort of multiplexor register */
+ { 0x79, 0x01 }, { 0xc8, 0xf0 },
+ { 0x79, 0x0f }, { 0xc8, 0x00 },
+ { 0x79, 0x10 }, { 0xc8, 0x7e },
+ { 0x79, 0x0a }, { 0xc8, 0x80 },
+ { 0x79, 0x0b }, { 0xc8, 0x01 },
+ { 0x79, 0x0c }, { 0xc8, 0x0f },
+ { 0x79, 0x0d }, { 0xc8, 0x20 },
+ { 0x79, 0x09 }, { 0xc8, 0x80 },
+ { 0x79, 0x02 }, { 0xc8, 0xc0 },
+ { 0x79, 0x03 }, { 0xc8, 0x40 },
+ { 0x79, 0x05 }, { 0xc8, 0x30 },
+ { 0x79, 0x26 },
+
+ /* Format YUV422 */
+ { OV7670_REG_COM7, OV7670_COM7_YUV }, /* Selects YUV mode */
+ { OV7670_REG_RGB444, 0 }, /* No RGB444 please */
+ { OV7670_REG_COM1, 0 },
+ { OV7670_REG_COM15, OV7670_COM15_R00FF },
+ { OV7670_REG_COM9, 0x18 },
+ /* 4x gain ceiling; 0x8 is reserved bit */
+ { 0x4f, 0x80 }, /* "matrix coefficient 1" */
+ { 0x50, 0x80 }, /* "matrix coefficient 2" */
+ { 0x52, 0x22 }, /* "matrix coefficient 4" */
+ { 0x53, 0x5e }, /* "matrix coefficient 5" */
+ { 0x54, 0x80 }, /* "matrix coefficient 6" */
+ { OV7670_REG_COM13, OV7670_COM13_GAMMA|OV7670_COM13_UVSAT },
+};
+
+ PDEBUG(D_PROBE, "starting OV7xx0 configuration");
+
+/* jfm:already done? */
+ if (init_ov_sensor(sd) < 0)
+ PDEBUG(D_ERR, "Failed to read sensor ID");
+ else
+ PDEBUG(D_PROBE, "OV7xx0 initialized");
+
+ /* Detect sensor (sub)type */
+ rc = i2c_r(sd, OV7610_REG_COM_I);
+
+ /* add OV7670 here
+ * it appears to be wrongly detected as a 7610 by default */
+ if (rc < 0) {
+ PDEBUG(D_ERR, "Error detecting sensor type");
+ return -1;
+ }
+ if ((rc & 3) == 3) {
+ /* quick hack to make OV7670s work */
+ high = i2c_r(sd, 0x0a);
+ low = i2c_r(sd, 0x0b);
+ /* info("%x, %x", high, low); */
+ if (high == 0x76 && low == 0x73) {
+ PDEBUG(D_PROBE, "Sensor is an OV7670");
+ sd->sensor = SEN_OV7670;
+ } else {
+ PDEBUG(D_PROBE, "Sensor is an OV7610");
+ sd->sensor = SEN_OV7610;
+ }
+ } else if ((rc & 3) == 1) {
+ /* I don't know what's different about the 76BE yet. */
+ if (i2c_r(sd, 0x15) & 1)
+ PDEBUG(D_PROBE, "Sensor is an OV7620AE");
+ else
+ PDEBUG(D_PROBE, "Sensor is an OV76BE");
+
+ /* OV511+ will return all zero isoc data unless we
+ * configure the sensor as a 7620. Someone needs to
+ * find the exact reg. setting that causes this. */
+ sd->sensor = SEN_OV76BE;
+ } else if ((rc & 3) == 0) {
+ /* try to read product id registers */
+ high = i2c_r(sd, 0x0a);
+ if (high < 0) {
+ PDEBUG(D_ERR, "Error detecting camera chip PID");
+ return high;
+ }
+ low = i2c_r(sd, 0x0b);
+ if (low < 0) {
+ PDEBUG(D_ERR, "Error detecting camera chip VER");
+ return low;
+ }
+ if (high == 0x76) {
+ if (low == 0x30) {
+ PDEBUG(D_PROBE, "Sensor is an OV7630/OV7635");
+ sd->sensor = SEN_OV7630;
+ } else if (low == 0x40) {
+ PDEBUG(D_PROBE, "Sensor is an OV7645");
+ sd->sensor = SEN_OV7640; /* FIXME */
+ } else if (low == 0x45) {
+ PDEBUG(D_PROBE, "Sensor is an OV7645B");
+ sd->sensor = SEN_OV7640; /* FIXME */
+ } else if (low == 0x48) {
+ PDEBUG(D_PROBE, "Sensor is an OV7648");
+ sd->sensor = SEN_OV7640; /* FIXME */
+ } else {
+ PDEBUG(D_PROBE, "Unknown sensor: 0x76%X", low);
+ return -1;
+ }
+ } else {
+ PDEBUG(D_PROBE, "Sensor is an OV7620");
+ sd->sensor = SEN_OV7620;
+ }
+ } else {
+ PDEBUG(D_ERR, "Unknown image sensor version: %d", rc & 3);
+ return -1;
+ }
+
+ if (sd->sensor == SEN_OV7620) {
+ PDEBUG(D_PROBE, "Writing 7620 registers");
+ if (write_i2c_regvals(sd, norm_7620,
+ sizeof norm_7620 / sizeof norm_7620[0]))
+ return -1;
+ } else if (sd->sensor == SEN_OV7630) {
+ PDEBUG(D_ERR, "7630 is not supported by this driver version");
+ return -1;
+ } else if (sd->sensor == SEN_OV7640) {
+ PDEBUG(D_PROBE, "Writing 7640 registers");
+ if (write_i2c_regvals(sd, norm_7640,
+ sizeof norm_7640 / sizeof norm_7640[0]))
+ return -1;
+ } else if (sd->sensor == SEN_OV7670) {
+ PDEBUG(D_PROBE, "Writing 7670 registers");
+ if (write_i2c_regvals(sd, norm_7670,
+ sizeof norm_7670 / sizeof norm_7670[0]))
+ return -1;
+ } else {
+ PDEBUG(D_PROBE, "Writing 7610 registers");
+ if (write_i2c_regvals(sd, norm_7610,
+ sizeof norm_7610 / sizeof norm_7610[0]))
+ return -1;
+ }
+
+ /* Set sensor-specific vars */
+ sd->maxwidth = 640;
+ sd->maxheight = 480;
+ return 0;
+}
+
+/* This initializes the OV6620, OV6630, OV6630AE, or OV6630AF sensor. */
+static int ov6xx0_configure(struct sd *sd)
+{
+ int rc;
+ static const struct ov_i2c_regvals norm_6x20[] = {
+ { 0x12, 0x80 }, /* reset */
+ { 0x11, 0x01 },
+ { 0x03, 0x60 },
+ { 0x05, 0x7f }, /* For when autoadjust is off */
+ { 0x07, 0xa8 },
+ /* The ratio of 0x0c and 0x0d controls the white point */
+ { 0x0c, 0x24 },
+ { 0x0d, 0x24 },
+ { 0x0f, 0x15 }, /* COMS */
+ { 0x10, 0x75 }, /* AEC Exposure time */
+ { 0x12, 0x24 }, /* Enable AGC */
+ { 0x14, 0x04 },
+ /* 0x16: 0x06 helps frame stability with moving objects */
+ { 0x16, 0x06 },
+/* { 0x20, 0x30 }, * Aperture correction enable */
+ { 0x26, 0xb2 }, /* BLC enable */
+ /* 0x28: 0x05 Selects RGB format if RGB on */
+ { 0x28, 0x05 },
+ { 0x2a, 0x04 }, /* Disable framerate adjust */
+/* { 0x2b, 0xac }, * Framerate; Set 2a[7] first */
+ { 0x2d, 0x99 },
+ { 0x33, 0xa0 }, /* Color Processing Parameter */
+ { 0x34, 0xd2 }, /* Max A/D range */
+ { 0x38, 0x8b },
+ { 0x39, 0x40 },
+
+ { 0x3c, 0x39 }, /* Enable AEC mode changing */
+ { 0x3c, 0x3c }, /* Change AEC mode */
+ { 0x3c, 0x24 }, /* Disable AEC mode changing */
+
+ { 0x3d, 0x80 },
+ /* These next two registers (0x4a, 0x4b) are undocumented.
+ * They control the color balance */
+ { 0x4a, 0x80 },
+ { 0x4b, 0x80 },
+ { 0x4d, 0xd2 }, /* This reduces noise a bit */
+ { 0x4e, 0xc1 },
+ { 0x4f, 0x04 },
+/* Do 50-53 have any effect? */
+/* Toggle 0x12[2] off and on here? */
+ };
+
+ static const struct ov_i2c_regvals norm_6x30[] = {
+ { 0x12, 0x80 }, /* Reset */
+ { 0x00, 0x1f }, /* Gain */
+ { 0x01, 0x99 }, /* Blue gain */
+ { 0x02, 0x7c }, /* Red gain */
+ { 0x03, 0xc0 }, /* Saturation */
+ { 0x05, 0x0a }, /* Contrast */
+ { 0x06, 0x95 }, /* Brightness */
+ { 0x07, 0x2d }, /* Sharpness */
+ { 0x0c, 0x20 },
+ { 0x0d, 0x20 },
+ { 0x0e, 0x20 },
+ { 0x0f, 0x05 },
+ { 0x10, 0x9a },
+ { 0x11, 0x00 }, /* Pixel clock = fastest */
+ { 0x12, 0x24 }, /* Enable AGC and AWB */
+ { 0x13, 0x21 },
+ { 0x14, 0x80 },
+ { 0x15, 0x01 },
+ { 0x16, 0x03 },
+ { 0x17, 0x38 },
+ { 0x18, 0xea },
+ { 0x19, 0x04 },
+ { 0x1a, 0x93 },
+ { 0x1b, 0x00 },
+ { 0x1e, 0xc4 },
+ { 0x1f, 0x04 },
+ { 0x20, 0x20 },
+ { 0x21, 0x10 },
+ { 0x22, 0x88 },
+ { 0x23, 0xc0 }, /* Crystal circuit power level */
+ { 0x25, 0x9a }, /* Increase AEC black ratio */
+ { 0x26, 0xb2 }, /* BLC enable */
+ { 0x27, 0xa2 },
+ { 0x28, 0x00 },
+ { 0x29, 0x00 },
+ { 0x2a, 0x84 }, /* 60 Hz power */
+ { 0x2b, 0xa8 }, /* 60 Hz power */
+ { 0x2c, 0xa0 },
+ { 0x2d, 0x95 }, /* Enable auto-brightness */
+ { 0x2e, 0x88 },
+ { 0x33, 0x26 },
+ { 0x34, 0x03 },
+ { 0x36, 0x8f },
+ { 0x37, 0x80 },
+ { 0x38, 0x83 },
+ { 0x39, 0x80 },
+ { 0x3a, 0x0f },
+ { 0x3b, 0x3c },
+ { 0x3c, 0x1a },
+ { 0x3d, 0x80 },
+ { 0x3e, 0x80 },
+ { 0x3f, 0x0e },
+ { 0x40, 0x00 }, /* White bal */
+ { 0x41, 0x00 }, /* White bal */
+ { 0x42, 0x80 },
+ { 0x43, 0x3f }, /* White bal */
+ { 0x44, 0x80 },
+ { 0x45, 0x20 },
+ { 0x46, 0x20 },
+ { 0x47, 0x80 },
+ { 0x48, 0x7f },
+ { 0x49, 0x00 },
+ { 0x4a, 0x00 },
+ { 0x4b, 0x80 },
+ { 0x4c, 0xd0 },
+ { 0x4d, 0x10 }, /* U = 0.563u, V = 0.714v */
+ { 0x4e, 0x40 },
+ { 0x4f, 0x07 }, /* UV avg., col. killer: max */
+ { 0x50, 0xff },
+ { 0x54, 0x23 }, /* Max AGC gain: 18dB */
+ { 0x55, 0xff },
+ { 0x56, 0x12 },
+ { 0x57, 0x81 },
+ { 0x58, 0x75 },
+ { 0x59, 0x01 }, /* AGC dark current comp.: +1 */
+ { 0x5a, 0x2c },
+ { 0x5b, 0x0f }, /* AWB chrominance levels */
+ { 0x5c, 0x10 },
+ { 0x3d, 0x80 },
+ { 0x27, 0xa6 },
+ { 0x12, 0x20 }, /* Toggle AWB */
+ { 0x12, 0x24 },
+ };
+
+ PDEBUG(D_PROBE, "starting sensor configuration");
+
+ if (init_ov_sensor(sd) < 0) {
+ PDEBUG(D_ERR, "Failed to read sensor ID.");
+ return -1;
+ }
+ PDEBUG(D_PROBE, "OV6xx0 sensor detected");
+
+ /* Detect sensor (sub)type */
+ rc = i2c_r(sd, OV7610_REG_COM_I);
+ if (rc < 0) {
+ PDEBUG(D_ERR, "Error detecting sensor type");
+ return -1;
+ }
+
+ /* Ugh. The first two bits are the version bits, but
+ * the entire register value must be used. I guess OVT
+ * underestimated how many variants they would make. */
+ if (rc == 0x00) {
+ sd->sensor = SEN_OV6630;
+ PDEBUG(D_ERR,
+ "WARNING: Sensor is an OV66308. Your camera may have");
+ PDEBUG(D_ERR, "been misdetected in previous driver versions.");
+ } else if (rc == 0x01) {
+ sd->sensor = SEN_OV6620;
+ PDEBUG(D_PROBE, "Sensor is an OV6620");
+ } else if (rc == 0x02) {
+ sd->sensor = SEN_OV6630;
+ PDEBUG(D_PROBE, "Sensor is an OV66308AE");
+ } else if (rc == 0x03) {
+ sd->sensor = SEN_OV6630;
+ PDEBUG(D_PROBE, "Sensor is an OV66308AF");
+ } else if (rc == 0x90) {
+ sd->sensor = SEN_OV6630;
+ PDEBUG(D_ERR,
+ "WARNING: Sensor is an OV66307. Your camera may have");
+ PDEBUG(D_ERR, "been misdetected in previous driver versions.");
+ } else {
+ PDEBUG(D_ERR, "FATAL: Unknown sensor version: 0x%02x", rc);
+ return -1;
+ }
+
+ /* Set sensor-specific vars */
+ sd->maxwidth = 352;
+ sd->maxheight = 288;
+
+ if (sd->sensor == SEN_OV6620) {
+ PDEBUG(D_PROBE, "Writing 6x20 registers");
+ if (write_i2c_regvals(sd, norm_6x20,
+ sizeof norm_6x20 / sizeof norm_6x20[0]))
+ return -1;
+ } else {
+ PDEBUG(D_PROBE, "Writing 6x30 registers");
+ if (write_i2c_regvals(sd, norm_6x30,
+ sizeof norm_6x30 / sizeof norm_6x30[0]))
+ return -1;
+ }
+ return 0;
+}
+
+/* Turns on or off the LED. Only has an effect with OV511+/OV518(+)/OV519 */
+static void ov51x_led_control(struct sd *sd, int on)
+{
+ PDEBUG(D_STREAM, "LED (%s)", on ? "on" : "off");
+
+/* if (sd->bridge == BRG_OV511PLUS) */
+/* reg_w(sd, R511_SYS_LED_CTL, on ? 1 : 0); */
+/* else if (sd->bridge == BRG_OV519) */
+ reg_w_mask(sd, OV519_GPIO_DATA_OUT0, !on, 1); /* 0 / 1 */
+/* else if (sd->bclass == BCL_OV518) */
+/* reg_w_mask(sd, R518_GPIO_OUT, on ? 0x02 : 0x00, 0x02); */
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+ const struct usb_device_id *id)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct cam *cam;
+
+/* (from ov519_configure) */
+ static const struct ov_regvals init_519[] = {
+ { 0x5a, 0x6d }, /* EnableSystem */
+/* jfm trace usbsnoop3-1.txt */
+/* jfm 53 = fb */
+ { 0x53, 0x9b },
+ { 0x54, 0xff }, /* set bit2 to enable jpeg */
+ { 0x5d, 0x03 },
+ { 0x49, 0x01 },
+ { 0x48, 0x00 },
+ /* Set LED pin to output mode. Bit 4 must be cleared or sensor
+ * detection will fail. This deserves further investigation. */
+ { OV519_GPIO_IO_CTRL0, 0xee },
+ { 0x51, 0x0f }, /* SetUsbInit */
+ { 0x51, 0x00 },
+ { 0x22, 0x00 },
+ /* windows reads 0x55 at this point*/
+ };
+
+ if (write_regvals(sd, init_519, ARRAY_SIZE(init_519)))
+ goto error;
+/* jfm: not seen in windows trace */
+ if (ov519_init_compression(sd))
+ goto error;
+ ov51x_led_control(sd, 0); /* turn LED off */
+
+ /* Test for 76xx */
+ sd->primary_i2c_slave = OV7xx0_SID;
+ if (ov51x_set_slave_ids(sd, OV7xx0_SID) < 0)
+ goto error;
+
+ /* The OV519 must be more aggressive about sensor detection since
+ * I2C write will never fail if the sensor is not present. We have
+ * to try to initialize the sensor to detect its presence */
+ if (init_ov_sensor(sd) < 0) {
+ /* Test for 6xx0 */
+ sd->primary_i2c_slave = OV6xx0_SID;
+ if (ov51x_set_slave_ids(sd, OV6xx0_SID) < 0)
+ goto error;
+
+ if (init_ov_sensor(sd) < 0) {
+ /* Test for 8xx0 */
+ sd->primary_i2c_slave = OV8xx0_SID;
+ if (ov51x_set_slave_ids(sd, OV8xx0_SID) < 0)
+ goto error;
+
+ if (init_ov_sensor(sd) < 0) {
+ PDEBUG(D_ERR,
+ "Can't determine sensor slave IDs");
+ goto error;
+ } else {
+ if (ov8xx0_configure(sd) < 0) {
+ PDEBUG(D_ERR,
+ "Failed to configure OV8xx0 sensor");
+ goto error;
+ }
+ }
+ } else {
+ if (ov6xx0_configure(sd) < 0) {
+ PDEBUG(D_ERR, "Failed to configure OV6xx0");
+ goto error;
+ }
+ }
+ } else {
+ if (ov7xx0_configure(sd) < 0) {
+ PDEBUG(D_ERR, "Failed to configure OV7xx0");
+ goto error;
+ }
+ }
+
+ cam = &gspca_dev->cam;
+ cam->epaddr = OV511_ENDPOINT_ADDRESS;
+ if (sd->maxwidth == 640) {
+ cam->cam_mode = vga_mode;
+ cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+ } else {
+ cam->cam_mode = sif_mode;
+ cam->nmodes = sizeof sif_mode / sizeof sif_mode[0];
+ }
+ cam->dev_name = (char *) id->driver_info;
+ sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
+ sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
+ sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value;
+ return 0;
+error:
+ PDEBUG(D_ERR, "OV519 Config failed");
+ return -EBUSY;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+ return 0;
+}
+
+/* Sets up the OV519 with the given image parameters
+ *
+ * OV519 needs a completely different approach, until we can figure out what
+ * the individual registers do.
+ *
+ * Do not put any sensor-specific code in here (including I2C I/O functions)
+ */
+static int ov519_mode_init_regs(struct sd *sd,
+ int width, int height)
+{
+ static const struct ov_regvals mode_init_519_ov7670[] = {
+ { 0x5d, 0x03 }, /* Turn off suspend mode */
+ { 0x53, 0x9f }, /* was 9b in 1.65-1.08 */
+ { 0x54, 0x0f }, /* bit2 (jpeg enable) */
+ { 0xa2, 0x20 }, /* a2-a5 are undocumented */
+ { 0xa3, 0x18 },
+ { 0xa4, 0x04 },
+ { 0xa5, 0x28 },
+ { 0x37, 0x00 }, /* SetUsbInit */
+ { 0x55, 0x02 }, /* 4.096 Mhz audio clock */
+ /* Enable both fields, YUV Input, disable defect comp (why?) */
+ { 0x20, 0x0c },
+ { 0x21, 0x38 },
+ { 0x22, 0x1d },
+ { 0x17, 0x50 }, /* undocumented */
+ { 0x37, 0x00 }, /* undocumented */
+ { 0x40, 0xff }, /* I2C timeout counter */
+ { 0x46, 0x00 }, /* I2C clock prescaler */
+ { 0x59, 0x04 }, /* new from windrv 090403 */
+ { 0xff, 0x00 }, /* undocumented */
+ /* windows reads 0x55 at this point, why? */
+ };
+
+ static const struct ov_regvals mode_init_519[] = {
+ { 0x5d, 0x03 }, /* Turn off suspend mode */
+ { 0x53, 0x9f }, /* was 9b in 1.65-1.08 */
+ { 0x54, 0x0f }, /* bit2 (jpeg enable) */
+ { 0xa2, 0x20 }, /* a2-a5 are undocumented */
+ { 0xa3, 0x18 },
+ { 0xa4, 0x04 },
+ { 0xa5, 0x28 },
+ { 0x37, 0x00 }, /* SetUsbInit */
+ { 0x55, 0x02 }, /* 4.096 Mhz audio clock */
+ /* Enable both fields, YUV Input, disable defect comp (why?) */
+ { 0x22, 0x1d },
+ { 0x17, 0x50 }, /* undocumented */
+ { 0x37, 0x00 }, /* undocumented */
+ { 0x40, 0xff }, /* I2C timeout counter */
+ { 0x46, 0x00 }, /* I2C clock prescaler */
+ { 0x59, 0x04 }, /* new from windrv 090403 */
+ { 0xff, 0x00 }, /* undocumented */
+ /* windows reads 0x55 at this point, why? */
+ };
+
+/* int hi_res; */
+
+ PDEBUG(D_CONF, "mode init %dx%d", width, height);
+
+/* if (width >= 800 && height >= 600)
+ hi_res = 1;
+ else
+ hi_res = 0; */
+
+/* if (ov51x_stop(sd) < 0)
+ return -EIO; */
+
+ /******** Set the mode ********/
+ if (sd->sensor != SEN_OV7670) {
+ if (write_regvals(sd, mode_init_519,
+ ARRAY_SIZE(mode_init_519)))
+ return -EIO;
+ } else {
+ if (write_regvals(sd, mode_init_519_ov7670,
+ ARRAY_SIZE(mode_init_519_ov7670)))
+ return -EIO;
+ }
+
+ if (sd->sensor == SEN_OV7640) {
+ /* Select 8-bit input mode */
+ reg_w_mask(sd, OV519_CAM_DFR, 0x10, 0x10);
+ }
+
+ reg_w(sd, OV519_CAM_H_SIZE, width >> 4);
+ reg_w(sd, OV519_CAM_V_SIZE, height >> 3);
+ reg_w(sd, OV519_CAM_X_OFFSETL, 0x00);
+ reg_w(sd, OV519_CAM_X_OFFSETH, 0x00);
+ reg_w(sd, OV519_CAM_Y_OFFSETL, 0x00);
+ reg_w(sd, OV519_CAM_Y_OFFSETH, 0x00);
+ reg_w(sd, OV519_CAM_DIVIDER, 0x00);
+ reg_w(sd, OV519_CAM_FORMAT, 0x03); /* YUV422 */
+ reg_w(sd, 0x26, 0x00); /* Undocumented */
+
+ /******** Set the framerate ********/
+ if (frame_rate > 0)
+ sd->frame_rate = frame_rate;
+
+/* FIXME: These are only valid at the max resolution. */
+ sd->clockdiv = 0;
+ if (sd->sensor == SEN_OV7640) {
+ switch (sd->frame_rate) {
+/*jfm: default was 30 fps */
+ case 30:
+ reg_w(sd, 0xa4, 0x0c);
+ reg_w(sd, 0x23, 0xff);
+ break;
+ case 25:
+ reg_w(sd, 0xa4, 0x0c);
+ reg_w(sd, 0x23, 0x1f);
+ break;
+ case 20:
+ reg_w(sd, 0xa4, 0x0c);
+ reg_w(sd, 0x23, 0x1b);
+ break;
+ default:
+/* case 15: */
+ reg_w(sd, 0xa4, 0x04);
+ reg_w(sd, 0x23, 0xff);
+ sd->clockdiv = 1;
+ break;
+ case 10:
+ reg_w(sd, 0xa4, 0x04);
+ reg_w(sd, 0x23, 0x1f);
+ sd->clockdiv = 1;
+ break;
+ case 5:
+ reg_w(sd, 0xa4, 0x04);
+ reg_w(sd, 0x23, 0x1b);
+ sd->clockdiv = 1;
+ break;
+ }
+ } else if (sd->sensor == SEN_OV8610) {
+ switch (sd->frame_rate) {
+ default: /* 15 fps */
+/* case 15: */
+ reg_w(sd, 0xa4, 0x06);
+ reg_w(sd, 0x23, 0xff);
+ break;
+ case 10:
+ reg_w(sd, 0xa4, 0x06);
+ reg_w(sd, 0x23, 0x1f);
+ break;
+ case 5:
+ reg_w(sd, 0xa4, 0x06);
+ reg_w(sd, 0x23, 0x1b);
+ break;
+ }
+ sd->clockdiv = 0;
+ } else if (sd->sensor == SEN_OV7670) { /* guesses, based on 7640 */
+ PDEBUG(D_STREAM, "Setting framerate to %d fps",
+ (sd->frame_rate == 0) ? 15 : sd->frame_rate);
+ switch (sd->frame_rate) {
+ case 30:
+ reg_w(sd, 0xa4, 0x10);
+ reg_w(sd, 0x23, 0xff);
+ break;
+ case 20:
+ reg_w(sd, 0xa4, 0x10);
+ reg_w(sd, 0x23, 0x1b);
+ break;
+ default: /* 15 fps */
+/* case 15: */
+ reg_w(sd, 0xa4, 0x10);
+ reg_w(sd, 0x23, 0xff);
+ sd->clockdiv = 1;
+ break;
+ }
+ }
+
+/* if (ov51x_restart(sd) < 0)
+ return -EIO; */
+
+ /* Reset it just for good measure */
+/* if (ov51x_reset(sd, OV511_RESET_NOREGS) < 0)
+ return -EIO; */
+ return 0;
+}
+
+static int mode_init_ov_sensor_regs(struct sd *sd,
+ struct ovsensor_window *win)
+{
+ int qvga = win->quarter;
+
+ /******** Mode (VGA/QVGA) and sensor specific regs ********/
+ switch (sd->sensor) {
+ case SEN_OV8610:
+ /* For OV8610 qvga means qsvga */
+ i2c_w_mask(sd, OV7610_REG_COM_C, qvga ? (1 << 5) : 0, 1 << 5);
+#if 0
+ /* FIXME: Does this improve the image quality or frame rate? */
+ i2c_w_mask(sd, 0x28, qvga ? 0x00 : 0x20, 0x20);
+ i2c_w(sd, 0x24, 0x10);
+ i2c_w(sd, 0x25, qvga ? 0x40 : 0x8a);
+ i2c_w(sd, 0x2f, qvga ? 0x30 : 0xb0);
+ i2c_w(sd, 0x35, qvga ? 0x1c : 0x9c);
+#endif
+ break;
+ case SEN_OV7610:
+ i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);
+#if 0
+ /* FIXME: Does this improve the image quality or frame rate? */
+ i2c_w_mask(sd, 0x28, qvga?0x00:0x20, 0x20);
+ i2c_w(sd, 0x24, 0x10);
+ i2c_w(sd, 0x25, qvga?0x40:0x8a);
+ i2c_w(sd, 0x2f, qvga?0x30:0xb0);
+ i2c_w(sd, 0x35, qvga?0x1c:0x9c);
+#endif
+ break;
+ case SEN_OV7620:
+/* i2c_w(sd, 0x2b, 0x00); */
+ i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);
+ i2c_w_mask(sd, 0x28, qvga ? 0x00 : 0x20, 0x20);
+ i2c_w(sd, 0x24, qvga ? 0x20 : 0x3a);
+ i2c_w(sd, 0x25, qvga ? 0x30 : 0x60);
+ i2c_w_mask(sd, 0x2d, qvga ? 0x40 : 0x00, 0x40);
+ i2c_w_mask(sd, 0x67, qvga ? 0xf0 : 0x90, 0xf0);
+ i2c_w_mask(sd, 0x74, qvga ? 0x20 : 0x00, 0x20);
+ break;
+ case SEN_OV76BE:
+/* i2c_w(sd, 0x2b, 0x00); */
+ i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);
+#if 0
+ /* FIXME: Enable this once 7620AE uses 7620 initial settings */
+ i2c_w_mask(sd, 0x28, qvga ? 0x00 : 0x20, 0x20);
+ i2c_w(sd, 0x24, qvga ? 0x20 : 0x3a);
+ i2c_w(sd, 0x25, qvga ? 0x30 : 0x60);
+ i2c_w_mask(sd, 0x2d, qvga ? 0x40 : 0x00, 0x40);
+ i2c_w_mask(sd, 0x67, qvga ? 0xb0 : 0x90, 0xf0);
+ i2c_w_mask(sd, 0x74, qvga ? 0x20 : 0x00, 0x20);
+#endif
+ break;
+ case SEN_OV7640:
+/* i2c_w(sd, 0x2b, 0x00); */
+ i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);
+ i2c_w_mask(sd, 0x28, qvga ? 0x00 : 0x20, 0x20);
+/* i2c_w(sd, 0x24, qvga ? 0x20 : 0x3a); */
+/* i2c_w(sd, 0x25, qvga ? 0x30 : 0x60); */
+/* i2c_w_mask(sd, 0x2d, qvga ? 0x40 : 0x00, 0x40); */
+/* i2c_w_mask(sd, 0x67, qvga ? 0xf0 : 0x90, 0xf0); */
+/* i2c_w_mask(sd, 0x74, qvga ? 0x20 : 0x00, 0x20); */
+ break;
+ case SEN_OV7670:
+ /* set COM7_FMT_VGA or COM7_FMT_QVGA
+ * do we need to set anything else?
+ * HSTART etc are set in set_ov_sensor_window itself */
+ i2c_w_mask(sd, OV7670_REG_COM7,
+ qvga ? OV7670_COM7_FMT_QVGA : OV7670_COM7_FMT_VGA,
+ OV7670_COM7_FMT_MASK);
+ break;
+ case SEN_OV6620:
+ i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);
+ break;
+ case SEN_OV6630:
+ i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /******** Palette-specific regs ********/
+/* Need to do work here for the OV7670 */
+
+#if 0
+ if (win->format == VIDEO_PALETTE_GREY) {
+ if (sd->sensor == SEN_OV7610 || sd->sensor == SEN_OV76BE) {
+ /* these aren't valid on the OV6620/OV7620/6630? */
+ i2c_w_mask(sd, 0x0e, 0x40, 0x40);
+ }
+
+ /* OV6630 default reg 0x13 value is always right */
+ /* OV7640 is 8-bit only */
+ if (sd->sensor != SEN_OV6630 && sd->sensor != SEN_OV7640)
+ i2c_w_mask(sd, 0x13, 0x20, 0x20);
+ else
+ return -EINVAL; /* No OV6630 greyscale support yet */
+ } else {
+#endif
+ if (sd->sensor == SEN_OV7610 || sd->sensor == SEN_OV76BE) {
+ /* not valid on the OV6620/OV7620/6630? */
+ i2c_w_mask(sd, 0x0e, 0x00, 0x40);
+ }
+
+ /* The OV518 needs special treatment. Although both the OV518
+ * and the OV6630 support a 16-bit video bus, only the 8 bit Y
+ * bus is actually used. The UV bus is tied to ground.
+ * Therefore, the OV6630 needs to be in 8-bit multiplexed
+ * output mode */
+
+ /* OV7640 is 8-bit only */
+
+ if (sd->sensor != SEN_OV6630 && sd->sensor != SEN_OV7640)
+ i2c_w_mask(sd, 0x13, 0x00, 0x20);
+/* } */
+
+ /******** Clock programming ********/
+ /* The OV6620 needs special handling. This prevents the
+ * severe banding that normally occurs */
+ if (sd->sensor == SEN_OV6620) {
+
+ /* Clock down */
+ i2c_w(sd, 0x2a, 0x04);
+ i2c_w(sd, 0x11, win->clockdiv);
+ i2c_w(sd, 0x2a, 0x84);
+ /* This next setting is critical. It seems to improve
+ * the gain or the contrast. The "reserved" bits seem
+ * to have some effect in this case. */
+ i2c_w(sd, 0x2d, 0x85);
+ } else if (win->clockdiv >= 0) {
+ i2c_w(sd, 0x11, win->clockdiv);
+ }
+
+ /******** Special Features ********/
+#if 0
+/* not how OV7670 does it! */
+ if (framedrop >= 0 && sd->sensor != SEN_OV7640
+ && sd->sensor != SEN_OV7670)
+ i2c_w(sd, 0x16, framedrop);
+#endif
+/* no evidence this is possible with OV7670, either */
+ /* Test Pattern */
+ if (sd->sensor != SEN_OV7640 && sd->sensor != SEN_OV7670)
+ i2c_w_mask(sd, 0x12, 0x00, 0x02);
+
+ /* Enable auto white balance */
+ if (sd->sensor == SEN_OV7670)
+ i2c_w_mask(sd, OV7670_REG_COM8, OV7670_COM8_AWB,
+ OV7670_COM8_AWB);
+ else
+ i2c_w_mask(sd, 0x12, 0x04, 0x04);
+
+ /* This will go away as soon as ov51x_mode_init_sensor_regs() */
+ /* is fully tested. */
+ /* 7620/6620/6630? don't have register 0x35, so play it safe */
+ if (sd->sensor == SEN_OV7610 || sd->sensor == SEN_OV76BE) {
+ if (win->width == 640 /*&& win->height == 480*/)
+ i2c_w(sd, 0x35, 0x9e);
+ else
+ i2c_w(sd, 0x35, 0x1e);
+ }
+ return 0;
+}
+
+static int set_ov_sensor_window(struct sd *sd,
+ struct ovsensor_window *win)
+{
+ int hwsbase, hwebase, vwsbase, vwebase, hwscale, vwscale;
+ int ret, hstart, hstop, vstop, vstart;
+ __u8 v;
+
+ /* The different sensor ICs handle setting up of window differently.
+ * IF YOU SET IT WRONG, YOU WILL GET ALL ZERO ISOC DATA FROM OV51x!! */
+ switch (sd->sensor) {
+ case SEN_OV8610:
+ hwsbase = 0x1e;
+ hwebase = 0x1e;
+ vwsbase = 0x02;
+ vwebase = 0x02;
+ break;
+ case SEN_OV7610:
+ case SEN_OV76BE:
+ hwsbase = 0x38;
+ hwebase = 0x3a;
+ vwsbase = vwebase = 0x05;
+ break;
+ case SEN_OV6620:
+ case SEN_OV6630:
+ hwsbase = 0x38;
+ hwebase = 0x3a;
+ vwsbase = 0x05;
+ vwebase = 0x06;
+ break;
+ case SEN_OV7620:
+ hwsbase = 0x2f; /* From 7620.SET (spec is wrong) */
+ hwebase = 0x2f;
+ vwsbase = vwebase = 0x05;
+ break;
+ case SEN_OV7640:
+ hwsbase = 0x1a;
+ hwebase = 0x1a;
+ vwsbase = vwebase = 0x03;
+ break;
+ case SEN_OV7670:
+ /*handling of OV7670 hardware sensor start and stop values
+ * is very odd, compared to the other OV sensors */
+ vwsbase = vwebase = hwebase = hwsbase = 0x00;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (sd->sensor) {
+ case SEN_OV6620:
+ case SEN_OV6630:
+ if (win->quarter) { /* QCIF */
+ hwscale = 0;
+ vwscale = 0;
+ } else { /* CIF */
+ hwscale = 1;
+ vwscale = 1; /* The datasheet says 0;
+ * it's wrong */
+ }
+ break;
+ case SEN_OV8610:
+ if (win->quarter) { /* QSVGA */
+ hwscale = 1;
+ vwscale = 1;
+ } else { /* SVGA */
+ hwscale = 2;
+ vwscale = 2;
+ }
+ break;
+ default: /* SEN_OV7xx0 */
+ if (win->quarter) { /* QVGA */
+ hwscale = 1;
+ vwscale = 0;
+ } else { /* VGA */
+ hwscale = 2;
+ vwscale = 1;
+ }
+ }
+
+ ret = mode_init_ov_sensor_regs(sd, win);
+ if (ret < 0)
+ return ret;
+
+ if (sd->sensor == SEN_OV8610) {
+ i2c_w_mask(sd, 0x2d, 0x05, 0x40);
+ /* old 0x95, new 0x05 from windrv 090403 */
+ /* bits 5-7: reserved */
+ i2c_w_mask(sd, 0x28, 0x20, 0x20);
+ /* bit 5: progressive mode on */
+ }
+
+ /* The below is wrong for OV7670s because their window registers
+ * only store the high bits in 0x17 to 0x1a */
+
+ /* SRH Use sd->max values instead of requested win values */
+ /* SCS Since we're sticking with only the max hardware widths
+ * for a given mode */
+ /* I can hard code this for OV7670s */
+ /* Yes, these numbers do look odd, but they're tested and work! */
+ if (sd->sensor == SEN_OV7670) {
+ if (win->quarter) { /* QVGA from ov7670.c by
+ * Jonathan Corbet */
+ hstart = 164;
+ hstop = 20;
+ vstart = 14;
+ vstop = 494;
+ } else { /* VGA */
+ hstart = 158;
+ hstop = 14;
+ vstart = 10;
+ vstop = 490;
+ }
+ /* OV7670 hardware window registers are split across
+ * multiple locations */
+ i2c_w(sd, OV7670_REG_HSTART, (hstart >> 3) & 0xff);
+ i2c_w(sd, OV7670_REG_HSTOP, (hstop >> 3) & 0xff);
+ v = i2c_r(sd, OV7670_REG_HREF);
+ v = (v & 0xc0) | ((hstop & 0x7) << 3) | (hstart & 0x07);
+ msleep(10); /* need to sleep between read and write to
+ * same reg! */
+ i2c_w(sd, OV7670_REG_HREF, v);
+
+ i2c_w(sd, OV7670_REG_VSTART, (vstart >> 2) & 0xff);
+ i2c_w(sd, OV7670_REG_VSTOP, (vstop >> 2) & 0xff);
+ v = i2c_r(sd, OV7670_REG_VREF);
+ v = (v & 0xc0) | ((vstop & 0x3) << 2) | (vstart & 0x03);
+ msleep(10); /* need to sleep between read and write to
+ * same reg! */
+ i2c_w(sd, OV7670_REG_VREF, v);
+
+ } else {
+ i2c_w(sd, 0x17, hwsbase + (win->x >> hwscale));
+ i2c_w(sd, 0x18, hwebase + ((win->x + win->width) >> hwscale));
+ i2c_w(sd, 0x19, vwsbase + (win->y >> vwscale));
+ i2c_w(sd, 0x1a, vwebase + ((win->y + win->height) >> vwscale));
+ }
+ return 0;
+}
+
+static int ov_sensor_mode_setup(struct sd *sd,
+ int width, int height)
+{
+ struct ovsensor_window win;
+
+/* win.format = mode; */
+
+ /* Unless subcapture is enabled,
+ * center the image window and downsample
+ * if possible to increase the field of view */
+ /* NOTE: OV518(+) and OV519 does downsampling on its own */
+ win.width = width;
+ win.height = height;
+ if (width == sd->maxwidth)
+ win.quarter = 0;
+ else
+ win.quarter = 1;
+
+ /* Center it */
+ win.x = (win.width - width) / 2;
+ win.y = (win.height - height) / 2;
+
+ /* Clock is determined by OV519 frame rate code */
+ win.clockdiv = sd->clockdiv;
+
+ PDEBUG(D_CONF, "Setting clock divider to %d", win.clockdiv);
+ return set_ov_sensor_window(sd, &win);
+}
+
+/* -- start the camera -- */
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int ret;
+
+#if 0
+ ret = usb_set_interface(gspca_dev->dev,
+ gspca_dev->iface,
+ gspca_dev->alt);
+ if (ret < 0)
+ goto out;
+#endif
+
+ ret = ov519_mode_init_regs(sd, gspca_dev->width, gspca_dev->height);
+ if (ret < 0)
+ goto out;
+ ret = ov_sensor_mode_setup(sd, gspca_dev->width, gspca_dev->height);
+ if (ret < 0)
+ goto out;
+
+ ret = ov51x_restart((struct sd *) gspca_dev);
+ if (ret < 0)
+ goto out;
+ PDEBUG(D_STREAM, "camera started alt: 0x%02x", gspca_dev->alt);
+ ov51x_led_control(sd, 1);
+ return;
+out:
+ PDEBUG(D_ERR, "camera start error:%d", ret);
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+ ov51x_stop((struct sd *) gspca_dev);
+ ov51x_led_control((struct sd *) gspca_dev, 0);
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ struct gspca_frame *frame, /* target */
+ __u8 *data, /* isoc packet */
+ int len) /* iso packet length */
+{
+ /* Header of ov519 is 16 bytes:
+ * Byte Value Description
+ * 0 0xff magic
+ * 1 0xff magic
+ * 2 0xff magic
+ * 3 0xXX 0x50 = SOF, 0x51 = EOF
+ * 9 0xXX 0x01 initial frame without data,
+ * 0x00 standard frame with image
+ * 14 Lo in EOF: length of image data / 8
+ * 15 Hi
+ */
+
+ if (data[0] == 0xff && data[1] == 0xff && data[2] == 0xff) {
+ switch (data[3]) {
+ case 0x50: /* start of frame */
+#define HDRSZ 16
+ data += HDRSZ;
+ len -= HDRSZ;
+#undef HDRSZ
+ if (data[0] == 0xff || data[1] == 0xd8)
+ gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+ data, len);
+ else
+ gspca_dev->last_packet_type = DISCARD_PACKET;
+ return;
+ case 0x51: /* end of frame */
+ if (data[9] != 0)
+ gspca_dev->last_packet_type = DISCARD_PACKET;
+ gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+ data, 0);
+ return;
+ }
+ }
+
+ /* intermediate packet */
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+ data, len);
+}
+
+/* -- management routines -- */
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int val;
+/* int was_streaming; */
+
+ val = sd->brightness;
+ PDEBUG(D_CONF, "brightness:%d", val);
+/* was_streaming = gspca_dev->streaming;
+ * if (was_streaming)
+ * ov51x_stop(sd); */
+ switch (sd->sensor) {
+ case SEN_OV8610:
+ case SEN_OV7610:
+ case SEN_OV76BE:
+ case SEN_OV6620:
+ case SEN_OV6630:
+ case SEN_OV7640:
+ i2c_w(sd, OV7610_REG_BRT, val);
+ break;
+ case SEN_OV7620:
+ /* 7620 doesn't like manual changes when in auto mode */
+/*fixme
+ * if (!sd->auto_brt) */
+ i2c_w(sd, OV7610_REG_BRT, val);
+ break;
+ case SEN_OV7670:
+/*jfm - from windblows
+ * i2c_w_mask(sd, OV7670_REG_COM8, 0, OV7670_COM8_AEC); */
+ i2c_w(sd, OV7670_REG_BRIGHT, ov7670_abs_to_sm(val));
+ break;
+ }
+/* if (was_streaming)
+ * ov51x_restart(sd); */
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int val;
+/* int was_streaming; */
+
+ val = sd->contrast;
+ PDEBUG(D_CONF, "contrast:%d", val);
+/* was_streaming = gspca_dev->streaming;
+ if (was_streaming)
+ ov51x_stop(sd); */
+ switch (sd->sensor) {
+ case SEN_OV7610:
+ case SEN_OV6620:
+ i2c_w(sd, OV7610_REG_CNT, val);
+ break;
+ case SEN_OV6630:
+ i2c_w_mask(sd, OV7610_REG_CNT, val >> 4, 0x0f);
+ case SEN_OV8610: {
+ static const __u8 ctab[] = {
+ 0x03, 0x09, 0x0b, 0x0f, 0x53, 0x6f, 0x35, 0x7f
+ };
+
+ /* Use Y gamma control instead. Bit 0 enables it. */
+ i2c_w(sd, 0x64, ctab[val >> 5]);
+ break;
+ }
+ case SEN_OV7620: {
+ static const __u8 ctab[] = {
+ 0x01, 0x05, 0x09, 0x11, 0x15, 0x35, 0x37, 0x57,
+ 0x5b, 0xa5, 0xa7, 0xc7, 0xc9, 0xcf, 0xef, 0xff
+ };
+
+ /* Use Y gamma control instead. Bit 0 enables it. */
+ i2c_w(sd, 0x64, ctab[val >> 4]);
+ break;
+ }
+ case SEN_OV7640:
+ /* Use gain control instead. */
+ i2c_w(sd, OV7610_REG_GAIN, val >> 2);
+ break;
+ case SEN_OV7670:
+ /* check that this isn't just the same as ov7610 */
+ i2c_w(sd, OV7670_REG_CONTRAS, val >> 1);
+ break;
+ }
+/* if (was_streaming)
+ ov51x_restart(sd); */
+}
+
+static void setcolors(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int val;
+/* int was_streaming; */
+
+ val = sd->colors;
+ PDEBUG(D_CONF, "saturation:%d", val);
+/* was_streaming = gspca_dev->streaming;
+ if (was_streaming)
+ ov51x_stop(sd); */
+ switch (sd->sensor) {
+ case SEN_OV8610:
+ case SEN_OV7610:
+ case SEN_OV76BE:
+ case SEN_OV6620:
+ case SEN_OV6630:
+ i2c_w(sd, OV7610_REG_SAT, val);
+ break;
+ case SEN_OV7620:
+ /* Use UV gamma control instead. Bits 0 & 7 are reserved. */
+/* rc = ov_i2c_write(sd->dev, 0x62, (val >> 9) & 0x7e);
+ if (rc < 0)
+ goto out; */
+ i2c_w(sd, OV7610_REG_SAT, val);
+ break;
+ case SEN_OV7640:
+ i2c_w(sd, OV7610_REG_SAT, val & 0xf0);
+ break;
+ case SEN_OV7670:
+ /* supported later once I work out how to do it
+ * transparently fail now! */
+ /* set REG_COM13 values for UV sat auto mode */
+ break;
+ }
+/* if (was_streaming)
+ ov51x_restart(sd); */
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->brightness = val;
+ setbrightness(gspca_dev);
+ return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->brightness;
+ return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->contrast = val;
+ setcontrast(gspca_dev);
+ return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->contrast;
+ return 0;
+}
+
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->colors = val;
+ setcolors(gspca_dev);
+ return 0;
+}
+
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->colors;
+ return 0;
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .ctrls = sd_ctrls,
+ .nctrls = ARRAY_SIZE(sd_ctrls),
+ .config = sd_config,
+ .open = sd_open,
+ .start = sd_start,
+ .stopN = sd_stopN,
+ .stop0 = sd_stop0,
+ .close = sd_close,
+ .pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static const __devinitdata struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x041e, 0x4052), DVNM("Creative Live! VISTA IM")},
+ {USB_DEVICE(0x041e, 0x405f), DVNM("Creative Live! VISTA VF0330")},
+ {USB_DEVICE(0x041e, 0x4060), DVNM("Creative Live! VISTA VF0350")},
+ {USB_DEVICE(0x041e, 0x4061), DVNM("Creative Live! VISTA VF0400")},
+ {USB_DEVICE(0x041e, 0x4064), DVNM("Creative Live! VISTA VF0420")},
+ {USB_DEVICE(0x041e, 0x4068), DVNM("Creative Live! VISTA VF0470")},
+ {USB_DEVICE(0x045e, 0x028c), DVNM("Microsoft xbox cam")},
+ {USB_DEVICE(0x054c, 0x0154), DVNM("Sonny toy4")},
+ {USB_DEVICE(0x054c, 0x0155), DVNM("Sonny toy5")},
+ {USB_DEVICE(0x05a9, 0x0519), DVNM("OmniVision")},
+ {USB_DEVICE(0x05a9, 0x0530), DVNM("OmniVision")},
+ {USB_DEVICE(0x05a9, 0x4519), DVNM("OmniVision")},
+ {USB_DEVICE(0x05a9, 0x8519), DVNM("OmniVision")},
+ {}
+};
+#undef DVNAME
+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,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+ if (usb_register(&sd_driver) < 0)
+ return -1;
+ PDEBUG(D_PROBE, "v%s registered", version);
+ return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+ usb_deregister(&sd_driver);
+ PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
+
+module_param(frame_rate, int, 0644);
+MODULE_PARM_DESC(frame_rate, "Frame rate (5, 10, 15, 20 or 30 fps)");
+
diff --git a/linux/drivers/media/video/gspca/pac207.c b/linux/drivers/media/video/gspca/pac207.c
new file mode 100644
index 000000000..4f197c1f4
--- /dev/null
+++ b/linux/drivers/media/video/gspca/pac207.c
@@ -0,0 +1,681 @@
+/*
+ * Pixart PAC207BCA library
+ *
+ * Copyright (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl>
+ * Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li
+ * Copyleft (C) 2005 Michel Xhaard mxhaard@magic.fr
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#define MODULE_NAME "pac207"
+
+#include "gspca.h"
+
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 5)
+static const char version[] = "2.1.5";
+
+MODULE_AUTHOR("Hans de Goede <j.w.r.degoede@hhs.nl>");
+MODULE_DESCRIPTION("Pixart PAC207");
+MODULE_LICENSE("GPL");
+
+#define PAC207_CTRL_TIMEOUT 100 /* ms */
+
+#define PAC207_BRIGHTNESS_MIN 0
+#define PAC207_BRIGHTNESS_MAX 255
+#define PAC207_BRIGHTNESS_DEFAULT 4 /* power on default: 4 */
+
+/* An exposure value of 4 also works (3 does not) but then we need to lower
+ the compression balance setting when in 352x288 mode, otherwise the usb
+ bandwidth is not enough and packets get dropped resulting in corrupt
+ frames. The problem with this is that when the compression balance gets
+ lowered below 0x80, the pac207 starts using a different compression
+ algorithm for some lines, these lines get prefixed with a 0x2dd2 prefix
+ and currently we do not know how to decompress these lines, so for now
+ we use a minimum exposure value of 5 */
+#define PAC207_EXPOSURE_MIN 5
+#define PAC207_EXPOSURE_MAX 26
+#define PAC207_EXPOSURE_DEFAULT 5 /* power on default: 3 ?? */
+#define PAC207_EXPOSURE_KNEE 11 /* 4 = 30 fps, 11 = 8, 15 = 6 */
+
+#define PAC207_GAIN_MIN 0
+#define PAC207_GAIN_MAX 31
+#define PAC207_GAIN_DEFAULT 9 /* power on default: 9 */
+#define PAC207_GAIN_KNEE 20
+
+#define PAC207_AUTOGAIN_DEADZONE 30
+/* We calculating the autogain at the end of the transfer of a frame, at this
+ moment a frame with the old settings is being transmitted, and a frame is
+ being captured with the old settings. So if we adjust the autogain we must
+ ignore atleast the 2 next frames for the new settings to come into effect
+ before doing any other adjustments */
+#define PAC207_AUTOGAIN_IGNORE_FRAMES 3
+
+/* specific webcam descriptor */
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+
+ u8 mode;
+
+ u8 brightness;
+ u8 exposure;
+ u8 autogain;
+ u8 gain;
+
+ u8 sof_read;
+ u8 header_read;
+ u8 autogain_ignore_frames;
+
+ atomic_t avg_lum;
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+#define SD_BRIGHTNESS 0
+ {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = PAC207_BRIGHTNESS_MIN,
+ .maximum = PAC207_BRIGHTNESS_MAX,
+ .step = 1,
+ .default_value = PAC207_BRIGHTNESS_DEFAULT,
+ .flags = 0,
+ },
+ .set = sd_setbrightness,
+ .get = sd_getbrightness,
+ },
+#define SD_EXPOSURE 1
+ {
+ {
+ .id = V4L2_CID_EXPOSURE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "exposure",
+ .minimum = PAC207_EXPOSURE_MIN,
+ .maximum = PAC207_EXPOSURE_MAX,
+ .step = 1,
+ .default_value = PAC207_EXPOSURE_DEFAULT,
+ .flags = 0,
+ },
+ .set = sd_setexposure,
+ .get = sd_getexposure,
+ },
+#define SD_AUTOGAIN 2
+ {
+ {
+ .id = V4L2_CID_AUTOGAIN,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Auto Gain",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 1,
+ .flags = 0,
+ },
+ .set = sd_setautogain,
+ .get = sd_getautogain,
+ },
+#define SD_GAIN 3
+ {
+ {
+ .id = V4L2_CID_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "gain",
+ .minimum = PAC207_GAIN_MIN,
+ .maximum = PAC207_GAIN_MAX,
+ .step = 1,
+ .default_value = PAC207_GAIN_DEFAULT,
+ .flags = 0,
+ },
+ .set = sd_setgain,
+ .get = sd_getgain,
+ },
+};
+
+static struct v4l2_pix_format sif_mode[] = {
+ {176, 144, V4L2_PIX_FMT_PAC207, V4L2_FIELD_NONE,
+ .bytesperline = 176,
+ .sizeimage = (176 + 2) * 144,
+ /* uncompressed, add 2 bytes / line for line header */
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 1},
+ {352, 288, V4L2_PIX_FMT_PAC207, V4L2_FIELD_NONE,
+ .bytesperline = 352,
+ /* compressed, but only when needed (not compressed
+ when the framerate is low) */
+ .sizeimage = (352 + 2) * 288,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0},
+};
+
+static const __u8 pac207_sensor_init[][8] = {
+ {0x10, 0x12, 0x0d, 0x12, 0x0c, 0x01, 0x29, 0xf0},
+ {0x00, 0x64, 0x64, 0x64, 0x04, 0x10, 0xf0, 0x30},
+ {0x00, 0x00, 0x00, 0x70, 0xa0, 0xf8, 0x00, 0x00},
+ {0x00, 0x00, 0x32, 0x00, 0x96, 0x00, 0xa2, 0x02},
+ {0x32, 0x00, 0x96, 0x00, 0xA2, 0x02, 0xaf, 0x00},
+};
+
+ /* 48 reg_72 Rate Control end BalSize_4a =0x36 */
+static const __u8 PacReg72[] = { 0x00, 0x00, 0x36, 0x00 };
+
+static const unsigned char pac207_sof_marker[5] =
+ { 0xff, 0xff, 0x00, 0xff, 0x96 };
+
+int pac207_write_regs(struct gspca_dev *gspca_dev, u16 index,
+ const u8 *buffer, u16 length)
+{
+ struct usb_device *udev = gspca_dev->dev;
+ int err;
+ u8 kbuf[8];
+
+ memcpy(kbuf, buffer, length);
+
+ err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x01,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+ 0x00, index, kbuf, length, PAC207_CTRL_TIMEOUT);
+ if (err < 0)
+ PDEBUG(D_ERR,
+ "Failed to write registers to index 0x%04X, error %d)",
+ index, err);
+
+ return err;
+}
+
+
+int pac207_write_reg(struct gspca_dev *gspca_dev, u16 index, u16 value)
+{
+ struct usb_device *udev = gspca_dev->dev;
+ int err;
+
+ err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+ value, index, NULL, 0, PAC207_CTRL_TIMEOUT);
+ if (err)
+ PDEBUG(D_ERR, "Failed to write a register (index 0x%04X,"
+ " value 0x%02X, error %d)", index, value, err);
+
+ return err;
+}
+
+
+int pac207_read_reg(struct gspca_dev *gspca_dev, u16 index)
+{
+ struct usb_device *udev = gspca_dev->dev;
+ u8 buff;
+ int res;
+
+ res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+ 0x00, index, &buff, 1, PAC207_CTRL_TIMEOUT);
+ if (res < 0) {
+ PDEBUG(D_ERR,
+ "Failed to read a register (index 0x%04X, error %d)",
+ index, res);
+ return res;
+ }
+
+ return buff;
+}
+
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+ const struct usb_device_id *id)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct cam *cam;
+ u8 idreg[2];
+
+ idreg[0] = pac207_read_reg(gspca_dev, 0x0000);
+ idreg[1] = pac207_read_reg(gspca_dev, 0x0001);
+ idreg[0] = ((idreg[0] & 0x0F) << 4) | ((idreg[1] & 0xf0) >> 4);
+ idreg[1] = idreg[1] & 0x0f;
+ PDEBUG(D_PROBE, "Pixart Sensor ID 0x%02X Chips ID 0x%02X",
+ idreg[0], idreg[1]);
+
+ if (idreg[0] != 0x27) {
+ PDEBUG(D_PROBE, "Error invalid sensor ID!");
+ return -ENODEV;
+ }
+
+ pac207_write_reg(gspca_dev, 0x41, 0x00);
+ /* Bit_0=Image Format,
+ * Bit_1=LED,
+ * Bit_2=Compression test mode enable */
+ pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */
+ pac207_write_reg(gspca_dev, 0x11, 0x30); /* Analog Bias */
+
+ PDEBUG(D_PROBE,
+ "Pixart PAC207BCA Image Processor and Control Chip detected"
+ " (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
+
+ cam = &gspca_dev->cam;
+ cam->dev_name = (char *) id->driver_info;
+ cam->epaddr = 0x05;
+ cam->cam_mode = sif_mode;
+ cam->nmodes = ARRAY_SIZE(sif_mode);
+ sd->brightness = PAC207_BRIGHTNESS_DEFAULT;
+ sd->exposure = PAC207_EXPOSURE_DEFAULT;
+ sd->gain = PAC207_GAIN_DEFAULT;
+
+ return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->autogain = 1;
+ return 0;
+}
+
+/* -- start the camera -- */
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ __u8 mode;
+
+ pac207_write_reg(gspca_dev, 0x0f, 0x10); /* Power control (Bit 6-0) */
+ pac207_write_regs(gspca_dev, 0x0002, pac207_sensor_init[0], 8);
+ pac207_write_regs(gspca_dev, 0x000a, pac207_sensor_init[1], 8);
+ pac207_write_regs(gspca_dev, 0x0012, pac207_sensor_init[2], 8);
+ pac207_write_regs(gspca_dev, 0x0040, pac207_sensor_init[3], 8);
+ pac207_write_regs(gspca_dev, 0x0042, pac207_sensor_init[4], 8);
+ pac207_write_regs(gspca_dev, 0x0048, PacReg72, 4);
+
+ /* Compression Balance */
+ if (gspca_dev->width == 176)
+ pac207_write_reg(gspca_dev, 0x4a, 0xff);
+ else
+ pac207_write_reg(gspca_dev, 0x4a, 0x88);
+ pac207_write_reg(gspca_dev, 0x4b, 0x00); /* Sram test value */
+ pac207_write_reg(gspca_dev, 0x08, sd->brightness);
+
+ /* PGA global gain (Bit 4-0) */
+ pac207_write_reg(gspca_dev, 0x0e, sd->gain);
+ pac207_write_reg(gspca_dev, 0x02, sd->exposure); /* PXCK = 12MHz /n */
+
+ mode = 0x02; /* Image Format (Bit 0), LED (1), Compr. test mode (2) */
+ if (gspca_dev->width == 176) { /* 176x144 */
+ mode |= 0x01;
+ PDEBUG(D_STREAM, "pac207_start mode 176x144");
+ } else { /* 352x288 */
+ PDEBUG(D_STREAM, "pac207_start mode 352x288");
+ }
+ pac207_write_reg(gspca_dev, 0x41, mode);
+
+ pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */
+ pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */
+ msleep(10);
+ pac207_write_reg(gspca_dev, 0x40, 0x01); /* Start ISO pipe */
+
+ sd->sof_read = 0;
+ sd->autogain_ignore_frames = 0;
+ atomic_set(&sd->avg_lum, -1);
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+ pac207_write_reg(gspca_dev, 0x40, 0x00); /* Stop ISO pipe */
+ pac207_write_reg(gspca_dev, 0x41, 0x00); /* Turn of LED */
+ pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+/* this function is called at close time */
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+/* auto gain and exposure algorithm based on the knee algorithm described here:
+ * <http://ytse.tricolour.net/docs/LowLightOptimization.html> */
+static void pac207_do_auto_gain(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int i, steps, desired_avg_lum;
+ int orig_gain = sd->gain;
+ int orig_exposure = sd->exposure;
+ int avg_lum = atomic_read(&sd->avg_lum);
+
+ if (!sd->autogain || avg_lum == -1)
+ return;
+
+ if (sd->autogain_ignore_frames > 0) {
+ sd->autogain_ignore_frames--;
+ return;
+ }
+
+ /* correct desired lumination for the configured brightness */
+ desired_avg_lum = 100 + sd->brightness / 2;
+
+ /* If we are of a multiple of deadzone, do multiple step to reach the
+ desired lumination fast (with the risc of a slight overshoot) */
+ steps = abs(desired_avg_lum - avg_lum) / PAC207_AUTOGAIN_DEADZONE;
+
+ for (i = 0; i < steps; i++) {
+ if (avg_lum > desired_avg_lum) {
+ if (sd->gain > PAC207_GAIN_KNEE)
+ sd->gain--;
+ else if (sd->exposure > PAC207_EXPOSURE_KNEE)
+ sd->exposure--;
+ else if (sd->gain > PAC207_GAIN_DEFAULT)
+ sd->gain--;
+ else if (sd->exposure > PAC207_EXPOSURE_MIN)
+ sd->exposure--;
+ else if (sd->gain > PAC207_GAIN_MIN)
+ sd->gain--;
+ else
+ break;
+ } else {
+ if (sd->gain < PAC207_GAIN_DEFAULT)
+ sd->gain++;
+ else if (sd->exposure < PAC207_EXPOSURE_KNEE)
+ sd->exposure++;
+ else if (sd->gain < PAC207_GAIN_KNEE)
+ sd->gain++;
+ else if (sd->exposure < PAC207_EXPOSURE_MAX)
+ sd->exposure++;
+ else if (sd->gain < PAC207_GAIN_MAX)
+ sd->gain++;
+ else
+ break;
+ }
+ }
+
+ if (sd->exposure != orig_exposure || sd->gain != orig_gain) {
+ if (sd->exposure != orig_exposure)
+ pac207_write_reg(gspca_dev, 0x0002, sd->exposure);
+ if (sd->gain != orig_gain)
+ pac207_write_reg(gspca_dev, 0x000e, sd->gain);
+ pac207_write_reg(gspca_dev, 0x13, 0x01); /* load reg to sen */
+ pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */
+ sd->autogain_ignore_frames = PAC207_AUTOGAIN_IGNORE_FRAMES;
+ }
+}
+
+static unsigned char *pac207_find_sof(struct gspca_dev *gspca_dev,
+ unsigned char *m, int len)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int i;
+
+ /* Search for the SOF marker (fixed part) in the header */
+ for (i = 0; i < len; i++) {
+ if (m[i] == pac207_sof_marker[sd->sof_read]) {
+ sd->sof_read++;
+ if (sd->sof_read == sizeof(pac207_sof_marker)) {
+ PDEBUG(D_STREAM,
+ "SOF found, bytes to analyze: %u."
+ " Frame starts at byte #%u",
+ len, i + 1);
+ sd->sof_read = 0;
+ return m + i + 1;
+ }
+ } else {
+ sd->sof_read = 0;
+ }
+ }
+
+ return NULL;
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ struct gspca_frame *frame,
+ __u8 *data,
+ int len)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ unsigned char *sof;
+
+ sof = pac207_find_sof(gspca_dev, data, len);
+ if (sof) {
+ int n;
+
+ /* finish decoding current frame */
+ n = sof - data;
+ if (n > sizeof pac207_sof_marker)
+ n -= sizeof pac207_sof_marker;
+ else
+ n = 0;
+ frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+ data, n);
+ sd->header_read = 0;
+ gspca_frame_add(gspca_dev, FIRST_PACKET, frame, NULL, 0);
+ len -= sof - data;
+ data = sof;
+ }
+ if (sd->header_read < 11) {
+ int needed;
+
+ /* get average lumination from frame header (byte 5) */
+ if (sd->header_read < 5) {
+ needed = 5 - sd->header_read;
+ if (len >= needed)
+ atomic_set(&sd->avg_lum, data[needed - 1]);
+ }
+ /* skip the rest of the header */
+ needed = 11 - sd->header_read;
+ if (len <= needed) {
+ sd->header_read += len;
+ return;
+ }
+ data += needed;
+ len -= needed;
+ sd->header_read = 11;
+ }
+
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ pac207_write_reg(gspca_dev, 0x08, sd->brightness);
+ pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */
+ pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */
+}
+
+static void setexposure(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ pac207_write_reg(gspca_dev, 0x02, sd->exposure);
+ pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */
+ pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */
+}
+
+static void setgain(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ pac207_write_reg(gspca_dev, 0x0e, sd->gain);
+ pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */
+ pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->brightness = val;
+ if (gspca_dev->streaming)
+ setbrightness(gspca_dev);
+ return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->brightness;
+ return 0;
+}
+
+static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ /* don't allow mucking with exposure when using autogain */
+ if (sd->autogain)
+ return -EINVAL;
+
+ sd->exposure = val;
+ if (gspca_dev->streaming)
+ setexposure(gspca_dev);
+ return 0;
+}
+
+static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->exposure;
+ return 0;
+}
+
+static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ /* don't allow mucking with gain when using autogain */
+ if (sd->autogain)
+ return -EINVAL;
+
+ sd->gain = val;
+ if (gspca_dev->streaming)
+ setgain(gspca_dev);
+ return 0;
+}
+
+static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->gain;
+ return 0;
+}
+
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->autogain = val;
+ /* when switching to autogain set defaults to make sure
+ we are on a valid point of the autogain gain /
+ exposure knee graph, and give this change time to
+ take effect before doing autogain. */
+ if (sd->autogain) {
+ sd->exposure = PAC207_EXPOSURE_DEFAULT;
+ sd->gain = PAC207_GAIN_DEFAULT;
+ if (gspca_dev->streaming) {
+ sd->autogain_ignore_frames =
+ PAC207_AUTOGAIN_IGNORE_FRAMES;
+ setexposure(gspca_dev);
+ setgain(gspca_dev);
+ }
+ }
+
+ return 0;
+}
+
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->autogain;
+ return 0;
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .ctrls = sd_ctrls,
+ .nctrls = ARRAY_SIZE(sd_ctrls),
+ .config = sd_config,
+ .open = sd_open,
+ .start = sd_start,
+ .stopN = sd_stopN,
+ .stop0 = sd_stop0,
+ .close = sd_close,
+ .dq_callback = pac207_do_auto_gain,
+ .pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static const __devinitdata struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x041e, 0x4028), DVNM("Creative Webcam Vista Plus")},
+ {USB_DEVICE(0x093a, 0x2460), DVNM("Q-Tec Webcam 100")},
+ {USB_DEVICE(0x093a, 0x2463), DVNM("Philips spc200nc pac207")},
+ {USB_DEVICE(0x093a, 0x2464), DVNM("Labtec Webcam 1200")},
+ {USB_DEVICE(0x093a, 0x2468), DVNM("PAC207")},
+ {USB_DEVICE(0x093a, 0x2470), DVNM("Genius GF112")},
+ {USB_DEVICE(0x093a, 0x2471), DVNM("Genius VideoCam GE111")},
+ {USB_DEVICE(0x093a, 0x2472), DVNM("Genius VideoCam GE110")},
+ {USB_DEVICE(0x2001, 0xf115), DVNM("D-Link DSB-C120")},
+ {}
+};
+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,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+ if (usb_register(&sd_driver) < 0)
+ return -1;
+ PDEBUG(D_PROBE, "v%s registered", version);
+ return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+ usb_deregister(&sd_driver);
+ PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/linux/drivers/media/video/gspca/pac7311.c b/linux/drivers/media/video/gspca/pac7311.c
new file mode 100644
index 000000000..5519c2f70
--- /dev/null
+++ b/linux/drivers/media/video/gspca/pac7311.c
@@ -0,0 +1,790 @@
+/*
+ * Pixart PAC7311 library
+ * Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define MODULE_NAME "pac7311"
+
+#include "gspca.h"
+
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 5)
+static const char version[] = "2.1.5";
+
+MODULE_AUTHOR("Thomas Kaiser thomas@kaiser-linux.li");
+MODULE_DESCRIPTION("Pixart PAC7311");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+
+ int avg_lum;
+
+ unsigned char brightness;
+ unsigned char contrast;
+ unsigned char colors;
+ unsigned char autogain;
+
+ char ffseq;
+ signed char ag_cnt;
+#define AG_CNT_START 13
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+ {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+#define BRIGHTNESS_MAX 0x20
+ .maximum = BRIGHTNESS_MAX,
+ .step = 1,
+#define BRIGHTNESS_DEF 0x10
+ .default_value = BRIGHTNESS_DEF,
+ },
+ .set = sd_setbrightness,
+ .get = sd_getbrightness,
+ },
+ {
+ {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+#define CONTRAST_DEF 127
+ .default_value = CONTRAST_DEF,
+ },
+ .set = sd_setcontrast,
+ .get = sd_getcontrast,
+ },
+ {
+ {
+ .id = V4L2_CID_SATURATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Color",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+#define COLOR_DEF 127
+ .default_value = COLOR_DEF,
+ },
+ .set = sd_setcolors,
+ .get = sd_getcolors,
+ },
+ {
+ {
+ .id = V4L2_CID_AUTOGAIN,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Auto Gain",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+#define AUTOGAIN_DEF 1
+ .default_value = AUTOGAIN_DEF,
+ },
+ .set = sd_setautogain,
+ .get = sd_getautogain,
+ },
+};
+
+static struct v4l2_pix_format vga_mode[] = {
+ {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 160,
+ .sizeimage = 160 * 120 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 2},
+ {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 1},
+ {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 0},
+};
+
+#define PAC7311_JPEG_HEADER_SIZE (sizeof pac7311_jpeg_header) /* (594) */
+
+static const __u8 pac7311_jpeg_header[] = {
+ 0xff, 0xd8,
+ 0xff, 0xe0, 0x00, 0x03, 0x20,
+ 0xff, 0xc0, 0x00, 0x11, 0x08,
+ 0x01, 0xe0, /* 12: height */
+ 0x02, 0x80, /* 14: width */
+ 0x03, /* 16 */
+ 0x01, 0x21, 0x00,
+ 0x02, 0x11, 0x01,
+ 0x03, 0x11, 0x01,
+ 0xff, 0xdb, 0x00, 0x84,
+ 0x00, 0x10, 0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e, 0x0d,
+ 0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28, 0x1a, 0x18, 0x16,
+ 0x16, 0x18, 0x31, 0x23, 0x25, 0x1d, 0x28, 0x3a, 0x33, 0x3d,
+ 0x3c, 0x39, 0x33, 0x38, 0x37, 0x40, 0x48, 0x5c, 0x4e, 0x40,
+ 0x44, 0x57, 0x45, 0x37, 0x38, 0x50, 0x6d, 0x51, 0x57, 0x5f,
+ 0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71, 0x79, 0x70, 0x64,
+ 0x78, 0x5c, 0x65, 0x67, 0x63, 0x01, 0x11, 0x12, 0x12, 0x18,
+ 0x15, 0x18, 0x2f, 0x1a, 0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42,
+ 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+ 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+ 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+ 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+ 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+ 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, 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, 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, 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, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03,
+ 0x11, 0x00, 0x3f, 0x00
+};
+
+static void reg_w(struct usb_device *dev,
+ __u16 index,
+ const char *buffer, __u16 len)
+{
+ __u8 tmpbuf[8];
+
+ memcpy(tmpbuf, buffer, len);
+ usb_control_msg(dev,
+ usb_sndctrlpipe(dev, 0),
+ 1, /* request */
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, /* value */
+ index, tmpbuf, len,
+ 500);
+}
+
+static void pac7311_reg_read(struct usb_device *dev, __u16 index,
+ __u8 *buffer)
+{
+ usb_control_msg(dev,
+ usb_rcvctrlpipe(dev, 0),
+ 0, /* request */
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, /* value */
+ index, buffer, 1,
+ 500);
+}
+
+static void pac7311_reg_write(struct usb_device *dev,
+ __u16 index,
+ __u8 value)
+{
+ __u8 buf;
+
+ buf = value;
+ usb_control_msg(dev,
+ usb_sndctrlpipe(dev, 0),
+ 0, /* request */
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value, index, &buf, 1,
+ 500);
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+ const struct usb_device_id *id)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+ struct cam *cam;
+
+ PDEBUG(D_CONF, "Find Sensor PAC7311");
+ pac7311_reg_write(dev, 0x78, 0x40); /* Bit_0=start stream, Bit_7=LED */
+ pac7311_reg_write(dev, 0x78, 0x40); /* Bit_0=start stream, Bit_7=LED */
+ pac7311_reg_write(dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
+ pac7311_reg_write(dev, 0xff, 0x04);
+ pac7311_reg_write(dev, 0x27, 0x80);
+ pac7311_reg_write(dev, 0x28, 0xca);
+ pac7311_reg_write(dev, 0x29, 0x53);
+ pac7311_reg_write(dev, 0x2a, 0x0e);
+ pac7311_reg_write(dev, 0xff, 0x01);
+ pac7311_reg_write(dev, 0x3e, 0x20);
+
+ cam = &gspca_dev->cam;
+ cam->dev_name = (char *) id->driver_info;
+ cam->epaddr = 0x05;
+ cam->cam_mode = vga_mode;
+ cam->nmodes = ARRAY_SIZE(vga_mode);
+
+ sd->brightness = BRIGHTNESS_DEF;
+ sd->contrast = CONTRAST_DEF;
+ sd->colors = COLOR_DEF;
+ sd->autogain = AUTOGAIN_DEF;
+ return 0;
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int brightness;
+
+/*jfm: inverted?*/
+ brightness = BRIGHTNESS_MAX - sd->brightness;
+ pac7311_reg_write(gspca_dev->dev, 0xff, 0x04);
+/* pac7311_reg_write(gspca_dev->dev, 0x0e, 0x00); */
+ pac7311_reg_write(gspca_dev->dev, 0x0f, brightness);
+ /* load registers to sensor (Bit 0, auto clear) */
+ pac7311_reg_write(gspca_dev->dev, 0x11, 0x01);
+ PDEBUG(D_CONF|D_STREAM, "brightness: %i", brightness);
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ pac7311_reg_write(gspca_dev->dev, 0xff, 0x01);
+ pac7311_reg_write(gspca_dev->dev, 0x80, sd->contrast);
+ /* load registers to sensor (Bit 0, auto clear) */
+ pac7311_reg_write(gspca_dev->dev, 0x11, 0x01);
+ PDEBUG(D_CONF|D_STREAM, "contrast: %i", sd->contrast);
+}
+
+static void setcolors(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ pac7311_reg_write(gspca_dev->dev, 0xff, 0x01);
+ pac7311_reg_write(gspca_dev->dev, 0x10, sd->colors);
+ /* load registers to sensor (Bit 0, auto clear) */
+ pac7311_reg_write(gspca_dev->dev, 0x11, 0x01);
+ PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors);
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+ pac7311_reg_write(gspca_dev->dev, 0x78, 0x00); /* Turn on LED */
+ return 0;
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+ struct usb_device *dev = gspca_dev->dev;
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ pac7311_reg_write(dev, 0xff, 0x01);
+ reg_w(dev, 0x0002, "\x48\x0a\x40\x08\x00\x00\x08\x00", 8);
+ reg_w(dev, 0x000a, "\x06\xff\x11\xff\x5a\x30\x90\x4c", 8);
+ reg_w(dev, 0x0012, "\x00\x07\x00\x0a\x10\x00\xa0\x10", 8);
+ reg_w(dev, 0x001a, "\x02\x00\x00\x00\x00\x0b\x01\x00", 8);
+ reg_w(dev, 0x0022, "\x00\x00\x00\x00\x00\x00\x00\x00", 8);
+ reg_w(dev, 0x002a, "\x00\x00\x00", 3);
+ reg_w(dev, 0x003e, "\x00\x00\x78\x52\x4a\x52\x78\x6e", 8);
+ reg_w(dev, 0x0046, "\x48\x46\x48\x6e\x5f\x49\x42\x49", 8);
+ reg_w(dev, 0x004e, "\x5f\x5f\x49\x42\x49\x5f\x6e\x48", 8);
+ reg_w(dev, 0x0056, "\x46\x48\x6e\x78\x52\x4a\x52\x78", 8);
+ reg_w(dev, 0x005e, "\x00\x00\x09\x1b\x34\x49\x5c\x9b", 8);
+ reg_w(dev, 0x0066, "\xd0\xff", 2);
+ reg_w(dev, 0x0078, "\x44\x00\xf2\x01\x01\x80", 6);
+ reg_w(dev, 0x007f, "\x2a\x1c\x00\xc8\x02\x58\x03\x84", 8);
+ reg_w(dev, 0x0087, "\x12\x00\x1a\x04\x08\x0c\x10\x14", 8);
+ reg_w(dev, 0x008f, "\x18\x20", 2);
+ reg_w(dev, 0x0096, "\x01\x08\x04", 3);
+ reg_w(dev, 0x00a0, "\x44\x44\x44\x04", 4);
+ reg_w(dev, 0x00f0, "\x01\x00\x00\x00\x22\x00\x20\x00", 8);
+ reg_w(dev, 0x00f8, "\x3f\x00\x0a\x01\x00", 5);
+
+ pac7311_reg_write(dev, 0xff, 0x04);
+ pac7311_reg_write(dev, 0x02, 0x04);
+ pac7311_reg_write(dev, 0x03, 0x54);
+ pac7311_reg_write(dev, 0x04, 0x07);
+ pac7311_reg_write(dev, 0x05, 0x2b);
+ pac7311_reg_write(dev, 0x06, 0x09);
+ pac7311_reg_write(dev, 0x07, 0x0f);
+ pac7311_reg_write(dev, 0x08, 0x09);
+ pac7311_reg_write(dev, 0x09, 0x00);
+ pac7311_reg_write(dev, 0x0c, 0x07);
+ pac7311_reg_write(dev, 0x0d, 0x00);
+ pac7311_reg_write(dev, 0x0e, 0x00);
+ pac7311_reg_write(dev, 0x0f, 0x62);
+ pac7311_reg_write(dev, 0x10, 0x08);
+ pac7311_reg_write(dev, 0x12, 0x07);
+ pac7311_reg_write(dev, 0x13, 0x00);
+ pac7311_reg_write(dev, 0x14, 0x00);
+ pac7311_reg_write(dev, 0x15, 0x00);
+ pac7311_reg_write(dev, 0x16, 0x00);
+ pac7311_reg_write(dev, 0x17, 0x00);
+ pac7311_reg_write(dev, 0x18, 0x00);
+ pac7311_reg_write(dev, 0x19, 0x00);
+ pac7311_reg_write(dev, 0x1a, 0x00);
+ pac7311_reg_write(dev, 0x1b, 0x03);
+ pac7311_reg_write(dev, 0x1c, 0xa0);
+ pac7311_reg_write(dev, 0x1d, 0x01);
+ pac7311_reg_write(dev, 0x1e, 0xf4);
+ pac7311_reg_write(dev, 0x21, 0x00);
+ pac7311_reg_write(dev, 0x22, 0x08);
+ pac7311_reg_write(dev, 0x24, 0x03);
+ pac7311_reg_write(dev, 0x26, 0x00);
+ pac7311_reg_write(dev, 0x27, 0x01);
+ pac7311_reg_write(dev, 0x28, 0xca);
+ pac7311_reg_write(dev, 0x29, 0x10);
+ pac7311_reg_write(dev, 0x2a, 0x06);
+ pac7311_reg_write(dev, 0x2b, 0x78);
+ pac7311_reg_write(dev, 0x2c, 0x00);
+ pac7311_reg_write(dev, 0x2d, 0x00);
+ pac7311_reg_write(dev, 0x2e, 0x00);
+ pac7311_reg_write(dev, 0x2f, 0x00);
+ pac7311_reg_write(dev, 0x30, 0x23);
+ pac7311_reg_write(dev, 0x31, 0x28);
+ pac7311_reg_write(dev, 0x32, 0x04);
+ pac7311_reg_write(dev, 0x33, 0x11);
+ pac7311_reg_write(dev, 0x34, 0x00);
+ pac7311_reg_write(dev, 0x35, 0x00);
+ pac7311_reg_write(dev, 0x11, 0x01);
+ setcontrast(gspca_dev);
+ setbrightness(gspca_dev);
+ setcolors(gspca_dev);
+
+ /* set correct resolution */
+ switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
+ case 2: /* 160x120 */
+ pac7311_reg_write(dev, 0xff, 0x04);
+ pac7311_reg_write(dev, 0x02, 0x03);
+ pac7311_reg_write(dev, 0xff, 0x01);
+ pac7311_reg_write(dev, 0x08, 0x09);
+ pac7311_reg_write(dev, 0x17, 0x20);
+ pac7311_reg_write(dev, 0x1b, 0x00);
+/* pac7311_reg_write(dev, 0x80, 0x69); */
+ pac7311_reg_write(dev, 0x87, 0x10);
+ break;
+ case 1: /* 320x240 */
+ pac7311_reg_write(dev, 0xff, 0x04);
+ pac7311_reg_write(dev, 0x02, 0x03);
+ pac7311_reg_write(dev, 0xff, 0x01);
+ pac7311_reg_write(dev, 0x08, 0x09);
+ pac7311_reg_write(dev, 0x17, 0x30);
+/* pac7311_reg_write(dev, 0x80, 0x3f); */
+ pac7311_reg_write(dev, 0x87, 0x11);
+ break;
+ case 0: /* 640x480 */
+ pac7311_reg_write(dev, 0xff, 0x04);
+ pac7311_reg_write(dev, 0x02, 0x03);
+ pac7311_reg_write(dev, 0xff, 0x01);
+ pac7311_reg_write(dev, 0x08, 0x08);
+ pac7311_reg_write(dev, 0x17, 0x00);
+/* pac7311_reg_write(dev, 0x80, 0x1c); */
+ pac7311_reg_write(dev, 0x87, 0x12);
+ break;
+ }
+
+ /* start stream */
+ pac7311_reg_write(dev, 0xff, 0x01);
+ pac7311_reg_write(dev, 0x78, 0x04);
+ pac7311_reg_write(dev, 0x78, 0x05);
+
+ if (sd->autogain) {
+ sd->ag_cnt = AG_CNT_START;
+ sd->avg_lum = 0;
+ } else {
+ sd->ag_cnt = -1;
+ }
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+ struct usb_device *dev = gspca_dev->dev;
+
+ pac7311_reg_write(dev, 0xff, 0x04);
+ pac7311_reg_write(dev, 0x27, 0x80);
+ pac7311_reg_write(dev, 0x28, 0xca);
+ pac7311_reg_write(dev, 0x29, 0x53);
+ pac7311_reg_write(dev, 0x2a, 0x0e);
+ pac7311_reg_write(dev, 0xff, 0x01);
+ pac7311_reg_write(dev, 0x3e, 0x20);
+ pac7311_reg_write(dev, 0x78, 0x04); /* Bit_0=start stream, Bit_7=LED */
+ pac7311_reg_write(dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
+ pac7311_reg_write(dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+/* this function is called at close time */
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+ struct usb_device *dev = gspca_dev->dev;
+
+ pac7311_reg_write(dev, 0xff, 0x04);
+ pac7311_reg_write(dev, 0x27, 0x80);
+ pac7311_reg_write(dev, 0x28, 0xca);
+ pac7311_reg_write(dev, 0x29, 0x53);
+ pac7311_reg_write(dev, 0x2a, 0x0e);
+ pac7311_reg_write(dev, 0xff, 0x01);
+ pac7311_reg_write(dev, 0x3e, 0x20);
+ pac7311_reg_write(dev, 0x78, 0x04); /* Bit_0=start stream, Bit_7=LED */
+ pac7311_reg_write(dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
+ pac7311_reg_write(dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
+}
+
+static void setautogain(struct gspca_dev *gspca_dev, int luma)
+{
+ int luma_mean = 128;
+ int luma_delta = 20;
+ __u8 spring = 5;
+ __u8 Pxclk;
+ int Gbright;
+
+ pac7311_reg_read(gspca_dev->dev, 0x02, &Pxclk);
+ Gbright = Pxclk;
+ PDEBUG(D_FRAM, "luma mean %d", luma);
+ if (luma < luma_mean - luma_delta ||
+ luma > luma_mean + luma_delta) {
+ Gbright += (luma_mean - luma) >> spring;
+ if (Gbright > 0x1a)
+ Gbright = 0x1a;
+ else if (Gbright < 4)
+ Gbright = 4;
+ PDEBUG(D_FRAM, "gbright %d", Gbright);
+ pac7311_reg_write(gspca_dev->dev, 0xff, 0x04);
+ pac7311_reg_write(gspca_dev->dev, 0x0f, Gbright);
+ /* load registers to sensor (Bit 0, auto clear) */
+ pac7311_reg_write(gspca_dev->dev, 0x11, 0x01);
+ }
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ struct gspca_frame *frame, /* target */
+ __u8 *data, /* isoc packet */
+ int len) /* iso packet length */
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ unsigned char tmpbuf[4];
+ int i, p, ffseq;
+
+/* if (len < 5) { */
+ if (len < 6) {
+/* gspca_dev->last_packet_type = DISCARD_PACKET; */
+ return;
+ }
+
+ ffseq = sd->ffseq;
+
+ for (p = 0; p < len - 6; p++) {
+ if ((data[0 + p] == 0xff)
+ && (data[1 + p] == 0xff)
+ && (data[2 + p] == 0x00)
+ && (data[3 + p] == 0xff)
+ && (data[4 + p] == 0x96)) {
+
+ /* start of frame */
+ if (sd->ag_cnt >= 0 && p > 28) {
+ sd->avg_lum += data[p - 23];
+ if (--sd->ag_cnt < 0) {
+ sd->ag_cnt = AG_CNT_START;
+ setautogain(gspca_dev,
+ sd->avg_lum / AG_CNT_START);
+ sd->avg_lum = 0;
+ }
+ }
+
+ /* copy the end of data to the current frame */
+ frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+ data, p);
+
+ /* put the JPEG header in the new frame */
+ gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+ (unsigned char *) pac7311_jpeg_header,
+ 12);
+ tmpbuf[0] = gspca_dev->height >> 8;
+ tmpbuf[1] = gspca_dev->height & 0xff;
+ tmpbuf[2] = gspca_dev->width >> 8;
+ tmpbuf[3] = gspca_dev->width & 0xff;
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+ tmpbuf, 4);
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+ (unsigned char *) &pac7311_jpeg_header[16],
+ PAC7311_JPEG_HEADER_SIZE - 16);
+
+ data += p + 7;
+ len -= p + 7;
+ ffseq = 0;
+ break;
+ }
+ }
+
+ /* remove the 'ff ff ff xx' sequences */
+ switch (ffseq) {
+ case 3:
+ data += 1;
+ len -= 1;
+ break;
+ case 2:
+ if (data[0] == 0xff) {
+ data += 2;
+ len -= 2;
+ frame->data_end -= 2;
+ }
+ break;
+ case 1:
+ if (data[0] == 0xff
+ && data[1] == 0xff) {
+ data += 3;
+ len -= 3;
+ frame->data_end -= 1;
+ }
+ break;
+ }
+ for (i = 0; i < len - 4; i++) {
+ if (data[i] == 0xff
+ && data[i + 1] == 0xff
+ && data[i + 2] == 0xff) {
+ memmove(&data[i], &data[i + 4], len - i - 4);
+ len -= 4;
+ }
+ }
+ ffseq = 0;
+ if (data[len - 4] == 0xff) {
+ if (data[len - 3] == 0xff
+ && data[len - 2] == 0xff) {
+ len -= 4;
+ }
+ } else if (data[len - 3] == 0xff) {
+ if (data[len - 2] == 0xff
+ && data[len - 1] == 0xff)
+ ffseq = 3;
+ } else if (data[len - 2] == 0xff) {
+ if (data[len - 1] == 0xff)
+ ffseq = 2;
+ } else if (data[len - 1] == 0xff)
+ ffseq = 1;
+ sd->ffseq = ffseq;
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+}
+
+static void getbrightness(struct gspca_dev *gspca_dev)
+{
+/* __u8 brightness = 0;
+
+ pac7311_reg_read(gspca_dev->dev, 0x0008, &brightness);
+ spca50x->brightness = brightness;
+ return spca50x->brightness; */
+/* PDEBUG(D_CONF, "Called pac7311_getbrightness: Not implemented yet"); */
+}
+
+#if 0
+static void getcontrast(struct gspca_dev *gspca_dev)
+{
+/* __u8 contrast = 0;
+
+ pac7311_reg_read(gspca_dev->dev, 0x000e, &contrast);
+ spca50x->contrast = contrast << 3;
+ return spca50x->contrast; */
+ PDEBUG(D_CONF, "getcontrast: Not implemented yet");
+}
+#endif
+
+#if 0
+static void getcolors(struct gspca_dev *gspca_dev)
+{
+}
+#endif
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->brightness = val;
+ if (gspca_dev->streaming)
+ setbrightness(gspca_dev);
+ return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ getbrightness(gspca_dev);
+ *val = sd->brightness;
+ return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->contrast = val;
+ if (gspca_dev->streaming)
+ setcontrast(gspca_dev);
+ return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+/* getcontrast(gspca_dev); */
+ *val = sd->contrast;
+ return 0;
+}
+
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->colors = val;
+ if (gspca_dev->streaming)
+ setcolors(gspca_dev);
+ return 0;
+}
+
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+/* getcolors(gspca_dev); */
+ *val = sd->colors;
+ return 0;
+}
+
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->autogain = val;
+ if (val) {
+ sd->ag_cnt = AG_CNT_START;
+ sd->avg_lum = 0;
+ } else {
+ sd->ag_cnt = -1;
+ }
+ return 0;
+}
+
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->autogain;
+ return 0;
+}
+
+/* sub-driver description */
+static struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .ctrls = sd_ctrls,
+ .nctrls = ARRAY_SIZE(sd_ctrls),
+ .config = sd_config,
+ .open = sd_open,
+ .start = sd_start,
+ .stopN = sd_stopN,
+ .stop0 = sd_stop0,
+ .close = sd_close,
+ .pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static __devinitdata struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x093a, 0x2600), DVNM("Typhoon")},
+ {USB_DEVICE(0x093a, 0x2601), DVNM("Philips SPC610NC")},
+ {USB_DEVICE(0x093a, 0x2603), DVNM("PAC7312")},
+ {USB_DEVICE(0x093a, 0x2608), DVNM("Trust WB-3300p")},
+ {USB_DEVICE(0x093a, 0x260e), DVNM("Gigaware VGA PC Camera")},
+ /* and also ', Trust WB-3350p, SIGMA cam 2350' */
+ {USB_DEVICE(0x093a, 0x260f), DVNM("SnakeCam")},
+ {USB_DEVICE(0x093a, 0x2621), DVNM("PAC731x")},
+ {}
+};
+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,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+ if (usb_register(&sd_driver) < 0)
+ return -1;
+ PDEBUG(D_PROBE, "v%s registered", version);
+ return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+ usb_deregister(&sd_driver);
+ PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/linux/drivers/media/video/gspca/sonixb.c b/linux/drivers/media/video/gspca/sonixb.c
new file mode 100644
index 000000000..a4594dc0e
--- /dev/null
+++ b/linux/drivers/media/video/gspca/sonixb.c
@@ -0,0 +1,921 @@
+/*
+ * sonix sn9c102 (bayer) library
+ * Copyright (C) 2003 2004 Michel Xhaard mxhaard@magic.fr
+ * Add Pas106 Stefano Mozzi (C) 2004
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define MODULE_NAME "sonixb"
+
+#include "gspca.h"
+
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 5)
+static const char version[] = "2.1.5";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("GSPCA/SN9C102 USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+
+ unsigned char brightness;
+ unsigned char contrast;
+
+ unsigned char fr_h_sz; /* size of frame header */
+ char sensor; /* Type of image sensor chip */
+#define SENSOR_HV7131R 0
+#define SENSOR_OV6650 1
+#define SENSOR_OV7630 2
+#define SENSOR_OV7630_3 3
+#define SENSOR_PAS106 4
+#define SENSOR_PAS202 5
+#define SENSOR_TAS5110 6
+#define SENSOR_TAS5130CXX 7
+};
+
+#define COMP2 0x8f
+#define COMP 0xc7 /* 0x87 //0x07 */
+#define COMP1 0xc9 /* 0x89 //0x09 */
+
+#define MCK_INIT 0x63
+#define MCK_INIT1 0x20 /*fixme: Bayer - 0x50 for JPEG ??*/
+
+#define SYS_CLK 0x04
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+#define SD_BRIGHTNESS 0
+ {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+ .default_value = 127,
+ },
+ .set = sd_setbrightness,
+ .get = sd_getbrightness,
+ },
+#define SD_CONTRAST 1
+ {
+ {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+ .default_value = 127,
+ },
+ .set = sd_setcontrast,
+ .get = sd_getcontrast,
+ },
+};
+
+static struct v4l2_pix_format vga_mode[] = {
+ {160, 120, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
+ .bytesperline = 160,
+ .sizeimage = 160 * 120,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 2},
+ {320, 240, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 1},
+ {640, 480, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0},
+};
+static struct v4l2_pix_format sif_mode[] = {
+ {176, 144, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
+ .bytesperline = 176,
+ .sizeimage = 176 * 144,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 1},
+ {352, 288, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
+ .bytesperline = 352,
+ .sizeimage = 352 * 288,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0},
+};
+
+static const __u8 probe_ov7630[] = {0x08, 0x44};
+
+static const __u8 initHv7131[] = {
+ 0x46, 0x77, 0x00, 0x04, 0x00, 0x00, 0x00, 0x80, 0x11, 0x00, 0x00, 0x00,
+ 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, /* shift from 0x02 0x01 0x00 */
+ 0x28, 0x1e, 0x60, 0x8a, 0x20,
+ 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c
+};
+static const __u8 hv7131_sensor_init[][8] = {
+ {0xc0, 0x11, 0x31, 0x38, 0x2a, 0x2e, 0x00, 0x10},
+ {0xa0, 0x11, 0x01, 0x08, 0x2a, 0x2e, 0x00, 0x10},
+ {0xb0, 0x11, 0x20, 0x00, 0xd0, 0x2e, 0x00, 0x10},
+ {0xc0, 0x11, 0x25, 0x03, 0x0e, 0x28, 0x00, 0x16},
+ {0xa0, 0x11, 0x30, 0x10, 0x0e, 0x28, 0x00, 0x15},
+};
+static const __u8 initOv6650[] = {
+#if 1
+ 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+ 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x02, 0x01, 0x0a, 0x16, 0x12, 0x68, 0x0b,
+ 0x10, 0x1d, 0x10, 0x00, 0x06, 0x1f, 0x00
+#else
+/* old version? */
+ 0x64, 0x44, 0x28, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x02, 0x01, 0x0a, 0x14, 0x0f, 0x68, 0x8b,
+ 0x10, 0x1d, 0x10, 0x01, 0x01, 0x07, 0x06
+#endif
+};
+static const __u8 ov6650_sensor_init[][8] =
+{
+ /* Bright, contrast, etc are set througth SCBB interface.
+ * AVCAP on win2 do not send any data on this controls. */
+ /* Anyway, some registers appears to alter bright and constrat */
+ {0xa0, 0x60, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10},
+ {0xd0, 0x60, 0x11, 0xc0, 0x1b, 0x18, 0xc1, 0x10},
+ {0xb0, 0x60, 0x15, 0x00, 0x02, 0x18, 0xc1, 0x10},
+/* {0xa0, 0x60, 0x1b, 0x01, 0x02, 0x18, 0xc1, 0x10},
+ * THIS SET GREEN SCREEN
+ * (pixels could be innverted in decode kind of "brg",
+ * but blue wont be there. Avoid this data ... */
+ {0xd0, 0x60, 0x26, 0x01, 0x14, 0xd8, 0xa4, 0x10}, /* format out? */
+ {0xd0, 0x60, 0x26, 0x01, 0x14, 0xd8, 0xa4, 0x10},
+ {0xa0, 0x60, 0x30, 0x3d, 0x0A, 0xd8, 0xa4, 0x10},
+ {0xb0, 0x60, 0x60, 0x66, 0x68, 0xd8, 0xa4, 0x10},
+ {0xa0, 0x60, 0x68, 0x04, 0x68, 0xd8, 0xa4, 0x10},
+ {0xd0, 0x60, 0x17, 0x24, 0xd6, 0x04, 0x94, 0x10}, /* Clipreg */
+ {0xa0, 0x60, 0x10, 0x5d, 0x99, 0x04, 0x94, 0x16},
+ {0xa0, 0x60, 0x2d, 0x0a, 0x99, 0x04, 0x94, 0x16},
+ {0xa0, 0x60, 0x32, 0x00, 0x99, 0x04, 0x94, 0x16},
+ {0xa0, 0x60, 0x33, 0x40, 0x99, 0x04, 0x94, 0x16},
+ {0xa0, 0x60, 0x11, 0xc0, 0x99, 0x04, 0x94, 0x16},
+ {0xa0, 0x60, 0x00, 0x16, 0x99, 0x04, 0x94, 0x15}, /* bright / Lumino */
+ {0xa0, 0x60, 0x2b, 0xab, 0x99, 0x04, 0x94, 0x15},
+ /* ?flicker o brillo */
+ {0xa0, 0x60, 0x2d, 0x2a, 0x99, 0x04, 0x94, 0x15},
+ {0xa0, 0x60, 0x2d, 0x2b, 0x99, 0x04, 0x94, 0x16},
+ {0xa0, 0x60, 0x32, 0x00, 0x99, 0x04, 0x94, 0x16},
+ {0xa0, 0x60, 0x33, 0x00, 0x99, 0x04, 0x94, 0x16},
+ {0xa0, 0x60, 0x10, 0x57, 0x99, 0x04, 0x94, 0x16},
+ {0xa0, 0x60, 0x2d, 0x2b, 0x99, 0x04, 0x94, 0x16},
+ {0xa0, 0x60, 0x32, 0x00, 0x99, 0x04, 0x94, 0x16},
+ /* Low Light (Enabled: 0x32 0x1 | Disabled: 0x32 0x00) */
+ {0xa0, 0x60, 0x33, 0x29, 0x99, 0x04, 0x94, 0x16},
+ /* Low Ligth (Enabled: 0x33 0x13 | Disabled: 0x33 0x29) */
+/* {0xa0, 0x60, 0x11, 0xc1, 0x99, 0x04, 0x94, 0x16}, */
+ {0xa0, 0x60, 0x00, 0x17, 0x99, 0x04, 0x94, 0x15}, /* clip? r */
+ {0xa0, 0x60, 0x00, 0x18, 0x99, 0x04, 0x94, 0x15}, /* clip? r */
+};
+static const __u8 initOv7630[] = {
+ 0x04, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, /* r01 .. r08 */
+ 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* r09 .. r10 */
+ 0x00, 0x02, 0x01, 0x0a, /* r11 .. r14 */
+ 0x28, 0x1e, /* H & V sizes r15 .. r16 */
+ 0x68, COMP1, MCK_INIT1, /* r17 .. r19 */
+ 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c /* r1a .. r1f */
+};
+static const __u8 initOv7630_3[] = {
+ 0x44, 0x44, 0x00, 0x1a, 0x20, 0x20, 0x20, 0x80, /* r01 .. r08 */
+ 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, /* r09 .. r10 */
+ 0x00, 0x02, 0x01, 0x0a, /* r11 .. r14 */
+ 0x28, 0x1e, /* H & V sizes r15 .. r16 */
+ 0x68, COMP1, MCK_INIT1, /* r17 .. r19 */
+ 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c /* r1a .. r1f */
+};
+static const __u8 ov7630_sensor_init_com[][8] = {
+ {0xa0, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10},
+ {0xb0, 0x21, 0x01, 0x77, 0x3a, 0x00, 0x00, 0x10},
+/* {0xd0, 0x21, 0x12, 0x7c, 0x01, 0x80, 0x34, 0x10}, jfm */
+ {0xd0, 0x21, 0x12, 0x78, 0x00, 0x80, 0x34, 0x10}, /* jfm */
+ {0xa0, 0x21, 0x1b, 0x04, 0x00, 0x80, 0x34, 0x10},
+ {0xa0, 0x21, 0x20, 0x44, 0x00, 0x80, 0x34, 0x10},
+ {0xa0, 0x21, 0x23, 0xee, 0x00, 0x80, 0x34, 0x10},
+ {0xd0, 0x21, 0x26, 0xa0, 0x9a, 0xa0, 0x30, 0x10},
+ {0xb0, 0x21, 0x2a, 0x80, 0x00, 0xa0, 0x30, 0x10},
+ {0xb0, 0x21, 0x2f, 0x3d, 0x24, 0xa0, 0x30, 0x10},
+ {0xa0, 0x21, 0x32, 0x86, 0x24, 0xa0, 0x30, 0x10},
+/* {0xb0, 0x21, 0x60, 0xa9, 0x4a, 0xa0, 0x30, 0x10}, jfm */
+ {0xb0, 0x21, 0x60, 0xa9, 0x42, 0xa0, 0x30, 0x10}, /* jfm */
+ {0xa0, 0x21, 0x65, 0x00, 0x42, 0xa0, 0x30, 0x10},
+ {0xa0, 0x21, 0x69, 0x38, 0x42, 0xa0, 0x30, 0x10},
+ {0xc0, 0x21, 0x6f, 0x88, 0x0b, 0x00, 0x30, 0x10},
+ {0xc0, 0x21, 0x74, 0x21, 0x8e, 0x00, 0x30, 0x10},
+ {0xa0, 0x21, 0x7d, 0xf7, 0x8e, 0x00, 0x30, 0x10},
+ {0xd0, 0x21, 0x17, 0x1c, 0xbd, 0x06, 0xf6, 0x10},
+};
+static const __u8 ov7630_sensor_init[][8] = {
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 200ms */
+ {0xa0, 0x21, 0x11, 0x01, 0xbd, 0x06, 0xf6, 0x10}, /* jfm */
+ {0xa0, 0x21, 0x10, 0x57, 0xbd, 0x06, 0xf6, 0x16},
+ {0xa0, 0x21, 0x76, 0x02, 0xbd, 0x06, 0xf6, 0x16},
+ {0xa0, 0x21, 0x00, 0x10, 0xbd, 0x06, 0xf6, 0x15}, /* gain */
+};
+static const __u8 ov7630_sensor_init_3[][8] = {
+ {0xa0, 0x21, 0x10, 0x36, 0xbd, 0x06, 0xf6, 0x16}, /* exposure */
+ {0xa0, 0x21, 0x76, 0x03, 0xbd, 0x06, 0xf6, 0x16},
+ {0xa0, 0x21, 0x11, 0x01, 0xbd, 0x06, 0xf6, 0x16},
+ {0xa0, 0x21, 0x00, 0x10, 0xbd, 0x06, 0xf6, 0x15}, /* gain */
+/* {0xb0, 0x21, 0x2a, 0xc0, 0x3c, 0x06, 0xf6, 0x1d},
+ * a0 1c,a0 1f,c0 3c frame rate ?line interval from ov6630 */
+/* {0xb0, 0x21, 0x2a, 0xa0, 0x1f, 0x06, 0xf6, 0x1d}, * from win */
+ {0xb0, 0x21, 0x2a, 0xa0, 0x1c, 0x06, 0xf6, 0x1d},
+};
+
+static const __u8 initPas106[] = {
+ 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x40, 0x00, 0x00, 0x00,
+ 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x05, 0x01, 0x00,
+ 0x16, 0x12, 0x28, COMP1, MCK_INIT1,
+ 0x18, 0x10, 0x04, 0x03, 0x11, 0x0c
+};
+/* compression 0x86 mckinit1 0x2b */
+static const __u8 pas106_data[][2] = {
+ {0x02, 0x04}, /* Pixel Clock Divider 6 */
+ {0x03, 0x13}, /* Frame Time MSB */
+/* {0x03, 0x12}, * Frame Time MSB */
+ {0x04, 0x06}, /* Frame Time LSB */
+/* {0x04, 0x05}, * Frame Time LSB */
+ {0x05, 0x65}, /* Shutter Time Line Offset */
+/* {0x05, 0x6d}, * Shutter Time Line Offset */
+/* {0x06, 0xb1}, * Shutter Time Pixel Offset */
+ {0x06, 0xcd}, /* Shutter Time Pixel Offset */
+ {0x07, 0xc1}, /* Black Level Subtract Sign */
+/* {0x07, 0x00}, * Black Level Subtract Sign */
+ {0x08, 0x06}, /* Black Level Subtract Level */
+ {0x08, 0x06}, /* Black Level Subtract Level */
+/* {0x08, 0x01}, * Black Level Subtract Level */
+ {0x09, 0x05}, /* Color Gain B Pixel 5 a */
+ {0x0a, 0x04}, /* Color Gain G1 Pixel 1 5 */
+ {0x0b, 0x04}, /* Color Gain G2 Pixel 1 0 5 */
+ {0x0c, 0x05}, /* Color Gain R Pixel 3 1 */
+ {0x0d, 0x00}, /* Color GainH Pixel */
+ {0x0e, 0x0e}, /* Global Gain */
+ {0x0f, 0x00}, /* Contrast */
+ {0x10, 0x06}, /* H&V synchro polarity */
+ {0x11, 0x06}, /* ?default */
+ {0x12, 0x06}, /* DAC scale */
+ {0x14, 0x02}, /* ?default */
+ {0x13, 0x01}, /* Validate Settings */
+};
+static const __u8 initPas202[] = {
+ 0x44, 0x44, 0x21, 0x30, 0x00, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, 0x00,
+ 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x07, 0x03, 0x0a, /* 6 */
+ 0x28, 0x1e, 0x28, 0x89, 0x30,
+ 0x00, 0x00, 0x02, 0x03, 0x0f, 0x0c
+};
+static const __u8 pas202_sensor_init[][8] = {
+ {0xa0, 0x40, 0x02, 0x03, 0x00, 0x00, 0x00, 0x10},
+ {0xd0, 0x40, 0x04, 0x07, 0x34, 0x00, 0x09, 0x10},
+ {0xd0, 0x40, 0x08, 0x01, 0x00, 0x00, 0x01, 0x10},
+ {0xd0, 0x40, 0x0C, 0x00, 0x0C, 0x00, 0x32, 0x10},
+ {0xd0, 0x40, 0x10, 0x00, 0x01, 0x00, 0x63, 0x10},
+ {0xa0, 0x40, 0x15, 0x70, 0x01, 0x00, 0x63, 0x10},
+ {0xa0, 0x40, 0x18, 0x00, 0x01, 0x00, 0x63, 0x10},
+ {0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10},
+ {0xa0, 0x40, 0x03, 0x56, 0x01, 0x00, 0x63, 0x10},
+ {0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10},
+ {0xb0, 0x40, 0x04, 0x07, 0x2a, 0x00, 0x63, 0x10},
+ {0xb0, 0x40, 0x0e, 0x00, 0x3d, 0x00, 0x63, 0x10},
+
+ {0xa0, 0x40, 0x11, 0x01, 0x3d, 0x00, 0x63, 0x16},
+ {0xa0, 0x40, 0x10, 0x08, 0x3d, 0x00, 0x63, 0x15},
+ {0xa0, 0x40, 0x02, 0x04, 0x3d, 0x00, 0x63, 0x16},
+ {0xa0, 0x40, 0x11, 0x01, 0x3d, 0x00, 0x63, 0x16},
+ {0xb0, 0x40, 0x0e, 0x00, 0x31, 0x00, 0x63, 0x16},
+ {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16},
+ {0xa0, 0x40, 0x10, 0x0e, 0x31, 0x00, 0x63, 0x15},
+ {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16},
+};
+
+static const __u8 initTas5110[] = {
+ 0x44, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00,
+ 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x46, 0x09, 0x0a, /* shift from 0x45 0x09 0x0a */
+ 0x16, 0x12, 0x60, 0x86, 0x2b,
+ 0x14, 0x0a, 0x02, 0x02, 0x09, 0x07
+};
+static const __u8 tas5110_sensor_init[][8] = {
+ {0x30, 0x11, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x10},
+ {0x30, 0x11, 0x02, 0x20, 0xa9, 0x00, 0x00, 0x10},
+ {0xa0, 0x61, 0x9a, 0xca, 0x00, 0x00, 0x00, 0x17},
+};
+
+static const __u8 initTas5130[] = {
+ 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00,
+ 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x69, 0x0c, 0x0a,
+ 0x28, 0x1e, 0x60, COMP, MCK_INIT,
+ 0x18, 0x10, 0x04, 0x03, 0x11, 0x0c
+};
+static const __u8 tas5130_sensor_init[][8] = {
+/* {0x30, 0x11, 0x00, 0x40, 0x47, 0x00, 0x00, 0x10},
+ * shutter 0x47 short exposure? */
+ {0x30, 0x11, 0x00, 0x40, 0x01, 0x00, 0x00, 0x10},
+ /* shutter 0x01 long exposure */
+ {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10},
+};
+
+static void reg_r(struct usb_device *dev,
+ __u16 value, __u8 *buffer)
+{
+ usb_control_msg(dev,
+ usb_rcvctrlpipe(dev, 0),
+ 0, /* request */
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+ value,
+ 0, /* index */
+ buffer, 1,
+ 500);
+}
+
+static void reg_w(struct usb_device *dev,
+ __u16 value,
+ const __u8 *buffer,
+ int len)
+{
+ __u8 tmpbuf[32];
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ if (len > sizeof tmpbuf) {
+ PDEBUG(D_ERR|D_PACK, "reg_w: buffer overflow");
+ return;
+ }
+#endif
+ memcpy(tmpbuf, buffer, len);
+ usb_control_msg(dev,
+ usb_sndctrlpipe(dev, 0),
+ 0x08, /* request */
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+ value,
+ 0, /* index */
+ tmpbuf, len,
+ 500);
+}
+
+static int i2c_w(struct usb_device *dev, const __u8 *buffer)
+{
+ int retry = 60;
+ __u8 ByteReceive;
+
+ /* is i2c ready */
+ reg_w(dev, 0x08, buffer, 8);
+ while (retry--) {
+ msleep(10);
+ reg_r(dev, 0x08, &ByteReceive);
+ if (ByteReceive == 4)
+ return 0;
+ }
+ return -1;
+}
+
+static void i2c_w_vector(struct usb_device *dev,
+ const __u8 buffer[][8], int len)
+{
+ for (;;) {
+ reg_w(dev, 0x08, *buffer, 8);
+ len -= 8;
+ if (len <= 0)
+ break;
+ buffer++;
+ }
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ __u8 value;
+
+ switch (sd->sensor) {
+ case SENSOR_OV6650: {
+ __u8 i2cOV6650[] =
+ {0xa0, 0x60, 0x06, 0x11, 0x99, 0x04, 0x94, 0x15};
+
+ i2cOV6650[3] = sd->brightness;
+ if (i2c_w(gspca_dev->dev, i2cOV6650) < 0)
+ goto err;
+ break;
+ }
+ case SENSOR_OV7630: {
+ __u8 i2cOV[] =
+ {0xa0, 0x21, 0x06, 0x36, 0xbd, 0x06, 0xf6, 0x16};
+
+ /* change reg 0x06 */
+ i2cOV[3] = sd->brightness;
+ if (i2c_w(gspca_dev->dev, i2cOV) < 0)
+ goto err;
+ break;
+ }
+ case SENSOR_PAS106: {
+ __u8 i2c1[] =
+ {0xa1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14};
+
+ i2c1[3] = sd->brightness >> 3;
+ i2c1[2] = 0x0e;
+ if (i2c_w(gspca_dev->dev, i2c1) < 0)
+ goto err;
+ i2c1[3] = 0x01;
+ i2c1[2] = 0x13;
+ if (i2c_w(gspca_dev->dev, i2c1) < 0)
+ goto err;
+ break;
+ }
+ case SENSOR_PAS202: {
+ /* __u8 i2cpexpo1[] =
+ {0xb0, 0x40, 0x04, 0x07, 0x2a, 0x00, 0x63, 0x16}; */
+ __u8 i2cpexpo[] =
+ {0xb0, 0x40, 0x0e, 0x01, 0xab, 0x00, 0x63, 0x16};
+ __u8 i2cp202[] =
+ {0xa0, 0x40, 0x10, 0x0e, 0x31, 0x00, 0x63, 0x15};
+ static __u8 i2cpdoit[] =
+ {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16};
+
+ /* change reg 0x10 */
+ i2cpexpo[4] = 0xff - sd->brightness;
+/* if(i2c_w(gspca_dev->dev,i2cpexpo1) < 0)
+ goto err; */
+/* if(i2c_w(gspca_dev->dev,i2cpdoit) < 0)
+ goto err; */
+ if (i2c_w(gspca_dev->dev, i2cpexpo) < 0)
+ goto err;
+ if (i2c_w(gspca_dev->dev, i2cpdoit) < 0)
+ goto err;
+ i2cp202[3] = sd->brightness >> 3;
+ if (i2c_w(gspca_dev->dev, i2cp202) < 0)
+ goto err;
+ if (i2c_w(gspca_dev->dev, i2cpdoit) < 0)
+ goto err;
+ break;
+ }
+ case SENSOR_TAS5130CXX:
+ case SENSOR_TAS5110: {
+ __u8 i2c[] =
+ {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10};
+
+ value = 0xff - sd->brightness;
+ i2c[4] = value;
+ PDEBUG(D_CONF, "brightness %d : %d", value, i2c[4]);
+ if (i2c_w(gspca_dev->dev, i2c) < 0)
+ goto err;
+ break;
+ }
+ }
+ return;
+err:
+ PDEBUG(D_ERR, "i2c error brightness");
+}
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ __u8 gain;
+ __u8 rgb_value;
+
+ gain = sd->contrast >> 4;
+ /* red and blue gain */
+ rgb_value = gain << 4 | gain;
+ reg_w(gspca_dev->dev, 0x10, &rgb_value, 1);
+ /* green gain */
+ rgb_value = gain;
+ reg_w(gspca_dev->dev, 0x11, &rgb_value, 1);
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+ const struct usb_device_id *id)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct cam *cam;
+/* __u16 vendor; */
+ __u16 product;
+ int sif = 0;
+
+ sd->fr_h_sz = 12; /* default size of the frame header */
+/* vendor = id->idVendor; */
+ product = id->idProduct;
+/* switch (vendor) { */
+/* case 0x0c45: * Sonix */
+ switch (product) {
+ case 0x6001: /* SN9C102 */
+ case 0x6005: /* SN9C101 */
+ case 0x6007: /* SN9C101 */
+ sd->sensor = SENSOR_TAS5110;
+ sif = 1;
+ break;
+ case 0x6009: /* SN9C101 */
+ case 0x600d: /* SN9C101 */
+ case 0x6029: /* SN9C101 */
+ sd->sensor = SENSOR_PAS106;
+ sif = 1;
+ break;
+ case 0x6011: /* SN9C101 - SN9C101G */
+ sd->sensor = SENSOR_OV6650;
+ sif = 1;
+ break;
+ case 0x6019: /* SN9C101 */
+ case 0x602c: /* SN9C102 */
+ case 0x602e: /* SN9C102 */
+ sd->sensor = SENSOR_OV7630;
+ break;
+ case 0x60b0: /* SN9C103 */
+ sd->sensor = SENSOR_OV7630_3;
+ sd->fr_h_sz = 18; /* size of frame header */
+ break;
+ case 0x6024: /* SN9C102 */
+ case 0x6025: /* SN9C102 */
+ sd->sensor = SENSOR_TAS5130CXX;
+ break;
+ case 0x6028: /* SN9C102 */
+ sd->sensor = SENSOR_PAS202;
+ break;
+ case 0x602d: /* SN9C102 */
+ sd->sensor = SENSOR_HV7131R;
+ break;
+ case 0x60af: /* SN9C103 */
+ sd->sensor = SENSOR_PAS202;
+ sd->fr_h_sz = 18; /* size of frame header (?) */
+ break;
+ }
+/* break; */
+/* } */
+
+ cam = &gspca_dev->cam;
+ cam->dev_name = (char *) id->driver_info;
+ cam->epaddr = 0x01;
+ if (!sif) {
+ cam->cam_mode = vga_mode;
+ cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+ } else {
+ cam->cam_mode = sif_mode;
+ cam->nmodes = sizeof sif_mode / sizeof sif_mode[0];
+ }
+ sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
+ sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
+ if (sd->sensor == SENSOR_OV7630_3) /* jfm: from win trace */
+ reg_w(gspca_dev->dev, 0x01, probe_ov7630, sizeof probe_ov7630);
+ return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+ __u8 ByteReceive;
+
+ reg_r(gspca_dev->dev, 0x00, &ByteReceive);
+ if (ByteReceive != 0x10)
+ return -ENODEV;
+ return 0;
+}
+
+static void pas106_i2cinit(struct usb_device *dev)
+{
+ int i;
+ const __u8 *data;
+ __u8 i2c1[] = { 0xa1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14 };
+
+ i = ARRAY_SIZE(pas106_data);
+ data = pas106_data[0];
+ while (--i >= 0) {
+ memcpy(&i2c1[2], data, 2);
+ /* copy 2 bytes from the template */
+ if (i2c_w(dev, i2c1) < 0)
+ PDEBUG(D_ERR, "i2c error pas106");
+ data += 2;
+ }
+}
+
+/* -- start the camera -- */
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+ int mode, l;
+ const __u8 *sn9c10x;
+ __u8 reg01, reg17;
+ __u8 reg17_19[3];
+
+ mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
+ switch (sd->sensor) {
+ case SENSOR_HV7131R:
+ sn9c10x = initHv7131;
+ reg17_19[0] = 0x60;
+ reg17_19[1] = (mode << 4) | 0x8a;
+ reg17_19[2] = 0x20;
+ break;
+ case SENSOR_OV6650:
+ sn9c10x = initOv6650;
+ reg17_19[0] = 0x68;
+ reg17_19[1] = (mode << 4) | 0x8b;
+ reg17_19[2] = 0x20;
+ break;
+ case SENSOR_OV7630:
+ sn9c10x = initOv7630;
+ reg17_19[0] = 0x68;
+ reg17_19[1] = (mode << 4) | COMP2;
+ reg17_19[2] = MCK_INIT1;
+ break;
+ case SENSOR_OV7630_3:
+ sn9c10x = initOv7630_3;
+ reg17_19[0] = 0x68;
+ reg17_19[1] = (mode << 4) | COMP2;
+ reg17_19[2] = MCK_INIT1;
+ break;
+ case SENSOR_PAS106:
+ sn9c10x = initPas106;
+ reg17_19[0] = 0x24; /* 0x28 */
+ reg17_19[1] = (mode << 4) | COMP1;
+ reg17_19[2] = MCK_INIT1;
+ break;
+ case SENSOR_PAS202:
+ sn9c10x = initPas202;
+ reg17_19[0] = mode ? 0x24 : 0x20;
+ reg17_19[1] = (mode << 4) | 0x89;
+ reg17_19[2] = 0x20;
+ break;
+ case SENSOR_TAS5110:
+ sn9c10x = initTas5110;
+ reg17_19[0] = 0x60;
+ reg17_19[1] = (mode << 4) | 0x86;
+ reg17_19[2] = 0x2b; /* 0xf3; */
+ break;
+ default:
+/* case SENSOR_TAS5130CXX: */
+ sn9c10x = initTas5130;
+ reg17_19[0] = 0x60;
+ reg17_19[1] = (mode << 4) | COMP;
+ reg17_19[2] = mode ? 0x23 : 0x43;
+ break;
+ }
+ switch (sd->sensor) {
+ case SENSOR_OV7630:
+ reg01 = 0x06;
+ reg17 = 0x29;
+ l = 0x10;
+ break;
+ case SENSOR_OV7630_3:
+ reg01 = 0x44;
+ reg17 = 0x68;
+ l = 0x10;
+ break;
+ default:
+ reg01 = sn9c10x[0];
+ reg17 = sn9c10x[0x17 - 1];
+ l = 0x1f;
+ break;
+ }
+
+ /* reg 0x01 bit 2 video transfert on */
+ reg_w(dev, 0x01, &reg01, 1);
+ /* reg 0x17 SensorClk enable inv Clk 0x60 */
+ reg_w(dev, 0x17, &reg17, 1);
+/*fixme: for ov7630 102
+ reg_w(dev, 0x01, {0x06, sn9c10x[1]}, 2); */
+ /* Set the registers from the template */
+ reg_w(dev, 0x01, sn9c10x, l);
+ switch (sd->sensor) {
+ case SENSOR_HV7131R:
+ i2c_w_vector(dev, hv7131_sensor_init,
+ sizeof hv7131_sensor_init);
+ break;
+ case SENSOR_OV6650:
+ i2c_w_vector(dev, ov6650_sensor_init,
+ sizeof ov6650_sensor_init);
+ break;
+ case SENSOR_OV7630:
+ i2c_w_vector(dev, ov7630_sensor_init_com,
+ sizeof ov7630_sensor_init_com);
+ msleep(200);
+ i2c_w_vector(dev, ov7630_sensor_init,
+ sizeof ov7630_sensor_init);
+ break;
+ case SENSOR_OV7630_3:
+ i2c_w_vector(dev, ov7630_sensor_init_com,
+ sizeof ov7630_sensor_init_com);
+ msleep(200);
+ i2c_w_vector(dev, ov7630_sensor_init_3,
+ sizeof ov7630_sensor_init_3);
+ break;
+ case SENSOR_PAS106:
+ pas106_i2cinit(dev);
+ break;
+ case SENSOR_PAS202:
+ i2c_w_vector(dev, pas202_sensor_init,
+ sizeof pas202_sensor_init);
+ break;
+ case SENSOR_TAS5110:
+ i2c_w_vector(dev, tas5110_sensor_init,
+ sizeof tas5110_sensor_init);
+ break;
+ default:
+/* case SENSOR_TAS5130CXX: */
+ i2c_w_vector(dev, tas5130_sensor_init,
+ sizeof tas5130_sensor_init);
+ break;
+ }
+ /* H_size V_size 0x28, 0x1e maybe 640x480 */
+ reg_w(dev, 0x15, &sn9c10x[0x15 - 1], 2);
+ /* compression register */
+ reg_w(dev, 0x18, &reg17_19[1], 1);
+ /* H_start */ /*fixme: not ov7630*/
+ reg_w(dev, 0x12, &sn9c10x[0x12 - 1], 1);
+ /* V_START */ /*fixme: not ov7630*/
+ reg_w(dev, 0x13, &sn9c10x[0x13 - 1], 1);
+ /* reset 0x17 SensorClk enable inv Clk 0x60 */
+ /*fixme: ov7630 [17]=68 8f (+20 if 102)*/
+ reg_w(dev, 0x17, &reg17_19[0], 1);
+ /*MCKSIZE ->3 */ /*fixme: not ov7630*/
+ reg_w(dev, 0x19, &reg17_19[2], 1);
+ /* AE_STRX AE_STRY AE_ENDX AE_ENDY */
+ reg_w(dev, 0x1c, &sn9c10x[0x1c - 1], 4);
+ /* Enable video transfert */
+ reg_w(dev, 0x01, &sn9c10x[0], 1);
+ /* Compression */
+ reg_w(dev, 0x18, &reg17_19[1], 2);
+ msleep(20);
+
+ setcontrast(gspca_dev);
+ setbrightness(gspca_dev);
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+ __u8 ByteSend = 0;
+
+ ByteSend = 0x09; /* 0X00 */
+ reg_w(gspca_dev->dev, 0x01, &ByteSend, 1);
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ struct gspca_frame *frame, /* target */
+ unsigned char *data, /* isoc packet */
+ int len) /* iso packet length */
+{
+ struct sd *sd;
+ int i;
+
+ if (len > 6 && len < 24) {
+ for (i = 0; i < len - 6; i++) {
+ if (data[0 + i] == 0xff
+ && data[1 + i] == 0xff
+ && data[2 + i] == 0x00
+ && data[3 + i] == 0xc4
+ && data[4 + i] == 0xc4
+ && data[5 + i] == 0x96) { /* start of frame */
+ frame = gspca_frame_add(gspca_dev, LAST_PACKET,
+ frame, data, 0);
+ sd = (struct sd *) gspca_dev;
+ data += i + sd->fr_h_sz;
+ len -= i + sd->fr_h_sz;
+ gspca_frame_add(gspca_dev, FIRST_PACKET,
+ frame, data, len);
+ return;
+ }
+ }
+ }
+ gspca_frame_add(gspca_dev, INTER_PACKET,
+ frame, data, len);
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->brightness = val;
+ if (gspca_dev->streaming)
+ setbrightness(gspca_dev);
+ return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->brightness;
+ return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->contrast = val;
+ if (gspca_dev->streaming)
+ setcontrast(gspca_dev);
+ return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->contrast;
+ return 0;
+}
+
+/* sub-driver description */
+static struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .ctrls = sd_ctrls,
+ .nctrls = ARRAY_SIZE(sd_ctrls),
+ .config = sd_config,
+ .open = sd_open,
+ .start = sd_start,
+ .stopN = sd_stopN,
+ .stop0 = sd_stop0,
+ .close = sd_close,
+ .pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static __devinitdata struct usb_device_id device_table[] = {
+#ifndef CONFIG_USB_SN9C102
+ {USB_DEVICE(0x0c45, 0x6001), DVNM("Genius VideoCAM NB")},
+ {USB_DEVICE(0x0c45, 0x6005), DVNM("Sweex Tas5110")},
+ {USB_DEVICE(0x0c45, 0x6007), DVNM("Sonix sn9c101 + Tas5110D")},
+ {USB_DEVICE(0x0c45, 0x6009), DVNM("spcaCam@120")},
+ {USB_DEVICE(0x0c45, 0x600d), DVNM("spcaCam@120")},
+ {USB_DEVICE(0x0c45, 0x6011), DVNM("MAX Webcam Microdia")},
+ {USB_DEVICE(0x0c45, 0x6019), DVNM("Generic Sonix OV7630")},
+ {USB_DEVICE(0x0c45, 0x6024), DVNM("Generic Sonix Tas5130c")},
+ {USB_DEVICE(0x0c45, 0x6025), DVNM("Xcam Shanga")},
+ {USB_DEVICE(0x0c45, 0x6028), DVNM("Sonix Btc Pc380")},
+ {USB_DEVICE(0x0c45, 0x6029), DVNM("spcaCam@150")},
+ {USB_DEVICE(0x0c45, 0x602c), DVNM("Generic Sonix OV7630")},
+ {USB_DEVICE(0x0c45, 0x602d), DVNM("LIC-200 LG")},
+ {USB_DEVICE(0x0c45, 0x602e), DVNM("Genius VideoCam Messenger")},
+ {USB_DEVICE(0x0c45, 0x60af), DVNM("Trust WB3100P")},
+ {USB_DEVICE(0x0c45, 0x60b0), DVNM("Genius VideoCam Look")},
+#endif
+ {}
+};
+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,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+ if (usb_register(&sd_driver) < 0)
+ return -1;
+ PDEBUG(D_PROBE, "v%s registered", version);
+ return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+ usb_deregister(&sd_driver);
+ PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/linux/drivers/media/video/gspca/sonixj.c b/linux/drivers/media/video/gspca/sonixj.c
new file mode 100644
index 000000000..785ca2e50
--- /dev/null
+++ b/linux/drivers/media/video/gspca/sonixj.c
@@ -0,0 +1,1686 @@
+/*
+ * Sonix sn9c102p sn9c105 sn9c120 (jpeg) library
+ * Copyright (C) 2005 Michel Xhaard mxhaard@magic.fr
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define MODULE_NAME "sonixj"
+
+#include "gspca.h"
+#include "jpeg.h"
+
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 5)
+static const char version[] = "2.1.5";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("GSPCA/SONIX JPEG USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+
+ int avg_lum;
+ unsigned int exposure;
+
+ unsigned short brightness;
+ unsigned char contrast;
+ unsigned char colors;
+ unsigned char autogain;
+
+ signed char ag_cnt;
+#define AG_CNT_START 13
+
+ char qindex;
+ char sensor; /* Type of image sensor chip */
+#define SENSOR_HV7131R 0
+#define SENSOR_MI0360 1
+#define SENSOR_MO4000 2
+#define SENSOR_OV7648 3
+#define SENSOR_OV7660 4
+ unsigned char customid;
+#define SN9C102P 0
+#define SN9C105 1
+#define SN9C110 2
+#define SN9C120 3
+#define SN9C325 4
+ unsigned char i2c_base;
+ unsigned char i2c_ctrl_reg;
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+ {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+ .maximum = 0xffff,
+ .step = 1,
+#define BRIGHTNESS_DEF 0x7fff
+ .default_value = BRIGHTNESS_DEF,
+ },
+ .set = sd_setbrightness,
+ .get = sd_getbrightness,
+ },
+ {
+ {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = 0,
+ .maximum = 127,
+ .step = 1,
+#define CONTRAST_DEF 63
+ .default_value = CONTRAST_DEF,
+ },
+ .set = sd_setcontrast,
+ .get = sd_getcontrast,
+ },
+ {
+ {
+ .id = V4L2_CID_SATURATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Color",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+#define COLOR_DEF 127
+ .default_value = COLOR_DEF,
+ },
+ .set = sd_setcolors,
+ .get = sd_getcolors,
+ },
+ {
+ {
+ .id = V4L2_CID_AUTOGAIN,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Auto Gain",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+#define AUTOGAIN_DEF 1
+ .default_value = AUTOGAIN_DEF,
+ },
+ .set = sd_setautogain,
+ .get = sd_getautogain,
+ },
+};
+
+static struct v4l2_pix_format vga_mode[] = {
+ {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 160,
+ .sizeimage = 160 * 120 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 2},
+ {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 1},
+ {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 0},
+};
+
+/*Data from sn9c102p+hv71331r */
+static const __u8 sn_hv7131[] = {
+ 0x00, 0x03, 0x64, 0x00, 0x1A, 0x20, 0x20, 0x20, 0xA1, 0x11,
+/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 reg9 */
+ 0x02, 0x09, 0x00, 0x00, 0x00, 0x10, 0x03, 0x00, /* 00 */
+/* rega regb regc regd rege regf reg10 reg11 */
+ 0x00, 0x01, 0x03, 0x28, 0x1e, 0x41, 0x0a, 0x00, 0x00, 0x00,
+/* reg12 reg13 reg14 reg15 reg16 reg17 reg18 reg19 reg1a reg1b */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+/* reg1c reg1d reg1e reg1f reg20 reg21 reg22 reg23 */
+};
+
+static const __u8 sn_mi0360[] = {
+ 0x00, 0x61, 0x44, 0x00, 0x1a, 0x20, 0x20, 0x20, 0xb1, 0x5d,
+/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 reg9 */
+ 0x07, 0x00, 0x00, 0x00, 0x00, 0x10, 0x03, 0x00,
+/* rega regb regc regd rege regf reg10 reg11 */
+ 0x00, 0x02, 0x0a, 0x28, 0x1e, 0x61, 0x06, 0x00, 0x00, 0x00,
+/* reg12 reg13 reg14 reg15 reg16 reg17 reg18 reg19 reg1a reg1b */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+/* reg1c reg1d reg1e reg1f reg20 reg21 reg22 reg23 */
+};
+
+static const __u8 sn_mo4000[] = {
+ 0x12, 0x23, 0x60, 0x00, 0x1A, 0x00, 0x20, 0x18, 0x81,
+/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 */
+ 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00,
+/* reg9 rega regb regc regd rege regf reg10 reg11*/
+ 0x0b, 0x0f, 0x14, 0x28, 0x1e, 0x40, 0x08, 0x00, 0x00,
+/* reg12 reg13 reg14 reg15 reg16 reg17 reg18 reg19 reg1a*/
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x25, 0x39, 0x4b,
+/* reg1b reg1c reg1d reg1e reg1f reg20 reg21 reg22 reg23*/
+ 0x5c, 0x6b, 0x79, 0x87, 0x95, 0xa2, 0xaf, 0xbb, 0xc7,
+ 0xd3, 0xdf, 0xea, 0xf5
+};
+
+static const __u8 sn_ov7648[] = {
+ 0x00, 0x21, 0x62, 0x00, 0x1a, 0x20, 0x20, 0x20, 0xA1, 0x6E, 0x18, 0x65,
+ 0x00, 0x00, 0x00, 0x10, 0x03, 0x00, 0x00, 0x06, 0x06, 0x28, 0x1E, 0x82,
+ 0x07, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static const __u8 sn_ov7660[] = {
+# if 1 /*jfm: from win trace */
+/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 */
+ 0x00, 0x61, 0x40, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x81,
+/* reg9 rega regb regc regd rege regf reg10 reg11*/
+ 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00,
+/* reg12 reg13 reg14 reg15 reg16 reg17 reg18 reg19 reg1a*/
+ 0x01, 0x01, 0x08, 0x28, 0x1e, 0x20, 0x07, 0x00, 0x00,
+/* reg1b reg1c reg1d reg1e reg1f reg20 reg21 reg22 reg23*/
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+#else
+/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 */
+ 0x00, 0x61, 0x40, 0x00, 0x1a, 0x20, 0x20, 0x20, 0x81,
+/* reg9 rega regb regc regd rege regf reg10 reg11*/
+ 0x21, 0x07, 0x00, 0x00, 0x00, 0x00, 0x10, 0x03, 0x00,
+/* reg12 reg13 reg14 reg15 reg16 reg17 reg18 reg19 reg1a*/
+ 0x01, 0x01, 0x08, 0x28, 0x1e, 0x20, 0x07, 0x00, 0x00,
+/* reg1b reg1c reg1d reg1e reg1f reg20 reg21 reg22 reg23*/
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+#endif
+};
+
+/* sequence specific to the sensors - !! index = SENSOR_xxx */
+static const __u8 *sn_tb[] = {
+ sn_hv7131,
+ sn_mi0360,
+ sn_mo4000,
+ sn_ov7648,
+ sn_ov7660
+};
+
+static const __u8 regsn20[] = {
+ 0x00, 0x2d, 0x46, 0x5a, 0x6c, 0x7c, 0x8b, 0x99,
+ 0xa6, 0xb2, 0xbf, 0xca, 0xd5, 0xe0, 0xeb, 0xf5, 0xff
+};
+static const __u8 regsn20_sn9c325[] = {
+ 0x0a, 0x3a, 0x56, 0x6c, 0x7e, 0x8d, 0x9a, 0xa4,
+ 0xaf, 0xbb, 0xc5, 0xcd, 0xd5, 0xde, 0xe8, 0xed, 0xf5
+};
+
+static const __u8 reg84[] = {
+ 0x14, 0x00, 0x27, 0x00, 0x07, 0x00, 0xe5, 0x0f,
+ 0xe4, 0x0f, 0x38, 0x00, 0x3e, 0x00, 0xc3, 0x0f,
+/* 0x00, 0x00, 0x00, 0x00, 0x00 */
+ 0xf7, 0x0f, 0x0a, 0x00, 0x00
+};
+static const __u8 reg84_sn9c325[] = {
+ 0x14, 0x00, 0x27, 0x00, 0x07, 0x00, 0xe4, 0x0f,
+ 0xd3, 0x0f, 0x4b, 0x00, 0x48, 0x00, 0xc0, 0x0f,
+ 0xf8, 0x0f, 0x00, 0x00, 0x00
+};
+
+static const __u8 hv7131r_sensor_init[][8] = {
+ {0xC1, 0x11, 0x01, 0x08, 0x01, 0x00, 0x00, 0x10},
+ {0xB1, 0x11, 0x34, 0x17, 0x7F, 0x00, 0x00, 0x10},
+ {0xD1, 0x11, 0x40, 0xFF, 0x7F, 0x7F, 0x7F, 0x10},
+ {0x91, 0x11, 0x44, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xD1, 0x11, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xD1, 0x11, 0x14, 0x01, 0xE2, 0x02, 0x82, 0x10},
+ {0x91, 0x11, 0x18, 0x00, 0x00, 0x00, 0x00, 0x10},
+
+ {0xA1, 0x11, 0x01, 0x08, 0x00, 0x00, 0x00, 0x10},
+ {0xA1, 0x11, 0x01, 0x08, 0x00, 0x00, 0x00, 0x10},
+ {0xC1, 0x11, 0x25, 0x00, 0x61, 0xA8, 0x00, 0x10},
+ {0xA1, 0x11, 0x30, 0x22, 0x00, 0x00, 0x00, 0x10},
+ {0xC1, 0x11, 0x31, 0x20, 0x2E, 0x20, 0x00, 0x10},
+ {0xC1, 0x11, 0x25, 0x00, 0xC3, 0x50, 0x00, 0x10},
+ {0xA1, 0x11, 0x30, 0x07, 0x00, 0x00, 0x00, 0x10}, /* gain14 */
+ {0xC1, 0x11, 0x31, 0x10, 0x10, 0x10, 0x00, 0x10}, /* r g b 101a10 */
+
+ {0xA1, 0x11, 0x01, 0x08, 0x00, 0x00, 0x00, 0x10},
+ {0xA1, 0x11, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xA1, 0x11, 0x21, 0xD0, 0x00, 0x00, 0x00, 0x10},
+ {0xA1, 0x11, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xA1, 0x11, 0x23, 0x09, 0x00, 0x00, 0x00, 0x10},
+
+ {0xA1, 0x11, 0x01, 0x08, 0x00, 0x00, 0x00, 0x10},
+ {0xA1, 0x11, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xA1, 0x11, 0x21, 0xD0, 0x00, 0x00, 0x00, 0x10},
+ {0xA1, 0x11, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xA1, 0x11, 0x23, 0x10, 0x00, 0x00, 0x00, 0x10},
+ {}
+};
+static const __u8 mi0360_sensor_init[][8] = {
+ {0xB1, 0x5D, 0x07, 0x00, 0x02, 0x00, 0x00, 0x10},
+ {0xB1, 0x5D, 0x0D, 0x00, 0x01, 0x00, 0x00, 0x10},
+ {0xB1, 0x5D, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xD1, 0x5D, 0x01, 0x00, 0x08, 0x00, 0x16, 0x10},
+ {0xD1, 0x5D, 0x03, 0x01, 0xE2, 0x02, 0x82, 0x10},
+ {0xD1, 0x5D, 0x05, 0x00, 0x09, 0x00, 0x53, 0x10},
+ {0xB1, 0x5D, 0x0D, 0x00, 0x02, 0x00, 0x00, 0x10},
+ {0xD1, 0x5D, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xD1, 0x5D, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xD1, 0x5D, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xD1, 0x5D, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xD1, 0x5D, 0x12, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xD1, 0x5D, 0x14, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xD1, 0x5D, 0x16, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xD1, 0x5D, 0x18, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xD1, 0x5D, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xD1, 0x5D, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xB1, 0x5D, 0x32, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xD1, 0x5D, 0x20, 0x91, 0x01, 0x00, 0x00, 0x10},
+ {0xD1, 0x5D, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xD1, 0x5D, 0x24, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xD1, 0x5D, 0x26, 0x00, 0x00, 0x00, 0x24, 0x10},
+ {0xD1, 0x5D, 0x2F, 0xF7, 0xB0, 0x00, 0x04, 0x10},
+ {0xD1, 0x5D, 0x31, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xD1, 0x5D, 0x33, 0x00, 0x00, 0x01, 0x00, 0x10},
+ {0xB1, 0x5D, 0x3D, 0x06, 0x8F, 0x00, 0x00, 0x10},
+ {0xD1, 0x5D, 0x40, 0x01, 0xE0, 0x00, 0xD1, 0x10},
+ {0xB1, 0x5D, 0x44, 0x00, 0x82, 0x00, 0x00, 0x10},
+ {0xD1, 0x5D, 0x58, 0x00, 0x78, 0x00, 0x43, 0x10},
+ {0xD1, 0x5D, 0x5A, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xD1, 0x5D, 0x5C, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xD1, 0x5D, 0x5E, 0x00, 0x00, 0xA3, 0x1D, 0x10},
+ {0xB1, 0x5D, 0x62, 0x04, 0x11, 0x00, 0x00, 0x10},
+
+ {0xB1, 0x5D, 0x20, 0x91, 0x01, 0x00, 0x00, 0x10},
+ {0xB1, 0x5D, 0x20, 0x11, 0x01, 0x00, 0x00, 0x10},
+ {0xB1, 0x5D, 0x09, 0x00, 0x64, 0x00, 0x00, 0x10},
+ {0xD1, 0x5D, 0x2B, 0x00, 0xA0, 0x00, 0xB0, 0x10},
+ {0xD1, 0x5D, 0x2D, 0x00, 0xA0, 0x00, 0xA0, 0x10},
+
+ {0xB1, 0x5D, 0x0A, 0x00, 0x02, 0x00, 0x00, 0x10}, /* sensor clck ?2 */
+ {0xB1, 0x5D, 0x06, 0x00, 0x30, 0x00, 0x00, 0x10},
+ {0xB1, 0x5D, 0x05, 0x00, 0x0A, 0x00, 0x00, 0x10},
+ {0xB1, 0x5D, 0x09, 0x02, 0x35, 0x00, 0x00, 0x10}, /* exposure 2 */
+
+ {0xD1, 0x5D, 0x2B, 0x00, 0xB9, 0x00, 0xE3, 0x10},
+ {0xD1, 0x5D, 0x2D, 0x00, 0x5f, 0x00, 0xB9, 0x10}, /* 42 */
+/* {0xB1, 0x5D, 0x35, 0x00, 0x67, 0x00, 0x00, 0x10}, * gain orig */
+/* {0xB1, 0x5D, 0x35, 0x00, 0x20, 0x00, 0x00, 0x10}, * gain */
+ {0xB1, 0x5D, 0x07, 0x00, 0x03, 0x00, 0x00, 0x10}, /* update */
+ {0xB1, 0x5D, 0x07, 0x00, 0x02, 0x00, 0x00, 0x10}, /* sensor on */
+ {}
+};
+static const __u8 mo4000_sensor_init[][8] = {
+ {0xa1, 0x21, 0x01, 0x02, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x02, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x04, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x05, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x05, 0x04, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x06, 0x80, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x06, 0x81, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x11, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x11, 0x20, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x11, 0x30, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x11, 0x38, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x11, 0x38, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x12, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x0f, 0x20, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x10, 0x20, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x11, 0x38, 0x00, 0x00, 0x00, 0x10},
+ {}
+};
+static const __u8 ov7660_sensor_init[][8] = {
+ {0xa1, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10}, /* reset SCCB */
+ {0xa1, 0x21, 0x12, 0x05, 0x00, 0x00, 0x00, 0x10},
+ /* Outformat ?? rawRGB */
+ {0xa1, 0x21, 0x13, 0xb8, 0x00, 0x00, 0x00, 0x10}, /* init COM8 */
+/* {0xd1, 0x21, 0x00, 0x01, 0x74, 0x92, 0x00, 0x10},
+ * GAIN BLUE RED VREF */
+ {0xd1, 0x21, 0x00, 0x01, 0x74, 0x74, 0x00, 0x10},
+ /* GAIN BLUE RED VREF */
+ {0xd1, 0x21, 0x04, 0x00, 0x7d, 0x62, 0x00, 0x10},
+ /* COM 1 BAVE GEAVE AECHH */
+ {0xb1, 0x21, 0x08, 0x83, 0x01, 0x00, 0x00, 0x10}, /* RAVE COM2 */
+ {0xd1, 0x21, 0x0c, 0x00, 0x08, 0x04, 0x4f, 0x10}, /* COM 3 4 5 6 */
+/* {0xd1, 0x21, 0x10, 0x7f, 0x40, 0x05, 0xf8, 0x10},
+ * AECH CLKRC COM7 COM8 */
+ {0xd1, 0x21, 0x10, 0x7f, 0x40, 0x05, 0xff, 0x10},
+ /* AECH CLKRC COM7 COM8 */
+ {0xc1, 0x21, 0x14, 0x2c, 0x00, 0x02, 0x00, 0x10}, /* COM9 COM10 */
+ {0xd1, 0x21, 0x17, 0x10, 0x60, 0x02, 0x7b, 0x10},
+ /* HSTART HSTOP VSTRT VSTOP */
+ {0xa1, 0x21, 0x1b, 0x02, 0x00, 0x00, 0x00, 0x10}, /* PSHFT */
+ {0xb1, 0x21, 0x1e, 0x01, 0x0e, 0x00, 0x00, 0x10}, /* MVFP LAEC */
+ {0xd1, 0x21, 0x20, 0x07, 0x07, 0x07, 0x07, 0x10},
+ /* BOS GBOS GROS ROS (BGGR offset) */
+/* {0xd1, 0x21, 0x24, 0x68, 0x58, 0xd4, 0x80, 0x10},
+ * AEW AEB VPT BBIAS */
+ {0xd1, 0x21, 0x24, 0x78, 0x68, 0xd4, 0x80, 0x10},
+ /* AEW AEB VPT BBIAS */
+ {0xd1, 0x21, 0x28, 0x80, 0x30, 0x00, 0x00, 0x10},
+ /* GbBIAS RSVD EXHCH EXHCL */
+ {0xd1, 0x21, 0x2c, 0x80, 0x00, 0x00, 0x62, 0x10},
+ /* RBIAS ADVFL ASDVFH YAVE */
+ {0xc1, 0x21, 0x30, 0x08, 0x30, 0xb4, 0x00, 0x10},
+ /* HSYST HSYEN HREF */
+ {0xd1, 0x21, 0x33, 0x00, 0x07, 0x84, 0x00, 0x10}, /* reserved */
+ {0xd1, 0x21, 0x37, 0x0c, 0x02, 0x43, 0x00, 0x10},
+ /* ADC ACOM OFON TSLB */
+ {0xd1, 0x21, 0x3b, 0x02, 0x6c, 0x19, 0x0e, 0x10},
+ /* COM11 COM12 COM13 COM14 */
+ {0xd1, 0x21, 0x3f, 0x41, 0xc1, 0x22, 0x08, 0x10},
+ /* EDGE COM15 COM16 COM17 */
+ {0xd1, 0x21, 0x43, 0xf0, 0x10, 0x78, 0xa8, 0x10}, /* reserved */
+ {0xd1, 0x21, 0x47, 0x60, 0x80, 0x00, 0x00, 0x10}, /* reserved */
+ {0xd1, 0x21, 0x4b, 0x00, 0x00, 0x00, 0x00, 0x10}, /* reserved */
+ {0xd1, 0x21, 0x4f, 0x46, 0x36, 0x0f, 0x17, 0x10}, /* MTX 1 2 3 4 */
+ {0xd1, 0x21, 0x53, 0x7f, 0x96, 0x40, 0x40, 0x10}, /* MTX 5 6 7 8 */
+ {0xb1, 0x21, 0x57, 0x40, 0x0f, 0x00, 0x00, 0x10}, /* MTX9 MTXS */
+ {0xd1, 0x21, 0x59, 0xba, 0x9a, 0x22, 0xb9, 0x10}, /* reserved */
+ {0xd1, 0x21, 0x5d, 0x9b, 0x10, 0xf0, 0x05, 0x10}, /* reserved */
+ {0xa1, 0x21, 0x61, 0x60, 0x00, 0x00, 0x00, 0x10}, /* reserved */
+ {0xd1, 0x21, 0x62, 0x00, 0x00, 0x50, 0x30, 0x10},
+ /* LCC1 LCC2 LCC3 LCC4 */
+ {0xa1, 0x21, 0x66, 0x00, 0x00, 0x00, 0x00, 0x10}, /* LCC5 */
+ {0xd1, 0x21, 0x67, 0x80, 0x7a, 0x90, 0x80, 0x10},
+ {0xa1, 0x21, 0x6b, 0x0a, 0x00, 0x00, 0x00, 0x10},
+ /* band gap reference [0..3] DBLV */
+ {0xd1, 0x21, 0x6c, 0x30, 0x48, 0x80, 0x74, 0x10}, /* gamma curve */
+ {0xd1, 0x21, 0x70, 0x64, 0x60, 0x5c, 0x58, 0x10}, /* gamma curve */
+ {0xd1, 0x21, 0x74, 0x54, 0x4c, 0x40, 0x38, 0x10}, /* gamma curve */
+ {0xd1, 0x21, 0x78, 0x34, 0x30, 0x2f, 0x2b, 0x10}, /* gamma curve */
+ {0xd1, 0x21, 0x7c, 0x03, 0x07, 0x17, 0x34, 0x10}, /* gamma curve */
+ {0xd1, 0x21, 0x80, 0x41, 0x4d, 0x58, 0x63, 0x10}, /* gamma curve */
+ {0xd1, 0x21, 0x84, 0x6e, 0x77, 0x87, 0x95, 0x10}, /* gamma curve */
+ {0xc1, 0x21, 0x88, 0xaf, 0xc7, 0xdf, 0x00, 0x10}, /* gamma curve */
+ {0xc1, 0x21, 0x8b, 0x99, 0x99, 0xcf, 0x00, 0x10}, /* reserved */
+ {0xb1, 0x21, 0x92, 0x00, 0x00, 0x00, 0x00, 0x10},
+/****** (some exchanges in the win trace) ******/
+ {0xa1, 0x21, 0x1e, 0x01, 0x00, 0x00, 0x00, 0x10},
+ /* bits[3..0]reserved */
+ {0xa1, 0x21, 0x1e, 0x01, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10},
+ /* VREF vertical frame ctrl */
+ {0xa1, 0x21, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x10, 0x20, 0x00, 0x00, 0x00, 0x10}, /* 0x20 */
+ {0xa1, 0x21, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x10},
+/* {0xb1, 0x21, 0x01, 0x78, 0x78, 0x00, 0x00, 0x10}, */
+/****** (some exchanges in the win trace) ******/
+ {0xa1, 0x21, 0x93, 0x00, 0x00, 0x00, 0x00, 0x10},/* dummy line hight */
+ {0xa1, 0x21, 0x92, 0x25, 0x00, 0x00, 0x00, 0x10},/* dummy line low */
+ {0xa1, 0x21, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x10},
+/* {0xa1, 0x21, 0x02, 0x90, 0x00, 0x00, 0x00, 0x10}, */
+/****** (some exchanges in the win trace) ******/
+/**********startsensor KO if changed !!****/
+ {0xa1, 0x21, 0x93, 0x01, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x92, 0xff, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x2b, 0xc3, 0x00, 0x00, 0x00, 0x10},
+/* here may start the isoc exchanges */
+ {}
+};
+/* reg0x04 reg0x07 reg 0x10 */
+/* expo = (COM1 & 0x02) | (AECHH & 0x2f <<10) [ (AECh << 2) */
+
+static const __u8 ov7648_sensor_init[][8] = {
+ {0xC1, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00},
+ {0xC1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00},
+ {0xC1, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00},
+ {0xA1, 0x6E, 0x3F, 0x20, 0x00, 0x00, 0x00, 0x10},
+ {0xA1, 0x6E, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xA1, 0x6E, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xD1, 0x6E, 0x04, 0x02, 0xB1, 0x02, 0x39, 0x10},
+ {0xD1, 0x6E, 0x08, 0x00, 0x01, 0x00, 0x00, 0x10},
+ {0xD1, 0x6E, 0x0C, 0x02, 0x7F, 0x01, 0xE0, 0x10},
+ {0xD1, 0x6E, 0x12, 0x03, 0x02, 0x00, 0x03, 0x10},
+ {0xD1, 0x6E, 0x16, 0x85, 0x40, 0x4A, 0x40, 0x10},
+ {0xC1, 0x6E, 0x1A, 0x00, 0x80, 0x00, 0x00, 0x10},
+ {0xD1, 0x6E, 0x1D, 0x08, 0x03, 0x00, 0x00, 0x10},
+ {0xD1, 0x6E, 0x23, 0x00, 0xB0, 0x00, 0x94, 0x10},
+ {0xD1, 0x6E, 0x27, 0x58, 0x00, 0x00, 0x00, 0x10},
+ {0xD1, 0x6E, 0x2D, 0x14, 0x35, 0x61, 0x84, 0x10},
+ {0xD1, 0x6E, 0x31, 0xA2, 0xBD, 0xD8, 0xFF, 0x10},
+ {0xD1, 0x6E, 0x35, 0x06, 0x1E, 0x12, 0x02, 0x10},
+ {0xD1, 0x6E, 0x39, 0xAA, 0x53, 0x37, 0xD5, 0x10},
+ {0xA1, 0x6E, 0x3D, 0xF2, 0x00, 0x00, 0x00, 0x10},
+ {0xD1, 0x6E, 0x3E, 0x00, 0x00, 0x80, 0x03, 0x10},
+ {0xD1, 0x6E, 0x42, 0x03, 0x00, 0x00, 0x00, 0x10},
+ {0xC1, 0x6E, 0x46, 0x00, 0x80, 0x80, 0x00, 0x10},
+ {0xD1, 0x6E, 0x4B, 0x02, 0xEF, 0x08, 0xCD, 0x10},
+ {0xD1, 0x6E, 0x4F, 0x00, 0xD0, 0x00, 0xA0, 0x10},
+ {0xD1, 0x6E, 0x53, 0x01, 0xAA, 0x01, 0x40, 0x10},
+ {0xD1, 0x6E, 0x5A, 0x50, 0x04, 0x30, 0x03, 0x10},
+ {0xA1, 0x6E, 0x5E, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xD1, 0x6E, 0x5F, 0x10, 0x40, 0xFF, 0x00, 0x10},
+ /* {0xD1, 0x6E, 0x63, 0x40, 0x40, 0x00, 0x00, 0x10},
+ {0xD1, 0x6E, 0x67, 0x00, 0x00, 0x00, 0x00, 0x10},
+ * This is currently setting a
+ * blue tint, and some things more , i leave it here for future test if
+ * somene is having problems with color on this sensor
+ {0xD1, 0x6E, 0x6B, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xD1, 0x6E, 0x6F, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xC1, 0x6E, 0x73, 0x10, 0x80, 0xEB, 0x00, 0x10},
+ {0xA1, 0x6E, 0x1E, 0x03, 0x00, 0x00, 0x00, 0x10},
+ {0xA1, 0x6E, 0x15, 0x01, 0x00, 0x00, 0x00, 0x10},
+ {0xC1, 0x6E, 0x16, 0x40, 0x40, 0x40, 0x00, 0x10},
+ {0xA1, 0x6E, 0x1D, 0x08, 0x00, 0x00, 0x00, 0x10},
+ {0xA1, 0x6E, 0x06, 0x02, 0x00, 0x00, 0x00, 0x10},
+ {0xA1, 0x6E, 0x07, 0xB5, 0x00, 0x00, 0x00, 0x10},
+ {0xA1, 0x6E, 0x18, 0x6B, 0x00, 0x00, 0x00, 0x10},
+ {0xA1, 0x6E, 0x1D, 0x08, 0x00, 0x00, 0x00, 0x10},
+ {0xA1, 0x6E, 0x06, 0x02, 0x00, 0x00, 0x00, 0x10},
+ {0xA1, 0x6E, 0x07, 0xB8, 0x00, 0x00, 0x00, 0x10}, */
+ {0xC1, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00},
+ {0xA1, 0x6E, 0x06, 0x03, 0x00, 0x00, 0x00, 0x10}, /* Bright... */
+ {0xA1, 0x6E, 0x07, 0x66, 0x00, 0x00, 0x00, 0x10}, /* B.. */
+ {0xC1, 0x6E, 0x1A, 0x03, 0x65, 0x90, 0x00, 0x10}, /* Bright/Witen....*/
+/* {0xC1, 0x6E, 0x16, 0x45, 0x40, 0x60, 0x00, 0x10}, * Bright/Witene */
+ {}
+};
+
+static const __u8 qtable4[] = {
+ 0x06, 0x04, 0x04, 0x06, 0x04, 0x04, 0x06, 0x06, 0x06, 0x06, 0x08, 0x06,
+ 0x06, 0x08, 0x0A, 0x11,
+ 0x0A, 0x0A, 0x08, 0x08, 0x0A, 0x15, 0x0F, 0x0F, 0x0C, 0x11, 0x19, 0x15,
+ 0x19, 0x19, 0x17, 0x15,
+ 0x17, 0x17, 0x1B, 0x1D, 0x25, 0x21, 0x1B, 0x1D, 0x23, 0x1D, 0x17, 0x17,
+ 0x21, 0x2E, 0x21, 0x23,
+ 0x27, 0x29, 0x2C, 0x2C, 0x2C, 0x19, 0x1F, 0x30, 0x32, 0x2E, 0x29, 0x32,
+ 0x25, 0x29, 0x2C, 0x29,
+ 0x06, 0x08, 0x08, 0x0A, 0x08, 0x0A, 0x13, 0x0A, 0x0A, 0x13, 0x29, 0x1B,
+ 0x17, 0x1B, 0x29, 0x29,
+ 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
+ 0x29, 0x29, 0x29, 0x29,
+ 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
+ 0x29, 0x29, 0x29, 0x29,
+ 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
+ 0x29, 0x29, 0x29, 0x29
+};
+
+static void reg_r(struct usb_device *dev,
+ __u16 value,
+ __u8 *buffer, int len)
+{
+ usb_control_msg(dev,
+ usb_rcvctrlpipe(dev, 0),
+ 0,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+ value, 0,
+ buffer, len,
+ 500);
+}
+
+static void reg_w(struct usb_device *dev,
+ __u16 value,
+ const __u8 *buffer,
+ int len)
+{
+ if (len < 16) {
+ __u8 tmpbuf[16];
+
+ memcpy(tmpbuf, buffer, len);
+ usb_control_msg(dev,
+ usb_sndctrlpipe(dev, 0),
+ 0x08,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+ value, 0,
+ tmpbuf, len,
+ 500);
+ } else {
+ __u8 *tmpbuf;
+
+ tmpbuf = kmalloc(len, GFP_KERNEL);
+ memcpy(tmpbuf, buffer, len);
+ usb_control_msg(dev,
+ usb_sndctrlpipe(dev, 0),
+ 0x08,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+ value, 0,
+ tmpbuf, len,
+ 500);
+ kfree(tmpbuf);
+ }
+}
+
+/* write 2 bytes */
+static void i2c_w2(struct gspca_dev *gspca_dev,
+ const __u8 *buffer)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+ __u8 mode[8];
+
+ /* is i2c ready */
+ mode[0] = sd->i2c_ctrl_reg | (2 << 4);
+ mode[1] = sd->i2c_base;
+ mode[2] = buffer[0];
+ mode[3] = buffer[1];
+ mode[4] = 0;
+ mode[5] = 0;
+ mode[6] = 0;
+ mode[7] = 0x10;
+ reg_w(dev, 0x08, mode, 8);
+}
+
+/* write 8 bytes */
+static void i2c_w8(struct usb_device *dev, const __u8 *buffer)
+{
+ reg_w(dev, 0x08, buffer, 8);
+ msleep(1);
+}
+
+/* read 5 bytes */
+static void i2c_r5(struct gspca_dev *gspca_dev, __u8 reg,
+ __u8 *buffer)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+ __u8 mode[8];
+
+ mode[0] = sd->i2c_ctrl_reg | 0x10;
+ mode[1] = sd->i2c_base;
+ mode[2] = reg;
+ mode[3] = 0;
+ mode[4] = 0;
+ mode[5] = 0;
+ mode[6] = 0;
+ mode[7] = 0x10;
+ i2c_w8(dev, mode);
+ mode[0] = sd->i2c_ctrl_reg | (5 << 4) | 0x02;
+ mode[2] = 0;
+ i2c_w8(dev, mode);
+ reg_r(dev, 0x0a, buffer, 5);
+}
+
+static int probesensor(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+ __u8 reg02;
+ static const __u8 datasend[] = { 2, 0 };
+ /* reg val1 val2 val3 val4 */
+ __u8 datarecd[6];
+
+ i2c_w2(gspca_dev, datasend);
+/* should write 0xa1 0x11 0x02 0x00 0x00 0x00 0x00 the 0x10 is add by i2cw */
+ msleep(10);
+ reg02 = 0x66;
+ reg_w(dev, 0x02, &reg02, 1); /* Gpio on */
+ msleep(10);
+ i2c_r5(gspca_dev, 0, datarecd); /* read sensor id */
+ if (datarecd[0] == 0x02
+ && datarecd[1] == 0x09
+ && datarecd[2] == 0x01
+ && datarecd[3] == 0x00
+ && datarecd[4] == 0x00) {
+ PDEBUG(D_PROBE, "Find Sensor sn9c102P HV7131R");
+ sd->sensor = SENSOR_HV7131R;
+ return SENSOR_HV7131R;
+ }
+ PDEBUG(D_PROBE, "Find Sensor %d %d %d",
+ datarecd[0], datarecd[1], datarecd[2]);
+ PDEBUG(D_PROBE, "Sensor sn9c102P Not found");
+ return -ENODEV;
+}
+
+static int configure_gpio(struct gspca_dev *gspca_dev,
+ const __u8 *sn9c1xx)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+ __u8 data;
+ __u8 regF1;
+ const __u8 *reg9a;
+ static const __u8 reg9a_def[] =
+ {0x08, 0x40, 0x20, 0x10, 0x00, 0x04};
+ static const __u8 reg9a_sn9c120[] = /* from win trace */
+ {0x00, 0x40, 0x38, 0x30, 0x00, 0x20};
+ static const __u8 reg9a_sn9c325[] =
+ {0x0a, 0x40, 0x38, 0x30, 0x00, 0x20};
+
+
+ regF1 = 0x00;
+ reg_w(dev, 0xf1, &regF1, 1);
+
+ reg_w(dev, 0x01, &sn9c1xx[0], 1); /*fixme:jfm was [1] en v1*/
+
+ /* configure gpio */
+ reg_w(dev, 0x01, &sn9c1xx[1], 2);
+ reg_w(dev, 0x08, &sn9c1xx[8], 2);
+ reg_w(dev, 0x17, &sn9c1xx[0x17], 3);
+ switch (sd->customid) {
+ case SN9C325:
+ reg9a = reg9a_sn9c325;
+ break;
+ case SN9C120:
+ reg9a = reg9a_sn9c120;
+ break;
+ default:
+ reg9a = reg9a_def;
+ break;
+ }
+ reg_w(dev, 0x9a, reg9a, 6);
+
+ data = 0x60; /*fixme:jfm 60 00 00 (3) */
+ reg_w(dev, 0xd4, &data, 1);
+
+ reg_w(dev, 0x03, &sn9c1xx[3], 0x0f);
+
+ switch (sd->customid) {
+ case SN9C120: /* from win trace */
+ data = 0x61;
+ reg_w(dev, 0x01, &data, 1);
+ data = 0x20;
+ reg_w(dev, 0x17, &data, 1);
+ data = 0x60;
+ reg_w(dev, 0x01, &data, 1);
+ break;
+ case SN9C325:
+ data = 0x43;
+ reg_w(dev, 0x01, &data, 1);
+ data = 0xae;
+ reg_w(dev, 0x17, &data, 1);
+ data = 0x42;
+ reg_w(dev, 0x01, &data, 1);
+ break;
+ default:
+ data = 0x43;
+ reg_w(dev, 0x01, &data, 1);
+ data = 0x61;
+ reg_w(dev, 0x17, &data, 1);
+ data = 0x42;
+ reg_w(dev, 0x01, &data, 1);
+ }
+
+ if (sd->sensor == SENSOR_HV7131R) {
+ if (probesensor(gspca_dev) < 0)
+ return -ENODEV;
+ }
+ return 0;
+}
+
+static void hv7131R_InitSensor(struct gspca_dev *gspca_dev)
+{
+ int i = 0;
+ struct usb_device *dev = gspca_dev->dev;
+ static const __u8 SetSensorClk[] = /* 0x08 Mclk */
+ { 0xa1, 0x11, 0x01, 0x18, 0x00, 0x00, 0x00, 0x10 };
+
+ while (hv7131r_sensor_init[i][0]) {
+ i2c_w8(dev, hv7131r_sensor_init[i]);
+ i++;
+ }
+ i2c_w8(dev, SetSensorClk);
+}
+
+static void mi0360_InitSensor(struct gspca_dev *gspca_dev)
+{
+ int i = 0;
+ struct usb_device *dev = gspca_dev->dev;
+
+ while (mi0360_sensor_init[i][0]) {
+ i2c_w8(dev, mi0360_sensor_init[i]);
+ i++;
+ }
+}
+
+static void mo4000_InitSensor(struct gspca_dev *gspca_dev)
+{
+ int i = 0;
+ struct usb_device *dev = gspca_dev->dev;
+
+ while (mo4000_sensor_init[i][0]) {
+ i2c_w8(dev, mo4000_sensor_init[i]);
+ i++;
+ }
+}
+
+static void ov7648_InitSensor(struct gspca_dev *gspca_dev)
+{
+ struct usb_device *dev = gspca_dev->dev;
+ int i = 0;
+
+ while (ov7648_sensor_init[i][0]) {
+ i2c_w8(dev, ov7648_sensor_init[i]);
+ i++;
+ }
+}
+
+static void ov7660_InitSensor(struct gspca_dev *gspca_dev)
+{
+ int i = 0;
+ struct usb_device *dev = gspca_dev->dev;
+
+ while (ov7660_sensor_init[i][0]) {
+ i2c_w8(dev, ov7660_sensor_init[i]);
+ i++;
+ }
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+ const struct usb_device_id *id)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct cam *cam;
+ __u16 vendor;
+ __u16 product;
+
+ vendor = id->idVendor;
+ product = id->idProduct;
+ sd->sensor = -1;
+ switch (vendor) {
+ case 0x0458: /* Genius */
+/* switch (product) {
+ case 0x7025: */
+ sd->customid = SN9C120;
+ sd->sensor = SENSOR_MI0360;
+ sd->i2c_ctrl_reg = 0x81;
+ sd->i2c_base = 0x5d;
+/* break;
+ } */
+ break;
+ case 0x045e:
+/* switch (product) {
+ case 0x00f5:
+ case 0x00f7: */
+ sd->customid = SN9C105;
+ sd->sensor = SENSOR_OV7660;
+ sd->i2c_ctrl_reg = 0x81;
+ sd->i2c_base = 0x21;
+/* break;
+ } */
+ break;
+ case 0x0471: /* Philips */
+/* switch (product) {
+ case 0x0327:
+ case 0x0328:
+ case 0x0330: */
+ sd->customid = SN9C105;
+ sd->sensor = SENSOR_MI0360;
+ sd->i2c_ctrl_reg = 0x81;
+ sd->i2c_base = 0x5d;
+/* break;
+ } */
+ break;
+ case 0x0c45: /* Sonix */
+ switch (product) {
+ case 0x6040:
+ sd->customid = SN9C102P;
+ sd->sensor = SENSOR_MI0360; /* from BW600.inf */
+/* sd->sensor = SENSOR_HV7131R; * gspcav1 value */
+ sd->i2c_ctrl_reg = 0x81;
+ sd->i2c_base = 0x11;
+ break;
+/* case 0x607a: * from BW600.inf
+ sd->customid = SN9C102P;
+ sd->sensor = SENSOR_OV7648;
+ sd->i2c_ctrl_reg = 0x??;
+ sd->i2c_base = 0x??;
+ break; */
+ case 0x607c:
+ sd->customid = SN9C102P;
+ sd->sensor = SENSOR_HV7131R;
+ sd->i2c_ctrl_reg = 0x81;
+ sd->i2c_base = 0x11;
+ break;
+/* case 0x607e: * from BW600.inf
+ sd->customid = SN9C102P;
+ sd->sensor = SENSOR_OV7630;
+ sd->i2c_ctrl_reg = 0x??;
+ sd->i2c_base = 0x??;
+ break; */
+ case 0x60c0:
+ sd->customid = SN9C105;
+ sd->sensor = SENSOR_MI0360;
+ sd->i2c_ctrl_reg = 0x81;
+ sd->i2c_base = 0x5d;
+ break;
+/* case 0x60c8: * from BW600.inf
+ sd->customid = SN9C105;
+ sd->sensor = SENSOR_OM6801;
+ sd->i2c_ctrl_reg = 0x??;
+ sd->i2c_base = 0x??;
+ break; */
+/* case 0x60cc: * from BW600.inf
+ sd->customid = SN9C105;
+ sd->sensor = SENSOR_HV7131GP;
+ sd->i2c_ctrl_reg = 0x??;
+ sd->i2c_base = 0x??;
+ break; */
+ case 0x60ec:
+ sd->customid = SN9C105;
+ sd->sensor = SENSOR_MO4000;
+ sd->i2c_ctrl_reg = 0x81;
+ sd->i2c_base = 0x21;
+ break;
+/* case 0x60ef: * from BW600.inf
+ sd->customid = SN9C105;
+ sd->sensor = SENSOR_ICM105C;
+ sd->i2c_ctrl_reg = 0x??;
+ sd->i2c_base = 0x??;
+ break; */
+/* case 0x60fa: * from BW600.inf
+ sd->customid = SN9C105;
+ sd->sensor = SENSOR_OV7648;
+ sd->i2c_ctrl_reg = 0x??;
+ sd->i2c_base = 0x??;
+ break; */
+ case 0x60fb:
+ sd->customid = SN9C105;
+ sd->sensor = SENSOR_OV7660;
+ sd->i2c_ctrl_reg = 0x81;
+ sd->i2c_base = 0x21;
+ break;
+ case 0x60fc:
+ sd->customid = SN9C105;
+ sd->sensor = SENSOR_HV7131R;
+ sd->i2c_ctrl_reg = 0x81;
+ sd->i2c_base = 0x11;
+ break;
+/* case 0x60fe: * from BW600.inf
+ sd->customid = SN9C105;
+ sd->sensor = SENSOR_OV7630;
+ sd->i2c_ctrl_reg = 0x??;
+ sd->i2c_base = 0x??;
+ break; */
+/* case 0x6108: * from BW600.inf
+ sd->customid = SN9C120;
+ sd->sensor = SENSOR_OM6801;
+ sd->i2c_ctrl_reg = 0x??;
+ sd->i2c_base = 0x??;
+ break; */
+/* case 0x6122: * from BW600.inf
+ sd->customid = SN9C110;
+ sd->sensor = SENSOR_ICM105C;
+ sd->i2c_ctrl_reg = 0x??;
+ sd->i2c_base = 0x??;
+ break; */
+ case 0x612a:
+/* sd->customid = SN9C110; * in BW600.inf */
+ sd->customid = SN9C325;
+ sd->sensor = SENSOR_OV7648;
+ sd->i2c_ctrl_reg = 0x81;
+ sd->i2c_base = 0x21;
+ break;
+/* case 0x6123: * from BW600.inf
+ sd->customid = SN9C110;
+ sd->sensor = SENSOR_SanyoCCD;
+ sd->i2c_ctrl_reg = 0x??;
+ sd->i2c_base = 0x??;
+ break; */
+ case 0x612c:
+ sd->customid = SN9C110;
+ sd->sensor = SENSOR_MO4000;
+ sd->i2c_ctrl_reg = 0x81;
+ sd->i2c_base = 0x21;
+ break;
+/* case 0x612e: * from BW600.inf
+ sd->customid = SN9C110;
+ sd->sensor = SENSOR_OV7630;
+ sd->i2c_ctrl_reg = 0x??;
+ sd->i2c_base = 0x??;
+ break; */
+/* case 0x612f: * from BW600.inf
+ sd->customid = SN9C110;
+ sd->sensor = SENSOR_ICM105C;
+ sd->i2c_ctrl_reg = 0x??;
+ sd->i2c_base = 0x??;
+ break; */
+ case 0x6130:
+ sd->customid = SN9C120;
+ sd->sensor = SENSOR_MI0360;
+ sd->i2c_ctrl_reg = 0x81;
+ sd->i2c_base = 0x5d;
+ break;
+ case 0x6138:
+ sd->customid = SN9C120;
+ sd->sensor = SENSOR_MO4000;
+ sd->i2c_ctrl_reg = 0x81;
+ sd->i2c_base = 0x21;
+ break;
+/* case 0x613a: * from BW600.inf
+ sd->customid = SN9C120;
+ sd->sensor = SENSOR_OV7648;
+ sd->i2c_ctrl_reg = 0x??;
+ sd->i2c_base = 0x??;
+ break; */
+ case 0x613b:
+ sd->customid = SN9C120;
+ sd->sensor = SENSOR_OV7660;
+ sd->i2c_ctrl_reg = 0x81;
+ sd->i2c_base = 0x21;
+ break;
+ case 0x613c:
+ sd->customid = SN9C120;
+ sd->sensor = SENSOR_HV7131R;
+ sd->i2c_ctrl_reg = 0x81;
+ sd->i2c_base = 0x11;
+ break;
+/* case 0x613e: * from BW600.inf
+ sd->customid = SN9C120;
+ sd->sensor = SENSOR_OV7630;
+ sd->i2c_ctrl_reg = 0x??;
+ sd->i2c_base = 0x??;
+ break; */
+ }
+ break;
+ }
+ if (sd->sensor < 0) {
+ PDEBUG(D_ERR, "Invalid vendor/product %04x:%04x",
+ vendor, product);
+ return -EINVAL;
+ }
+
+ cam = &gspca_dev->cam;
+ cam->dev_name = (char *) id->driver_info;
+ cam->epaddr = 0x01;
+ cam->cam_mode = vga_mode;
+ cam->nmodes = ARRAY_SIZE(vga_mode);
+
+ sd->qindex = 4; /* set the quantization table */
+ sd->brightness = BRIGHTNESS_DEF;
+ sd->contrast = CONTRAST_DEF;
+ sd->colors = COLOR_DEF;
+ sd->autogain = AUTOGAIN_DEF;
+ return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+/* const __u8 *sn9c1xx; */
+ __u8 regF1;
+ __u8 regGpio[] = { 0x29, 0x74 };
+
+ /* setup a selector by customid */
+ regF1 = 0x01;
+ reg_w(dev, 0xf1, &regF1, 1);
+ reg_r(dev, 0x00, &regF1, 1); /* -> regF1 = 0x00 */
+ reg_w(dev, 0xf1, &regF1, 1);
+ reg_r(dev, 0x00, &regF1, 1);
+ switch (sd->customid) {
+ case SN9C102P:
+ if (regF1 != 0x11)
+ return -ENODEV;
+ reg_w(dev, 0x02, &regGpio[1], 1);
+ break;
+ case SN9C105:
+ if (regF1 != 0x11)
+ return -ENODEV;
+ reg_w(dev, 0x02, regGpio, 2);
+ break;
+ case SN9C110:
+ if (regF1 != 0x12)
+ return -ENODEV;
+ regGpio[1] = 0x62;
+ reg_w(dev, 0x02, &regGpio[1], 1);
+ break;
+ case SN9C120:
+ if (regF1 != 0x12)
+ return -ENODEV;
+ regGpio[1] = 0x70;
+ reg_w(dev, 0x02, regGpio, 2);
+ break;
+ default:
+/* case SN9C325: */
+ if (regF1 != 0x12)
+ return -ENODEV;
+ regGpio[1] = 0x62;
+ reg_w(dev, 0x02, &regGpio[1], 1);
+ break;
+ }
+
+ regF1 = 0x01;
+ reg_w(dev, 0xf1, &regF1, 1);
+
+#if 1 /*jfm: from win trace*/
+ return 0;
+#else
+ sn9c1xx = sn_tb[(int) sd->sensor];
+ return configure_gpio(gspca_dev, sn9c1xx);
+#endif
+}
+
+static unsigned int setexposure(struct gspca_dev *gspca_dev,
+ unsigned int expo)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ static const __u8 doit[] = /* update sensor */
+ { 0xb1, 0x5d, 0x07, 0x00, 0x03, 0x00, 0x00, 0x10 };
+ static const __u8 sensorgo[] = /* sensor on */
+ { 0xb1, 0x5d, 0x07, 0x00, 0x02, 0x00, 0x00, 0x10 };
+ static const __u8 gainMo[] =
+ { 0xa1, 0x21, 0x00, 0x10, 0x00, 0x00, 0x00, 0x1d };
+
+ switch (sd->sensor) {
+ case SENSOR_HV7131R: {
+ __u8 Expodoit[] =
+ { 0xc1, 0x11, 0x25, 0x07, 0x27, 0xc0, 0x00, 0x16 };
+
+ Expodoit[3] = expo >> 16;
+ Expodoit[4] = expo >> 8;
+ Expodoit[5] = expo;
+ i2c_w8(gspca_dev->dev, Expodoit);
+ break;
+ }
+ case SENSOR_MI0360: {
+ __u8 expoMi[] = /* exposure 0x0635 -> 4 fp/s 0x10 */
+ { 0xb1, 0x5d, 0x09, 0x06, 0x35, 0x00, 0x00, 0x16 };
+
+ if (expo > 0x0635)
+ expo = 0x0635;
+ else if (expo < 0x0001)
+ expo = 0x0001;
+ expoMi[3] = expo >> 8;
+ expoMi[4] = expo;
+ i2c_w8(gspca_dev->dev, expoMi);
+ i2c_w8(gspca_dev->dev, doit);
+ i2c_w8(gspca_dev->dev, sensorgo);
+ break;
+ }
+ case SENSOR_MO4000: {
+ __u8 expoMof[] =
+ { 0xa1, 0x21, 0x0f, 0x20, 0x00, 0x00, 0x00, 0x10 };
+ __u8 expoMo10[] =
+ { 0xa1, 0x21, 0x10, 0x20, 0x00, 0x00, 0x00, 0x10 };
+
+ if (expo > 0x1fff)
+ expo = 0x1fff;
+ else if (expo < 0x0001)
+ expo = 0x0001;
+ expoMof[3] = (expo & 0x03fc) >> 2;
+ i2c_w8(gspca_dev->dev, expoMof);
+ expoMo10[3] = ((expo & 0x1c00) >> 10)
+ | ((expo & 0x0003) << 4);
+ i2c_w8(gspca_dev->dev, expoMo10);
+ i2c_w8(gspca_dev->dev, gainMo);
+ PDEBUG(D_CONF, "set exposure %d",
+ ((expoMo10[3] & 0x07) << 10)
+ | (expoMof[3] << 2)
+ | ((expoMo10[3] & 0x30) >> 4));
+ break;
+ }
+ }
+ return expo;
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ unsigned int expo;
+ __u8 k2;
+
+ switch (sd->sensor) {
+ case SENSOR_HV7131R:
+ expo = sd->brightness << 4;
+ if (expo > 0x002dc6c0)
+ expo = 0x002dc6c0;
+ else if (expo < 0x02a0)
+ expo = 0x02a0;
+ sd->exposure = setexposure(gspca_dev, expo);
+ break;
+ case SENSOR_MI0360:
+ expo = sd->brightness >> 4;
+ sd->exposure = setexposure(gspca_dev, expo);
+ break;
+ case SENSOR_MO4000:
+ expo = sd->brightness >> 4;
+ sd->exposure = setexposure(gspca_dev, expo);
+ break;
+ case SENSOR_OV7660:
+ return; /*jfm??*/
+ }
+
+ k2 = sd->brightness >> 10;
+ reg_w(gspca_dev->dev, 0x96, &k2, 1);
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ __u8 k2;
+ __u8 contrast[] = { 0x00, 0x00, 0x28, 0x00, 0x07, 0x00 };
+
+ if (sd->sensor == SENSOR_OV7660)
+ return; /*jfm??*/
+ k2 = sd->contrast;
+ contrast[2] = k2;
+ contrast[0] = (k2 + 1) >> 1;
+ contrast[4] = (k2 + 1) / 5;
+ reg_w(gspca_dev->dev, 0x84, contrast, 6);
+}
+
+static void setcolors(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ __u8 data;
+ int colour;
+
+ colour = sd->colors - 128;
+ if (colour > 0)
+ data = (colour + 32) & 0x7f; /* blue */
+ else
+ data = (-colour + 32) & 0x7f; /* red */
+ reg_w(gspca_dev->dev, 0x05, &data, 1);
+}
+
+/* -- start the camera -- */
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+ int i;
+ __u8 data;
+ __u8 reg1;
+ __u8 reg17;
+ const __u8 *sn9c1xx;
+ int mode;
+ static const __u8 DC29[] = { 0x6a, 0x50, 0x00, 0x00, 0x50, 0x3c };
+ static const __u8 C0[] = { 0x2d, 0x2d, 0x3a, 0x05, 0x04, 0x3f };
+ static const __u8 CA[] = { 0x28, 0xd8, 0x14, 0xec };
+ static const __u8 CA_sn9c120[] =
+ { 0x14, 0xec, 0x0a, 0xf6 }; /* SN9C120 */
+ static const __u8 CE[] = { 0x32, 0xdd, 0x2d, 0xdd }; /* MI0360 */
+ static const __u8 CE_sn9c325[] =
+ { 0x32, 0xdd, 0x32, 0xdd }; /* OV7648 - SN9C325 */
+
+ sn9c1xx = sn_tb[(int) sd->sensor];
+ configure_gpio(gspca_dev, sn9c1xx);
+
+/*fixme:jfm this sequence should appear at end of sd_start */
+/* with
+ data = 0x44;
+ reg_w(dev, 0x01, &data, 1); */
+ reg_w(dev, 0x15, &sn9c1xx[0x15], 1);
+ reg_w(dev, 0x16, &sn9c1xx[0x16], 1);
+ reg_w(dev, 0x12, &sn9c1xx[0x12], 1);
+ reg_w(dev, 0x13, &sn9c1xx[0x13], 1);
+ reg_w(dev, 0x18, &sn9c1xx[0x18], 1);
+ reg_w(dev, 0xd2, &DC29[0], 1);
+ reg_w(dev, 0xd3, &DC29[1], 1);
+ reg_w(dev, 0xc6, &DC29[2], 1);
+ reg_w(dev, 0xc7, &DC29[3], 1);
+ reg_w(dev, 0xc8, &DC29[4], 1);
+ reg_w(dev, 0xc9, &DC29[5], 1);
+/*fixme:jfm end of ending sequence */
+ reg_w(dev, 0x18, &sn9c1xx[0x18], 1);
+ if (sd->customid == SN9C325)
+ data = 0xae;
+ else
+ data = 0x60;
+ reg_w(dev, 0x17, &data, 1);
+ reg_w(dev, 0x05, &sn9c1xx[5], 1);
+ reg_w(dev, 0x07, &sn9c1xx[7], 1);
+ reg_w(dev, 0x06, &sn9c1xx[6], 1);
+ reg_w(dev, 0x14, &sn9c1xx[0x14], 1);
+ if (sd->customid == SN9C325) {
+ reg_w(dev, 0x20, regsn20_sn9c325, 0x11);
+ for (i = 0; i < 8; i++)
+ reg_w(dev, 0x84, reg84_sn9c325, 0x15);
+ data = 0x0a;
+ reg_w(dev, 0x9a, &data, 1);
+ data = 0x60;
+ reg_w(dev, 0x99, &data, 1);
+ } else {
+ reg_w(dev, 0x20, regsn20, 0x11);
+ for (i = 0; i < 8; i++)
+ reg_w(dev, 0x84, reg84, 0x15);
+ data = 0x08;
+ reg_w(dev, 0x9a, &data, 1);
+ data = 0x59;
+ reg_w(dev, 0x99, &data, 1);
+ }
+
+ mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
+ reg1 = 0x02;
+ reg17 = 0x61;
+ switch (sd->sensor) {
+ case SENSOR_HV7131R:
+ hv7131R_InitSensor(gspca_dev);
+ if (mode)
+ reg1 = 0x46; /* 320 clk 48Mhz */
+ else
+ reg1 = 0x06; /* 640 clk 24Mz */
+ break;
+ case SENSOR_MI0360:
+ mi0360_InitSensor(gspca_dev);
+ if (mode)
+ reg1 = 0x46; /* 320 clk 48Mhz */
+ else
+ reg1 = 0x06; /* 640 clk 24Mz */
+ break;
+ case SENSOR_MO4000:
+ mo4000_InitSensor(gspca_dev);
+ if (mode) {
+/* reg1 = 0x46; * 320 clk 48Mhz 60fp/s */
+ reg1 = 0x06; /* clk 24Mz */
+ } else {
+ reg17 = 0x22; /* 640 MCKSIZE */
+ reg1 = 0x06; /* 640 clk 24Mz */
+ }
+ break;
+ case SENSOR_OV7648:
+ reg17 = 0xa2;
+ reg1 = 0x44;
+ ov7648_InitSensor(gspca_dev);
+/* if (mode)
+ ; * 320x2...
+ else
+ ; * 640x... */
+ break;
+ default:
+/* case SENSOR_OV7660: */
+ ov7660_InitSensor(gspca_dev);
+ if (mode) {
+/* reg17 = 0x21; * 320 */
+/* reg1 = 0x44; */
+ reg1 = 0x46;
+ } else {
+#if 1
+ reg17 = 0xa2; /* 640 */
+ reg1 = 0x40;
+#else
+ reg17 = 0x22; /* 640 MCKSIZE */
+ reg1 = 0x06;
+#endif
+ }
+ break;
+ }
+ reg_w(dev, 0xc0, C0, 6);
+ switch (sd->customid) {
+ case SN9C120: /*jfm ?? */
+ reg_w(dev, 0xca, CA_sn9c120, 4);
+ break;
+ default:
+ reg_w(dev, 0xca, CA, 4);
+ break;
+ }
+ switch (sd->customid) {
+ case SN9C120: /*jfm ?? */
+ case SN9C325:
+ reg_w(dev, 0xce, CE_sn9c325, 4);
+ break;
+ default:
+ reg_w(dev, 0xce, CE, 4);
+ /* ?? {0x1e, 0xdd, 0x2d, 0xe7} */
+ break;
+ }
+
+ /* here change size mode 0 -> VGA; 1 -> CIF */
+ data = 0x40 | sn9c1xx[0x18] | (mode << 4);
+ reg_w(dev, 0x18, &data, 1);
+
+ reg_w(dev, 0x100, qtable4, 0x40);
+ reg_w(dev, 0x140, qtable4 + 0x40, 0x40);
+
+ data = sn9c1xx[0x18] | (mode << 4);
+ reg_w(dev, 0x18, &data, 1);
+
+ reg_w(dev, 0x17, &reg17, 1);
+ reg_w(dev, 0x01, &reg1, 1);
+ setbrightness(gspca_dev);
+ setcontrast(gspca_dev);
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+ static const __u8 stophv7131[] =
+ { 0xa1, 0x11, 0x02, 0x09, 0x00, 0x00, 0x00, 0x10 };
+ static const __u8 stopmi0360[] =
+ { 0xb1, 0x5d, 0x07, 0x00, 0x00, 0x00, 0x00, 0x10 };
+ __u8 regF1;
+ __u8 data;
+ const __u8 *sn9c1xx;
+
+ data = 0x0b;
+ switch (sd->sensor) {
+ case SENSOR_HV7131R:
+ i2c_w8(dev, stophv7131);
+ data = 0x2b;
+ break;
+ case SENSOR_MI0360:
+ i2c_w8(dev, stopmi0360);
+ data = 0x29;
+ break;
+ case SENSOR_MO4000:
+ break;
+ case SENSOR_OV7648:
+ data = 0x29;
+ break;
+ default:
+/* case SENSOR_OV7660: */
+ break;
+ }
+ sn9c1xx = sn_tb[(int) sd->sensor];
+ reg_w(dev, 0x01, &sn9c1xx[1], 1);
+ reg_w(dev, 0x17, &sn9c1xx[0x17], 1);
+ reg_w(dev, 0x01, &sn9c1xx[1], 1);
+ reg_w(dev, 0x01, &data, 1);
+ regF1 = 0x01;
+ reg_w(dev, 0xf1, &regF1, 1);
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+static void setautogain(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ /* Thanks S., without your advice, autobright should not work :) */
+ int delta;
+ int expotimes = 0;
+ __u8 luma_mean = 130;
+ __u8 luma_delta = 20;
+
+ delta = sd->avg_lum;
+ if (delta < luma_mean - luma_delta ||
+ delta > luma_mean + luma_delta) {
+ switch (sd->sensor) {
+ case SENSOR_HV7131R:
+ expotimes = sd->exposure >> 8;
+ expotimes += (luma_mean - delta) >> 4;
+ if (expotimes < 0)
+ expotimes = 0;
+ sd->exposure = setexposure(gspca_dev,
+ (unsigned int) (expotimes << 8));
+ break;
+ case SENSOR_MO4000:
+ case SENSOR_MI0360:
+ expotimes = sd->exposure;
+ expotimes += (luma_mean - delta) >> 6;
+ if (expotimes < 0)
+ expotimes = 0;
+ sd->exposure = setexposure(gspca_dev,
+ (unsigned int) expotimes);
+ setcolors(gspca_dev);
+ break;
+ }
+ }
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ struct gspca_frame *frame, /* target */
+ __u8 *data, /* isoc packet */
+ int len) /* iso packet length */
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int sof, avg_lum;
+
+ sof = len - 64;
+ if (sof >= 0 && data[sof] == 0xff && data[sof + 1] == 0xd9) {
+
+ /* end of frame */
+ gspca_frame_add(gspca_dev, LAST_PACKET,
+ frame, data, sof + 2);
+ if (sd->ag_cnt < 0)
+ return;
+ if (--sd->ag_cnt >= 0)
+ return;
+ sd->ag_cnt = AG_CNT_START;
+/* w1 w2 w3 */
+/* w4 w5 w6 */
+/* w7 w8 */
+/* w4 */
+ avg_lum = ((data[sof + 29] << 8) | data[sof + 30]) >> 6;
+/* w6 */
+ avg_lum += ((data[sof + 33] << 8) | data[sof + 34]) >> 6;
+/* w2 */
+ avg_lum += ((data[sof + 25] << 8) | data[sof + 26]) >> 6;
+/* w8 */
+ avg_lum += ((data[sof + 37] << 8) | data[sof + 38]) >> 6;
+/* w5 */
+ avg_lum += ((data[sof + 31] << 8) | data[sof + 32]) >> 4;
+ avg_lum >>= 4;
+ sd->avg_lum = avg_lum;
+ PDEBUG(D_PACK, "mean lum %d", avg_lum);
+ setautogain(gspca_dev);
+ return;
+ }
+ if (gspca_dev->last_packet_type == LAST_PACKET) {
+
+ /* put the JPEG 422 header */
+ jpeg_put_header(gspca_dev, frame, sd->qindex, 0x21);
+ }
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+}
+
+static unsigned int getexposure(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ __u8 hexpo, mexpo, lexpo;
+ __u8 expo[6];
+
+ switch (sd->sensor) {
+ case SENSOR_HV7131R:
+ /* read sensor exposure */
+ i2c_r5(gspca_dev, 0x25, expo);
+ return (expo[0] << 16) | (expo[1] << 8) | expo[2];
+ case SENSOR_MI0360:
+ /* read sensor exposure */
+ i2c_r5(gspca_dev, 0x09, expo);
+ return (expo[0] << 8) | expo[1];
+ case SENSOR_MO4000:
+ i2c_r5(gspca_dev, 0x0e, expo);
+ hexpo = 0; /* expo[1] & 0x07; */
+ mexpo = 0x40; /* expo[2] &0xff; */
+ lexpo = (expo[1] & 0x30) >> 4;
+ PDEBUG(D_CONF, "exposure %d",
+ (hexpo << 10) | (mexpo << 2) | lexpo);
+ return (hexpo << 10) | (mexpo << 2) | lexpo;
+ default:
+/* case SENSOR_OV7660: */
+ /* read sensor exposure */
+ i2c_r5(gspca_dev, 0x04, expo);
+ hexpo = expo[3] & 0x2f;
+ lexpo = expo[0] & 0x02;
+ i2c_r5(gspca_dev, 0x08, expo);
+ mexpo = expo[2];
+ return (hexpo << 10) | (mexpo << 2) | lexpo;
+ }
+}
+
+static void getbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ /* hardcoded registers seem not readable */
+ switch (sd->sensor) {
+ case SENSOR_HV7131R:
+/* sd->brightness = 0x7fff; */
+ sd->brightness = getexposure(gspca_dev) >> 4;
+ break;
+ case SENSOR_MI0360:
+ sd->brightness = getexposure(gspca_dev) << 4;
+ break;
+ case SENSOR_MO4000:
+/* sd->brightness = 0x1fff; */
+ sd->brightness = getexposure(gspca_dev) << 4;
+ break;
+ }
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->brightness = val;
+ if (gspca_dev->streaming)
+ setbrightness(gspca_dev);
+ return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ getbrightness(gspca_dev);
+ *val = sd->brightness;
+ return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->contrast = val;
+ if (gspca_dev->streaming)
+ setcontrast(gspca_dev);
+ return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->contrast;
+ return 0;
+}
+
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->colors = val;
+ if (gspca_dev->streaming)
+ setcolors(gspca_dev);
+ return 0;
+}
+
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->colors;
+ return 0;
+}
+
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->autogain = val;
+ if (val)
+ sd->ag_cnt = AG_CNT_START;
+ else
+ sd->ag_cnt = -1;
+ return 0;
+}
+
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->autogain;
+ return 0;
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .ctrls = sd_ctrls,
+ .nctrls = ARRAY_SIZE(sd_ctrls),
+ .config = sd_config,
+ .open = sd_open,
+ .start = sd_start,
+ .stopN = sd_stopN,
+ .stop0 = sd_stop0,
+ .close = sd_close,
+ .pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static const __devinitdata struct usb_device_id device_table[] = {
+#ifndef CONFIG_USB_SN9C102
+ {USB_DEVICE(0x0458, 0x7025), DVNM("Genius Eye 311Q")},
+ {USB_DEVICE(0x045e, 0x00f5), DVNM("MicroSoft VX3000")},
+ {USB_DEVICE(0x045e, 0x00f7), DVNM("MicroSoft VX1000")},
+ {USB_DEVICE(0x0471, 0x0327), DVNM("Philips SPC 600 NC")},
+ {USB_DEVICE(0x0471, 0x0328), DVNM("Philips SPC 700 NC")},
+#endif
+ {USB_DEVICE(0x0471, 0x0330), DVNM("Philips SPC 710NC")},
+ {USB_DEVICE(0x0c45, 0x6040), DVNM("Speed NVC 350K")},
+ {USB_DEVICE(0x0c45, 0x607c), DVNM("Sonix sn9c102p Hv7131R")},
+ {USB_DEVICE(0x0c45, 0x60c0), DVNM("Sangha Sn535")},
+ {USB_DEVICE(0x0c45, 0x60ec), DVNM("SN9C105+MO4000")},
+ {USB_DEVICE(0x0c45, 0x60fb), DVNM("Surfer NoName")},
+ {USB_DEVICE(0x0c45, 0x60fc), DVNM("LG-LIC300")},
+ {USB_DEVICE(0x0c45, 0x612a), DVNM("Avant Camera")},
+ {USB_DEVICE(0x0c45, 0x612c), DVNM("Typhoon Rasy Cam 1.3MPix")},
+#ifndef CONFIG_USB_SN9C102
+ {USB_DEVICE(0x0c45, 0x6130), DVNM("Sonix Pccam")},
+ {USB_DEVICE(0x0c45, 0x6138), DVNM("Sn9c120 Mo4000")},
+ {USB_DEVICE(0x0c45, 0x613b), DVNM("Surfer SN-206")},
+ {USB_DEVICE(0x0c45, 0x613c), DVNM("Sonix Pccam168")},
+#endif
+ {}
+};
+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,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+ if (usb_register(&sd_driver) < 0)
+ return -1;
+ info("v%s registered", version);
+ return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+ usb_deregister(&sd_driver);
+ info("deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/linux/drivers/media/video/gspca/spca500.c b/linux/drivers/media/video/gspca/spca500.c
new file mode 100644
index 000000000..1860fc7f5
--- /dev/null
+++ b/linux/drivers/media/video/gspca/spca500.c
@@ -0,0 +1,1234 @@
+/*
+ * SPCA500 chip based cameras initialization data
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#define MODULE_NAME "spca500"
+
+#include "gspca.h"
+#include "jpeg.h"
+
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 5)
+static const char version[] = "2.1.5";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("GSPCA/SPCA500 USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+
+ __u8 packet[ISO_MAX_SIZE + 128];
+ /* !! no more than 128 ff in an ISO packet */
+
+ unsigned char brightness;
+ unsigned char contrast;
+ unsigned char colors;
+
+ char qindex;
+ char subtype;
+#define AgfaCl20 0
+#define AiptekPocketDV 1
+#define BenqDC1016 2
+#define CreativePCCam300 3
+#define DLinkDSC350 4
+#define Gsmartmini 5
+#define IntelPocketPCCamera 6
+#define KodakEZ200 7
+#define LogitechClickSmart310 8
+#define LogitechClickSmart510 9
+#define LogitechTraveler 10
+#define MustekGsmart300 11
+#define Optimedia 12
+#define PalmPixDC85 13
+#define ToptroIndus 14
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+ {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+#define BRIGHTNESS_DEF 127
+ .default_value = BRIGHTNESS_DEF,
+ },
+ .set = sd_setbrightness,
+ .get = sd_getbrightness,
+ },
+ {
+ {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = 0,
+ .maximum = 63,
+ .step = 1,
+#define CONTRAST_DEF 31
+ .default_value = CONTRAST_DEF,
+ },
+ .set = sd_setcontrast,
+ .get = sd_getcontrast,
+ },
+ {
+ {
+ .id = V4L2_CID_SATURATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Color",
+ .minimum = 0,
+ .maximum = 63,
+ .step = 1,
+#define COLOR_DEF 31
+ .default_value = COLOR_DEF,
+ },
+ .set = sd_setcolors,
+ .get = sd_getcolors,
+ },
+};
+
+static struct v4l2_pix_format vga_mode[] = {
+ {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 1},
+ {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 0},
+};
+
+static struct v4l2_pix_format sif_mode[] = {
+ {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 176,
+ .sizeimage = 176 * 144 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 1},
+ {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 352,
+ .sizeimage = 352 * 288 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 0},
+};
+
+/* Frame packet header offsets for the spca500 */
+#define SPCA500_OFFSET_PADDINGLB 2
+#define SPCA500_OFFSET_PADDINGHB 3
+#define SPCA500_OFFSET_MODE 4
+#define SPCA500_OFFSET_IMGWIDTH 5
+#define SPCA500_OFFSET_IMGHEIGHT 6
+#define SPCA500_OFFSET_IMGMODE 7
+#define SPCA500_OFFSET_QTBLINDEX 8
+#define SPCA500_OFFSET_FRAMSEQ 9
+#define SPCA500_OFFSET_CDSPINFO 10
+#define SPCA500_OFFSET_GPIO 11
+#define SPCA500_OFFSET_AUGPIO 12
+#define SPCA500_OFFSET_DATA 16
+
+#if 0
+static const __u16 spca500_read_stats[][3] = {
+ {0x0c, 0x0000, 0x0000},
+ {0x30, 0x03fd, 0x0001},
+ /* possible values for following call: 0x01b3, 0x01e6, 0x01f7, 0x0218 */
+ {0x30, 0x01b3, 0x0002},
+ /* possible values for following call: 0x0000, 0x0001, 0x0002 */
+ {0x30, 0x0000, 0x0003},
+ {0x30, 0x003b, 0x0004},
+ /* possible values for following call: 0x00aa, 0x00e0 */
+ {0x30, 0x00e0, 0x0005},
+ {0x30, 0x0001, 0x0006},
+ {0x30, 0x0080, 0x0007},
+ {0x30, 0x0004, 0x0000},
+ {}
+};
+#endif
+
+static const __u16 spca500_visual_defaults[][3] = {
+ {0x00, 0x0003, 0x816b}, /* SSI not active sync with vsync,
+ * hue (H byte) = 0,
+ * saturation/hue enable,
+ * brightness/contrast enable.
+ */
+ {0x00, 0x0000, 0x8167}, /* brightness = 0 */
+ {0x00, 0x0020, 0x8168}, /* contrast = 0 */
+ {0x00, 0x0003, 0x816b}, /* SSI not active sync with vsync,
+ * hue (H byte) = 0, saturation/hue enable,
+ * brightness/contrast enable.
+ * was 0x0003, now 0x0000.
+ */
+ {0x00, 0x0000, 0x816a}, /* hue (L byte) = 0 */
+ {0x00, 0x0020, 0x8169}, /* saturation = 0x20 */
+ {0x00, 0x0050, 0x8157}, /* edge gain high threshold */
+ {0x00, 0x0030, 0x8158}, /* edge gain low threshold */
+ {0x00, 0x0028, 0x8159}, /* edge bandwidth high threshold */
+ {0x00, 0x000a, 0x815a}, /* edge bandwidth low threshold */
+ {0x00, 0x0001, 0x8202}, /* clock rate compensation = 1/25 sec/frame */
+ {0x0c, 0x0004, 0x0000},
+ /* set interface */
+ {}
+};
+static const __u16 Clicksmart510_defaults[][3] = {
+ {0x00, 0x00, 0x8211},
+ {0x00, 0x01, 0x82c0},
+ {0x00, 0x10, 0x82cb},
+ {0x00, 0x0f, 0x800d},
+ {0x00, 0x82, 0x8225},
+ {0x00, 0x21, 0x8228},
+ {0x00, 0x00, 0x8203},
+ {0x00, 0x00, 0x8204},
+ {0x00, 0x08, 0x8205},
+ {0x00, 0xf8, 0x8206},
+ {0x00, 0x28, 0x8207},
+ {0x00, 0xa0, 0x8208},
+ {0x00, 0x08, 0x824a},
+ {0x00, 0x08, 0x8214},
+ {0x00, 0x80, 0x82c1},
+ {0x00, 0x00, 0x82c2},
+ {0x00, 0x00, 0x82ca},
+ {0x00, 0x80, 0x82c1},
+ {0x00, 0x04, 0x82c2},
+ {0x00, 0x00, 0x82ca},
+ {0x00, 0xfc, 0x8100},
+ {0x00, 0xfc, 0x8105},
+ {0x00, 0x30, 0x8101},
+ {0x00, 0x00, 0x8102},
+ {0x00, 0x00, 0x8103},
+ {0x00, 0x66, 0x8107},
+ {0x00, 0x00, 0x816b},
+ {0x00, 0x00, 0x8155},
+ {0x00, 0x01, 0x8156},
+ {0x00, 0x60, 0x8157},
+ {0x00, 0x40, 0x8158},
+ {0x00, 0x0a, 0x8159},
+ {0x00, 0x06, 0x815a},
+ {0x00, 0x00, 0x813f},
+ {0x00, 0x00, 0x8200},
+ {0x00, 0x19, 0x8201},
+ {0x00, 0x00, 0x82c1},
+ {0x00, 0xa0, 0x82c2},
+ {0x00, 0x00, 0x82ca},
+ {0x00, 0x00, 0x8117},
+ {0x00, 0x00, 0x8118},
+ {0x00, 0x65, 0x8119},
+ {0x00, 0x00, 0x811a},
+ {0x00, 0x00, 0x811b},
+ {0x00, 0x55, 0x811c},
+ {0x00, 0x65, 0x811d},
+ {0x00, 0x55, 0x811e},
+ {0x00, 0x16, 0x811f},
+ {0x00, 0x19, 0x8120},
+ {0x00, 0x80, 0x8103},
+ {0x00, 0x83, 0x816b},
+ {0x00, 0x25, 0x8168},
+ {0x00, 0x01, 0x820f},
+ {0x00, 0xff, 0x8115},
+ {0x00, 0x48, 0x8116},
+ {0x00, 0x50, 0x8151},
+ {0x00, 0x40, 0x8152},
+ {0x00, 0x78, 0x8153},
+ {0x00, 0x40, 0x8154},
+ {0x00, 0x00, 0x8167},
+ {0x00, 0x20, 0x8168},
+ {0x00, 0x00, 0x816a},
+ {0x00, 0x03, 0x816b},
+ {0x00, 0x20, 0x8169},
+ {0x00, 0x60, 0x8157},
+ {0x00, 0x00, 0x8190},
+ {0x00, 0x00, 0x81a1},
+ {0x00, 0x00, 0x81b2},
+ {0x00, 0x27, 0x8191},
+ {0x00, 0x27, 0x81a2},
+ {0x00, 0x27, 0x81b3},
+ {0x00, 0x4b, 0x8192},
+ {0x00, 0x4b, 0x81a3},
+ {0x00, 0x4b, 0x81b4},
+ {0x00, 0x66, 0x8193},
+ {0x00, 0x66, 0x81a4},
+ {0x00, 0x66, 0x81b5},
+ {0x00, 0x79, 0x8194},
+ {0x00, 0x79, 0x81a5},
+ {0x00, 0x79, 0x81b6},
+ {0x00, 0x8a, 0x8195},
+ {0x00, 0x8a, 0x81a6},
+ {0x00, 0x8a, 0x81b7},
+ {0x00, 0x9b, 0x8196},
+ {0x00, 0x9b, 0x81a7},
+ {0x00, 0x9b, 0x81b8},
+ {0x00, 0xa6, 0x8197},
+ {0x00, 0xa6, 0x81a8},
+ {0x00, 0xa6, 0x81b9},
+ {0x00, 0xb2, 0x8198},
+ {0x00, 0xb2, 0x81a9},
+ {0x00, 0xb2, 0x81ba},
+ {0x00, 0xbe, 0x8199},
+ {0x00, 0xbe, 0x81aa},
+ {0x00, 0xbe, 0x81bb},
+ {0x00, 0xc8, 0x819a},
+ {0x00, 0xc8, 0x81ab},
+ {0x00, 0xc8, 0x81bc},
+ {0x00, 0xd2, 0x819b},
+ {0x00, 0xd2, 0x81ac},
+ {0x00, 0xd2, 0x81bd},
+ {0x00, 0xdb, 0x819c},
+ {0x00, 0xdb, 0x81ad},
+ {0x00, 0xdb, 0x81be},
+ {0x00, 0xe4, 0x819d},
+ {0x00, 0xe4, 0x81ae},
+ {0x00, 0xe4, 0x81bf},
+ {0x00, 0xed, 0x819e},
+ {0x00, 0xed, 0x81af},
+ {0x00, 0xed, 0x81c0},
+ {0x00, 0xf7, 0x819f},
+ {0x00, 0xf7, 0x81b0},
+ {0x00, 0xf7, 0x81c1},
+ {0x00, 0xff, 0x81a0},
+ {0x00, 0xff, 0x81b1},
+ {0x00, 0xff, 0x81c2},
+ {0x00, 0x03, 0x8156},
+ {0x00, 0x00, 0x8211},
+ {0x00, 0x20, 0x8168},
+ {0x00, 0x01, 0x8202},
+ {0x00, 0x30, 0x8101},
+ {0x00, 0x00, 0x8111},
+ {0x00, 0x00, 0x8112},
+ {0x00, 0x00, 0x8113},
+ {0x00, 0x00, 0x8114},
+ {}
+};
+
+static const __u8 qtable_creative_pccam[2][64] = {
+ { /* Q-table Y-components */
+ 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
+ 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
+ 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11,
+ 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13,
+ 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17,
+ 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c,
+ 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e,
+ 0x16, 0x1c, 0x1d, 0x1d, 0x22, 0x1e, 0x1f, 0x1e},
+ { /* Q-table C-components */
+ 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e,
+ 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e,
+ 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+ 0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+ 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+ 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+ 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+ 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
+};
+
+static const __u8 qtable_kodak_ez200[2][64] = {
+ { /* Q-table Y-components */
+ 0x02, 0x01, 0x01, 0x02, 0x02, 0x04, 0x05, 0x06,
+ 0x01, 0x01, 0x01, 0x02, 0x03, 0x06, 0x06, 0x06,
+ 0x01, 0x01, 0x02, 0x02, 0x04, 0x06, 0x07, 0x06,
+ 0x01, 0x02, 0x02, 0x03, 0x05, 0x09, 0x08, 0x06,
+ 0x02, 0x02, 0x04, 0x06, 0x07, 0x0b, 0x0a, 0x08,
+ 0x02, 0x04, 0x06, 0x06, 0x08, 0x0a, 0x0b, 0x09,
+ 0x05, 0x06, 0x08, 0x09, 0x0a, 0x0c, 0x0c, 0x0a,
+ 0x07, 0x09, 0x0a, 0x0a, 0x0b, 0x0a, 0x0a, 0x0a},
+ { /* Q-table C-components */
+ 0x02, 0x02, 0x02, 0x05, 0x0a, 0x0a, 0x0a, 0x0a,
+ 0x02, 0x02, 0x03, 0x07, 0x0a, 0x0a, 0x0a, 0x0a,
+ 0x02, 0x03, 0x06, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+ 0x05, 0x07, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+ 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+ 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+ 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+ 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a}
+};
+
+static const __u8 qtable_pocketdv[2][64] = {
+ { /* Q-table Y-components start registers 0x8800 */
+ 0x06, 0x04, 0x04, 0x06, 0x0a, 0x10, 0x14, 0x18,
+ 0x05, 0x05, 0x06, 0x08, 0x0a, 0x17, 0x18, 0x16,
+ 0x06, 0x05, 0x06, 0x0a, 0x10, 0x17, 0x1c, 0x16,
+ 0x06, 0x07, 0x09, 0x0c, 0x14, 0x23, 0x20, 0x19,
+ 0x07, 0x09, 0x0f, 0x16, 0x1b, 0x2c, 0x29, 0x1f,
+ 0x0a, 0x0e, 0x16, 0x1a, 0x20, 0x2a, 0x2d, 0x25,
+ 0x14, 0x1a, 0x1f, 0x23, 0x29, 0x30, 0x30, 0x28,
+ 0x1d, 0x25, 0x26, 0x27, 0x2d, 0x28, 0x29, 0x28,
+ },
+ { /* Q-table C-components start registers 0x8840 */
+ 0x07, 0x07, 0x0a, 0x13, 0x28, 0x28, 0x28, 0x28,
+ 0x07, 0x08, 0x0a, 0x1a, 0x28, 0x28, 0x28, 0x28,
+ 0x0a, 0x0a, 0x16, 0x28, 0x28, 0x28, 0x28, 0x28,
+ 0x13, 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}
+};
+
+static void reg_r(struct usb_device *dev,
+ __u16 index,
+ __u8 *buffer, __u16 length)
+{
+ usb_control_msg(dev,
+ usb_rcvctrlpipe(dev, 0),
+ 0,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, /* value */
+ index, buffer, length, 500);
+}
+
+static int reg_w(struct usb_device *dev,
+ __u16 req, __u16 index, __u16 value)
+{
+ int ret;
+
+ PDEBUG(D_USBO, "reg write: [0x%02x] = 0x%02x", index, value);
+ ret = usb_control_msg(dev,
+ usb_sndctrlpipe(dev, 0),
+ req,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value, index, NULL, 0, 500);
+ if (ret < 0)
+ PDEBUG(D_ERR, "reg write: error %d", ret);
+ return ret;
+}
+
+/* returns: negative is error, pos or zero is data */
+static int reg_r_12(struct usb_device *dev,
+ __u16 req, /* bRequest */
+ __u16 index, /* wIndex */
+ __u16 length) /* wLength (1 or 2 only) */
+{
+ int ret;
+ __u8 buf[2];
+
+ buf[1] = 0;
+ ret = usb_control_msg(dev,
+ usb_rcvctrlpipe(dev, 0),
+ req,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, /* value */
+ index,
+ buf, length,
+ 500); /* timeout */
+ if (ret < 0) {
+ PDEBUG(D_ERR, "reg_r_12 err %d", ret);
+ return -1;
+ }
+ return (buf[1] << 8) + buf[0];
+}
+
+/*
+ * Simple function to wait for a given 8-bit value to be returned from
+ * a reg_read call.
+ * Returns: negative is error or timeout, zero is success.
+ */
+static int reg_r_wait(struct usb_device *dev,
+ __u16 reg, __u16 index, __u16 value)
+{
+ int ret, cnt = 20;
+
+ while (--cnt > 0) {
+ ret = reg_r_12(dev, reg, index, 1);
+ if (ret == value)
+ return 0;
+ msleep(50);
+ }
+ return -EIO;
+}
+
+static int write_vector(struct gspca_dev *gspca_dev,
+ const __u16 data[][3])
+{
+ struct usb_device *dev = gspca_dev->dev;
+ int ret, i = 0;
+
+ while (data[i][0] != 0 || data[i][1] != 0 || data[i][2] != 0) {
+ ret = reg_w(dev, data[i][0], data[i][2], data[i][1]);
+ if (ret < 0)
+ return ret;
+ i++;
+ }
+ return 0;
+}
+
+static int spca50x_setup_qtable(struct gspca_dev *gspca_dev,
+ unsigned int request,
+ unsigned int ybase,
+ unsigned int cbase,
+ const __u8 qtable[2][64])
+{
+ struct usb_device *dev = gspca_dev->dev;
+ int i, err;
+
+ /* loop over y components */
+ for (i = 0; i < 64; i++) {
+ err = reg_w(dev, request, ybase + i, qtable[0][i]);
+ if (err < 0)
+ return err;
+ }
+
+ /* loop over c components */
+ for (i = 0; i < 64; i++) {
+ err = reg_w(dev, request, cbase + i, qtable[1][i]);
+ if (err < 0)
+ return err;
+ }
+ return 0;
+}
+
+static void spca500_ping310(struct gspca_dev *gspca_dev)
+{
+ __u8 Data[2];
+
+ reg_r(gspca_dev->dev, 0x0d04, Data, 2);
+ PDEBUG(D_STREAM, "ClickSmart310 ping 0x0d04 0x%02x 0x%02x",
+ Data[0], Data[1]);
+}
+
+static void spca500_clksmart310_init(struct gspca_dev *gspca_dev)
+{
+ __u8 Data[2];
+
+ reg_r(gspca_dev->dev, 0x0d05, Data, 2);
+ PDEBUG(D_STREAM, "ClickSmart310 init 0x0d05 0x%02x 0x%02x",
+ Data[0], Data[1]);
+ reg_w(gspca_dev->dev, 0x00, 0x8167, 0x5a);
+ spca500_ping310(gspca_dev);
+
+ reg_w(gspca_dev->dev, 0x00, 0x8168, 0x22);
+ reg_w(gspca_dev->dev, 0x00, 0x816a, 0xc0);
+ reg_w(gspca_dev->dev, 0x00, 0x816b, 0x0b);
+ reg_w(gspca_dev->dev, 0x00, 0x8169, 0x25);
+ reg_w(gspca_dev->dev, 0x00, 0x8157, 0x5b);
+ reg_w(gspca_dev->dev, 0x00, 0x8158, 0x5b);
+ reg_w(gspca_dev->dev, 0x00, 0x813f, 0x03);
+ reg_w(gspca_dev->dev, 0x00, 0x8151, 0x4a);
+ reg_w(gspca_dev->dev, 0x00, 0x8153, 0x78);
+ reg_w(gspca_dev->dev, 0x00, 0x0d01, 0x04);
+ /* 00 for adjust shutter */
+ reg_w(gspca_dev->dev, 0x00, 0x0d02, 0x01);
+ reg_w(gspca_dev->dev, 0x00, 0x8169, 0x25);
+ reg_w(gspca_dev->dev, 0x00, 0x0d01, 0x02);
+}
+
+static void spca500_setmode(struct gspca_dev *gspca_dev,
+ __u8 xmult, __u8 ymult)
+{
+ int mode;
+
+ /* set x multiplier */
+ reg_w(gspca_dev->dev, 0, 0x8001, xmult);
+
+ /* set y multiplier */
+ reg_w(gspca_dev->dev, 0, 0x8002, ymult);
+
+ /* use compressed mode, VGA, with mode specific subsample */
+ mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
+ reg_w(gspca_dev->dev, 0, 0x8003, mode << 4);
+}
+
+static int spca500_full_reset(struct gspca_dev *gspca_dev)
+{
+ int err;
+
+ /* send the reset command */
+ err = reg_w(gspca_dev->dev, 0xe0, 0x0001, 0x0000);
+ if (err < 0)
+ return err;
+
+ /* wait for the reset to complete */
+ err = reg_r_wait(gspca_dev->dev, 0x06, 0x0000, 0x0000);
+ if (err < 0)
+ return err;
+ err = reg_w(gspca_dev->dev, 0xe0, 0x0000, 0x0000);
+ if (err < 0)
+ return err;
+ err = reg_r_wait(gspca_dev->dev, 0x06, 0, 0);
+ if (err < 0) {
+ PDEBUG(D_ERR, "reg_r_wait() failed");
+ return err;
+ }
+ /* all ok */
+ return 0;
+}
+
+/* Synchro the Bridge with sensor */
+/* Maybe that will work on all spca500 chip */
+/* because i only own a clicksmart310 try for that chip */
+/* using spca50x_set_packet_size() cause an Ooops here */
+/* usb_set_interface from kernel 2.6.x clear all the urb stuff */
+/* up-port the same feature as in 2.4.x kernel */
+static int spca500_synch310(struct gspca_dev *gspca_dev)
+{
+ __u8 Data;
+
+ if (usb_set_interface(gspca_dev->dev, gspca_dev->iface, 0) < 0) {
+ PDEBUG(D_ERR, "Set packet size: set interface error");
+ goto error;
+ }
+ spca500_ping310(gspca_dev);
+
+ reg_r(gspca_dev->dev, 0x0d00, &Data, 1);
+
+ /* need alt setting here */
+ PDEBUG(D_PACK, "ClickSmart310 sync alt: %d", gspca_dev->alt);
+
+ /* Windoze use pipe with altsetting 6 why 7 here */
+ if (usb_set_interface(gspca_dev->dev,
+ gspca_dev->iface,
+ gspca_dev->alt) < 0) {
+ PDEBUG(D_ERR, "Set packet size: set interface error");
+ goto error;
+ }
+ return 0;
+error:
+ return -EBUSY;
+}
+
+static void spca500_reinit(struct gspca_dev *gspca_dev)
+{
+ int err;
+ __u8 Data;
+
+ /* some unknow command from Aiptek pocket dv and family300 */
+
+ reg_w(gspca_dev->dev, 0x00, 0x0d01, 0x01);
+ reg_w(gspca_dev->dev, 0x00, 0x0d03, 0x00);
+ reg_w(gspca_dev->dev, 0x00, 0x0d02, 0x01);
+
+ /* enable drop packet */
+ reg_w(gspca_dev->dev, 0x00, 0x850a, 0x0001);
+
+ err = spca50x_setup_qtable(gspca_dev, 0x00, 0x8800, 0x8840,
+ qtable_pocketdv);
+ if (err < 0)
+ PDEBUG(D_ERR|D_STREAM, "spca50x_setup_qtable failed on init");
+
+ /* set qtable index */
+ reg_w(gspca_dev->dev, 0x00, 0x8880, 2);
+ /* family cam Quicksmart stuff */
+ reg_w(gspca_dev->dev, 0x00, 0x800a, 0x00);
+ /* Set agc transfer: synced inbetween frames */
+ reg_w(gspca_dev->dev, 0x00, 0x820f, 0x01);
+ /* Init SDRAM - needed for SDRAM access */
+ reg_w(gspca_dev->dev, 0x00, 0x870a, 0x04);
+ /*Start init sequence or stream */
+
+ reg_w(gspca_dev->dev, 0, 0x8003, 0x00);
+ /* switch to video camera mode */
+ reg_w(gspca_dev->dev, 0x00, 0x8000, 0x0004);
+ msleep(2000);
+ if (reg_r_wait(gspca_dev->dev, 0, 0x8000, 0x44) != 0)
+ reg_r(gspca_dev->dev, 0x816b, &Data, 1);
+ reg_w(gspca_dev->dev, 0x00, 0x816b, Data);
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+ const struct usb_device_id *id)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct cam *cam;
+ __u16 vendor;
+ __u16 product;
+
+ vendor = id->idVendor;
+ product = id->idProduct;
+ switch (vendor) {
+ case 0x040a: /* Kodak cameras */
+/* switch (product) { */
+/* case 0x0300: */
+ sd->subtype = KodakEZ200;
+/* break; */
+/* } */
+ break;
+ case 0x041e: /* Creative cameras */
+/* switch (product) { */
+/* case 0x400a: */
+ sd->subtype = CreativePCCam300;
+/* break; */
+/* } */
+ break;
+ case 0x046d: /* Logitech Labtec */
+ switch (product) {
+ case 0x0890:
+ sd->subtype = LogitechTraveler;
+ break;
+ case 0x0900:
+ sd->subtype = LogitechClickSmart310;
+ break;
+ case 0x0901:
+ sd->subtype = LogitechClickSmart510;
+ break;
+ }
+ break;
+ case 0x04a5: /* Benq */
+/* switch (product) { */
+/* case 0x300c: */
+ sd->subtype = BenqDC1016;
+/* break; */
+/* } */
+ break;
+ case 0x04fc: /* SunPlus */
+/* switch (product) { */
+/* case 0x7333: */
+ sd->subtype = PalmPixDC85;
+/* break; */
+/* } */
+ break;
+ case 0x055f: /* Mustek cameras */
+ switch (product) {
+ case 0xc200:
+ sd->subtype = MustekGsmart300;
+ break;
+ case 0xc220:
+ sd->subtype = Gsmartmini;
+ break;
+ }
+ break;
+ case 0x06bd: /* Agfa Cl20 */
+/* switch (product) { */
+/* case 0x0404: */
+ sd->subtype = AgfaCl20;
+/* break; */
+/* } */
+ break;
+ case 0x06be: /* Optimedia */
+/* switch (product) { */
+/* case 0x0800: */
+ sd->subtype = Optimedia;
+/* break; */
+/* } */
+ break;
+ case 0x084d: /* D-Link / Minton */
+/* switch (product) { */
+/* case 0x0003: * DSC-350 / S-Cam F5 */
+ sd->subtype = DLinkDSC350;
+/* break; */
+/* } */
+ break;
+ case 0x08ca: /* Aiptek */
+/* switch (product) { */
+/* case 0x0103: */
+ sd->subtype = AiptekPocketDV;
+/* break; */
+/* } */
+ break;
+ case 0x2899: /* ToptroIndustrial */
+/* switch (product) { */
+/* case 0x012c: */
+ sd->subtype = ToptroIndus;
+/* break; */
+/* } */
+ break;
+ case 0x8086: /* Intel */
+/* switch (product) { */
+/* case 0x0630: * Pocket PC Camera */
+ sd->subtype = IntelPocketPCCamera;
+/* break; */
+/* } */
+ break;
+ }
+ cam = &gspca_dev->cam;
+ cam->dev_name = (char *) id->driver_info;
+ cam->epaddr = 0x01;
+ if (sd->subtype != LogitechClickSmart310) {
+ cam->cam_mode = vga_mode;
+ cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+ } else {
+ cam->cam_mode = sif_mode;
+ cam->nmodes = sizeof sif_mode / sizeof sif_mode[0];
+ }
+ sd->qindex = 5;
+ sd->brightness = BRIGHTNESS_DEF;
+ sd->contrast = CONTRAST_DEF;
+ sd->colors = COLOR_DEF;
+ return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ /* initialisation of spca500 based cameras is deferred */
+ PDEBUG(D_STREAM, "SPCA500 init");
+ if (sd->subtype == LogitechClickSmart310)
+ spca500_clksmart310_init(gspca_dev);
+/* else
+ spca500_initialise(gspca_dev); */
+ PDEBUG(D_STREAM, "SPCA500 init done");
+ return 0;
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int err;
+ __u8 Data;
+ __u8 xmult, ymult;
+
+ if (sd->subtype == LogitechClickSmart310) {
+ xmult = 0x16;
+ ymult = 0x12;
+ } else {
+ xmult = 0x28;
+ ymult = 0x1e;
+ }
+
+ /* is there a sensor here ? */
+ reg_r(gspca_dev->dev, 0x8a04, &Data, 1);
+ PDEBUG(D_STREAM, "Spca500 Sensor Address 0x%02X", Data);
+ PDEBUG(D_STREAM, "Spca500 curr_mode: %d Xmult: 0x%02X, Ymult: 0x%02X",
+ gspca_dev->curr_mode, xmult, ymult);
+
+ /* setup qtable */
+ switch (sd->subtype) {
+ case LogitechClickSmart310:
+ spca500_setmode(gspca_dev, xmult, ymult);
+
+ /* enable drop packet */
+ reg_w(gspca_dev->dev, 0x00, 0x850a, 0x0001);
+ reg_w(gspca_dev->dev, 0x00, 0x8880, 3);
+ err = spca50x_setup_qtable(gspca_dev,
+ 0x00, 0x8800, 0x8840,
+ qtable_creative_pccam);
+ if (err < 0)
+ PDEBUG(D_ERR, "spca50x_setup_qtable failed");
+ /* Init SDRAM - needed for SDRAM access */
+ reg_w(gspca_dev->dev, 0x00, 0x870a, 0x04);
+
+ /* switch to video camera mode */
+ reg_w(gspca_dev->dev, 0x00, 0x8000, 0x0004);
+ msleep(500);
+ if (reg_r_wait(gspca_dev->dev, 0, 0x8000, 0x44) != 0)
+ PDEBUG(D_ERR, "reg_r_wait() failed");
+
+ reg_r(gspca_dev->dev, 0x816b, &Data, 1);
+ reg_w(gspca_dev->dev, 0x00, 0x816b, Data);
+
+ spca500_synch310(gspca_dev);
+
+ write_vector(gspca_dev, spca500_visual_defaults);
+ spca500_setmode(gspca_dev, xmult, ymult);
+ /* enable drop packet */
+ reg_w(gspca_dev->dev, 0x00, 0x850a, 0x0001);
+ PDEBUG(D_ERR, "failed to enable drop packet");
+ reg_w(gspca_dev->dev, 0x00, 0x8880, 3);
+ err = spca50x_setup_qtable(gspca_dev,
+ 0x00, 0x8800, 0x8840,
+ qtable_creative_pccam);
+ if (err < 0)
+ PDEBUG(D_ERR, "spca50x_setup_qtable failed");
+
+ /* Init SDRAM - needed for SDRAM access */
+ reg_w(gspca_dev->dev, 0x00, 0x870a, 0x04);
+
+ /* switch to video camera mode */
+ reg_w(gspca_dev->dev, 0x00, 0x8000, 0x0004);
+
+ if (reg_r_wait(gspca_dev->dev, 0, 0x8000, 0x44) != 0)
+ PDEBUG(D_ERR, "reg_r_wait() failed");
+
+ reg_r(gspca_dev->dev, 0x816b, &Data, 1);
+ reg_w(gspca_dev->dev, 0x00, 0x816b, Data);
+ break;
+ case CreativePCCam300: /* Creative PC-CAM 300 640x480 CCD */
+ case IntelPocketPCCamera: /* FIXME: Temporary fix for
+ * Intel Pocket PC Camera
+ * - NWG (Sat 29th March 2003) */
+
+ /* do a full reset */
+ err = spca500_full_reset(gspca_dev);
+ if (err < 0)
+ PDEBUG(D_ERR, "spca500_full_reset failed");
+
+ /* enable drop packet */
+ err = reg_w(gspca_dev->dev, 0x00, 0x850a, 0x0001);
+ if (err < 0)
+ PDEBUG(D_ERR, "failed to enable drop packet");
+ reg_w(gspca_dev->dev, 0x00, 0x8880, 3);
+ err = spca50x_setup_qtable(gspca_dev,
+ 0x00, 0x8800, 0x8840,
+ qtable_creative_pccam);
+ if (err < 0)
+ PDEBUG(D_ERR, "spca50x_setup_qtable failed");
+
+ spca500_setmode(gspca_dev, xmult, ymult);
+ reg_w(gspca_dev->dev, 0x20, 0x0001, 0x0004);
+
+ /* switch to video camera mode */
+ reg_w(gspca_dev->dev, 0x00, 0x8000, 0x0004);
+
+ if (reg_r_wait(gspca_dev->dev, 0, 0x8000, 0x44) != 0)
+ PDEBUG(D_ERR, "reg_r_wait() failed");
+
+ reg_r(gspca_dev->dev, 0x816b, &Data, 1);
+ reg_w(gspca_dev->dev, 0x00, 0x816b, Data);
+
+/* write_vector(gspca_dev, spca500_visual_defaults); */
+ break;
+ case KodakEZ200: /* Kodak EZ200 */
+
+ /* do a full reset */
+ err = spca500_full_reset(gspca_dev);
+ if (err < 0)
+ PDEBUG(D_ERR, "spca500_full_reset failed");
+ /* enable drop packet */
+ reg_w(gspca_dev->dev, 0x00, 0x850a, 0x0001);
+ reg_w(gspca_dev->dev, 0x00, 0x8880, 0);
+ err = spca50x_setup_qtable(gspca_dev,
+ 0x00, 0x8800, 0x8840,
+ qtable_kodak_ez200);
+ if (err < 0)
+ PDEBUG(D_ERR, "spca50x_setup_qtable failed");
+ spca500_setmode(gspca_dev, xmult, ymult);
+
+ reg_w(gspca_dev->dev, 0x20, 0x0001, 0x0004);
+
+ /* switch to video camera mode */
+ reg_w(gspca_dev->dev, 0x00, 0x8000, 0x0004);
+
+ if (reg_r_wait(gspca_dev->dev, 0, 0x8000, 0x44) != 0)
+ PDEBUG(D_ERR, "reg_r_wait() failed");
+
+ reg_r(gspca_dev->dev, 0x816b, &Data, 1);
+ reg_w(gspca_dev->dev, 0x00, 0x816b, Data);
+
+/* write_vector(gspca_dev, spca500_visual_defaults); */
+ break;
+
+ case BenqDC1016:
+ case DLinkDSC350: /* FamilyCam 300 */
+ case AiptekPocketDV: /* Aiptek PocketDV */
+ case Gsmartmini: /*Mustek Gsmart Mini */
+ case MustekGsmart300: /* Mustek Gsmart 300 */
+ case PalmPixDC85:
+ case Optimedia:
+ case ToptroIndus:
+ case AgfaCl20:
+ spca500_reinit(gspca_dev);
+ reg_w(gspca_dev->dev, 0x00, 0x0d01, 0x01);
+ /* enable drop packet */
+ reg_w(gspca_dev->dev, 0x00, 0x850a, 0x0001);
+
+ err = spca50x_setup_qtable(gspca_dev,
+ 0x00, 0x8800, 0x8840, qtable_pocketdv);
+ if (err < 0)
+ PDEBUG(D_ERR, "spca50x_setup_qtable failed");
+ reg_w(gspca_dev->dev, 0x00, 0x8880, 2);
+
+ /* familycam Quicksmart pocketDV stuff */
+ reg_w(gspca_dev->dev, 0x00, 0x800a, 0x00);
+ /* Set agc transfer: synced inbetween frames */
+ reg_w(gspca_dev->dev, 0x00, 0x820f, 0x01);
+ /* Init SDRAM - needed for SDRAM access */
+ reg_w(gspca_dev->dev, 0x00, 0x870a, 0x04);
+
+ spca500_setmode(gspca_dev, xmult, ymult);
+ /* switch to video camera mode */
+ reg_w(gspca_dev->dev, 0x00, 0x8000, 0x0004);
+
+ reg_r_wait(gspca_dev->dev, 0, 0x8000, 0x44);
+
+ reg_r(gspca_dev->dev, 0x816b, &Data, 1);
+ reg_w(gspca_dev->dev, 0x00, 0x816b, Data);
+ break;
+ case LogitechTraveler:
+ case LogitechClickSmart510:
+ reg_w(gspca_dev->dev, 0x02, 0x00, 0x00);
+ /* enable drop packet */
+ reg_w(gspca_dev->dev, 0x00, 0x850a, 0x0001);
+
+ err = spca50x_setup_qtable(gspca_dev,
+ 0x00, 0x8800,
+ 0x8840, qtable_creative_pccam);
+ if (err < 0)
+ PDEBUG(D_ERR, "spca50x_setup_qtable failed");
+ reg_w(gspca_dev->dev, 0x00, 0x8880, 3);
+ reg_w(gspca_dev->dev, 0x00, 0x800a, 0x00);
+ /* Init SDRAM - needed for SDRAM access */
+ reg_w(gspca_dev->dev, 0x00, 0x870a, 0x04);
+
+ spca500_setmode(gspca_dev, xmult, ymult);
+
+ /* switch to video camera mode */
+ reg_w(gspca_dev->dev, 0x00, 0x8000, 0x0004);
+ reg_r_wait(gspca_dev->dev, 0, 0x8000, 0x44);
+
+ reg_r(gspca_dev->dev, 0x816b, &Data, 1);
+ reg_w(gspca_dev->dev, 0x00, 0x816b, Data);
+ write_vector(gspca_dev, Clicksmart510_defaults);
+ break;
+ }
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+ __u8 data;
+
+ reg_w(gspca_dev->dev, 0, 0x8003, 0x00);
+
+ /* switch to video camera mode */
+ reg_w(gspca_dev->dev, 0x00, 0x8000, 0x0004);
+ reg_r(gspca_dev->dev, 0x8000, &data, 1);
+ PDEBUG(D_STREAM, "stop SPCA500 done reg8000: 0x%2x", data);
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ struct gspca_frame *frame, /* target */
+ __u8 *data, /* isoc packet */
+ int len) /* iso packet length */
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int i;
+ __u8 *s, *d;
+ static __u8 ffd9[] = {0xff, 0xd9};
+
+/* frames are jpeg 4.1.1 without 0xff escape */
+ if (data[0] == 0xff) {
+ if (data[1] != 0x01) { /* drop packet */
+/* gspca_dev->last_packet_type = DISCARD_PACKET; */
+ return;
+ }
+ frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+ ffd9, 2);
+
+ /* put the JPEG header in the new frame */
+ jpeg_put_header(gspca_dev, frame, sd->qindex, 0x22);
+
+ data += SPCA500_OFFSET_DATA;
+ len -= SPCA500_OFFSET_DATA;
+ } else {
+ data += 1;
+ len -= 1;
+ }
+
+ /* add 0x00 after 0xff */
+ for (i = len; --i >= 0; )
+ if (data[i] == 0xff)
+ break;
+ if (i < 0) { /* no 0xff */
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+ return;
+ }
+ s = data;
+ d = sd->packet;
+ for (i = 0; i < len; i++) {
+ *d++ = *s++;
+ if (s[-1] == 0xff)
+ *d++ = 0x00;
+ }
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+ sd->packet, d - sd->packet);
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ reg_w(gspca_dev->dev, 0x00, 0x8167,
+ (__u8) (sd->brightness - 128));
+}
+
+static void getbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int ret;
+
+ ret = reg_r_12(gspca_dev->dev, 0x00, 0x8167, 1);
+ if (ret >= 0)
+ sd->brightness = ret + 128;
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ reg_w(gspca_dev->dev, 0x00, 0x8168, sd->contrast);
+}
+
+static void getcontrast(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int ret;
+
+ ret = reg_r_12(gspca_dev->dev, 0x0, 0x8168, 1);
+ if (ret >= 0)
+ sd->contrast = ret;
+}
+
+static void setcolors(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ reg_w(gspca_dev->dev, 0x00, 0x8169, sd->colors);
+}
+
+static void getcolors(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int ret;
+
+ ret = reg_r_12(gspca_dev->dev, 0x0, 0x8169, 1);
+ if (ret >= 0)
+ sd->colors = ret;
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->brightness = val;
+ if (gspca_dev->streaming)
+ setbrightness(gspca_dev);
+ return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ getbrightness(gspca_dev);
+ *val = sd->brightness;
+ return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->contrast = val;
+ if (gspca_dev->streaming)
+ setcontrast(gspca_dev);
+ return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ getcontrast(gspca_dev);
+ *val = sd->contrast;
+ return 0;
+}
+
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->colors = val;
+ if (gspca_dev->streaming)
+ setcolors(gspca_dev);
+ return 0;
+}
+
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ getcolors(gspca_dev);
+ *val = sd->colors;
+ return 0;
+}
+
+/* sub-driver description */
+static struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .ctrls = sd_ctrls,
+ .nctrls = ARRAY_SIZE(sd_ctrls),
+ .config = sd_config,
+ .open = sd_open,
+ .start = sd_start,
+ .stopN = sd_stopN,
+ .stop0 = sd_stop0,
+ .close = sd_close,
+ .pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static const __devinitdata struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x040a, 0x0300), DVNM("Kodak EZ200")},
+ {USB_DEVICE(0x041e, 0x400a), DVNM("Creative PC-CAM 300")},
+ {USB_DEVICE(0x046d, 0x0890), DVNM("Logitech QuickCam traveler")},
+ {USB_DEVICE(0x046d, 0x0900), DVNM("Logitech Inc. ClickSmart 310")},
+ {USB_DEVICE(0x046d, 0x0901), DVNM("Logitech Inc. ClickSmart 510")},
+ {USB_DEVICE(0x04a5, 0x300c), DVNM("Benq DC1016")},
+ {USB_DEVICE(0x04fc, 0x7333), DVNM("PalmPixDC85")},
+ {USB_DEVICE(0x055f, 0xc200), DVNM("Mustek Gsmart 300")},
+ {USB_DEVICE(0x055f, 0xc220), DVNM("Gsmart Mini")},
+ {USB_DEVICE(0x06bd, 0x0404), DVNM("Agfa CL20")},
+ {USB_DEVICE(0x06be, 0x0800), DVNM("Optimedia")},
+ {USB_DEVICE(0x084d, 0x0003), DVNM("D-Link DSC-350")},
+ {USB_DEVICE(0x08ca, 0x0103), DVNM("Aiptek PocketDV")},
+ {USB_DEVICE(0x2899, 0x012c), DVNM("Toptro Industrial")},
+ {USB_DEVICE(0x8086, 0x0630), DVNM("Intel Pocket PC Camera")},
+ {}
+};
+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,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+ if (usb_register(&sd_driver) < 0)
+ return -1;
+ PDEBUG(D_PROBE, "v%s registered", version);
+ return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+ usb_deregister(&sd_driver);
+ PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/linux/drivers/media/video/gspca/spca501.c b/linux/drivers/media/video/gspca/spca501.c
new file mode 100644
index 000000000..762e8ae97
--- /dev/null
+++ b/linux/drivers/media/video/gspca/spca501.c
@@ -0,0 +1,2241 @@
+/*
+ * SPCA501 chip based cameras initialization data
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#define MODULE_NAME "spca501"
+
+#include "gspca.h"
+
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 5)
+static const char version[] = "2.1.5";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("GSPCA/SPCA501 USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+
+ unsigned short contrast;
+ __u8 brightness;
+ __u8 colors;
+
+ char subtype;
+#define Arowana300KCMOSCamera 0
+#define IntelCreateAndShare 1
+#define KodakDVC325 2
+#define MystFromOriUnknownCamera 3
+#define SmileIntlCamera 4
+#define ThreeComHomeConnectLite 5
+#define ViewQuestM318B 6
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+#define MY_BRIGHTNESS 0
+ {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+ .maximum = 127,
+ .step = 1,
+ .default_value = 63,
+ },
+ .set = sd_setbrightness,
+ .get = sd_getbrightness,
+ },
+#define MY_CONTRAST 1
+ {
+ {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = 0,
+ .maximum = 0xffff,
+ .step = 1,
+ .default_value = 0xaa00,
+ },
+ .set = sd_setcontrast,
+ .get = sd_getcontrast,
+ },
+#define MY_COLOR 2
+ {
+ {
+ .id = V4L2_CID_SATURATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Color",
+ .minimum = 0,
+ .maximum = 63,
+ .step = 1,
+ .default_value = 31,
+ },
+ .set = sd_setcolors,
+ .get = sd_getcolors,
+ },
+};
+
+static struct v4l2_pix_format vga_mode[] = {
+ {160, 120, V4L2_PIX_FMT_SPCA501, V4L2_FIELD_NONE,
+ .bytesperline = 160,
+ .sizeimage = 160 * 120 * 3 / 8,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 2},
+ {320, 240, V4L2_PIX_FMT_SPCA501, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240 * 3 / 8,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 1},
+ {640, 480, V4L2_PIX_FMT_SPCA501, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480 * 3 / 8,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0},
+};
+
+#define SPCA50X_REG_USB 0x2 /* spca505 501 */
+/*
+ * Data to initialize a SPCA501. From a capture file provided by Bill Roehl
+ * With SPCA501 chip description
+ */
+#define CCDSP_SET /* set CCDSP parameters */
+#define TG_SET /* set time generator set */
+#undef DSPWIN_SET /* set DSP windows parameters */
+#undef ALTER_GAMA /* Set alternate set to YUV transform coeffs. */
+#define SPCA501_SNAPBIT 0x80
+#define SPCA501_SNAPCTRL 0x10
+/* Frame packet header offsets for the spca501 */
+#define SPCA501_OFFSET_GPIO 1
+#define SPCA501_OFFSET_TYPE 2
+#define SPCA501_OFFSET_TURN3A 3
+#define SPCA501_OFFSET_FRAMSEQ 4
+#define SPCA501_OFFSET_COMPRESS 5
+#define SPCA501_OFFSET_QUANT 6
+#define SPCA501_OFFSET_QUANT2 7
+#define SPCA501_OFFSET_DATA 8
+
+#define SPCA501_PROP_COMP_ENABLE(d) ((d) & 1)
+#define SPCA501_PROP_SNAP(d) ((d) & 0x40)
+#define SPCA501_PROP_SNAP_CTRL(d) ((d) & 0x10)
+#define SPCA501_PROP_COMP_THRESH(d) (((d) & 0x0e) >> 1)
+#define SPCA501_PROP_COMP_QUANT(d) (((d) & 0x70) >> 4)
+
+/* SPCA501 CCDSP control */
+#define SPCA501_REG_CCDSP 0x01
+/* SPCA501 control/status registers */
+#define SPCA501_REG_CTLRL 0x02
+
+/* registers for color correction and YUV transformation */
+#define SPCA501_A11 0x08
+#define SPCA501_A12 0x09
+#define SPCA501_A13 0x0A
+#define SPCA501_A21 0x0B
+#define SPCA501_A22 0x0C
+#define SPCA501_A23 0x0D
+#define SPCA501_A31 0x0E
+#define SPCA501_A32 0x0F
+#define SPCA501_A33 0x10
+
+/* Data for video camera initialization before capturing */
+static const __u16 spca501_open_data[][3] = {
+ /* bmRequest,value,index */
+
+ {0x2, 0x50, 0x00}, /* C/S enable soft reset */
+ {0x2, 0x40, 0x00}, /* C/S disable soft reset */
+ {0x2, 0x02, 0x05}, /* C/S general purpose I/O data */
+ {0x2, 0x03, 0x05}, /* C/S general purpose I/O data */
+
+#ifdef CCDSP_SET
+ {0x1, 0x38, 0x01}, /* CCDSP options */
+ {0x1, 0x05, 0x02}, /* CCDSP Optical black level for user settings */
+ {0x1, 0xC0, 0x03}, /* CCDSP Optical black settings */
+
+ {0x1, 0x67, 0x07},
+ {0x1, 0x63, 0x3f}, /* CCDSP CCD gamma enable */
+ {0x1, 0x03, 0x56}, /* Add gamma correction */
+
+ {0x1, 0xFF, 0x15}, /* CCDSP High luminance for white balance */
+ {0x1, 0x01, 0x16}, /* CCDSP Low luminance for white balance */
+
+/* Color correction and RGB-to-YUV transformation coefficients changing */
+#ifdef ALTER_GAMA
+ {0x0, 0x00, 0x08}, /* A11 */
+ {0x0, 0x00, 0x09}, /* A12 */
+ {0x0, 0x90, 0x0A}, /* A13 */
+ {0x0, 0x12, 0x0B}, /* A21 */
+ {0x0, 0x00, 0x0C}, /* A22 */
+ {0x0, 0x00, 0x0D}, /* A23 */
+ {0x0, 0x00, 0x0E}, /* A31 */
+ {0x0, 0x02, 0x0F}, /* A32 */
+ {0x0, 0x00, 0x10}, /* A33 */
+#else
+ {0x1, 0x2a, 0x08}, /* A11 0x31 */
+ {0x1, 0xf8, 0x09}, /* A12 f8 */
+ {0x1, 0xf8, 0x0A}, /* A13 f8 */
+ {0x1, 0xf8, 0x0B}, /* A21 f8 */
+ {0x1, 0x14, 0x0C}, /* A22 0x14 */
+ {0x1, 0xf8, 0x0D}, /* A23 f8 */
+ {0x1, 0xf8, 0x0E}, /* A31 f8 */
+ {0x1, 0xf8, 0x0F}, /* A32 f8 */
+ {0x1, 0x20, 0x10}, /* A33 0x20 */
+#endif
+ {0x1, 0x00, 0x11}, /* R offset */
+ {0x1, 0x00, 0x12}, /* G offset */
+ {0x1, 0x00, 0x13}, /* B offset */
+ {0x1, 0x00, 0x14}, /* GB offset */
+
+#endif
+
+#ifdef TG_SET
+ /* Time generator manipulations */
+ {0x0, 0xfc, 0x0}, /* Set up high bits of shutter speed */
+ {0x0, 0x01, 0x1}, /* Set up low bits of shutter speed */
+
+ {0x0, 0xe4, 0x04}, /* DCLK*2 clock phase adjustment */
+ {0x0, 0x08, 0x05}, /* ADCK phase adjustment, inv. ext. VB */
+ {0x0, 0x03, 0x06}, /* FR phase adjustment */
+ {0x0, 0x01, 0x07}, /* FCDS phase adjustment */
+ {0x0, 0x39, 0x08}, /* FS phase adjustment */
+ {0x0, 0x88, 0x0a}, /* FH1 phase and delay adjustment */
+ {0x0, 0x03, 0x0f}, /* pixel identification */
+ {0x0, 0x00, 0x11}, /* clock source selection (default) */
+
+ /*VERY strange manipulations with
+ * select DMCLP or OBPX to be ADCLP output (0x0C)
+ * OPB always toggle or not (0x0D) but they allow
+ * us to set up brightness
+ */
+ {0x0, 0x01, 0x0c},
+ {0x0, 0xe0, 0x0d},
+ /* Done */
+#endif
+
+#ifdef DSPWIN_SET
+ {0x1, 0xa0, 0x01}, /* Setting image processing parameters */
+ {0x1, 0x1c, 0x17}, /* Changing Windows positions X1 */
+ {0x1, 0xe2, 0x19}, /* X2 */
+ {0x1, 0x1c, 0x1b}, /* X3 */
+ {0x1, 0xe2, 0x1d}, /* X4 */
+ {0x1, 0x5f, 0x1f}, /* X5 */
+ {0x1, 0x32, 0x20}, /* Y5 */
+ {0x1, 0x01, 0x10}, /* Changing A33 */
+#endif
+
+ {0x2, 0x204a, 0x07},/* Setting video compression & resolution 160x120 */
+ {0x2, 0x94, 0x06}, /* Setting video no compression */
+ {}
+};
+
+/*
+ The SPCAxxx docs from Sunplus document these values
+ in tables, one table per register number. In the data
+ below, dmRequest is the register number, index is the Addr,
+ and value is a combination of Bit values.
+ Bit Value (hex)
+ 0 01
+ 1 02
+ 2 04
+ 3 08
+ 4 10
+ 5 20
+ 6 40
+ 7 80
+ */
+
+/* Data for chip initialization (set default values) */
+static const __u16 spca501_init_data[][3] = {
+ /* Set all the values to powerup defaults */
+ /* bmRequest,value,index */
+ {0x0, 0xAA, 0x00},
+ {0x0, 0x02, 0x01},
+ {0x0, 0x01, 0x02},
+ {0x0, 0x02, 0x03},
+ {0x0, 0xCE, 0x04},
+ {0x0, 0x00, 0x05},
+ {0x0, 0x00, 0x06},
+ {0x0, 0x00, 0x07},
+ {0x0, 0x00, 0x08},
+ {0x0, 0x00, 0x09},
+ {0x0, 0x90, 0x0A},
+ {0x0, 0x12, 0x0B},
+ {0x0, 0x00, 0x0C},
+ {0x0, 0x00, 0x0D},
+ {0x0, 0x00, 0x0E},
+ {0x0, 0x02, 0x0F},
+ {0x0, 0x00, 0x10},
+ {0x0, 0x00, 0x11},
+ {0x0, 0x00, 0x12},
+ {0x0, 0x00, 0x13},
+ {0x0, 0x00, 0x14},
+ {0x0, 0x00, 0x15},
+ {0x0, 0x00, 0x16},
+ {0x0, 0x00, 0x17},
+ {0x0, 0x00, 0x18},
+ {0x0, 0x00, 0x19},
+ {0x0, 0x00, 0x1A},
+ {0x0, 0x00, 0x1B},
+ {0x0, 0x00, 0x1C},
+ {0x0, 0x00, 0x1D},
+ {0x0, 0x00, 0x1E},
+ {0x0, 0x00, 0x1F},
+ {0x0, 0x00, 0x20},
+ {0x0, 0x00, 0x21},
+ {0x0, 0x00, 0x22},
+ {0x0, 0x00, 0x23},
+ {0x0, 0x00, 0x24},
+ {0x0, 0x00, 0x25},
+ {0x0, 0x00, 0x26},
+ {0x0, 0x00, 0x27},
+ {0x0, 0x00, 0x28},
+ {0x0, 0x00, 0x29},
+ {0x0, 0x00, 0x2A},
+ {0x0, 0x00, 0x2B},
+ {0x0, 0x00, 0x2C},
+ {0x0, 0x00, 0x2D},
+ {0x0, 0x00, 0x2E},
+ {0x0, 0x00, 0x2F},
+ {0x0, 0x00, 0x30},
+ {0x0, 0x00, 0x31},
+ {0x0, 0x00, 0x32},
+ {0x0, 0x00, 0x33},
+ {0x0, 0x00, 0x34},
+ {0x0, 0x00, 0x35},
+ {0x0, 0x00, 0x36},
+ {0x0, 0x00, 0x37},
+ {0x0, 0x00, 0x38},
+ {0x0, 0x00, 0x39},
+ {0x0, 0x00, 0x3A},
+ {0x0, 0x00, 0x3B},
+ {0x0, 0x00, 0x3C},
+ {0x0, 0x00, 0x3D},
+ {0x0, 0x00, 0x3E},
+ {0x0, 0x00, 0x3F},
+ {0x0, 0x00, 0x40},
+ {0x0, 0x00, 0x41},
+ {0x0, 0x00, 0x42},
+ {0x0, 0x00, 0x43},
+ {0x0, 0x00, 0x44},
+ {0x0, 0x00, 0x45},
+ {0x0, 0x00, 0x46},
+ {0x0, 0x00, 0x47},
+ {0x0, 0x00, 0x48},
+ {0x0, 0x00, 0x49},
+ {0x0, 0x00, 0x4A},
+ {0x0, 0x00, 0x4B},
+ {0x0, 0x00, 0x4C},
+ {0x0, 0x00, 0x4D},
+ {0x0, 0x00, 0x4E},
+ {0x0, 0x00, 0x4F},
+ {0x0, 0x00, 0x50},
+ {0x0, 0x00, 0x51},
+ {0x0, 0x00, 0x52},
+ {0x0, 0x00, 0x53},
+ {0x0, 0x00, 0x54},
+ {0x0, 0x00, 0x55},
+ {0x0, 0x00, 0x56},
+ {0x0, 0x00, 0x57},
+ {0x0, 0x00, 0x58},
+ {0x0, 0x00, 0x59},
+ {0x0, 0x00, 0x5A},
+ {0x0, 0x00, 0x5B},
+ {0x0, 0x00, 0x5C},
+ {0x0, 0x00, 0x5D},
+ {0x0, 0x00, 0x5E},
+ {0x0, 0x00, 0x5F},
+ {0x0, 0x00, 0x60},
+ {0x0, 0x00, 0x61},
+ {0x0, 0x00, 0x62},
+ {0x0, 0x00, 0x63},
+ {0x0, 0x00, 0x64},
+ {0x0, 0x00, 0x65},
+ {0x0, 0x00, 0x66},
+ {0x0, 0x00, 0x67},
+ {0x0, 0x00, 0x68},
+ {0x0, 0x00, 0x69},
+ {0x0, 0x00, 0x6A},
+ {0x0, 0x00, 0x6B},
+ {0x0, 0x00, 0x6C},
+ {0x0, 0x00, 0x6D},
+ {0x0, 0x00, 0x6E},
+ {0x0, 0x00, 0x6F},
+ {0x0, 0x00, 0x70},
+ {0x0, 0x00, 0x71},
+ {0x0, 0x00, 0x72},
+ {0x0, 0x00, 0x73},
+ {0x0, 0x00, 0x74},
+ {0x0, 0x00, 0x75},
+ {0x0, 0x00, 0x76},
+ {0x0, 0x00, 0x77},
+ {0x0, 0x00, 0x78},
+ {0x0, 0x00, 0x79},
+ {0x0, 0x00, 0x7A},
+ {0x0, 0x00, 0x7B},
+ {0x0, 0x00, 0x7C},
+ {0x0, 0x00, 0x7D},
+ {0x0, 0x00, 0x7E},
+ {0x0, 0x00, 0x7F},
+ {0x0, 0x00, 0x80},
+ {0x0, 0x00, 0x81},
+ {0x0, 0x00, 0x82},
+ {0x0, 0x00, 0x83},
+ {0x0, 0x00, 0x84},
+ {0x0, 0x00, 0x85},
+ {0x0, 0x00, 0x86},
+ {0x0, 0x00, 0x87},
+ {0x0, 0x00, 0x88},
+ {0x0, 0x00, 0x89},
+ {0x0, 0x00, 0x8A},
+ {0x0, 0x00, 0x8B},
+ {0x0, 0x00, 0x8C},
+ {0x0, 0x00, 0x8D},
+ {0x0, 0x00, 0x8E},
+ {0x0, 0x00, 0x8F},
+ {0x0, 0x00, 0x90},
+ {0x0, 0x00, 0x91},
+ {0x0, 0x00, 0x92},
+ {0x0, 0x00, 0x93},
+ {0x0, 0x00, 0x94},
+ {0x0, 0x00, 0x95},
+ {0x0, 0x00, 0x96},
+ {0x0, 0x00, 0x97},
+ {0x0, 0x00, 0x98},
+ {0x0, 0x00, 0x99},
+ {0x0, 0x00, 0x9A},
+ {0x0, 0x00, 0x9B},
+ {0x0, 0x00, 0x9C},
+ {0x0, 0x00, 0x9D},
+ {0x0, 0x00, 0x9E},
+ {0x0, 0x00, 0x9F},
+ {0x0, 0x00, 0xA0},
+ {0x0, 0x00, 0xA1},
+ {0x0, 0x00, 0xA2},
+ {0x0, 0x00, 0xA3},
+ {0x0, 0x00, 0xA4},
+ {0x0, 0x00, 0xA5},
+ {0x0, 0x00, 0xA6},
+ {0x0, 0x00, 0xA7},
+ {0x0, 0x00, 0xA8},
+ {0x0, 0x00, 0xA9},
+ {0x0, 0x00, 0xAA},
+ {0x0, 0x00, 0xAB},
+ {0x0, 0x00, 0xAC},
+ {0x0, 0x00, 0xAD},
+ {0x0, 0x00, 0xAE},
+ {0x0, 0x00, 0xAF},
+ {0x0, 0x00, 0xB0},
+ {0x0, 0x00, 0xB1},
+ {0x0, 0x00, 0xB2},
+ {0x0, 0x00, 0xB3},
+ {0x0, 0x00, 0xB4},
+ {0x0, 0x00, 0xB5},
+ {0x0, 0x00, 0xB6},
+ {0x0, 0x00, 0xB7},
+ {0x0, 0x00, 0xB8},
+ {0x0, 0x00, 0xB9},
+ {0x0, 0x00, 0xBA},
+ {0x0, 0x00, 0xBB},
+ {0x0, 0x00, 0xBC},
+ {0x0, 0x00, 0xBD},
+ {0x0, 0x00, 0xBE},
+ {0x0, 0x00, 0xBF},
+ {0x0, 0x00, 0xC0},
+ {0x0, 0x00, 0xC1},
+ {0x0, 0x00, 0xC2},
+ {0x0, 0x00, 0xC3},
+ {0x0, 0x00, 0xC4},
+ {0x0, 0x00, 0xC5},
+ {0x0, 0x00, 0xC6},
+ {0x0, 0x00, 0xC7},
+ {0x0, 0x00, 0xC8},
+ {0x0, 0x00, 0xC9},
+ {0x0, 0x00, 0xCA},
+ {0x0, 0x00, 0xCB},
+ {0x0, 0x00, 0xCC},
+ {0x1, 0xF4, 0x00},
+ {0x1, 0x38, 0x01},
+ {0x1, 0x40, 0x02},
+ {0x1, 0x0A, 0x03},
+ {0x1, 0x40, 0x04},
+ {0x1, 0x40, 0x05},
+ {0x1, 0x40, 0x06},
+ {0x1, 0x67, 0x07},
+ {0x1, 0x31, 0x08},
+ {0x1, 0x00, 0x09},
+ {0x1, 0x00, 0x0A},
+ {0x1, 0x00, 0x0B},
+ {0x1, 0x14, 0x0C},
+ {0x1, 0x00, 0x0D},
+ {0x1, 0x00, 0x0E},
+ {0x1, 0x00, 0x0F},
+ {0x1, 0x1E, 0x10},
+ {0x1, 0x00, 0x11},
+ {0x1, 0x00, 0x12},
+ {0x1, 0x00, 0x13},
+ {0x1, 0x00, 0x14},
+ {0x1, 0xFF, 0x15},
+ {0x1, 0x01, 0x16},
+ {0x1, 0x32, 0x17},
+ {0x1, 0x23, 0x18},
+ {0x1, 0xCE, 0x19},
+ {0x1, 0x23, 0x1A},
+ {0x1, 0x32, 0x1B},
+ {0x1, 0x8D, 0x1C},
+ {0x1, 0xCE, 0x1D},
+ {0x1, 0x8D, 0x1E},
+ {0x1, 0x00, 0x1F},
+ {0x1, 0x00, 0x20},
+ {0x1, 0xFF, 0x3E},
+ {0x1, 0x02, 0x3F},
+ {0x1, 0x00, 0x40},
+ {0x1, 0x00, 0x41},
+ {0x1, 0x00, 0x42},
+ {0x1, 0x00, 0x43},
+ {0x1, 0x00, 0x44},
+ {0x1, 0x00, 0x45},
+ {0x1, 0x00, 0x46},
+ {0x1, 0x00, 0x47},
+ {0x1, 0x00, 0x48},
+ {0x1, 0x00, 0x49},
+ {0x1, 0x00, 0x4A},
+ {0x1, 0x00, 0x4B},
+ {0x1, 0x00, 0x4C},
+ {0x1, 0x00, 0x4D},
+ {0x1, 0x00, 0x4E},
+ {0x1, 0x00, 0x4F},
+ {0x1, 0x00, 0x50},
+ {0x1, 0x00, 0x51},
+ {0x1, 0x00, 0x52},
+ {0x1, 0x00, 0x53},
+ {0x1, 0x00, 0x54},
+ {0x1, 0x00, 0x55},
+ {0x1, 0x00, 0x56},
+ {0x1, 0x00, 0x57},
+ {0x1, 0x00, 0x58},
+ {0x1, 0x00, 0x59},
+ {0x1, 0x00, 0x5A},
+ {0x2, 0x03, 0x00},
+ {0x2, 0x00, 0x01},
+ {0x2, 0x00, 0x05},
+ {0x2, 0x00, 0x06},
+ {0x2, 0x00, 0x07},
+ {0x2, 0x00, 0x10},
+ {0x2, 0x00, 0x11},
+ /* Strange - looks like the 501 driver doesn't do anything
+ * at insert time except read the EEPROM
+ */
+ {}
+};
+
+/* Data for video camera init before capture.
+ * Capture and decoding by Colin Peart.
+ * This is is for the 3com HomeConnect Lite which is spca501a based.
+ */
+static const __u16 spca501_3com_open_data[][3] = {
+ /* bmRequest,value,index */
+ {0x2, 0x0050, 0x0000}, /* C/S Enable TG soft reset, timing mode=010 */
+ {0x2, 0x0043, 0x0000}, /* C/S Disable TG soft reset, timing mode=010 */
+ {0x2, 0x0002, 0x0005}, /* C/S GPIO */
+ {0x2, 0x0003, 0x0005}, /* C/S GPIO */
+
+#ifdef CCDSP_SET
+ {0x1, 0x0020, 0x0001}, /* CCDSP Options */
+
+ {0x1, 0x0020, 0x0002}, /* CCDSP Black Level */
+ {0x1, 0x006e, 0x0007}, /* CCDSP Gamma options */
+ {0x1, 0x0090, 0x0015}, /* CCDSP Luminance Low */
+ {0x1, 0x00ff, 0x0016}, /* CCDSP Luminance High */
+ {0x1, 0x0003, 0x003F}, /* CCDSP Gamma correction toggle */
+
+#ifdef ALTER_GAMMA
+ {0x1, 0x0010, 0x0008}, /* CCDSP YUV A11 */
+ {0x1, 0x0000, 0x0009}, /* CCDSP YUV A12 */
+ {0x1, 0x0000, 0x000a}, /* CCDSP YUV A13 */
+ {0x1, 0x0000, 0x000b}, /* CCDSP YUV A21 */
+ {0x1, 0x0010, 0x000c}, /* CCDSP YUV A22 */
+ {0x1, 0x0000, 0x000d}, /* CCDSP YUV A23 */
+ {0x1, 0x0000, 0x000e}, /* CCDSP YUV A31 */
+ {0x1, 0x0000, 0x000f}, /* CCDSP YUV A32 */
+ {0x1, 0x0010, 0x0010}, /* CCDSP YUV A33 */
+ {0x1, 0x0000, 0x0011}, /* CCDSP R Offset */
+ {0x1, 0x0000, 0x0012}, /* CCDSP G Offset */
+ {0x1, 0x0001, 0x0013}, /* CCDSP B Offset */
+ {0x1, 0x0001, 0x0014}, /* CCDSP BG Offset */
+ {0x1, 0x003f, 0x00C1}, /* CCDSP Gamma Correction Enable */
+#endif
+#endif
+
+#ifdef TG_SET
+ {0x0, 0x00fc, 0x0000}, /* TG Shutter Speed High Bits */
+ {0x0, 0x0000, 0x0001}, /* TG Shutter Speed Low Bits */
+ {0x0, 0x00e4, 0x0004}, /* TG DCLK*2 Adjust */
+ {0x0, 0x0008, 0x0005}, /* TG ADCK Adjust */
+ {0x0, 0x0003, 0x0006}, /* TG FR Phase Adjust */
+ {0x0, 0x0001, 0x0007}, /* TG FCDS Phase Adjust */
+ {0x0, 0x0039, 0x0008}, /* TG FS Phase Adjust */
+ {0x0, 0x0088, 0x000a}, /* TG MH1 */
+ {0x0, 0x0003, 0x000f}, /* TG Pixel ID */
+
+ /* Like below, unexplained toglleing */
+ {0x0, 0x0080, 0x000c},
+ {0x0, 0x0000, 0x000d},
+ {0x0, 0x0080, 0x000c},
+ {0x0, 0x0004, 0x000d},
+ {0x0, 0x0000, 0x000c},
+ {0x0, 0x0000, 0x000d},
+ {0x0, 0x0040, 0x000c},
+ {0x0, 0x0017, 0x000d},
+ {0x0, 0x00c0, 0x000c},
+ {0x0, 0x0000, 0x000d},
+ {0x0, 0x0080, 0x000c},
+ {0x0, 0x0006, 0x000d},
+ {0x0, 0x0080, 0x000c},
+ {0x0, 0x0004, 0x000d},
+ {0x0, 0x0002, 0x0003},
+#endif
+
+#ifdef DSPWIN_SET
+ {0x1, 0x001c, 0x0017}, /* CCDSP W1 Start X */
+ {0x1, 0x00e2, 0x0019}, /* CCDSP W2 Start X */
+ {0x1, 0x001c, 0x001b}, /* CCDSP W3 Start X */
+ {0x1, 0x00e2, 0x001d}, /* CCDSP W4 Start X */
+ {0x1, 0x00aa, 0x001f}, /* CCDSP W5 Start X */
+ {0x1, 0x0070, 0x0020}, /* CCDSP W5 Start Y */
+#endif
+ {0x0, 0x0001, 0x0010}, /* TG Start Clock */
+
+/* {0x2, 0x006a, 0x0001}, * C/S Enable ISOSYNCH Packet Engine */
+ {0x2, 0x0068, 0x0001}, /* C/S Diable ISOSYNCH Packet Engine */
+ {0x2, 0x0000, 0x0005},
+ {0x2, 0x0043, 0x0000}, /* C/S Set Timing Mode, Disable TG soft reset */
+ {0x2, 0x0043, 0x0000}, /* C/S Set Timing Mode, Disable TG soft reset */
+ {0x2, 0x0002, 0x0005}, /* C/S GPIO */
+ {0x2, 0x0003, 0x0005}, /* C/S GPIO */
+
+ {0x2, 0x006a, 0x0001}, /* C/S Enable ISOSYNCH Packet Engine */
+ {}
+};
+
+/*
+ * Data used to initialize a SPCA501C with HV7131B sensor.
+ * From a capture file taken with USBSnoop v 1.5
+ * I have a "SPCA501C pc camera chipset" manual by sunplus, but some
+ * of the value meanings are obscure or simply "reserved".
+ * to do list:
+ * 1) Understand what every value means
+ * 2) Understand why some values seem to appear more than once
+ * 3) Write a small comment for each line of the following arrays.
+ */
+static const __u16 spca501c_arowana_open_data[][3] = {
+ /* bmRequest,value,index */
+ {0x02, 0x0007, 0x0005},
+ {0x02, 0xa048, 0x0000},
+ {0x05, 0x0022, 0x0004},
+ {0x01, 0x0006, 0x0011},
+ {0x01, 0x00ff, 0x0012},
+ {0x01, 0x0014, 0x0013},
+ {0x01, 0x0000, 0x0014},
+ {0x01, 0x0042, 0x0051},
+ {0x01, 0x0040, 0x0052},
+ {0x01, 0x0051, 0x0053},
+ {0x01, 0x0040, 0x0054},
+ {0x01, 0x0000, 0x0055},
+ {0x00, 0x0025, 0x0000},
+ {0x00, 0x0026, 0x0000},
+ {0x00, 0x0001, 0x0000},
+ {0x00, 0x0027, 0x0000},
+ {0x00, 0x008a, 0x0000},
+ {}
+};
+
+static const __u16 spca501c_arowana_init_data[][3] = {
+ /* bmRequest,value,index */
+ {0x02, 0x0007, 0x0005},
+ {0x02, 0xa048, 0x0000},
+ {0x05, 0x0022, 0x0004},
+ {0x01, 0x0006, 0x0011},
+ {0x01, 0x00ff, 0x0012},
+ {0x01, 0x0014, 0x0013},
+ {0x01, 0x0000, 0x0014},
+ {0x01, 0x0042, 0x0051},
+ {0x01, 0x0040, 0x0052},
+ {0x01, 0x0051, 0x0053},
+ {0x01, 0x0040, 0x0054},
+ {0x01, 0x0000, 0x0055},
+ {0x00, 0x0025, 0x0000},
+ {0x00, 0x0026, 0x0000},
+ {0x00, 0x0001, 0x0000},
+ {0x00, 0x0027, 0x0000},
+ {0x00, 0x008a, 0x0000},
+ {0x02, 0x0000, 0x0005},
+ {0x02, 0x0007, 0x0005},
+ {0x02, 0x2000, 0x0000},
+ {0x05, 0x0022, 0x0004},
+ {0x05, 0x0015, 0x0001},
+ {0x05, 0x00ea, 0x0000},
+ {0x05, 0x0021, 0x0001},
+ {0x05, 0x00d2, 0x0000},
+ {0x05, 0x0023, 0x0001},
+ {0x05, 0x0003, 0x0000},
+ {0x05, 0x0030, 0x0001},
+ {0x05, 0x002b, 0x0000},
+ {0x05, 0x0031, 0x0001},
+ {0x05, 0x0023, 0x0000},
+ {0x05, 0x0032, 0x0001},
+ {0x05, 0x0023, 0x0000},
+ {0x05, 0x0033, 0x0001},
+ {0x05, 0x0023, 0x0000},
+ {0x05, 0x0034, 0x0001},
+ {0x05, 0x0002, 0x0000},
+ {0x05, 0x0050, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0051, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0052, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0054, 0x0001},
+ {0x05, 0x0001, 0x0000},
+ {0x00, 0x0000, 0x0001},
+ {0x00, 0x0000, 0x0002},
+ {0x00, 0x000c, 0x0003},
+ {0x00, 0x0000, 0x0004},
+ {0x00, 0x0090, 0x0005},
+ {0x00, 0x0000, 0x0006},
+ {0x00, 0x0040, 0x0007},
+ {0x00, 0x00c0, 0x0008},
+ {0x00, 0x004a, 0x0009},
+ {0x00, 0x0000, 0x000a},
+ {0x00, 0x0000, 0x000b},
+ {0x00, 0x0001, 0x000c},
+ {0x00, 0x0001, 0x000d},
+ {0x00, 0x0000, 0x000e},
+ {0x00, 0x0002, 0x000f},
+ {0x00, 0x0001, 0x0010},
+ {0x00, 0x0000, 0x0011},
+ {0x00, 0x0000, 0x0012},
+ {0x00, 0x0002, 0x0020},
+ {0x00, 0x0080, 0x0021},
+ {0x00, 0x0001, 0x0022},
+ {0x00, 0x00e0, 0x0023},
+ {0x00, 0x0000, 0x0024},
+ {0x00, 0x00d5, 0x0025},
+ {0x00, 0x0000, 0x0026},
+ {0x00, 0x000b, 0x0027},
+ {0x00, 0x0000, 0x0046},
+ {0x00, 0x0000, 0x0047},
+ {0x00, 0x0000, 0x0048},
+ {0x00, 0x0000, 0x0049},
+ {0x00, 0x0008, 0x004a},
+ {0xff, 0x0000, 0x00d0},
+ {0xff, 0x00d8, 0x00d1},
+ {0xff, 0x0000, 0x00d4},
+ {0xff, 0x0000, 0x00d5},
+ {0x01, 0x00a6, 0x0000},
+ {0x01, 0x0028, 0x0001},
+ {0x01, 0x0000, 0x0002},
+ {0x01, 0x000a, 0x0003},
+ {0x01, 0x0040, 0x0004},
+ {0x01, 0x0066, 0x0007},
+ {0x01, 0x0011, 0x0008},
+ {0x01, 0x0032, 0x0009},
+ {0x01, 0x00fd, 0x000a},
+ {0x01, 0x0038, 0x000b},
+ {0x01, 0x00d1, 0x000c},
+ {0x01, 0x00f7, 0x000d},
+ {0x01, 0x00ed, 0x000e},
+ {0x01, 0x00d8, 0x000f},
+ {0x01, 0x0038, 0x0010},
+ {0x01, 0x00ff, 0x0015},
+ {0x01, 0x0001, 0x0016},
+ {0x01, 0x0032, 0x0017},
+ {0x01, 0x0023, 0x0018},
+ {0x01, 0x00ce, 0x0019},
+ {0x01, 0x0023, 0x001a},
+ {0x01, 0x0032, 0x001b},
+ {0x01, 0x008d, 0x001c},
+ {0x01, 0x00ce, 0x001d},
+ {0x01, 0x008d, 0x001e},
+ {0x01, 0x0000, 0x001f},
+ {0x01, 0x0000, 0x0020},
+ {0x01, 0x00ff, 0x003e},
+ {0x01, 0x0003, 0x003f},
+ {0x01, 0x0000, 0x0040},
+ {0x01, 0x0035, 0x0041},
+ {0x01, 0x0053, 0x0042},
+ {0x01, 0x0069, 0x0043},
+ {0x01, 0x007c, 0x0044},
+ {0x01, 0x008c, 0x0045},
+ {0x01, 0x009a, 0x0046},
+ {0x01, 0x00a8, 0x0047},
+ {0x01, 0x00b4, 0x0048},
+ {0x01, 0x00bf, 0x0049},
+ {0x01, 0x00ca, 0x004a},
+ {0x01, 0x00d4, 0x004b},
+ {0x01, 0x00dd, 0x004c},
+ {0x01, 0x00e7, 0x004d},
+ {0x01, 0x00ef, 0x004e},
+ {0x01, 0x00f8, 0x004f},
+ {0x01, 0x00ff, 0x0050},
+ {0x01, 0x0001, 0x0056},
+ {0x01, 0x0060, 0x0057},
+ {0x01, 0x0040, 0x0058},
+ {0x01, 0x0011, 0x0059},
+ {0x01, 0x0001, 0x005a},
+ {0x02, 0x0007, 0x0005},
+ {0x02, 0xa048, 0x0000},
+ {0x02, 0x0007, 0x0005},
+ {0x02, 0x0015, 0x0006},
+ {0x02, 0x100a, 0x0007},
+ {0x02, 0xa048, 0x0000},
+ {0x02, 0xc002, 0x0001},
+ {0x02, 0x000f, 0x0005},
+ {0x02, 0xa048, 0x0000},
+ {0x05, 0x0022, 0x0004},
+ {0x05, 0x0025, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0026, 0x0001},
+ {0x05, 0x0001, 0x0000},
+ {0x05, 0x0027, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0001, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0021, 0x0001},
+ {0x05, 0x00d2, 0x0000},
+ {0x05, 0x0020, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x00, 0x0090, 0x0005},
+ {0x01, 0x00a6, 0x0000},
+ {0x02, 0x0007, 0x0005},
+ {0x02, 0x2000, 0x0000},
+ {0x05, 0x0022, 0x0004},
+ {0x05, 0x0015, 0x0001},
+ {0x05, 0x00ea, 0x0000},
+ {0x05, 0x0021, 0x0001},
+ {0x05, 0x00d2, 0x0000},
+ {0x05, 0x0023, 0x0001},
+ {0x05, 0x0003, 0x0000},
+ {0x05, 0x0030, 0x0001},
+ {0x05, 0x002b, 0x0000},
+ {0x05, 0x0031, 0x0001},
+ {0x05, 0x0023, 0x0000},
+ {0x05, 0x0032, 0x0001},
+ {0x05, 0x0023, 0x0000},
+ {0x05, 0x0033, 0x0001},
+ {0x05, 0x0023, 0x0000},
+ {0x05, 0x0034, 0x0001},
+ {0x05, 0x0002, 0x0000},
+ {0x05, 0x0050, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0051, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0052, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0054, 0x0001},
+ {0x05, 0x0001, 0x0000},
+ {0x00, 0x0000, 0x0001},
+ {0x00, 0x0000, 0x0002},
+ {0x00, 0x000c, 0x0003},
+ {0x00, 0x0000, 0x0004},
+ {0x00, 0x0090, 0x0005},
+ {0x00, 0x0000, 0x0006},
+ {0x00, 0x0040, 0x0007},
+ {0x00, 0x00c0, 0x0008},
+ {0x00, 0x004a, 0x0009},
+ {0x00, 0x0000, 0x000a},
+ {0x00, 0x0000, 0x000b},
+ {0x00, 0x0001, 0x000c},
+ {0x00, 0x0001, 0x000d},
+ {0x00, 0x0000, 0x000e},
+ {0x00, 0x0002, 0x000f},
+ {0x00, 0x0001, 0x0010},
+ {0x00, 0x0000, 0x0011},
+ {0x00, 0x0000, 0x0012},
+ {0x00, 0x0002, 0x0020},
+ {0x00, 0x0080, 0x0021},
+ {0x00, 0x0001, 0x0022},
+ {0x00, 0x00e0, 0x0023},
+ {0x00, 0x0000, 0x0024},
+ {0x00, 0x00d5, 0x0025},
+ {0x00, 0x0000, 0x0026},
+ {0x00, 0x000b, 0x0027},
+ {0x00, 0x0000, 0x0046},
+ {0x00, 0x0000, 0x0047},
+ {0x00, 0x0000, 0x0048},
+ {0x00, 0x0000, 0x0049},
+ {0x00, 0x0008, 0x004a},
+ {0xff, 0x0000, 0x00d0},
+ {0xff, 0x00d8, 0x00d1},
+ {0xff, 0x0000, 0x00d4},
+ {0xff, 0x0000, 0x00d5},
+ {0x01, 0x00a6, 0x0000},
+ {0x01, 0x0028, 0x0001},
+ {0x01, 0x0000, 0x0002},
+ {0x01, 0x000a, 0x0003},
+ {0x01, 0x0040, 0x0004},
+ {0x01, 0x0066, 0x0007},
+ {0x01, 0x0011, 0x0008},
+ {0x01, 0x0032, 0x0009},
+ {0x01, 0x00fd, 0x000a},
+ {0x01, 0x0038, 0x000b},
+ {0x01, 0x00d1, 0x000c},
+ {0x01, 0x00f7, 0x000d},
+ {0x01, 0x00ed, 0x000e},
+ {0x01, 0x00d8, 0x000f},
+ {0x01, 0x0038, 0x0010},
+ {0x01, 0x00ff, 0x0015},
+ {0x01, 0x0001, 0x0016},
+ {0x01, 0x0032, 0x0017},
+ {0x01, 0x0023, 0x0018},
+ {0x01, 0x00ce, 0x0019},
+ {0x01, 0x0023, 0x001a},
+ {0x01, 0x0032, 0x001b},
+ {0x01, 0x008d, 0x001c},
+ {0x01, 0x00ce, 0x001d},
+ {0x01, 0x008d, 0x001e},
+ {0x01, 0x0000, 0x001f},
+ {0x01, 0x0000, 0x0020},
+ {0x01, 0x00ff, 0x003e},
+ {0x01, 0x0003, 0x003f},
+ {0x01, 0x0000, 0x0040},
+ {0x01, 0x0035, 0x0041},
+ {0x01, 0x0053, 0x0042},
+ {0x01, 0x0069, 0x0043},
+ {0x01, 0x007c, 0x0044},
+ {0x01, 0x008c, 0x0045},
+ {0x01, 0x009a, 0x0046},
+ {0x01, 0x00a8, 0x0047},
+ {0x01, 0x00b4, 0x0048},
+ {0x01, 0x00bf, 0x0049},
+ {0x01, 0x00ca, 0x004a},
+ {0x01, 0x00d4, 0x004b},
+ {0x01, 0x00dd, 0x004c},
+ {0x01, 0x00e7, 0x004d},
+ {0x01, 0x00ef, 0x004e},
+ {0x01, 0x00f8, 0x004f},
+ {0x01, 0x00ff, 0x0050},
+ {0x01, 0x0001, 0x0056},
+ {0x01, 0x0060, 0x0057},
+ {0x01, 0x0040, 0x0058},
+ {0x01, 0x0011, 0x0059},
+ {0x01, 0x0001, 0x005a},
+ {0x02, 0x0007, 0x0005},
+ {0x02, 0xa048, 0x0000},
+ {0x02, 0x0007, 0x0005},
+ {0x02, 0x0015, 0x0006},
+ {0x02, 0x100a, 0x0007},
+ {0x02, 0xa048, 0x0000},
+ {0x02, 0xc002, 0x0001},
+ {0x02, 0x000f, 0x0005},
+ {0x02, 0xa048, 0x0000},
+ {0x05, 0x0022, 0x0004},
+ {0x05, 0x0025, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0026, 0x0001},
+ {0x05, 0x0001, 0x0000},
+ {0x05, 0x0027, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0001, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0021, 0x0001},
+ {0x05, 0x00d2, 0x0000},
+ {0x05, 0x0020, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x00, 0x0090, 0x0005},
+ {0x01, 0x00a6, 0x0000},
+ {0x01, 0x0003, 0x003f},
+ {0x01, 0x0001, 0x0056},
+ {0x01, 0x0011, 0x0008},
+ {0x01, 0x0032, 0x0009},
+ {0x01, 0xfffd, 0x000a},
+ {0x01, 0x0023, 0x000b},
+ {0x01, 0xffea, 0x000c},
+ {0x01, 0xfff4, 0x000d},
+ {0x01, 0xfffc, 0x000e},
+ {0x01, 0xffe3, 0x000f},
+ {0x01, 0x001f, 0x0010},
+ {0x01, 0x00a8, 0x0001},
+ {0x01, 0x0067, 0x0007},
+ {0x01, 0x0032, 0x0017},
+ {0x01, 0x0023, 0x0018},
+ {0x01, 0x00ce, 0x0019},
+ {0x01, 0x0023, 0x001a},
+ {0x01, 0x0032, 0x001b},
+ {0x01, 0x008d, 0x001c},
+ {0x01, 0x00ce, 0x001d},
+ {0x01, 0x008d, 0x001e},
+ {0x01, 0x00c8, 0x0015},
+ {0x01, 0x0032, 0x0016},
+ {0x01, 0x0000, 0x0011},
+ {0x01, 0x0000, 0x0012},
+ {0x01, 0x0000, 0x0013},
+ {0x01, 0x000a, 0x0003},
+ {0x02, 0xc002, 0x0001},
+ {0x02, 0x0007, 0x0005},
+ {0x02, 0xc000, 0x0001},
+ {0x02, 0x0000, 0x0005},
+ {0x02, 0x0007, 0x0005},
+ {0x02, 0x2000, 0x0000},
+ {0x05, 0x0022, 0x0004},
+ {0x05, 0x0015, 0x0001},
+ {0x05, 0x00ea, 0x0000},
+ {0x05, 0x0021, 0x0001},
+ {0x05, 0x00d2, 0x0000},
+ {0x05, 0x0023, 0x0001},
+ {0x05, 0x0003, 0x0000},
+ {0x05, 0x0030, 0x0001},
+ {0x05, 0x002b, 0x0000},
+ {0x05, 0x0031, 0x0001},
+ {0x05, 0x0023, 0x0000},
+ {0x05, 0x0032, 0x0001},
+ {0x05, 0x0023, 0x0000},
+ {0x05, 0x0033, 0x0001},
+ {0x05, 0x0023, 0x0000},
+ {0x05, 0x0034, 0x0001},
+ {0x05, 0x0002, 0x0000},
+ {0x05, 0x0050, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0051, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0052, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0054, 0x0001},
+ {0x05, 0x0001, 0x0000},
+ {0x00, 0x0000, 0x0001},
+ {0x00, 0x0000, 0x0002},
+ {0x00, 0x000c, 0x0003},
+ {0x00, 0x0000, 0x0004},
+ {0x00, 0x0090, 0x0005},
+ {0x00, 0x0000, 0x0006},
+ {0x00, 0x0040, 0x0007},
+ {0x00, 0x00c0, 0x0008},
+ {0x00, 0x004a, 0x0009},
+ {0x00, 0x0000, 0x000a},
+ {0x00, 0x0000, 0x000b},
+ {0x00, 0x0001, 0x000c},
+ {0x00, 0x0001, 0x000d},
+ {0x00, 0x0000, 0x000e},
+ {0x00, 0x0002, 0x000f},
+ {0x00, 0x0001, 0x0010},
+ {0x00, 0x0000, 0x0011},
+ {0x00, 0x0000, 0x0012},
+ {0x00, 0x0002, 0x0020},
+ {0x00, 0x0080, 0x0021},
+ {0x00, 0x0001, 0x0022},
+ {0x00, 0x00e0, 0x0023},
+ {0x00, 0x0000, 0x0024},
+ {0x00, 0x00d5, 0x0025},
+ {0x00, 0x0000, 0x0026},
+ {0x00, 0x000b, 0x0027},
+ {0x00, 0x0000, 0x0046},
+ {0x00, 0x0000, 0x0047},
+ {0x00, 0x0000, 0x0048},
+ {0x00, 0x0000, 0x0049},
+ {0x00, 0x0008, 0x004a},
+ {0xff, 0x0000, 0x00d0},
+ {0xff, 0x00d8, 0x00d1},
+ {0xff, 0x0000, 0x00d4},
+ {0xff, 0x0000, 0x00d5},
+ {0x01, 0x00a6, 0x0000},
+ {0x01, 0x0028, 0x0001},
+ {0x01, 0x0000, 0x0002},
+ {0x01, 0x000a, 0x0003},
+ {0x01, 0x0040, 0x0004},
+ {0x01, 0x0066, 0x0007},
+ {0x01, 0x0011, 0x0008},
+ {0x01, 0x0032, 0x0009},
+ {0x01, 0x00fd, 0x000a},
+ {0x01, 0x0038, 0x000b},
+ {0x01, 0x00d1, 0x000c},
+ {0x01, 0x00f7, 0x000d},
+ {0x01, 0x00ed, 0x000e},
+ {0x01, 0x00d8, 0x000f},
+ {0x01, 0x0038, 0x0010},
+ {0x01, 0x00ff, 0x0015},
+ {0x01, 0x0001, 0x0016},
+ {0x01, 0x0032, 0x0017},
+ {0x01, 0x0023, 0x0018},
+ {0x01, 0x00ce, 0x0019},
+ {0x01, 0x0023, 0x001a},
+ {0x01, 0x0032, 0x001b},
+ {0x01, 0x008d, 0x001c},
+ {0x01, 0x00ce, 0x001d},
+ {0x01, 0x008d, 0x001e},
+ {0x01, 0x0000, 0x001f},
+ {0x01, 0x0000, 0x0020},
+ {0x01, 0x00ff, 0x003e},
+ {0x01, 0x0003, 0x003f},
+ {0x01, 0x0000, 0x0040},
+ {0x01, 0x0035, 0x0041},
+ {0x01, 0x0053, 0x0042},
+ {0x01, 0x0069, 0x0043},
+ {0x01, 0x007c, 0x0044},
+ {0x01, 0x008c, 0x0045},
+ {0x01, 0x009a, 0x0046},
+ {0x01, 0x00a8, 0x0047},
+ {0x01, 0x00b4, 0x0048},
+ {0x01, 0x00bf, 0x0049},
+ {0x01, 0x00ca, 0x004a},
+ {0x01, 0x00d4, 0x004b},
+ {0x01, 0x00dd, 0x004c},
+ {0x01, 0x00e7, 0x004d},
+ {0x01, 0x00ef, 0x004e},
+ {0x01, 0x00f8, 0x004f},
+ {0x01, 0x00ff, 0x0050},
+ {0x01, 0x0001, 0x0056},
+ {0x01, 0x0060, 0x0057},
+ {0x01, 0x0040, 0x0058},
+ {0x01, 0x0011, 0x0059},
+ {0x01, 0x0001, 0x005a},
+ {0x02, 0x0007, 0x0005},
+ {0x02, 0xa048, 0x0000},
+ {0x02, 0x0007, 0x0005},
+ {0x02, 0x0015, 0x0006},
+ {0x02, 0x100a, 0x0007},
+ {0x02, 0xa048, 0x0000},
+ {0x02, 0xc002, 0x0001},
+ {0x02, 0x000f, 0x0005},
+ {0x02, 0xa048, 0x0000},
+ {0x05, 0x0022, 0x0004},
+ {0x05, 0x0025, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0026, 0x0001},
+ {0x05, 0x0001, 0x0000},
+ {0x05, 0x0027, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0001, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0021, 0x0001},
+ {0x05, 0x00d2, 0x0000},
+ {0x05, 0x0020, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x00, 0x0090, 0x0005},
+ {0x01, 0x00a6, 0x0000},
+ {0x02, 0x0007, 0x0005},
+ {0x02, 0x2000, 0x0000},
+ {0x05, 0x0022, 0x0004},
+ {0x05, 0x0015, 0x0001},
+ {0x05, 0x00ea, 0x0000},
+ {0x05, 0x0021, 0x0001},
+ {0x05, 0x00d2, 0x0000},
+ {0x05, 0x0023, 0x0001},
+ {0x05, 0x0003, 0x0000},
+ {0x05, 0x0030, 0x0001},
+ {0x05, 0x002b, 0x0000},
+ {0x05, 0x0031, 0x0001},
+ {0x05, 0x0023, 0x0000},
+ {0x05, 0x0032, 0x0001},
+ {0x05, 0x0023, 0x0000},
+ {0x05, 0x0033, 0x0001},
+ {0x05, 0x0023, 0x0000},
+ {0x05, 0x0034, 0x0001},
+ {0x05, 0x0002, 0x0000},
+ {0x05, 0x0050, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0051, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0052, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0054, 0x0001},
+ {0x05, 0x0001, 0x0000},
+ {0x00, 0x0000, 0x0001},
+ {0x00, 0x0000, 0x0002},
+ {0x00, 0x000c, 0x0003},
+ {0x00, 0x0000, 0x0004},
+ {0x00, 0x0090, 0x0005},
+ {0x00, 0x0000, 0x0006},
+ {0x00, 0x0040, 0x0007},
+ {0x00, 0x00c0, 0x0008},
+ {0x00, 0x004a, 0x0009},
+ {0x00, 0x0000, 0x000a},
+ {0x00, 0x0000, 0x000b},
+ {0x00, 0x0001, 0x000c},
+ {0x00, 0x0001, 0x000d},
+ {0x00, 0x0000, 0x000e},
+ {0x00, 0x0002, 0x000f},
+ {0x00, 0x0001, 0x0010},
+ {0x00, 0x0000, 0x0011},
+ {0x00, 0x0000, 0x0012},
+ {0x00, 0x0002, 0x0020},
+ {0x00, 0x0080, 0x0021},
+ {0x00, 0x0001, 0x0022},
+ {0x00, 0x00e0, 0x0023},
+ {0x00, 0x0000, 0x0024},
+ {0x00, 0x00d5, 0x0025},
+ {0x00, 0x0000, 0x0026},
+ {0x00, 0x000b, 0x0027},
+ {0x00, 0x0000, 0x0046},
+ {0x00, 0x0000, 0x0047},
+ {0x00, 0x0000, 0x0048},
+ {0x00, 0x0000, 0x0049},
+ {0x00, 0x0008, 0x004a},
+ {0xff, 0x0000, 0x00d0},
+ {0xff, 0x00d8, 0x00d1},
+ {0xff, 0x0000, 0x00d4},
+ {0xff, 0x0000, 0x00d5},
+ {0x01, 0x00a6, 0x0000},
+ {0x01, 0x0028, 0x0001},
+ {0x01, 0x0000, 0x0002},
+ {0x01, 0x000a, 0x0003},
+ {0x01, 0x0040, 0x0004},
+ {0x01, 0x0066, 0x0007},
+ {0x01, 0x0011, 0x0008},
+ {0x01, 0x0032, 0x0009},
+ {0x01, 0x00fd, 0x000a},
+ {0x01, 0x0038, 0x000b},
+ {0x01, 0x00d1, 0x000c},
+ {0x01, 0x00f7, 0x000d},
+ {0x01, 0x00ed, 0x000e},
+ {0x01, 0x00d8, 0x000f},
+ {0x01, 0x0038, 0x0010},
+ {0x01, 0x00ff, 0x0015},
+ {0x01, 0x0001, 0x0016},
+ {0x01, 0x0032, 0x0017},
+ {0x01, 0x0023, 0x0018},
+ {0x01, 0x00ce, 0x0019},
+ {0x01, 0x0023, 0x001a},
+ {0x01, 0x0032, 0x001b},
+ {0x01, 0x008d, 0x001c},
+ {0x01, 0x00ce, 0x001d},
+ {0x01, 0x008d, 0x001e},
+ {0x01, 0x0000, 0x001f},
+ {0x01, 0x0000, 0x0020},
+ {0x01, 0x00ff, 0x003e},
+ {0x01, 0x0003, 0x003f},
+ {0x01, 0x0000, 0x0040},
+ {0x01, 0x0035, 0x0041},
+ {0x01, 0x0053, 0x0042},
+ {0x01, 0x0069, 0x0043},
+ {0x01, 0x007c, 0x0044},
+ {0x01, 0x008c, 0x0045},
+ {0x01, 0x009a, 0x0046},
+ {0x01, 0x00a8, 0x0047},
+ {0x01, 0x00b4, 0x0048},
+ {0x01, 0x00bf, 0x0049},
+ {0x01, 0x00ca, 0x004a},
+ {0x01, 0x00d4, 0x004b},
+ {0x01, 0x00dd, 0x004c},
+ {0x01, 0x00e7, 0x004d},
+ {0x01, 0x00ef, 0x004e},
+ {0x01, 0x00f8, 0x004f},
+ {0x01, 0x00ff, 0x0050},
+ {0x01, 0x0001, 0x0056},
+ {0x01, 0x0060, 0x0057},
+ {0x01, 0x0040, 0x0058},
+ {0x01, 0x0011, 0x0059},
+ {0x01, 0x0001, 0x005a},
+ {0x02, 0x0007, 0x0005},
+ {0x02, 0xa048, 0x0000},
+ {0x02, 0x0007, 0x0005},
+ {0x02, 0x0015, 0x0006},
+ {0x02, 0x100a, 0x0007},
+ {0x02, 0xa048, 0x0000},
+ {0x02, 0xc002, 0x0001},
+ {0x02, 0x000f, 0x0005},
+ {0x02, 0xa048, 0x0000},
+ {0x05, 0x0022, 0x0004},
+ {0x05, 0x0025, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0026, 0x0001},
+ {0x05, 0x0001, 0x0000},
+ {0x05, 0x0027, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0001, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0021, 0x0001},
+ {0x05, 0x00d2, 0x0000},
+ {0x05, 0x0020, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x00, 0x0090, 0x0005},
+ {0x01, 0x00a6, 0x0000},
+ {0x05, 0x0026, 0x0001},
+ {0x05, 0x0001, 0x0000},
+ {0x05, 0x0027, 0x0001},
+ {0x05, 0x000f, 0x0000},
+ {0x01, 0x0003, 0x003f},
+ {0x01, 0x0001, 0x0056},
+ {0x01, 0x0011, 0x0008},
+ {0x01, 0x0032, 0x0009},
+ {0x01, 0xfffd, 0x000a},
+ {0x01, 0x0023, 0x000b},
+ {0x01, 0xffea, 0x000c},
+ {0x01, 0xfff4, 0x000d},
+ {0x01, 0xfffc, 0x000e},
+ {0x01, 0xffe3, 0x000f},
+ {0x01, 0x001f, 0x0010},
+ {0x01, 0x00a8, 0x0001},
+ {0x01, 0x0067, 0x0007},
+ {0x01, 0x0042, 0x0051},
+ {0x01, 0x0051, 0x0053},
+ {0x01, 0x000a, 0x0003},
+ {0x02, 0xc002, 0x0001},
+ {0x02, 0x0007, 0x0005},
+ {0x02, 0xc000, 0x0001},
+ {0x02, 0x0000, 0x0005},
+ {0x02, 0x0007, 0x0005},
+ {0x02, 0x2000, 0x0000},
+ {0x05, 0x0022, 0x0004},
+ {0x05, 0x0015, 0x0001},
+ {0x05, 0x00ea, 0x0000},
+ {0x05, 0x0021, 0x0001},
+ {0x05, 0x00d2, 0x0000},
+ {0x05, 0x0023, 0x0001},
+ {0x05, 0x0003, 0x0000},
+ {0x05, 0x0030, 0x0001},
+ {0x05, 0x002b, 0x0000},
+ {0x05, 0x0031, 0x0001},
+ {0x05, 0x0023, 0x0000},
+ {0x05, 0x0032, 0x0001},
+ {0x05, 0x0023, 0x0000},
+ {0x05, 0x0033, 0x0001},
+ {0x05, 0x0023, 0x0000},
+ {0x05, 0x0034, 0x0001},
+ {0x05, 0x0002, 0x0000},
+ {0x05, 0x0050, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0051, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0052, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0054, 0x0001},
+ {0x05, 0x0001, 0x0000},
+ {0x00, 0x0000, 0x0001},
+ {0x00, 0x0000, 0x0002},
+ {0x00, 0x000c, 0x0003},
+ {0x00, 0x0000, 0x0004},
+ {0x00, 0x0090, 0x0005},
+ {0x00, 0x0000, 0x0006},
+ {0x00, 0x0040, 0x0007},
+ {0x00, 0x00c0, 0x0008},
+ {0x00, 0x004a, 0x0009},
+ {0x00, 0x0000, 0x000a},
+ {0x00, 0x0000, 0x000b},
+ {0x00, 0x0001, 0x000c},
+ {0x00, 0x0001, 0x000d},
+ {0x00, 0x0000, 0x000e},
+ {0x00, 0x0002, 0x000f},
+ {0x00, 0x0001, 0x0010},
+ {0x00, 0x0000, 0x0011},
+ {0x00, 0x0000, 0x0012},
+ {0x00, 0x0002, 0x0020},
+ {0x00, 0x0080, 0x0021},
+ {0x00, 0x0001, 0x0022},
+ {0x00, 0x00e0, 0x0023},
+ {0x00, 0x0000, 0x0024},
+ {0x00, 0x00d5, 0x0025},
+ {0x00, 0x0000, 0x0026},
+ {0x00, 0x000b, 0x0027},
+ {0x00, 0x0000, 0x0046},
+ {0x00, 0x0000, 0x0047},
+ {0x00, 0x0000, 0x0048},
+ {0x00, 0x0000, 0x0049},
+ {0x00, 0x0008, 0x004a},
+ {0xff, 0x0000, 0x00d0},
+ {0xff, 0x00d8, 0x00d1},
+ {0xff, 0x0000, 0x00d4},
+ {0xff, 0x0000, 0x00d5},
+ {0x01, 0x00a6, 0x0000},
+ {0x01, 0x0028, 0x0001},
+ {0x01, 0x0000, 0x0002},
+ {0x01, 0x000a, 0x0003},
+ {0x01, 0x0040, 0x0004},
+ {0x01, 0x0066, 0x0007},
+ {0x01, 0x0011, 0x0008},
+ {0x01, 0x0032, 0x0009},
+ {0x01, 0x00fd, 0x000a},
+ {0x01, 0x0038, 0x000b},
+ {0x01, 0x00d1, 0x000c},
+ {0x01, 0x00f7, 0x000d},
+ {0x01, 0x00ed, 0x000e},
+ {0x01, 0x00d8, 0x000f},
+ {0x01, 0x0038, 0x0010},
+ {0x01, 0x00ff, 0x0015},
+ {0x01, 0x0001, 0x0016},
+ {0x01, 0x0032, 0x0017},
+ {0x01, 0x0023, 0x0018},
+ {0x01, 0x00ce, 0x0019},
+ {0x01, 0x0023, 0x001a},
+ {0x01, 0x0032, 0x001b},
+ {0x01, 0x008d, 0x001c},
+ {0x01, 0x00ce, 0x001d},
+ {0x01, 0x008d, 0x001e},
+ {0x01, 0x0000, 0x001f},
+ {0x01, 0x0000, 0x0020},
+ {0x01, 0x00ff, 0x003e},
+ {0x01, 0x0003, 0x003f},
+ {0x01, 0x0000, 0x0040},
+ {0x01, 0x0035, 0x0041},
+ {0x01, 0x0053, 0x0042},
+ {0x01, 0x0069, 0x0043},
+ {0x01, 0x007c, 0x0044},
+ {0x01, 0x008c, 0x0045},
+ {0x01, 0x009a, 0x0046},
+ {0x01, 0x00a8, 0x0047},
+ {0x01, 0x00b4, 0x0048},
+ {0x01, 0x00bf, 0x0049},
+ {0x01, 0x00ca, 0x004a},
+ {0x01, 0x00d4, 0x004b},
+ {0x01, 0x00dd, 0x004c},
+ {0x01, 0x00e7, 0x004d},
+ {0x01, 0x00ef, 0x004e},
+ {0x01, 0x00f8, 0x004f},
+ {0x01, 0x00ff, 0x0050},
+ {0x01, 0x0001, 0x0056},
+ {0x01, 0x0060, 0x0057},
+ {0x01, 0x0040, 0x0058},
+ {0x01, 0x0011, 0x0059},
+ {0x01, 0x0001, 0x005a},
+ {0x02, 0x0007, 0x0005},
+ {0x02, 0xa048, 0x0000},
+ {0x02, 0x0007, 0x0005},
+ {0x02, 0x0015, 0x0006},
+ {0x02, 0x100a, 0x0007},
+ {0x02, 0xa048, 0x0000},
+ {0x02, 0xc002, 0x0001},
+ {0x02, 0x000f, 0x0005},
+ {0x02, 0xa048, 0x0000},
+ {0x05, 0x0022, 0x0004},
+ {0x05, 0x0025, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0026, 0x0001},
+ {0x05, 0x0001, 0x0000},
+ {0x05, 0x0027, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0001, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0021, 0x0001},
+ {0x05, 0x00d2, 0x0000},
+ {0x05, 0x0020, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x00, 0x0090, 0x0005},
+ {0x01, 0x00a6, 0x0000},
+ {0x02, 0x0007, 0x0005},
+ {0x02, 0x2000, 0x0000},
+ {0x05, 0x0022, 0x0004},
+ {0x05, 0x0015, 0x0001},
+ {0x05, 0x00ea, 0x0000},
+ {0x05, 0x0021, 0x0001},
+ {0x05, 0x00d2, 0x0000},
+ {0x05, 0x0023, 0x0001},
+ {0x05, 0x0003, 0x0000},
+ {0x05, 0x0030, 0x0001},
+ {0x05, 0x002b, 0x0000},
+ {0x05, 0x0031, 0x0001},
+ {0x05, 0x0023, 0x0000},
+ {0x05, 0x0032, 0x0001},
+ {0x05, 0x0023, 0x0000},
+ {0x05, 0x0033, 0x0001},
+ {0x05, 0x0023, 0x0000},
+ {0x05, 0x0034, 0x0001},
+ {0x05, 0x0002, 0x0000},
+ {0x05, 0x0050, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0051, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0052, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0054, 0x0001},
+ {0x05, 0x0001, 0x0000},
+ {0x00, 0x0000, 0x0001},
+ {0x00, 0x0000, 0x0002},
+ {0x00, 0x000c, 0x0003},
+ {0x00, 0x0000, 0x0004},
+ {0x00, 0x0090, 0x0005},
+ {0x00, 0x0000, 0x0006},
+ {0x00, 0x0040, 0x0007},
+ {0x00, 0x00c0, 0x0008},
+ {0x00, 0x004a, 0x0009},
+ {0x00, 0x0000, 0x000a},
+ {0x00, 0x0000, 0x000b},
+ {0x00, 0x0001, 0x000c},
+ {0x00, 0x0001, 0x000d},
+ {0x00, 0x0000, 0x000e},
+ {0x00, 0x0002, 0x000f},
+ {0x00, 0x0001, 0x0010},
+ {0x00, 0x0000, 0x0011},
+ {0x00, 0x0000, 0x0012},
+ {0x00, 0x0002, 0x0020},
+ {0x00, 0x0080, 0x0021},
+ {0x00, 0x0001, 0x0022},
+ {0x00, 0x00e0, 0x0023},
+ {0x00, 0x0000, 0x0024},
+ {0x00, 0x00d5, 0x0025},
+ {0x00, 0x0000, 0x0026},
+ {0x00, 0x000b, 0x0027},
+ {0x00, 0x0000, 0x0046},
+ {0x00, 0x0000, 0x0047},
+ {0x00, 0x0000, 0x0048},
+ {0x00, 0x0000, 0x0049},
+ {0x00, 0x0008, 0x004a},
+ {0xff, 0x0000, 0x00d0},
+ {0xff, 0x00d8, 0x00d1},
+ {0xff, 0x0000, 0x00d4},
+ {0xff, 0x0000, 0x00d5},
+ {0x01, 0x00a6, 0x0000},
+ {0x01, 0x0028, 0x0001},
+ {0x01, 0x0000, 0x0002},
+ {0x01, 0x000a, 0x0003},
+ {0x01, 0x0040, 0x0004},
+ {0x01, 0x0066, 0x0007},
+ {0x01, 0x0011, 0x0008},
+ {0x01, 0x0032, 0x0009},
+ {0x01, 0x00fd, 0x000a},
+ {0x01, 0x0038, 0x000b},
+ {0x01, 0x00d1, 0x000c},
+ {0x01, 0x00f7, 0x000d},
+ {0x01, 0x00ed, 0x000e},
+ {0x01, 0x00d8, 0x000f},
+ {0x01, 0x0038, 0x0010},
+ {0x01, 0x00ff, 0x0015},
+ {0x01, 0x0001, 0x0016},
+ {0x01, 0x0032, 0x0017},
+ {0x01, 0x0023, 0x0018},
+ {0x01, 0x00ce, 0x0019},
+ {0x01, 0x0023, 0x001a},
+ {0x01, 0x0032, 0x001b},
+ {0x01, 0x008d, 0x001c},
+ {0x01, 0x00ce, 0x001d},
+ {0x01, 0x008d, 0x001e},
+ {0x01, 0x0000, 0x001f},
+ {0x01, 0x0000, 0x0020},
+ {0x01, 0x00ff, 0x003e},
+ {0x01, 0x0003, 0x003f},
+ {0x01, 0x0000, 0x0040},
+ {0x01, 0x0035, 0x0041},
+ {0x01, 0x0053, 0x0042},
+ {0x01, 0x0069, 0x0043},
+ {0x01, 0x007c, 0x0044},
+ {0x01, 0x008c, 0x0045},
+ {0x01, 0x009a, 0x0046},
+ {0x01, 0x00a8, 0x0047},
+ {0x01, 0x00b4, 0x0048},
+ {0x01, 0x00bf, 0x0049},
+ {0x01, 0x00ca, 0x004a},
+ {0x01, 0x00d4, 0x004b},
+ {0x01, 0x00dd, 0x004c},
+ {0x01, 0x00e7, 0x004d},
+ {0x01, 0x00ef, 0x004e},
+ {0x01, 0x00f8, 0x004f},
+ {0x01, 0x00ff, 0x0050},
+ {0x01, 0x0001, 0x0056},
+ {0x01, 0x0060, 0x0057},
+ {0x01, 0x0040, 0x0058},
+ {0x01, 0x0011, 0x0059},
+ {0x01, 0x0001, 0x005a},
+ {0x02, 0x0007, 0x0005},
+ {0x02, 0xa048, 0x0000},
+ {0x02, 0x0007, 0x0005},
+ {0x02, 0x0015, 0x0006},
+ {0x02, 0x100a, 0x0007},
+ {0x02, 0xa048, 0x0000},
+ {0x02, 0xc002, 0x0001},
+ {0x02, 0x000f, 0x0005},
+ {0x02, 0xa048, 0x0000},
+ {0x05, 0x0022, 0x0004},
+ {0x05, 0x0025, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0026, 0x0001},
+ {0x05, 0x0001, 0x0000},
+ {0x05, 0x0027, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0001, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0021, 0x0001},
+ {0x05, 0x00d2, 0x0000},
+ {0x05, 0x0020, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x00, 0x0090, 0x0005},
+ {0x01, 0x00a6, 0x0000},
+ {0x05, 0x0026, 0x0001},
+ {0x05, 0x0001, 0x0000},
+ {0x05, 0x0027, 0x0001},
+ {0x05, 0x001e, 0x0000},
+ {0x01, 0x0003, 0x003f},
+ {0x01, 0x0001, 0x0056},
+ {0x01, 0x0011, 0x0008},
+ {0x01, 0x0032, 0x0009},
+ {0x01, 0xfffd, 0x000a},
+ {0x01, 0x0023, 0x000b},
+ {0x01, 0xffea, 0x000c},
+ {0x01, 0xfff4, 0x000d},
+ {0x01, 0xfffc, 0x000e},
+ {0x01, 0xffe3, 0x000f},
+ {0x01, 0x001f, 0x0010},
+ {0x01, 0x00a8, 0x0001},
+ {0x01, 0x0067, 0x0007},
+ {0x01, 0x0042, 0x0051},
+ {0x01, 0x0051, 0x0053},
+ {0x01, 0x000a, 0x0003},
+ {0x02, 0xc002, 0x0001},
+ {0x02, 0x0007, 0x0005},
+ {0x01, 0x0042, 0x0051},
+ {0x01, 0x0051, 0x0053},
+ {0x05, 0x0026, 0x0001},
+ {0x05, 0x0001, 0x0000},
+ {0x05, 0x0027, 0x0001},
+ {0x05, 0x002d, 0x0000},
+ {0x01, 0x0003, 0x003f},
+ {0x01, 0x0001, 0x0056},
+ {0x02, 0xc000, 0x0001},
+ {0x02, 0x0000, 0x0005},
+ {}
+};
+
+/* Unknow camera from Ori Usbid 0x0000:0x0000 */
+/* Based on snoops from Ori Cohen */
+static const __u16 spca501c_mysterious_open_data[][3] = {
+ {0x02, 0x000f, 0x0005},
+ {0x02, 0xa048, 0x0000},
+ {0x05, 0x0022, 0x0004},
+/* DSP Registers */
+ {0x01, 0x0016, 0x0011}, /* RGB offset */
+ {0x01, 0x0000, 0x0012},
+ {0x01, 0x0006, 0x0013},
+ {0x01, 0x0078, 0x0051},
+ {0x01, 0x0040, 0x0052},
+ {0x01, 0x0046, 0x0053},
+ {0x01, 0x0040, 0x0054},
+ {0x00, 0x0025, 0x0000},
+/* {0x00, 0x0000, 0x0000 }, */
+/* Part 2 */
+/* TG Registers */
+ {0x00, 0x0026, 0x0000},
+ {0x00, 0x0001, 0x0000},
+ {0x00, 0x0027, 0x0000},
+ {0x00, 0x008a, 0x0000},
+ {0x02, 0x0007, 0x0005},
+ {0x02, 0x2000, 0x0000},
+ {0x05, 0x0022, 0x0004},
+ {0x05, 0x0015, 0x0001},
+ {0x05, 0x00ea, 0x0000},
+ {0x05, 0x0021, 0x0001},
+ {0x05, 0x00d2, 0x0000},
+ {0x05, 0x0023, 0x0001},
+ {0x05, 0x0003, 0x0000},
+ {0x05, 0x0030, 0x0001},
+ {0x05, 0x002b, 0x0000},
+ {0x05, 0x0031, 0x0001},
+ {0x05, 0x0023, 0x0000},
+ {0x05, 0x0032, 0x0001},
+ {0x05, 0x0023, 0x0000},
+ {0x05, 0x0033, 0x0001},
+ {0x05, 0x0023, 0x0000},
+ {0x05, 0x0034, 0x0001},
+ {0x05, 0x0002, 0x0000},
+ {0x05, 0x0050, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0051, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0052, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0054, 0x0001},
+ {0x05, 0x0001, 0x0000},
+ {}
+};
+
+/* Based on snoops from Ori Cohen */
+static const __u16 spca501c_mysterious_init_data[][3] = {
+/* Part 3 */
+/* TG registers */
+/* {0x00, 0x0000, 0x0000}, */
+ {0x00, 0x0000, 0x0001},
+ {0x00, 0x0000, 0x0002},
+ {0x00, 0x0006, 0x0003},
+ {0x00, 0x0000, 0x0004},
+ {0x00, 0x0090, 0x0005},
+ {0x00, 0x0000, 0x0006},
+ {0x00, 0x0040, 0x0007},
+ {0x00, 0x00c0, 0x0008},
+ {0x00, 0x004a, 0x0009},
+ {0x00, 0x0000, 0x000a},
+ {0x00, 0x0000, 0x000b},
+ {0x00, 0x0001, 0x000c},
+ {0x00, 0x0001, 0x000d},
+ {0x00, 0x0000, 0x000e},
+ {0x00, 0x0002, 0x000f},
+ {0x00, 0x0001, 0x0010},
+ {0x00, 0x0000, 0x0011},
+ {0x00, 0x0001, 0x0012},
+ {0x00, 0x0002, 0x0020},
+ {0x00, 0x0080, 0x0021}, /* 640 */
+ {0x00, 0x0001, 0x0022},
+ {0x00, 0x00e0, 0x0023}, /* 480 */
+ {0x00, 0x0000, 0x0024}, /* Offset H hight */
+ {0x00, 0x00d3, 0x0025}, /* low */
+ {0x00, 0x0000, 0x0026}, /* Offset V */
+ {0x00, 0x000d, 0x0027}, /* low */
+ {0x00, 0x0000, 0x0046},
+ {0x00, 0x0000, 0x0047},
+ {0x00, 0x0000, 0x0048},
+ {0x00, 0x0000, 0x0049},
+ {0x00, 0x0008, 0x004a},
+/* DSP Registers */
+ {0x01, 0x00a6, 0x0000},
+ {0x01, 0x0028, 0x0001},
+ {0x01, 0x0000, 0x0002},
+ {0x01, 0x000a, 0x0003}, /* Level Calc bit7 ->1 Auto */
+ {0x01, 0x0040, 0x0004},
+ {0x01, 0x0066, 0x0007},
+ {0x01, 0x000f, 0x0008}, /* A11 Color correction coeff */
+ {0x01, 0x002d, 0x0009}, /* A12 */
+ {0x01, 0x0005, 0x000a}, /* A13 */
+ {0x01, 0x0023, 0x000b}, /* A21 */
+ {0x01, 0x00e0, 0x000c}, /* A22 */
+ {0x01, 0x00fd, 0x000d}, /* A23 */
+ {0x01, 0x00f4, 0x000e}, /* A31 */
+ {0x01, 0x00e4, 0x000f}, /* A32 */
+ {0x01, 0x0028, 0x0010}, /* A33 */
+ {0x01, 0x00ff, 0x0015}, /* Reserved */
+ {0x01, 0x0001, 0x0016}, /* Reserved */
+ {0x01, 0x0032, 0x0017}, /* Win1 Start begin */
+ {0x01, 0x0023, 0x0018},
+ {0x01, 0x00ce, 0x0019},
+ {0x01, 0x0023, 0x001a},
+ {0x01, 0x0032, 0x001b},
+ {0x01, 0x008d, 0x001c},
+ {0x01, 0x00ce, 0x001d},
+ {0x01, 0x008d, 0x001e},
+ {0x01, 0x0000, 0x001f},
+ {0x01, 0x0000, 0x0020}, /* Win1 Start end */
+ {0x01, 0x00ff, 0x003e}, /* Reserved begin */
+ {0x01, 0x0002, 0x003f},
+ {0x01, 0x0000, 0x0040},
+ {0x01, 0x0035, 0x0041},
+ {0x01, 0x0053, 0x0042},
+ {0x01, 0x0069, 0x0043},
+ {0x01, 0x007c, 0x0044},
+ {0x01, 0x008c, 0x0045},
+ {0x01, 0x009a, 0x0046},
+ {0x01, 0x00a8, 0x0047},
+ {0x01, 0x00b4, 0x0048},
+ {0x01, 0x00bf, 0x0049},
+ {0x01, 0x00ca, 0x004a},
+ {0x01, 0x00d4, 0x004b},
+ {0x01, 0x00dd, 0x004c},
+ {0x01, 0x00e7, 0x004d},
+ {0x01, 0x00ef, 0x004e},
+ {0x01, 0x00f8, 0x004f},
+ {0x01, 0x00ff, 0x0050},
+ {0x01, 0x0003, 0x0056}, /* Reserved end */
+ {0x01, 0x0060, 0x0057}, /* Edge Gain */
+ {0x01, 0x0040, 0x0058},
+ {0x01, 0x0011, 0x0059}, /* Edge Bandwidth */
+ {0x01, 0x0001, 0x005a},
+ {0x02, 0x0007, 0x0005},
+ {0x02, 0xa048, 0x0000},
+ {0x02, 0x0007, 0x0005},
+ {0x02, 0x0015, 0x0006},
+ {0x02, 0x200a, 0x0007},
+ {0x02, 0xa048, 0x0000},
+ {0x02, 0xc000, 0x0001},
+ {0x02, 0x000f, 0x0005},
+ {0x02, 0xa048, 0x0000},
+ {0x05, 0x0022, 0x0004},
+ {0x05, 0x0025, 0x0001},
+ {0x05, 0x0000, 0x0000},
+/* Part 4 */
+ {0x05, 0x0026, 0x0001},
+ {0x05, 0x0001, 0x0000},
+ {0x05, 0x0027, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0001, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x05, 0x0021, 0x0001},
+ {0x05, 0x00d2, 0x0000},
+ {0x05, 0x0020, 0x0001},
+ {0x05, 0x0000, 0x0000},
+ {0x00, 0x0090, 0x0005},
+ {0x01, 0x00a6, 0x0000},
+ {0x02, 0x0000, 0x0005},
+ {0x05, 0x0026, 0x0001},
+ {0x05, 0x0001, 0x0000},
+ {0x05, 0x0027, 0x0001},
+ {0x05, 0x004e, 0x0000},
+/* Part 5 */
+ {0x01, 0x0003, 0x003f},
+ {0x01, 0x0001, 0x0056},
+ {0x01, 0x000f, 0x0008},
+ {0x01, 0x002d, 0x0009},
+ {0x01, 0x0005, 0x000a},
+ {0x01, 0x0023, 0x000b},
+ {0x01, 0xffe0, 0x000c},
+ {0x01, 0xfffd, 0x000d},
+ {0x01, 0xfff4, 0x000e},
+ {0x01, 0xffe4, 0x000f},
+ {0x01, 0x0028, 0x0010},
+ {0x01, 0x00a8, 0x0001},
+ {0x01, 0x0066, 0x0007},
+ {0x01, 0x0032, 0x0017},
+ {0x01, 0x0023, 0x0018},
+ {0x01, 0x00ce, 0x0019},
+ {0x01, 0x0023, 0x001a},
+ {0x01, 0x0032, 0x001b},
+ {0x01, 0x008d, 0x001c},
+ {0x01, 0x00ce, 0x001d},
+ {0x01, 0x008d, 0x001e},
+ {0x01, 0x00c8, 0x0015}, /* c8 Poids fort Luma */
+ {0x01, 0x0032, 0x0016}, /* 32 */
+ {0x01, 0x0016, 0x0011}, /* R 00 */
+ {0x01, 0x0016, 0x0012}, /* G 00 */
+ {0x01, 0x0016, 0x0013}, /* B 00 */
+ {0x01, 0x000a, 0x0003},
+ {0x02, 0xc002, 0x0001},
+ {0x02, 0x0007, 0x0005},
+ {}
+};
+
+static int reg_write(struct usb_device *dev,
+ __u16 req, __u16 index, __u16 value)
+{
+ int ret;
+
+ ret = usb_control_msg(dev,
+ usb_sndctrlpipe(dev, 0),
+ req,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value, index, NULL, 0, 500);
+ PDEBUG(D_USBO, "reg write: 0x%02x 0x%02x 0x%02x",
+ req, index, value);
+ if (ret < 0)
+ PDEBUG(D_ERR, "reg write: error %d", ret);
+ return ret;
+}
+
+/* returns: negative is error, pos or zero is data */
+static int reg_read(struct usb_device *dev,
+ __u16 req, /* bRequest */
+ __u16 index, /* wIndex */
+ __u16 length) /* wLength (1 or 2 only) */
+{
+ int ret;
+ __u8 buf[2];
+
+ buf[1] = 0;
+ ret = usb_control_msg(dev,
+ usb_rcvctrlpipe(dev, 0),
+ req,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, /* value */
+ index,
+ buf, length,
+ 500); /* timeout */
+ if (ret < 0) {
+ PDEBUG(D_ERR, "reg_read err %d", ret);
+ return -1;
+ }
+ return (buf[1] << 8) + buf[0];
+}
+
+static int write_vector(struct gspca_dev *gspca_dev,
+ const __u16 data[][3])
+{
+ struct usb_device *dev = gspca_dev->dev;
+ int ret, i = 0;
+
+ while (data[i][0] != 0 || data[i][1] != 0 || data[i][2] != 0) {
+ ret = reg_write(dev, data[i][0], data[i][2], data[i][1]);
+ if (ret < 0) {
+ PDEBUG(D_ERR,
+ "Reg write failed for 0x%02x,0x%02x,0x%02x",
+ data[i][0], data[i][1], data[i][2]);
+ return ret;
+ }
+ i++;
+ }
+ return 0;
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x11, sd->brightness);
+ reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x12, sd->brightness);
+ reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x13, sd->brightness);
+}
+
+static void getbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ __u16 brightness;
+
+ brightness = reg_read(gspca_dev->dev, SPCA501_REG_CCDSP, 0x11, 2);
+ sd->brightness = brightness << 1;
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ reg_write(gspca_dev->dev, 0x00, 0x00,
+ (sd->contrast >> 8) & 0xff);
+ reg_write(gspca_dev->dev, 0x00, 0x01,
+ sd->contrast & 0xff);
+}
+
+static void getcontrast(struct gspca_dev *gspca_dev)
+{
+#if 0
+ __u8 byte = 0;
+ byte = (reg_read(gspca_dev->dev,
+ 0x00,
+ 0x00,
+ 1) & 0xff) << 8;
+ ss->contrast = byte | (reg_read(gspca_dev->dev,
+ 0x00,
+ 0x01,
+ 1) & 0xff);
+#endif
+/* spca50x->contrast = 0xaa01; */
+}
+
+static void setcolors(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x0c, sd->colors);
+}
+
+static void getcolors(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->colors = reg_read(gspca_dev->dev, SPCA501_REG_CCDSP, 0x0c, 2);
+/* sd->hue = (reg_read(gspca_dev->dev, SPCA501_REG_CCDSP, 0x13, */
+/* 2) & 0xFF) << 8; */
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+ const struct usb_device_id *id)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct cam *cam;
+ __u16 vendor;
+ __u16 product;
+
+ vendor = id->idVendor;
+ product = id->idProduct;
+ switch (vendor) {
+ case 0x0000: /* Unknow Camera */
+/* switch (product) { */
+/* case 0x0000: */
+ sd->subtype = MystFromOriUnknownCamera;
+/* break; */
+/* } */
+ break;
+ case 0x040a: /* Kodak cameras */
+/* switch (product) { */
+/* case 0x0002: */
+ sd->subtype = KodakDVC325;
+/* break; */
+/* } */
+ break;
+ case 0x0497: /* Smile International */
+/* switch (product) { */
+/* case 0xc001: */
+ sd->subtype = SmileIntlCamera;
+/* break; */
+/* } */
+ break;
+ case 0x0506: /* 3COM cameras */
+/* switch (product) { */
+/* case 0x00df: */
+ sd->subtype = ThreeComHomeConnectLite;
+/* break; */
+/* } */
+ break;
+ case 0x0733: /* Rebadged ViewQuest (Intel) and ViewQuest cameras */
+ switch (product) {
+ case 0x0401:
+ sd->subtype = IntelCreateAndShare;
+ break;
+ case 0x0402:
+ sd->subtype = ViewQuestM318B;
+ break;
+ }
+ break;
+ case 0x1776: /* Arowana */
+/* switch (product) { */
+/* case 0x501c: */
+ sd->subtype = Arowana300KCMOSCamera;
+/* break; */
+/* } */
+ break;
+ }
+ cam = &gspca_dev->cam;
+ cam->dev_name = (char *) id->driver_info;
+ cam->epaddr = 0x01;
+ cam->cam_mode = vga_mode;
+ cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+ sd->brightness = sd_ctrls[MY_BRIGHTNESS].qctrl.default_value;
+ sd->contrast = sd_ctrls[MY_CONTRAST].qctrl.default_value;
+ sd->colors = sd_ctrls[MY_COLOR].qctrl.default_value;
+
+ switch (sd->subtype) {
+ case Arowana300KCMOSCamera:
+ case SmileIntlCamera:
+ /* Arowana 300k CMOS Camera data */
+ if (write_vector(gspca_dev, spca501c_arowana_init_data))
+ goto error;
+ break;
+ case MystFromOriUnknownCamera:
+ /* UnKnow Ori CMOS Camera data */
+ if (write_vector(gspca_dev, spca501c_mysterious_open_data))
+ goto error;
+ break;
+ default:
+ /* generic spca501 init data */
+ if (write_vector(gspca_dev, spca501_init_data))
+ goto error;
+ break;
+ }
+ return 0;
+error:
+ return -EINVAL;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ switch (sd->subtype) {
+ case ThreeComHomeConnectLite:
+ /* Special handling for 3com data */
+ write_vector(gspca_dev, spca501_3com_open_data);
+ break;
+ case Arowana300KCMOSCamera:
+ case SmileIntlCamera:
+ /* Arowana 300k CMOS Camera data */
+ write_vector(gspca_dev, spca501c_arowana_open_data);
+ break;
+ case MystFromOriUnknownCamera:
+ /* UnKnow CMOS Camera data */
+ write_vector(gspca_dev, spca501c_mysterious_init_data);
+ break;
+ default:
+ /* Generic 501 open data */
+ write_vector(gspca_dev, spca501_open_data);
+ }
+ PDEBUG(D_STREAM, "Initializing SPCA501 finished");
+ return 0;
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+ struct usb_device *dev = gspca_dev->dev;
+ int mode;
+
+ /* memorize the wanted pixel format */
+ mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
+
+ /* Enable ISO packet machine CTRL reg=2,
+ * index=1 bitmask=0x2 (bit ordinal 1) */
+ reg_write(dev, SPCA50X_REG_USB, 0x6, 0x94);
+ switch (mode) {
+ case 0: /* 640x480 */
+ reg_write(dev, SPCA50X_REG_USB, 0x07, 0x004a);
+ break;
+ case 1: /* 320x240 */
+ reg_write(dev, SPCA50X_REG_USB, 0x07, 0x104a);
+ break;
+ default:
+/* case 2: * 160x120 */
+ reg_write(dev, SPCA50X_REG_USB, 0x07, 0x204a);
+ break;
+ }
+ reg_write(dev, SPCA501_REG_CTLRL, 0x01, 0x02);
+
+ /* HDG atleast the Intel CreateAndShare needs to have one of its
+ * brightness / contrast / color set otherwise it assumes what seems
+ * max contrast. Note that strange enough setting any of these is
+ * enough to fix the max contrast problem, to be sure we set all 3 */
+ setbrightness(gspca_dev);
+ setcontrast(gspca_dev);
+ setcolors(gspca_dev);
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+ /* Disable ISO packet
+ * machine CTRL reg=2, index=1 bitmask=0x0 (bit ordinal 1) */
+ reg_write(gspca_dev->dev, SPCA501_REG_CTLRL, 0x01, 0x00);
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+/* this function is called at close time */
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+ reg_write(gspca_dev->dev, SPCA501_REG_CTLRL, 0x05, 0x00);
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ struct gspca_frame *frame, /* target */
+ __u8 *data, /* isoc packet */
+ int len) /* iso packet length */
+{
+ switch (data[0]) {
+ case 0: /* start of frame */
+ frame = gspca_frame_add(gspca_dev,
+ LAST_PACKET,
+ frame,
+ data, 0);
+ data += SPCA501_OFFSET_DATA;
+ len -= SPCA501_OFFSET_DATA;
+ gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+ data, len);
+ return;
+ case 0xff: /* drop */
+/* gspca_dev->last_packet_type = DISCARD_PACKET; */
+ return;
+ }
+ data++;
+ len--;
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+ data, len);
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->brightness = val;
+ if (gspca_dev->streaming)
+ setbrightness(gspca_dev);
+ return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ getbrightness(gspca_dev);
+ *val = sd->brightness;
+ return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->contrast = val;
+ if (gspca_dev->streaming)
+ setcontrast(gspca_dev);
+ return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ getcontrast(gspca_dev);
+ *val = sd->contrast;
+ return 0;
+}
+
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->colors = val;
+ if (gspca_dev->streaming)
+ setcolors(gspca_dev);
+ return 0;
+}
+
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ getcolors(gspca_dev);
+ *val = sd->colors;
+ return 0;
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .ctrls = sd_ctrls,
+ .nctrls = ARRAY_SIZE(sd_ctrls),
+ .config = sd_config,
+ .open = sd_open,
+ .start = sd_start,
+ .stopN = sd_stopN,
+ .stop0 = sd_stop0,
+ .close = sd_close,
+ .pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static const __devinitdata struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x040a, 0x0002), DVNM("Kodak DVC-325")},
+ {USB_DEVICE(0x0497, 0xc001), DVNM("Smile International")},
+ {USB_DEVICE(0x0506, 0x00df), DVNM("3Com HomeConnect Lite")},
+ {USB_DEVICE(0x0733, 0x0401), DVNM("Intel Create and Share")},
+ {USB_DEVICE(0x0733, 0x0402), DVNM("ViewQuest M318B")},
+ {USB_DEVICE(0x1776, 0x501c), DVNM("Arowana 300K CMOS Camera")},
+ {USB_DEVICE(0x0000, 0x0000), DVNM("MystFromOri Unknow Camera")},
+ {}
+};
+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,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+ if (usb_register(&sd_driver) < 0)
+ return -1;
+ PDEBUG(D_PROBE, "v%s registered", version);
+ return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+ usb_deregister(&sd_driver);
+ PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/linux/drivers/media/video/gspca/spca505.c b/linux/drivers/media/video/gspca/spca505.c
new file mode 100644
index 000000000..cecbc4362
--- /dev/null
+++ b/linux/drivers/media/video/gspca/spca505.c
@@ -0,0 +1,1022 @@
+/*
+ * SPCA505 chip based cameras initialization data
+ *
+ * V4L2 by Jean-Francis Moine <http://moinejf.free.fr>
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#define MODULE_NAME "spca505"
+
+#include "gspca.h"
+
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 5)
+static const char version[] = "2.1.5";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("GSPCA/SPCA505 USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+
+ int buflen;
+ unsigned char tmpbuf[640 * 480 * 3 / 2]; /* YYUV per line */
+ unsigned char tmpbuf2[640 * 480 * 2]; /* YUYV */
+
+ unsigned char brightness;
+
+ char subtype;
+#define IntelPCCameraPro 0
+#define Nxultra 1
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+#define SD_BRIGHTNESS 0
+ {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+ .default_value = 127,
+ },
+ .set = sd_setbrightness,
+ .get = sd_getbrightness,
+ },
+};
+
+static struct v4l2_pix_format vga_mode[] = {
+ {160, 120, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
+ .bytesperline = 160 * 2,
+ .sizeimage = 160 * 120 * 2,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 5},
+ {176, 144, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
+ .bytesperline = 176 * 2,
+ .sizeimage = 176 * 144 * 2,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 4},
+ {320, 240, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
+ .bytesperline = 320 * 2,
+ .sizeimage = 320 * 240 * 2,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 2},
+ {352, 288, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
+ .bytesperline = 352 * 2,
+ .sizeimage = 352 * 288 * 2,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 1},
+ {640, 480, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
+ .bytesperline = 640 * 2,
+ .sizeimage = 640 * 480 * 2,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0},
+};
+
+#define SPCA50X_OFFSET_DATA 10
+
+#define SPCA50X_REG_USB 0x02 /* spca505 501 */
+
+#define SPCA50X_USB_CTRL 0x00 /* spca505 */
+#define SPCA50X_CUSB_ENABLE 0x01 /* spca505 */
+#define SPCA50X_REG_GLOBAL 0x03 /* spca505 */
+#define SPCA50X_GMISC0_IDSEL 0x01 /* Global control device ID select spca505 */
+#define SPCA50X_GLOBAL_MISC0 0x00 /* Global control miscellaneous 0 spca505 */
+
+#define SPCA50X_GLOBAL_MISC1 0x01 /* 505 */
+#define SPCA50X_GLOBAL_MISC3 0x03 /* 505 */
+#define SPCA50X_GMISC3_SAA7113RST 0x20 /* Not sure about this one spca505 */
+
+/*
+ * Data to initialize a SPCA505. Common to the CCD and external modes
+ */
+static const __u16 spca505_init_data[][3] = {
+ /* line bmRequest,value,index */
+ /* 1819 */
+ {SPCA50X_REG_GLOBAL, SPCA50X_GMISC3_SAA7113RST, SPCA50X_GLOBAL_MISC3},
+ /* Sensor reset */
+ /* 1822 */ {SPCA50X_REG_GLOBAL, 0x00, SPCA50X_GLOBAL_MISC3},
+ /* 1825 */ {SPCA50X_REG_GLOBAL, 0x00, SPCA50X_GLOBAL_MISC1},
+ /* Block USB reset */
+ /* 1828 */ {SPCA50X_REG_GLOBAL, SPCA50X_GMISC0_IDSEL,
+ SPCA50X_GLOBAL_MISC0},
+
+ /* 1831 */ {0x5, 0x01, 0x10},
+ /* Maybe power down some stuff */
+ /* 1834 */ {0x5, 0x0f, 0x11},
+
+ /* Setup internal CCD ? */
+ /* 1837 */ {0x6, 0x10, 0x08},
+ /* 1840 */ {0x6, 0x00, 0x09},
+ /* 1843 */ {0x6, 0x00, 0x0a},
+ /* 1846 */ {0x6, 0x00, 0x0b},
+ /* 1849 */ {0x6, 0x10, 0x0c},
+ /* 1852 */ {0x6, 0x00, 0x0d},
+ /* 1855 */ {0x6, 0x00, 0x0e},
+ /* 1858 */ {0x6, 0x00, 0x0f},
+ /* 1861 */ {0x6, 0x10, 0x10},
+ /* 1864 */ {0x6, 0x02, 0x11},
+ /* 1867 */ {0x6, 0x00, 0x12},
+ /* 1870 */ {0x6, 0x04, 0x13},
+ /* 1873 */ {0x6, 0x02, 0x14},
+ /* 1876 */ {0x6, 0x8a, 0x51},
+ /* 1879 */ {0x6, 0x40, 0x52},
+ /* 1882 */ {0x6, 0xb6, 0x53},
+ /* 1885 */ {0x6, 0x3d, 0x54},
+ {}
+};
+
+/*
+ * Data to initialize the camera using the internal CCD
+ */
+static const __u16 spca505_open_data_ccd[][3] = {
+ /* line bmRequest,value,index */
+ /* Internal CCD data set */
+ /* 1891 */ {0x3, 0x04, 0x01},
+ /* This could be a reset */
+ /* 1894 */ {0x3, 0x00, 0x01},
+
+ /* Setup compression and image registers. 0x6 and 0x7 seem to be
+ related to H&V hold, and are resolution mode specific */
+ /* 1897 */ {0x4, 0x10, 0x01},
+ /* DIFF(0x50), was (0x10) */
+ /* 1900 */ {0x4, 0x00, 0x04},
+ /* 1903 */ {0x4, 0x00, 0x05},
+ /* 1906 */ {0x4, 0x20, 0x06},
+ /* 1909 */ {0x4, 0x20, 0x07},
+
+ /* 1912 */ {0x8, 0x0a, 0x00},
+ /* DIFF (0x4a), was (0xa) */
+
+ /* 1915 */ {0x5, 0x00, 0x10},
+ /* 1918 */ {0x5, 0x00, 0x11},
+ /* 1921 */ {0x5, 0x00, 0x00},
+ /* DIFF not written */
+ /* 1924 */ {0x5, 0x00, 0x01},
+ /* DIFF not written */
+ /* 1927 */ {0x5, 0x00, 0x02},
+ /* DIFF not written */
+ /* 1930 */ {0x5, 0x00, 0x03},
+ /* DIFF not written */
+ /* 1933 */ {0x5, 0x00, 0x04},
+ /* DIFF not written */
+ /* 1936 */ {0x5, 0x80, 0x05},
+ /* DIFF not written */
+ /* 1939 */ {0x5, 0xe0, 0x06},
+ /* DIFF not written */
+ /* 1942 */ {0x5, 0x20, 0x07},
+ /* DIFF not written */
+ /* 1945 */ {0x5, 0xa0, 0x08},
+ /* DIFF not written */
+ /* 1948 */ {0x5, 0x0, 0x12},
+ /* DIFF not written */
+ /* 1951 */ {0x5, 0x02, 0x0f},
+ /* DIFF not written */
+ /* 1954 */ {0x5, 0x10, 0x46},
+ /* DIFF not written */
+ /* 1957 */ {0x5, 0x8, 0x4a},
+ /* DIFF not written */
+
+ /* 1960 */ {0x3, 0x08, 0x03},
+ /* DIFF (0x3,0x28,0x3) */
+ /* 1963 */ {0x3, 0x08, 0x01},
+ /* 1966 */ {0x3, 0x0c, 0x03},
+ /* DIFF not written */
+ /* 1969 */ {0x3, 0x21, 0x00},
+ /* DIFF (0x39) */
+
+/* Extra block copied from init to hopefully ensure CCD is in a sane state */
+ /* 1837 */ {0x6, 0x10, 0x08},
+ /* 1840 */ {0x6, 0x00, 0x09},
+ /* 1843 */ {0x6, 0x00, 0x0a},
+ /* 1846 */ {0x6, 0x00, 0x0b},
+ /* 1849 */ {0x6, 0x10, 0x0c},
+ /* 1852 */ {0x6, 0x00, 0x0d},
+ /* 1855 */ {0x6, 0x00, 0x0e},
+ /* 1858 */ {0x6, 0x00, 0x0f},
+ /* 1861 */ {0x6, 0x10, 0x10},
+ /* 1864 */ {0x6, 0x02, 0x11},
+ /* 1867 */ {0x6, 0x00, 0x12},
+ /* 1870 */ {0x6, 0x04, 0x13},
+ /* 1873 */ {0x6, 0x02, 0x14},
+ /* 1876 */ {0x6, 0x8a, 0x51},
+ /* 1879 */ {0x6, 0x40, 0x52},
+ /* 1882 */ {0x6, 0xb6, 0x53},
+ /* 1885 */ {0x6, 0x3d, 0x54},
+ /* End of extra block */
+
+ /* 1972 */ {0x6, 0x3f, 0x1},
+ /* Block skipped */
+ /* 1975 */ {0x6, 0x10, 0x02},
+ /* 1978 */ {0x6, 0x64, 0x07},
+ /* 1981 */ {0x6, 0x10, 0x08},
+ /* 1984 */ {0x6, 0x00, 0x09},
+ /* 1987 */ {0x6, 0x00, 0x0a},
+ /* 1990 */ {0x6, 0x00, 0x0b},
+ /* 1993 */ {0x6, 0x10, 0x0c},
+ /* 1996 */ {0x6, 0x00, 0x0d},
+ /* 1999 */ {0x6, 0x00, 0x0e},
+ /* 2002 */ {0x6, 0x00, 0x0f},
+ /* 2005 */ {0x6, 0x10, 0x10},
+ /* 2008 */ {0x6, 0x02, 0x11},
+ /* 2011 */ {0x6, 0x00, 0x12},
+ /* 2014 */ {0x6, 0x04, 0x13},
+ /* 2017 */ {0x6, 0x02, 0x14},
+ /* 2020 */ {0x6, 0x8a, 0x51},
+ /* 2023 */ {0x6, 0x40, 0x52},
+ /* 2026 */ {0x6, 0xb6, 0x53},
+ /* 2029 */ {0x6, 0x3d, 0x54},
+ /* 2032 */ {0x6, 0x60, 0x57},
+ /* 2035 */ {0x6, 0x20, 0x58},
+ /* 2038 */ {0x6, 0x15, 0x59},
+ /* 2041 */ {0x6, 0x05, 0x5a},
+
+ /* 2044 */ {0x5, 0x01, 0xc0},
+ /* 2047 */ {0x5, 0x10, 0xcb},
+ /* 2050 */ {0x5, 0x80, 0xc1},
+ /* */
+ /* 2053 */ {0x5, 0x0, 0xc2},
+ /* 4 was 0 */
+ /* 2056 */ {0x5, 0x00, 0xca},
+ /* 2059 */ {0x5, 0x80, 0xc1},
+ /* */
+ /* 2062 */ {0x5, 0x04, 0xc2},
+ /* 2065 */ {0x5, 0x00, 0xca},
+ /* 2068 */ {0x5, 0x0, 0xc1},
+ /* */
+ /* 2071 */ {0x5, 0x00, 0xc2},
+ /* 2074 */ {0x5, 0x00, 0xca},
+ /* 2077 */ {0x5, 0x40, 0xc1},
+ /* */
+ /* 2080 */ {0x5, 0x17, 0xc2},
+ /* 2083 */ {0x5, 0x00, 0xca},
+ /* 2086 */ {0x5, 0x80, 0xc1},
+ /* */
+ /* 2089 */ {0x5, 0x06, 0xc2},
+ /* 2092 */ {0x5, 0x00, 0xca},
+ /* 2095 */ {0x5, 0x80, 0xc1},
+ /* */
+ /* 2098 */ {0x5, 0x04, 0xc2},
+ /* 2101 */ {0x5, 0x00, 0xca},
+
+ /* 2104 */ {0x3, 0x4c, 0x3},
+ /* 2107 */ {0x3, 0x18, 0x1},
+
+ /* 2110 */ {0x6, 0x70, 0x51},
+ /* 2113 */ {0x6, 0xbe, 0x53},
+ /* 2116 */ {0x6, 0x71, 0x57},
+ /* 2119 */ {0x6, 0x20, 0x58},
+ /* 2122 */ {0x6, 0x05, 0x59},
+ /* 2125 */ {0x6, 0x15, 0x5a},
+
+ /* 2128 */ {0x4, 0x00, 0x08},
+ /* Compress = OFF (0x1 to turn on) */
+ /* 2131 */ {0x4, 0x12, 0x09},
+ /* 2134 */ {0x4, 0x21, 0x0a},
+ /* 2137 */ {0x4, 0x10, 0x0b},
+ /* 2140 */ {0x4, 0x21, 0x0c},
+ /* 2143 */ {0x4, 0x05, 0x00},
+ /* was 5 (Image Type ? ) */
+ /* 2146 */ {0x4, 0x00, 0x01},
+
+ /* 2149 */ {0x6, 0x3f, 0x01},
+
+ /* 2152 */ {0x4, 0x00, 0x04},
+ /* 2155 */ {0x4, 0x00, 0x05},
+ /* 2158 */ {0x4, 0x40, 0x06},
+ /* 2161 */ {0x4, 0x40, 0x07},
+
+ /* 2164 */ {0x6, 0x1c, 0x17},
+ /* 2167 */ {0x6, 0xe2, 0x19},
+ /* 2170 */ {0x6, 0x1c, 0x1b},
+ /* 2173 */ {0x6, 0xe2, 0x1d},
+ /* 2176 */ {0x6, 0xaa, 0x1f},
+ /* 2179 */ {0x6, 0x70, 0x20},
+
+ /* 2182 */ {0x5, 0x01, 0x10},
+ /* 2185 */ {0x5, 0x00, 0x11},
+ /* 2188 */ {0x5, 0x01, 0x00},
+ /* 2191 */ {0x5, 0x05, 0x01},
+ /* 2194 */ {0x5, 0x00, 0xc1},
+ /* */
+ /* 2197 */ {0x5, 0x00, 0xc2},
+ /* 2200 */ {0x5, 0x00, 0xca},
+
+ /* 2203 */ {0x6, 0x70, 0x51},
+ /* 2206 */ {0x6, 0xbe, 0x53},
+ {}
+};
+
+#if 0
+/*
+ * Data to initialize the camera in external video mode
+ */
+static const __u16 spca505_open_data_ext[][3] = {
+ /* line bmRequest,value,index */
+ /* External video input dataset */
+ /* 0808 */ {0x3, 0x04, 0x01},
+ /* 0809 */ {0x3, 0x00, 0x01},
+
+ /* 0810 */ {0x4, 0x50, 0x01},
+ /* 0811 */ {0x4, 0x00, 0x04},
+ /* 0812 */ {0x4, 0x0a, 0x05},
+ /* 0813 */ {0x4, 0x20, 0x06},
+ /* 0814 */ {0x4, 0x20, 0x07},
+
+ /* 0815 */ {0x8, 0x4a, 0x00},
+
+ /* 0816 */ {0x5, 0x00, 0x10},
+ /* 0817 */ {0x5, 0x00, 0x11},
+
+ /* 0818 */ {0x3, 0x08, 0x03},
+ /* 0819 */ {0x3, 0x28, 0x03},
+ /* 0820 */ {0x3, 0x08, 0x01},
+ /* 0821 */ {0x3, 0x39, 0x00},
+
+ /* 0822 */ {0x5, 0x01, 0xc0},
+ /* 0823 */ {0x5, 0x10, 0xcb},
+ /* 0824 */ {0x5, 0x80, 0xc1},
+ /* 0825 */ {0x5, 0x05, 0xc2},
+ /* 0826 */ {0x5, 0x00, 0xca},
+ /* 0827 */ {0x5, 0x00, 0xc1},
+ /* 0828 */ {0x5, 0x01, 0xc2},
+ /* 0829 */ {0x5, 0x00, 0xca},
+ /* 0830 */ {0x5, 0x01, 0x10},
+ /* 0831 */ {0x5, 0x0f, 0x11},
+ {}
+};
+
+/*
+ * Additional data needed to initialze the camera in external mode
+ */
+static const __u16 spca505_open_data2[][3] = {
+ /* line bmRequest,value,index */
+ /* 1384 */ {0x3, 0x68, 0x03},
+ /* 1385 */ {0x3, 0x10, 0x01},
+ /* 1386 */ {0x8, 0x4a, 0x00},
+ /* 1387 */ {0x4, 0x00, 0x08},
+ /* was 1 COMPRESSION ENABLE ! */
+ /* 1388 */ {0x4, 0x12, 0x09},
+ /* Think these are the compression registers */
+ /* 1389 */ {0x4, 0x21, 0x0a},
+ /* 1390 */ {0x4, 0x10, 0x0b},
+ /* 1391 */ {0x4, 0x21, 0x0c},
+ /* 1392 */ {0x4, 0x05, 0x00},
+ /* This may be the picture type code (5=160x120 as YUV4:2:0) */
+ /* 1393 */ {0x4, 0x00, 0x01},
+ /* 1394 */ {0x6, 0x3f, 0x01},
+ /* 1395 */ {0x4, 0x00, 0x04},
+ /* 1396 */ {0x4, 0x0a, 0x05},
+ /* 1397 */ {0x4, 0x40, 0x06},
+ /* was 40 */
+ /* 1398 */ {0x4, 0x40, 0x07},
+ /* was 50 */
+ /* 1399 */ {0x4, 0x02, 0x05},
+ /* 1400 */ {0x4, 0x00, 0x04},
+ {}
+};
+#endif
+/*
+ Made by Tomasz Zablocki (skalamandra@poczta.onet.pl)
+ * SPCA505b chip based cameras initialization data
+ *
+ */
+/* jfm */
+#define initial_brightness 0x7f /* 0x0(white)-0xff(black) */
+/* #define initial_brightness 0x0 //0x0(white)-0xff(black) */
+/*
+ * Data to initialize a SPCA505. Common to the CCD and external modes
+ */
+static const __u16 spca505b_init_data[][3] = {
+/* start */
+ {0x02, 0x00, 0x00}, /* init */
+ {0x02, 0x00, 0x01},
+ {0x02, 0x00, 0x02},
+ {0x02, 0x00, 0x03},
+ {0x02, 0x00, 0x04},
+ {0x02, 0x00, 0x05},
+ {0x02, 0x00, 0x06},
+ {0x02, 0x00, 0x07},
+ {0x02, 0x00, 0x08},
+ {0x02, 0x00, 0x09},
+ {0x03, 0x00, 0x00},
+ {0x03, 0x00, 0x01},
+ {0x03, 0x00, 0x02},
+ {0x03, 0x00, 0x03},
+ {0x03, 0x00, 0x04},
+ {0x03, 0x00, 0x05},
+ {0x03, 0x00, 0x06},
+ {0x04, 0x00, 0x00},
+ {0x04, 0x00, 0x02},
+ {0x04, 0x00, 0x04},
+ {0x04, 0x00, 0x05},
+ {0x04, 0x00, 0x06},
+ {0x04, 0x00, 0x07},
+ {0x04, 0x00, 0x08},
+ {0x04, 0x00, 0x09},
+ {0x04, 0x00, 0x0a},
+ {0x04, 0x00, 0x0b},
+ {0x04, 0x00, 0x0c},
+ {0x07, 0x00, 0x00},
+ {0x07, 0x00, 0x03},
+ {0x08, 0x00, 0x00},
+ {0x08, 0x00, 0x01},
+ {0x08, 0x00, 0x02},
+ {0x00, 0x01, 0x00},
+ {0x00, 0x01, 0x01},
+ {0x00, 0x01, 0x34},
+ {0x00, 0x01, 0x35},
+ {0x06, 0x18, 0x08},
+ {0x06, 0xfc, 0x09},
+ {0x06, 0xfc, 0x0a},
+ {0x06, 0xfc, 0x0b},
+ {0x06, 0x18, 0x0c},
+ {0x06, 0xfc, 0x0d},
+ {0x06, 0xfc, 0x0e},
+ {0x06, 0xfc, 0x0f},
+ {0x06, 0x18, 0x10},
+ {0x06, 0xfe, 0x12},
+ {0x06, 0x00, 0x11},
+ {0x06, 0x00, 0x14},
+ {0x06, 0x00, 0x13},
+ {0x06, 0x28, 0x51},
+ {0x06, 0xff, 0x53},
+ {0x02, 0x00, 0x08},
+
+ {0x03, 0x00, 0x03},
+ {0x03, 0x10, 0x03},
+ {}
+};
+
+/*
+ * Data to initialize the camera using the internal CCD
+ */
+static const __u16 spca505b_open_data_ccd[][3] = {
+
+/* {0x02,0x00,0x00}, */
+ {0x03, 0x04, 0x01}, /* rst */
+ {0x03, 0x00, 0x01},
+ {0x03, 0x00, 0x00},
+ {0x03, 0x21, 0x00},
+ {0x03, 0x00, 0x04},
+ {0x03, 0x00, 0x03},
+ {0x03, 0x18, 0x03},
+ {0x03, 0x08, 0x01},
+ {0x03, 0x1c, 0x03},
+ {0x03, 0x5c, 0x03},
+ {0x03, 0x5c, 0x03},
+ {0x03, 0x18, 0x01},
+
+/* same as 505 */
+ {0x04, 0x10, 0x01},
+ {0x04, 0x00, 0x04},
+ {0x04, 0x00, 0x05},
+ {0x04, 0x20, 0x06},
+ {0x04, 0x20, 0x07},
+
+ {0x08, 0x0a, 0x00},
+
+ {0x05, 0x00, 0x10},
+ {0x05, 0x00, 0x11},
+ {0x05, 0x00, 0x12},
+ {0x05, 0x6f, 0x00},
+ {0x05, initial_brightness >> 6, 0x00},
+ {0x05, initial_brightness << 2, 0x01},
+ {0x05, 0x00, 0x02},
+ {0x05, 0x01, 0x03},
+ {0x05, 0x00, 0x04},
+ {0x05, 0x03, 0x05},
+ {0x05, 0xe0, 0x06},
+ {0x05, 0x20, 0x07},
+ {0x05, 0xa0, 0x08},
+ {0x05, 0x00, 0x12},
+ {0x05, 0x02, 0x0f},
+ {0x05, 128, 0x14}, /* max exposure off (0=on) */
+ {0x05, 0x01, 0xb0},
+ {0x05, 0x01, 0xbf},
+ {0x03, 0x02, 0x06},
+ {0x05, 0x10, 0x46},
+ {0x05, 0x08, 0x4a},
+
+ {0x06, 0x00, 0x01},
+ {0x06, 0x10, 0x02},
+ {0x06, 0x64, 0x07},
+ {0x06, 0x18, 0x08},
+ {0x06, 0xfc, 0x09},
+ {0x06, 0xfc, 0x0a},
+ {0x06, 0xfc, 0x0b},
+ {0x04, 0x00, 0x01},
+ {0x06, 0x18, 0x0c},
+ {0x06, 0xfc, 0x0d},
+ {0x06, 0xfc, 0x0e},
+ {0x06, 0xfc, 0x0f},
+ {0x06, 0x11, 0x10}, /* contrast */
+ {0x06, 0x00, 0x11},
+ {0x06, 0xfe, 0x12},
+ {0x06, 0x00, 0x13},
+ {0x06, 0x00, 0x14},
+ {0x06, 0x9d, 0x51},
+ {0x06, 0x40, 0x52},
+ {0x06, 0x7c, 0x53},
+ {0x06, 0x40, 0x54},
+ {0x06, 0x02, 0x57},
+ {0x06, 0x03, 0x58},
+ {0x06, 0x15, 0x59},
+ {0x06, 0x05, 0x5a},
+ {0x06, 0x03, 0x56},
+ {0x06, 0x02, 0x3f},
+ {0x06, 0x00, 0x40},
+ {0x06, 0x39, 0x41},
+ {0x06, 0x69, 0x42},
+ {0x06, 0x87, 0x43},
+ {0x06, 0x9e, 0x44},
+ {0x06, 0xb1, 0x45},
+ {0x06, 0xbf, 0x46},
+ {0x06, 0xcc, 0x47},
+ {0x06, 0xd5, 0x48},
+ {0x06, 0xdd, 0x49},
+ {0x06, 0xe3, 0x4a},
+ {0x06, 0xe8, 0x4b},
+ {0x06, 0xed, 0x4c},
+ {0x06, 0xf2, 0x4d},
+ {0x06, 0xf7, 0x4e},
+ {0x06, 0xfc, 0x4f},
+ {0x06, 0xff, 0x50},
+
+ {0x05, 0x01, 0xc0},
+ {0x05, 0x10, 0xcb},
+ {0x05, 0x40, 0xc1},
+ {0x05, 0x04, 0xc2},
+ {0x05, 0x00, 0xca},
+ {0x05, 0x40, 0xc1},
+ {0x05, 0x09, 0xc2},
+ {0x05, 0x00, 0xca},
+ {0x05, 0xc0, 0xc1},
+ {0x05, 0x09, 0xc2},
+ {0x05, 0x00, 0xca},
+ {0x05, 0x40, 0xc1},
+ {0x05, 0x59, 0xc2},
+ {0x05, 0x00, 0xca},
+ {0x04, 0x00, 0x01},
+ {0x05, 0x80, 0xc1},
+ {0x05, 0xec, 0xc2},
+ {0x05, 0x0, 0xca},
+
+ {0x06, 0x02, 0x57},
+ {0x06, 0x01, 0x58},
+ {0x06, 0x15, 0x59},
+ {0x06, 0x0a, 0x5a},
+ {0x06, 0x01, 0x57},
+ {0x06, 0x8a, 0x03},
+ {0x06, 0x0a, 0x6c},
+ {0x06, 0x30, 0x01},
+ {0x06, 0x20, 0x02},
+ {0x06, 0x00, 0x03},
+
+ {0x05, 0x8c, 0x25},
+
+ {0x06, 0x4d, 0x51}, /* maybe saturation (4d) */
+ {0x06, 0x84, 0x53}, /* making green (84) */
+ {0x06, 0x00, 0x57}, /* sharpness (1) */
+ {0x06, 0x18, 0x08},
+ {0x06, 0xfc, 0x09},
+ {0x06, 0xfc, 0x0a},
+ {0x06, 0xfc, 0x0b},
+ {0x06, 0x18, 0x0c}, /* maybe hue (18) */
+ {0x06, 0xfc, 0x0d},
+ {0x06, 0xfc, 0x0e},
+ {0x06, 0xfc, 0x0f},
+ {0x06, 0x18, 0x10}, /* maybe contrast (18) */
+
+ {0x05, 0x01, 0x02},
+
+ {0x04, 0x00, 0x08}, /* compression */
+ {0x04, 0x12, 0x09},
+ {0x04, 0x21, 0x0a},
+ {0x04, 0x10, 0x0b},
+ {0x04, 0x21, 0x0c},
+ {0x04, 0x1d, 0x00}, /* imagetype (1d) */
+ {0x04, 0x41, 0x01}, /* hardware snapcontrol */
+
+ {0x04, 0x00, 0x04},
+ {0x04, 0x00, 0x05},
+ {0x04, 0x10, 0x06},
+ {0x04, 0x10, 0x07},
+ {0x04, 0x40, 0x06},
+ {0x04, 0x40, 0x07},
+ {0x04, 0x00, 0x04},
+ {0x04, 0x00, 0x05},
+
+ {0x06, 0x1c, 0x17},
+ {0x06, 0xe2, 0x19},
+ {0x06, 0x1c, 0x1b},
+ {0x06, 0xe2, 0x1d},
+ {0x06, 0x5f, 0x1f},
+ {0x06, 0x32, 0x20},
+
+ {0x05, initial_brightness >> 6, 0x00},
+ {0x05, initial_brightness << 2, 0x01},
+ {0x05, 0x06, 0xc1},
+ {0x05, 0x58, 0xc2},
+ {0x05, 0x0, 0xca},
+ {0x05, 0x0, 0x11},
+ {}
+};
+
+static int reg_write(struct usb_device *dev,
+ __u16 reg, __u16 index, __u16 value)
+{
+ int ret;
+
+ ret = usb_control_msg(dev,
+ usb_sndctrlpipe(dev, 0),
+ reg,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value, index, NULL, 0, 500);
+ PDEBUG(D_PACK, "reg write: 0x%02x,0x%02x:0x%02x, 0x%x",
+ reg, index, value, ret);
+ if (ret < 0)
+ PDEBUG(D_ERR, "reg write: error %d", ret);
+ return ret;
+}
+
+/* returns: negative is error, pos or zero is data */
+static int reg_read(struct usb_device *dev,
+ __u16 reg, /* bRequest */
+ __u16 index, /* wIndex */
+ __u16 length) /* wLength (1 or 2 only) */
+{
+ int ret;
+ __u8 buf[4];
+
+ buf[1] = 0;
+ ret = usb_control_msg(dev,
+ usb_rcvctrlpipe(dev, 0),
+ reg,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ (__u16) 0, /* value */
+ (__u16) index,
+ buf,
+ length,
+ 500); /* timeout */
+ if (ret < 0) {
+ PDEBUG(D_ERR, "reg_read err %d", ret);
+ return -1;
+ }
+ return (buf[1] << 8) + buf[0];
+}
+
+static int write_vector(struct gspca_dev *gspca_dev,
+ const __u16 data[][3])
+{
+ struct usb_device *dev = gspca_dev->dev;
+ int ret, i = 0;
+
+ while (data[i][0] != 0 || data[i][1] != 0 || data[i][2] != 0) {
+ ret = reg_write(dev, data[i][0], data[i][2], data[i][1]);
+ if (ret < 0) {
+ PDEBUG(D_ERR,
+ "Register write failed for 0x%x,0x%x,0x%x",
+ data[i][0], data[i][1], data[i][2]);
+ return ret;
+ }
+ i++;
+ }
+ return 0;
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+ const struct usb_device_id *id)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct cam *cam;
+ __u16 vendor;
+ __u16 product;
+
+ vendor = id->idVendor;
+ product = id->idProduct;
+ switch (vendor) {
+ case 0x041e: /* Creative cameras */
+/* switch (product) { */
+/* case 0x401d: * here505b */
+ sd->subtype = Nxultra;
+/* break; */
+/* } */
+ break;
+ case 0x0733: /* Rebadged ViewQuest (Intel) and ViewQuest cameras */
+/* switch (product) { */
+/* case 0x0430: */
+/* fixme: may be UsbGrabberPV321 BRIDGE_SPCA506 SENSOR_SAA7113 */
+ sd->subtype = IntelPCCameraPro;
+/* break; */
+/* } */
+ break;
+ }
+
+ cam = &gspca_dev->cam;
+ cam->dev_name = (char *) id->driver_info;
+ cam->epaddr = 0x01;
+ cam->cam_mode = vga_mode;
+ if (sd->subtype != IntelPCCameraPro)
+ cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+ else /* no 640x480 for IntelPCCameraPro */
+ cam->nmodes = sizeof vga_mode / sizeof vga_mode[0] - 1;
+ sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
+
+ if (sd->subtype == Nxultra) {
+ if (write_vector(gspca_dev, spca505b_init_data))
+ return -EIO;
+ } else {
+ if (write_vector(gspca_dev, spca505_init_data))
+ return -EIO;
+ }
+ return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int ret;
+
+ PDEBUG(D_STREAM, "Initializing SPCA505");
+ if (sd->subtype == Nxultra)
+ write_vector(gspca_dev, spca505b_open_data_ccd);
+ else
+ write_vector(gspca_dev, spca505_open_data_ccd);
+ ret = reg_read(gspca_dev->dev, 6, 0x16, 2);
+
+ if (ret < 0) {
+ PDEBUG(D_ERR|D_STREAM,
+ "register read failed for after vector read err = %d",
+ ret);
+ return -EIO;
+ }
+ PDEBUG(D_STREAM,
+ "After vector read returns : 0x%x should be 0x0101",
+ ret & 0xffff);
+
+ ret = reg_write(gspca_dev->dev, 6, 0x16, 0x0a);
+ if (ret < 0) {
+ PDEBUG(D_ERR, "register write failed for (6,0xa,0x16) err=%d",
+ ret);
+ return -EIO;
+ }
+ reg_write(gspca_dev->dev, 5, 0xc2, 18);
+ return 0;
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+ struct usb_device *dev = gspca_dev->dev;
+ int ret;
+
+ /* necessary because without it we can see stream
+ * only once after loading module */
+ /* stopping usb registers Tomasz change */
+ reg_write(dev, 0x02, 0x0, 0x0);
+ switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
+ case 0:
+ reg_write(dev, 0x04, 0x00, 0x00);
+ reg_write(dev, 0x04, 0x06, 0x10);
+ reg_write(dev, 0x04, 0x07, 0x10);
+ break;
+ case 1:
+ reg_write(dev, 0x04, 0x00, 0x01);
+ reg_write(dev, 0x04, 0x06, 0x1a);
+ reg_write(dev, 0x04, 0x07, 0x1a);
+ break;
+ case 2:
+ reg_write(dev, 0x04, 0x00, 0x02);
+ reg_write(dev, 0x04, 0x06, 0x1c);
+ reg_write(dev, 0x04, 0x07, 0x1d);
+ break;
+ case 4:
+ reg_write(dev, 0x04, 0x00, 0x04);
+ reg_write(dev, 0x04, 0x06, 0x34);
+ reg_write(dev, 0x04, 0x07, 0x34);
+ break;
+ default:
+/* case 5: */
+ reg_write(dev, 0x04, 0x00, 0x05);
+ reg_write(dev, 0x04, 0x06, 0x40);
+ reg_write(dev, 0x04, 0x07, 0x40);
+ break;
+ }
+/* Enable ISO packet machine - should we do this here or in ISOC init ? */
+ ret = reg_write(dev, SPCA50X_REG_USB,
+ SPCA50X_USB_CTRL,
+ SPCA50X_CUSB_ENABLE);
+
+/* reg_write(dev, 0x5, 0x0, 0x0); */
+/* reg_write(dev, 0x5, 0x0, 0x1); */
+/* reg_write(dev, 0x5, 0x11, 0x2); */
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+ /* Disable ISO packet machine */
+ reg_write(gspca_dev->dev, 0x02, 0x00, 0x00);
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+/* this function is called at close time */
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+ /* This maybe reset or power control */
+ reg_write(gspca_dev->dev, 0x03, 0x03, 0x20);
+ reg_write(gspca_dev->dev, 0x03, 0x01, 0x0);
+ reg_write(gspca_dev->dev, 0x03, 0x00, 0x1);
+ reg_write(gspca_dev->dev, 0x05, 0x10, 0x1);
+ reg_write(gspca_dev->dev, 0x05, 0x11, 0xf);
+}
+
+/* convert YYUV per line to YUYV (YUV 4:2:2) */
+static void yyuv_decode(unsigned char *out,
+ unsigned char *in,
+ int width,
+ int height)
+{
+ unsigned char *Ui, *Vi, *yi, *yi1;
+ unsigned char *out1;
+ int i, j;
+
+ yi = in;
+ for (i = height / 2; --i >= 0; ) {
+ out1 = out + width * 2; /* next line */
+ yi1 = yi + width;
+ Ui = yi1 + width;
+ Vi = Ui + width / 2;
+ for (j = width / 2; --j >= 0; ) {
+ *out++ = 128 + *yi++;
+ *out++ = 128 + *Ui;
+ *out++ = 128 + *yi++;
+ *out++ = 128 + *Vi;
+
+ *out1++ = 128 + *yi1++;
+ *out1++ = 128 + *Ui++;
+ *out1++ = 128 + *yi1++;
+ *out1++ = 128 + *Vi++;
+ }
+ yi += width * 2;
+ out = out1;
+ }
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ struct gspca_frame *frame, /* target */
+ __u8 *data, /* isoc packet */
+ int len) /* iso packet length */
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ switch (data[0]) {
+ case 0: /* start of frame */
+ if (gspca_dev->last_packet_type == FIRST_PACKET) {
+ yyuv_decode(sd->tmpbuf2, sd->tmpbuf,
+ gspca_dev->width,
+ gspca_dev->height);
+ frame = gspca_frame_add(gspca_dev,
+ LAST_PACKET,
+ frame,
+ sd->tmpbuf2,
+ gspca_dev->width
+ * gspca_dev->height
+ * 2);
+ }
+ gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+ data, 0);
+ data += SPCA50X_OFFSET_DATA;
+ len -= SPCA50X_OFFSET_DATA;
+ if (len > 0)
+ memcpy(sd->tmpbuf, data, len);
+ else
+ len = 0;
+ sd->buflen = len;
+ return;
+ case 0xff: /* drop */
+/* gspca_dev->last_packet_type = DISCARD_PACKET; */
+ return;
+ }
+ data += 1;
+ len -= 1;
+ memcpy(&sd->tmpbuf[sd->buflen], data, len);
+ sd->buflen += len;
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ __u8 brightness = sd->brightness;
+ reg_write(gspca_dev->dev, 5, 0x00, (255 - brightness) >> 6);
+ reg_write(gspca_dev->dev, 5, 0x01, (255 - brightness) << 2);
+
+}
+static void getbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->brightness = 255
+ - ((reg_read(gspca_dev->dev, 5, 0x01, 1) >> 2)
+ + (reg_read(gspca_dev->dev, 5, 0x0, 1) << 6));
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->brightness = val;
+ if (gspca_dev->streaming)
+ setbrightness(gspca_dev);
+ return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ getbrightness(gspca_dev);
+ *val = sd->brightness;
+ return 0;
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .ctrls = sd_ctrls,
+ .nctrls = ARRAY_SIZE(sd_ctrls),
+ .config = sd_config,
+ .open = sd_open,
+ .start = sd_start,
+ .stopN = sd_stopN,
+ .stop0 = sd_stop0,
+ .close = sd_close,
+ .pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static const __devinitdata struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x041e, 0x401d), DVNM("Creative Webcam NX ULTRA")},
+ {USB_DEVICE(0x0733, 0x0430), DVNM("Intel PC Camera Pro")},
+ {}
+};
+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,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+ if (usb_register(&sd_driver) < 0)
+ return -1;
+ PDEBUG(D_PROBE, "v%s registered", version);
+ return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+ usb_deregister(&sd_driver);
+ PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/linux/drivers/media/video/gspca/spca506.c b/linux/drivers/media/video/gspca/spca506.c
new file mode 100644
index 000000000..2d249b00b
--- /dev/null
+++ b/linux/drivers/media/video/gspca/spca506.c
@@ -0,0 +1,850 @@
+/*
+ * SPCA506 chip based cameras function
+ * M Xhaard 15/04/2004 based on different work Mark Taylor and others
+ * and my own snoopy file on a pv-321c donate by a german compagny
+ * "Firma Frank Gmbh" from Saarbruecken
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define MODULE_NAME "spca506"
+
+#include "gspca.h"
+
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 5)
+static const char version[] = "2.1.5";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("GSPCA/SPCA506 USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+
+ int buflen;
+ __u8 tmpbuf[640 * 480 * 3]; /* YYUV per line */
+ __u8 tmpbuf2[640 * 480 * 2]; /* YUYV */
+
+ unsigned char brightness;
+ unsigned char contrast;
+ unsigned char colors;
+ unsigned char hue;
+ char norme;
+ char channel;
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+#define SD_BRIGHTNESS 0
+ {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+ .maximum = 0xff,
+ .step = 1,
+ .default_value = 0x80,
+ },
+ .set = sd_setbrightness,
+ .get = sd_getbrightness,
+ },
+#define SD_CONTRAST 1
+ {
+ {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = 0,
+ .maximum = 0xff,
+ .step = 1,
+ .default_value = 0x47,
+ },
+ .set = sd_setcontrast,
+ .get = sd_getcontrast,
+ },
+#define SD_COLOR 2
+ {
+ {
+ .id = V4L2_CID_SATURATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Saturation",
+ .minimum = 0,
+ .maximum = 0xff,
+ .step = 1,
+ .default_value = 0x40,
+ },
+ .set = sd_setcolors,
+ .get = sd_getcolors,
+ },
+#define SD_HUE 3
+ {
+ {
+ .id = V4L2_CID_HUE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Hue",
+ .minimum = 0,
+ .maximum = 0xff,
+ .step = 1,
+ .default_value = 0,
+ },
+ .set = sd_sethue,
+ .get = sd_gethue,
+ },
+};
+
+static struct v4l2_pix_format vga_mode[] = {
+ {160, 120, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
+ .bytesperline = 160 * 2,
+ .sizeimage = 160 * 120 * 2,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 5},
+ {176, 144, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
+ .bytesperline = 176 * 2,
+ .sizeimage = 176 * 144 * 2,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 4},
+ {320, 240, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
+ .bytesperline = 320 * 2,
+ .sizeimage = 320 * 240 * 2,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 2},
+ {352, 288, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
+ .bytesperline = 352 * 2,
+ .sizeimage = 352 * 288 * 2,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 1},
+ {640, 480, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
+ .bytesperline = 640 * 2,
+ .sizeimage = 640 * 480 * 2,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0},
+};
+
+#define SPCA50X_OFFSET_DATA 10
+
+#define SAA7113_bright 0x0a /* defaults 0x80 */
+#define SAA7113_contrast 0x0b /* defaults 0x47 */
+#define SAA7113_saturation 0x0c /* defaults 0x40 */
+#define SAA7113_hue 0x0d /* defaults 0x00 */
+#define SAA7113_I2C_BASE_WRITE 0x4a
+
+static void reg_r(struct usb_device *dev,
+ __u16 req,
+ __u16 index,
+ __u8 *buffer, __u16 length)
+{
+ usb_control_msg(dev,
+ usb_rcvctrlpipe(dev, 0),
+ req,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, /* value */
+ index, buffer, length,
+ 500);
+}
+
+static void reg_w(struct usb_device *dev,
+ __u16 req,
+ __u16 value,
+ __u16 index)
+{
+ usb_control_msg(dev,
+ usb_sndctrlpipe(dev, 0),
+ req,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value, index,
+ NULL, 0, 500);
+}
+
+static void spca506_Initi2c(struct gspca_dev *gspca_dev)
+{
+ reg_w(gspca_dev->dev, 0x07, SAA7113_I2C_BASE_WRITE, 0x0004);
+}
+
+static void spca506_WriteI2c(struct gspca_dev *gspca_dev, __u16 valeur,
+ __u16 reg)
+{
+ int retry = 60;
+ __u8 Data[2];
+
+ reg_w(gspca_dev->dev, 0x07, reg, 0x0001);
+ reg_w(gspca_dev->dev, 0x07, valeur, 0x0000);
+ while (retry--) {
+ reg_r(gspca_dev->dev, 0x07, 0x0003, Data, 2);
+ if ((Data[0] | Data[1]) == 0x00)
+ break;
+ }
+}
+
+static int spca506_ReadI2c(struct gspca_dev *gspca_dev, __u16 reg)
+{
+ int retry = 60;
+ __u8 Data[2];
+ __u8 value;
+
+ reg_w(gspca_dev->dev, 0x07, SAA7113_I2C_BASE_WRITE, 0x0004);
+ reg_w(gspca_dev->dev, 0x07, reg, 0x0001);
+ reg_w(gspca_dev->dev, 0x07, 0x01, 0x0002);
+ while (--retry) {
+ reg_r(gspca_dev->dev, 0x07, 0x0003, Data, 2);
+ if ((Data[0] | Data[1]) == 0x00)
+ break;
+ }
+ if (retry == 0)
+ return -1;
+ reg_r(gspca_dev->dev, 0x07, 0x0000, &value, 1);
+ return value;
+}
+
+static void spca506_SetNormeInput(struct gspca_dev *gspca_dev,
+ __u16 norme,
+ __u16 channel)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+/* fixme: check if channel == 0..3 and 6..9 (8 values) */
+ __u8 setbit0 = 0x00;
+ __u8 setbit1 = 0x00;
+ __u8 videomask = 0x00;
+
+ PDEBUG(D_STREAM, "** Open Set Norme **");
+ spca506_Initi2c(gspca_dev);
+ /* NTSC bit0 -> 1(525 l) PAL SECAM bit0 -> 0 (625 l) */
+ /* Composite channel bit1 -> 1 S-video bit 1 -> 0 */
+ /* and exclude SAA7113 reserved channel set default 0 otherwise */
+ if (norme & V4L2_STD_NTSC)
+ setbit0 = 0x01;
+ if (channel == 4 || channel == 5 || channel > 9)
+ channel = 0;
+ if (channel < 4)
+ setbit1 = 0x02;
+ videomask = (0x48 | setbit0 | setbit1);
+ reg_w(gspca_dev->dev, 0x08, videomask, 0x0000);
+ spca506_WriteI2c(gspca_dev, (0xc0 | (channel & 0x0F)), 0x02);
+
+ if (norme & V4L2_STD_NTSC)
+ spca506_WriteI2c(gspca_dev, 0x33, 0x0e);
+ /* Chrominance Control NTSC N */
+ else if (norme & V4L2_STD_SECAM)
+ spca506_WriteI2c(gspca_dev, 0x53, 0x0e);
+ /* Chrominance Control SECAM */
+ else
+ spca506_WriteI2c(gspca_dev, 0x03, 0x0e);
+ /* Chrominance Control PAL BGHIV */
+
+ sd->norme = norme;
+ sd->channel = channel;
+ PDEBUG(D_STREAM, "Set Video Byte to 0x%2x", videomask);
+ PDEBUG(D_STREAM, "Set Norme: %08x Channel %d", norme, channel);
+}
+
+static void spca506_GetNormeInput(struct gspca_dev *gspca_dev,
+ __u16 *norme, __u16 *channel)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ /* Read the register is not so good value change so
+ we use your own copy in spca50x struct */
+ *norme = sd->norme;
+ *channel = sd->channel;
+ PDEBUG(D_STREAM, "Get Norme: %d Channel %d", *norme, *channel);
+}
+
+static void spca506_Setsize(struct gspca_dev *gspca_dev, __u16 code,
+ __u16 xmult, __u16 ymult)
+{
+ struct usb_device *dev = gspca_dev->dev;
+
+ PDEBUG(D_STREAM, "** SetSize **");
+ reg_w(dev, 0x04, (0x18 | (code & 0x07)), 0x0000);
+ /* Soft snap 0x40 Hard 0x41 */
+ reg_w(dev, 0x04, 0x41, 0x0001);
+ reg_w(dev, 0x04, 0x00, 0x0002);
+ /* reserved */
+ reg_w(dev, 0x04, 0x00, 0x0003);
+
+ /* reserved */
+ reg_w(dev, 0x04, 0x00, 0x0004);
+ /* reserved */
+ reg_w(dev, 0x04, 0x01, 0x0005);
+ /* reserced */
+ reg_w(dev, 0x04, xmult, 0x0006);
+ /* reserved */
+ reg_w(dev, 0x04, ymult, 0x0007);
+ /* compression 1 */
+ reg_w(dev, 0x04, 0x00, 0x0008);
+ /* T=64 -> 2 */
+ reg_w(dev, 0x04, 0x00, 0x0009);
+ /* threshold2D */
+ reg_w(dev, 0x04, 0x21, 0x000a);
+ /* quantization */
+ reg_w(dev, 0x04, 0x00, 0x000b);
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+ const struct usb_device_id *id)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct cam *cam;
+
+ cam = &gspca_dev->cam;
+ cam->dev_name = (char *) id->driver_info;
+ cam->epaddr = 0x01;
+ cam->cam_mode = vga_mode;
+ cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+ sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
+ sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
+ sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value;
+ sd->hue = sd_ctrls[SD_HUE].qctrl.default_value;
+ return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+ struct usb_device *dev = gspca_dev->dev;
+
+ reg_w(dev, 0x03, 0x00, 0x0004);
+ reg_w(dev, 0x03, 0xFF, 0x0003);
+ reg_w(dev, 0x03, 0x00, 0x0000);
+ reg_w(dev, 0x03, 0x1c, 0x0001);
+ reg_w(dev, 0x03, 0x18, 0x0001);
+ /* Init on PAL and composite input0 */
+ spca506_SetNormeInput(gspca_dev, 0, 0);
+ reg_w(dev, 0x03, 0x1c, 0x0001);
+ reg_w(dev, 0x03, 0x18, 0x0001);
+ reg_w(dev, 0x05, 0x00, 0x0000);
+ reg_w(dev, 0x05, 0xef, 0x0001);
+ reg_w(dev, 0x05, 0x00, 0x00c1);
+ reg_w(dev, 0x05, 0x00, 0x00c2);
+ reg_w(dev, 0x06, 0x18, 0x0002);
+ reg_w(dev, 0x06, 0xf5, 0x0011);
+ reg_w(dev, 0x06, 0x02, 0x0012);
+ reg_w(dev, 0x06, 0xfb, 0x0013);
+ reg_w(dev, 0x06, 0x00, 0x0014);
+ reg_w(dev, 0x06, 0xa4, 0x0051);
+ reg_w(dev, 0x06, 0x40, 0x0052);
+ reg_w(dev, 0x06, 0x71, 0x0053);
+ reg_w(dev, 0x06, 0x40, 0x0054);
+ /************************************************/
+ reg_w(dev, 0x03, 0x00, 0x0004);
+ reg_w(dev, 0x03, 0x00, 0x0003);
+ reg_w(dev, 0x03, 0x00, 0x0004);
+ reg_w(dev, 0x03, 0xFF, 0x0003);
+ reg_w(dev, 0x02, 0x00, 0x0000);
+ reg_w(dev, 0x03, 0x60, 0x0000);
+ reg_w(dev, 0x03, 0x18, 0x0001);
+ /* for a better reading mx :) */
+ /*sdca506_WriteI2c(value,register) */
+ spca506_Initi2c(gspca_dev);
+ spca506_WriteI2c(gspca_dev, 0x08, 0x01);
+ spca506_WriteI2c(gspca_dev, 0xc0, 0x02);
+ /* input composite video */
+ spca506_WriteI2c(gspca_dev, 0x33, 0x03);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x04);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x05);
+ spca506_WriteI2c(gspca_dev, 0x0d, 0x06);
+ spca506_WriteI2c(gspca_dev, 0xf0, 0x07);
+ spca506_WriteI2c(gspca_dev, 0x98, 0x08);
+ spca506_WriteI2c(gspca_dev, 0x03, 0x09);
+ spca506_WriteI2c(gspca_dev, 0x80, 0x0a);
+ spca506_WriteI2c(gspca_dev, 0x47, 0x0b);
+ spca506_WriteI2c(gspca_dev, 0x48, 0x0c);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x0d);
+ spca506_WriteI2c(gspca_dev, 0x03, 0x0e); /* Chroma Pal adjust */
+ spca506_WriteI2c(gspca_dev, 0x2a, 0x0f);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x10);
+ spca506_WriteI2c(gspca_dev, 0x0c, 0x11);
+ spca506_WriteI2c(gspca_dev, 0xb8, 0x12);
+ spca506_WriteI2c(gspca_dev, 0x01, 0x13);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x14);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x15);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x16);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x17);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x18);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x19);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x1a);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x1b);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x1c);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x1d);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x1e);
+ spca506_WriteI2c(gspca_dev, 0xa1, 0x1f);
+ spca506_WriteI2c(gspca_dev, 0x02, 0x40);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x41);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x42);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x43);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x44);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x45);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x46);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x47);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x48);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x49);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x4a);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x4b);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x4c);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x4d);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x4e);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x4f);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x50);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x51);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x52);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x53);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x54);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x55);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x56);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x57);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x58);
+ spca506_WriteI2c(gspca_dev, 0x54, 0x59);
+ spca506_WriteI2c(gspca_dev, 0x07, 0x5a);
+ spca506_WriteI2c(gspca_dev, 0x83, 0x5b);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x5c);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x5d);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x5e);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x5f);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x60);
+ spca506_WriteI2c(gspca_dev, 0x05, 0x61);
+ spca506_WriteI2c(gspca_dev, 0x9f, 0x62);
+ PDEBUG(D_STREAM, "** Close Init *");
+ return 0;
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+ struct usb_device *dev = gspca_dev->dev;
+ __u16 norme;
+ __u16 channel;
+ __u8 Data[2];
+
+ /**************************************/
+ reg_w(dev, 0x03, 0x00, 0x0004);
+ reg_w(dev, 0x03, 0x00, 0x0003);
+ reg_w(dev, 0x03, 0x00, 0x0004);
+ reg_w(dev, 0x03, 0xFF, 0x0003);
+ reg_w(dev, 0x02, 0x00, 0x0000);
+ reg_w(dev, 0x03, 0x60, 0x0000);
+ reg_w(dev, 0x03, 0x18, 0x0001);
+
+ /*sdca506_WriteI2c(value,register) */
+ spca506_Initi2c(gspca_dev);
+ spca506_WriteI2c(gspca_dev, 0x08, 0x01); /* Increment Delay */
+/* spca506_WriteI2c(gspca_dev, 0xc0, 0x02); * Analog Input Control 1 */
+ spca506_WriteI2c(gspca_dev, 0x33, 0x03);
+ /* Analog Input Control 2 */
+ spca506_WriteI2c(gspca_dev, 0x00, 0x04);
+ /* Analog Input Control 3 */
+ spca506_WriteI2c(gspca_dev, 0x00, 0x05);
+ /* Analog Input Control 4 */
+ spca506_WriteI2c(gspca_dev, 0x0d, 0x06);
+ /* Horizontal Sync Start 0xe9-0x0d */
+ spca506_WriteI2c(gspca_dev, 0xf0, 0x07);
+ /* Horizontal Sync Stop 0x0d-0xf0 */
+
+ spca506_WriteI2c(gspca_dev, 0x98, 0x08); /* Sync Control */
+/* Defaults value */
+ spca506_WriteI2c(gspca_dev, 0x03, 0x09); /* Luminance Control */
+ spca506_WriteI2c(gspca_dev, 0x80, 0x0a);
+ /* Luminance Brightness */
+ spca506_WriteI2c(gspca_dev, 0x47, 0x0b); /* Luminance Contrast */
+ spca506_WriteI2c(gspca_dev, 0x48, 0x0c);
+ /* Chrominance Saturation */
+ spca506_WriteI2c(gspca_dev, 0x00, 0x0d);
+ /* Chrominance Hue Control */
+ spca506_WriteI2c(gspca_dev, 0x2a, 0x0f);
+ /* Chrominance Gain Control */
+ /**************************************/
+ spca506_WriteI2c(gspca_dev, 0x00, 0x10);
+ /* Format/Delay Control */
+ spca506_WriteI2c(gspca_dev, 0x0c, 0x11); /* Output Control 1 */
+ spca506_WriteI2c(gspca_dev, 0xb8, 0x12); /* Output Control 2 */
+ spca506_WriteI2c(gspca_dev, 0x01, 0x13); /* Output Control 3 */
+ spca506_WriteI2c(gspca_dev, 0x00, 0x14); /* reserved */
+ spca506_WriteI2c(gspca_dev, 0x00, 0x15); /* VGATE START */
+ spca506_WriteI2c(gspca_dev, 0x00, 0x16); /* VGATE STOP */
+ spca506_WriteI2c(gspca_dev, 0x00, 0x17); /* VGATE Control (MSB) */
+ spca506_WriteI2c(gspca_dev, 0x00, 0x18);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x19);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x1a);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x1b);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x1c);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x1d);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x1e);
+ spca506_WriteI2c(gspca_dev, 0xa1, 0x1f);
+ spca506_WriteI2c(gspca_dev, 0x02, 0x40);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x41);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x42);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x43);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x44);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x45);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x46);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x47);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x48);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x49);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x4a);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x4b);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x4c);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x4d);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x4e);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x4f);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x50);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x51);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x52);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x53);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x54);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x55);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x56);
+ spca506_WriteI2c(gspca_dev, 0xff, 0x57);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x58);
+ spca506_WriteI2c(gspca_dev, 0x54, 0x59);
+ spca506_WriteI2c(gspca_dev, 0x07, 0x5a);
+ spca506_WriteI2c(gspca_dev, 0x83, 0x5b);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x5c);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x5d);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x5e);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x5f);
+ spca506_WriteI2c(gspca_dev, 0x00, 0x60);
+ spca506_WriteI2c(gspca_dev, 0x05, 0x61);
+ spca506_WriteI2c(gspca_dev, 0x9f, 0x62);
+ /**************************************/
+ reg_w(dev, 0x05, 0x00, 0x0003);
+ reg_w(dev, 0x05, 0x00, 0x0004);
+ reg_w(dev, 0x03, 0x10, 0x0001);
+ reg_w(dev, 0x03, 0x78, 0x0000);
+ switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
+ case 0:
+ spca506_Setsize(gspca_dev, 0, 0x10, 0x10);
+ break;
+ case 1:
+ spca506_Setsize(gspca_dev, 1, 0x1a, 0x1a);
+ break;
+ case 2:
+ spca506_Setsize(gspca_dev, 2, 0x1c, 0x1c);
+ break;
+ case 4:
+ spca506_Setsize(gspca_dev, 4, 0x34, 0x34);
+ break;
+ default:
+/* case 5: */
+ spca506_Setsize(gspca_dev, 5, 0x40, 0x40);
+ break;
+ }
+
+ /* compress setting and size */
+ /* set i2c luma */
+ reg_w(dev, 0x02, 0x01, 0x0000);
+ reg_w(dev, 0x03, 0x12, 0x000);
+ reg_r(dev, 0x04, 0x0001, Data, 2);
+ PDEBUG(D_STREAM, "webcam started");
+ spca506_GetNormeInput(gspca_dev, &norme, &channel);
+ spca506_SetNormeInput(gspca_dev, norme, channel);
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+ struct usb_device *dev = gspca_dev->dev;
+
+ reg_w(dev, 0x02, 0x00, 0x0000);
+ reg_w(dev, 0x03, 0x00, 0x0004);
+ reg_w(dev, 0x03, 0x00, 0x0003);
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+/* convert YYUV per line to YUYV (YUV 4:2:2) */
+static void yyuv_decode(unsigned char *out,
+ unsigned char *in,
+ int width,
+ int height)
+{
+ unsigned char *Ui, *Vi, *yi, *yi1;
+ unsigned char *out1;
+ int i, j;
+
+ yi = in;
+ for (i = height / 2; --i >= 0; ) {
+ out1 = out + width * 2; /* next line */
+ yi1 = yi + width;
+ Ui = yi1 + width;
+ Vi = Ui + width / 2;
+ for (j = width / 2; --j >= 0; ) {
+ *out++ = 128 + *yi++;
+ *out++ = 128 + *Ui;
+ *out++ = 128 + *yi++;
+ *out++ = 128 + *Vi;
+
+ *out1++ = 128 + *yi1++;
+ *out1++ = 128 + *Ui++;
+ *out1++ = 128 + *yi1++;
+ *out1++ = 128 + *Vi++;
+ }
+ yi += width * 2;
+ out = out1;
+ }
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ struct gspca_frame *frame, /* target */
+ __u8 *data, /* isoc packet */
+ int len) /* iso packet length */
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ switch (data[0]) {
+ case 0: /* start of frame */
+ if (gspca_dev->last_packet_type == FIRST_PACKET) {
+ yyuv_decode(sd->tmpbuf2, sd->tmpbuf,
+ gspca_dev->width,
+ gspca_dev->height);
+ frame = gspca_frame_add(gspca_dev,
+ LAST_PACKET,
+ frame,
+ sd->tmpbuf2,
+ gspca_dev->width
+ * gspca_dev->height
+ * 2);
+ }
+ gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+ data, 0);
+ data += SPCA50X_OFFSET_DATA;
+ len -= SPCA50X_OFFSET_DATA;
+ if (len > 0)
+ memcpy(sd->tmpbuf, data, len);
+ else
+ len = 0;
+ sd->buflen = len;
+ return;
+ case 0xff: /* drop */
+/* gspca_dev->last_packet_type = DISCARD_PACKET; */
+ return;
+ }
+ data += 1;
+ len -= 1;
+ memcpy(&sd->tmpbuf[sd->buflen], data, len);
+ sd->buflen += len;
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ spca506_Initi2c(gspca_dev);
+ spca506_WriteI2c(gspca_dev, sd->brightness, SAA7113_bright);
+ spca506_WriteI2c(gspca_dev, 0x01, 0x09);
+}
+
+static void getbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->brightness = spca506_ReadI2c(gspca_dev, SAA7113_bright);
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ spca506_Initi2c(gspca_dev);
+ spca506_WriteI2c(gspca_dev, sd->contrast, SAA7113_contrast);
+ spca506_WriteI2c(gspca_dev, 0x01, 0x09);
+}
+
+static void getcontrast(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->contrast = spca506_ReadI2c(gspca_dev, SAA7113_contrast);
+}
+
+static void setcolors(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ spca506_Initi2c(gspca_dev);
+ spca506_WriteI2c(gspca_dev, sd->colors, SAA7113_saturation);
+ spca506_WriteI2c(gspca_dev, 0x01, 0x09);
+}
+
+static void getcolors(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->colors = spca506_ReadI2c(gspca_dev, SAA7113_saturation);
+}
+
+static void sethue(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ spca506_Initi2c(gspca_dev);
+ spca506_WriteI2c(gspca_dev, sd->hue, SAA7113_hue);
+ spca506_WriteI2c(gspca_dev, 0x01, 0x09);
+}
+
+static void gethue(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->hue = spca506_ReadI2c(gspca_dev, SAA7113_hue);
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->brightness = val;
+ if (gspca_dev->streaming)
+ setbrightness(gspca_dev);
+ return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ getbrightness(gspca_dev);
+ *val = sd->brightness;
+ return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->contrast = val;
+ if (gspca_dev->streaming)
+ setcontrast(gspca_dev);
+ return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ getcontrast(gspca_dev);
+ *val = sd->contrast;
+ return 0;
+}
+
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->colors = val;
+ if (gspca_dev->streaming)
+ setcolors(gspca_dev);
+ return 0;
+}
+
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ getcolors(gspca_dev);
+ *val = sd->colors;
+ return 0;
+}
+
+static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->hue = val;
+ if (gspca_dev->streaming)
+ sethue(gspca_dev);
+ return 0;
+}
+
+static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ gethue(gspca_dev);
+ *val = sd->hue;
+ return 0;
+}
+
+/* sub-driver description */
+static struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .ctrls = sd_ctrls,
+ .nctrls = ARRAY_SIZE(sd_ctrls),
+ .config = sd_config,
+ .open = sd_open,
+ .start = sd_start,
+ .stopN = sd_stopN,
+ .stop0 = sd_stop0,
+ .close = sd_close,
+ .pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static __devinitdata struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x06e1, 0xa190), DVNM("ADS Instant VCD")},
+/* {USB_DEVICE(0x0733, 0x0430), DVNM("UsbGrabber PV321c")}, */
+ {USB_DEVICE(0x0734, 0x043b), DVNM("3DeMon USB Capture aka")},
+ {USB_DEVICE(0x99fa, 0x8988), DVNM("Grandtec V.cap")},
+ {}
+};
+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,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+ if (usb_register(&sd_driver) < 0)
+ return -1;
+ PDEBUG(D_PROBE, "v%s registered", version);
+ return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+ usb_deregister(&sd_driver);
+ PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/linux/drivers/media/video/gspca/spca508.c b/linux/drivers/media/video/gspca/spca508.c
new file mode 100644
index 000000000..a70d51117
--- /dev/null
+++ b/linux/drivers/media/video/gspca/spca508.c
@@ -0,0 +1,1832 @@
+/*
+ * SPCA508 chip based cameras subdriver
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define MODULE_NAME "spca508"
+
+#include "gspca.h"
+
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 5)
+static const char version[] = "2.1.5";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("GSPCA/SPCA508 USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+
+ int buflen;
+ unsigned char tmpbuf[352 * 288 * 3 / 2]; /* YUVY per line */
+ unsigned char tmpbuf2[352 * 288 * 2]; /* YUYV */
+
+ unsigned char brightness;
+
+ char subtype;
+#define CreativeVista 0
+#define HamaUSBSightcam 1
+#define HamaUSBSightcam2 2
+#define IntelEasyPCCamera 3
+#define MicroInnovationIC200 4
+#define ViewQuestVQ110 5
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+ {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+#define BRIGHTNESS_DEF 128
+ .default_value = BRIGHTNESS_DEF,
+ },
+ .set = sd_setbrightness,
+ .get = sd_getbrightness,
+ },
+};
+
+static struct v4l2_pix_format sif_mode[] = {
+ {160, 120, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
+ .bytesperline = 160 * 2,
+ .sizeimage = 160 * 120 * 2,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 3},
+ {176, 144, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
+ .bytesperline = 176 * 2,
+ .sizeimage = 176 * 144 * 2,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 2},
+ {320, 240, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
+ .bytesperline = 320 * 2,
+ .sizeimage = 320 * 240 * 2,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 1},
+ {352, 288, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
+ .bytesperline = 352 * 2,
+ .sizeimage = 352 * 288 * 2,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0},
+};
+
+/* Frame packet header offsets for the spca508 */
+#define SPCA508_OFFSET_TYPE 1
+#define SPCA508_OFFSET_COMPRESS 2
+#define SPCA508_OFFSET_FRAMSEQ 8
+#define SPCA508_OFFSET_WIN1LUM 11
+#define SPCA508_OFFSET_DATA 37
+
+#define SPCA508_SNAPBIT 0x20
+#define SPCA508_SNAPCTRL 0x40
+/*************** I2c ****************/
+#define SPCA508_INDEX_I2C_BASE 0x8800
+
+/*
+ * Initialization data: this is the first set-up data written to the
+ * device (before the open data).
+ */
+static const __u16 spca508_init_data[][3] =
+#define IGN(x) /* nothing */
+{
+ /* line URB value, index */
+ /* 44274 1804 */ {0x0000, 0x870b},
+
+ /* 44299 1805 */ {0x0020, 0x8112},
+ /* Video drop enable, ISO streaming disable */
+ /* 44324 1806 */ {0x0003, 0x8111},
+ /* Reset compression & memory */
+ /* 44349 1807 */ {0x0000, 0x8110},
+ /* Disable all outputs */
+ /* 44372 1808 */ /* READ {0x0000, 0x8114} -> 0000: 00 */
+ /* 44398 1809 */ {0x0000, 0x8114},
+ /* SW GPIO data */
+ /* 44423 1810 */ {0x0008, 0x8110},
+ /* Enable charge pump output */
+ /* 44527 1811 */ {0x0002, 0x8116},
+ /* 200 kHz pump clock */
+ /* 44555 1812 */
+ /* UNKNOWN DIRECTION (URB_FUNCTION_SELECT_INTERFACE:) */
+ /* 44590 1813 */ {0x0003, 0x8111},
+ /* Reset compression & memory */
+ /* 44615 1814 */ {0x0000, 0x8111},
+ /* Normal mode (not reset) */
+ /* 44640 1815 */ {0x0098, 0x8110},
+ /* Enable charge pump output, sync.serial,external 2x clock */
+ /* 44665 1816 */ {0x000d, 0x8114},
+ /* SW GPIO data */
+ /* 44690 1817 */ {0x0002, 0x8116},
+ /* 200 kHz pump clock */
+ /* 44715 1818 */ {0x0020, 0x8112},
+ /* Video drop enable, ISO streaming disable */
+/* --------------------------------------- */
+ /* 44740 1819 */ {0x000f, 0x8402},
+ /* memory bank */
+ /* 44765 1820 */ {0x0000, 0x8403},
+ /* ... address */
+/* --------------------------------------- */
+/* 0x88__ is Synchronous Serial Interface. */
+/* TBD: This table could be expressed more compactly */
+/* using spca508_write_i2c_vector(). */
+/* TBD: Should see if the values in spca50x_i2c_data */
+/* would work with the VQ110 instead of the values */
+/* below. */
+ /* 44790 1821 */ {0x00c0, 0x8804},
+ /* SSI slave addr */
+ /* 44815 1822 */ {0x0008, 0x8802},
+ /* 375 Khz SSI clock */
+ /* 44838 1823 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 44862 1824 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 44888 1825 */ {0x0008, 0x8802},
+ /* 375 Khz SSI clock */
+ /* 44913 1826 */ {0x0012, 0x8801},
+ /* SSI reg addr */
+ /* 44938 1827 */ {0x0080, 0x8800},
+ /* SSI data to write */
+ /* 44961 1828 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 44985 1829 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 45009 1830 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 45035 1831 */ {0x0008, 0x8802},
+ /* 375 Khz SSI clock */
+ /* 45060 1832 */ {0x0012, 0x8801},
+ /* SSI reg addr */
+ /* 45085 1833 */ {0x0000, 0x8800},
+ /* SSI data to write */
+ /* 45108 1834 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 45132 1835 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 45156 1836 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 45182 1837 */ {0x0008, 0x8802},
+ /* 375 Khz SSI clock */
+ /* 45207 1838 */ {0x0011, 0x8801},
+ /* SSI reg addr */
+ /* 45232 1839 */ {0x0040, 0x8800},
+ /* SSI data to write */
+ /* 45255 1840 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 45279 1841 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 45303 1842 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 45329 1843 */ {0x0008, 0x8802},
+ /* 45354 1844 */ {0x0013, 0x8801},
+ /* 45379 1845 */ {0x0000, 0x8800},
+ /* 45402 1846 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 45426 1847 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 45450 1848 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 45476 1849 */ {0x0008, 0x8802},
+ /* 45501 1850 */ {0x0014, 0x8801},
+ /* 45526 1851 */ {0x0000, 0x8800},
+ /* 45549 1852 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 45573 1853 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 45597 1854 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 45623 1855 */ {0x0008, 0x8802},
+ /* 45648 1856 */ {0x0015, 0x8801},
+ /* 45673 1857 */ {0x0001, 0x8800},
+ /* 45696 1858 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 45720 1859 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 45744 1860 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 45770 1861 */ {0x0008, 0x8802},
+ /* 45795 1862 */ {0x0016, 0x8801},
+ /* 45820 1863 */ {0x0003, 0x8800},
+ /* 45843 1864 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 45867 1865 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 45891 1866 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 45917 1867 */ {0x0008, 0x8802},
+ /* 45942 1868 */ {0x0017, 0x8801},
+ /* 45967 1869 */ {0x0036, 0x8800},
+ /* 45990 1870 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 46014 1871 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 46038 1872 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 46064 1873 */ {0x0008, 0x8802},
+ /* 46089 1874 */ {0x0018, 0x8801},
+ /* 46114 1875 */ {0x00ec, 0x8800},
+ /* 46137 1876 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 46161 1877 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 46185 1878 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 46211 1879 */ {0x0008, 0x8802},
+ /* 46236 1880 */ {0x001a, 0x8801},
+ /* 46261 1881 */ {0x0094, 0x8800},
+ /* 46284 1882 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 46308 1883 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 46332 1884 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 46358 1885 */ {0x0008, 0x8802},
+ /* 46383 1886 */ {0x001b, 0x8801},
+ /* 46408 1887 */ {0x0000, 0x8800},
+ /* 46431 1888 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 46455 1889 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 46479 1890 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 46505 1891 */ {0x0008, 0x8802},
+ /* 46530 1892 */ {0x0027, 0x8801},
+ /* 46555 1893 */ {0x00a2, 0x8800},
+ /* 46578 1894 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 46602 1895 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 46626 1896 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 46652 1897 */ {0x0008, 0x8802},
+ /* 46677 1898 */ {0x0028, 0x8801},
+ /* 46702 1899 */ {0x0040, 0x8800},
+ /* 46725 1900 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 46749 1901 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 46773 1902 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 46799 1903 */ {0x0008, 0x8802},
+ /* 46824 1904 */ {0x002a, 0x8801},
+ /* 46849 1905 */ {0x0084, 0x8800},
+ /* 46872 1906 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 46896 1907 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 46920 1908 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 46946 1909 */ {0x0008, 0x8802},
+ /* 46971 1910 */ {0x002b, 0x8801},
+ /* 46996 1911 */ {0x00a8, 0x8800},
+ /* 47019 1912 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 47043 1913 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 47067 1914 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 47093 1915 */ {0x0008, 0x8802},
+ /* 47118 1916 */ {0x002c, 0x8801},
+ /* 47143 1917 */ {0x00fe, 0x8800},
+ /* 47166 1918 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 47190 1919 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 47214 1920 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 47240 1921 */ {0x0008, 0x8802},
+ /* 47265 1922 */ {0x002d, 0x8801},
+ /* 47290 1923 */ {0x0003, 0x8800},
+ /* 47313 1924 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 47337 1925 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 47361 1926 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 47387 1927 */ {0x0008, 0x8802},
+ /* 47412 1928 */ {0x0038, 0x8801},
+ /* 47437 1929 */ {0x0083, 0x8800},
+ /* 47460 1930 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 47484 1931 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 47508 1932 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 47534 1933 */ {0x0008, 0x8802},
+ /* 47559 1934 */ {0x0033, 0x8801},
+ /* 47584 1935 */ {0x0081, 0x8800},
+ /* 47607 1936 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 47631 1937 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 47655 1938 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 47681 1939 */ {0x0008, 0x8802},
+ /* 47706 1940 */ {0x0034, 0x8801},
+ /* 47731 1941 */ {0x004a, 0x8800},
+ /* 47754 1942 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 47778 1943 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 47802 1944 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 47828 1945 */ {0x0008, 0x8802},
+ /* 47853 1946 */ {0x0039, 0x8801},
+ /* 47878 1947 */ {0x0000, 0x8800},
+ /* 47901 1948 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 47925 1949 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 47949 1950 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 47975 1951 */ {0x0008, 0x8802},
+ /* 48000 1952 */ {0x0010, 0x8801},
+ /* 48025 1953 */ {0x00a8, 0x8800},
+ /* 48048 1954 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 48072 1955 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 48096 1956 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 48122 1957 */ {0x0008, 0x8802},
+ /* 48147 1958 */ {0x0006, 0x8801},
+ /* 48172 1959 */ {0x0058, 0x8800},
+ /* 48195 1960 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 48219 1961 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 48243 1962 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 48269 1963 */ {0x0008, 0x8802},
+ /* 48294 1964 */ {0x0000, 0x8801},
+ /* 48319 1965 */ {0x0004, 0x8800},
+ /* 48342 1966 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 48366 1967 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 48390 1968 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 48416 1969 */ {0x0008, 0x8802},
+ /* 48441 1970 */ {0x0040, 0x8801},
+ /* 48466 1971 */ {0x0080, 0x8800},
+ /* 48489 1972 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 48513 1973 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 48537 1974 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 48563 1975 */ {0x0008, 0x8802},
+ /* 48588 1976 */ {0x0041, 0x8801},
+ /* 48613 1977 */ {0x000c, 0x8800},
+ /* 48636 1978 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 48660 1979 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 48684 1980 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 48710 1981 */ {0x0008, 0x8802},
+ /* 48735 1982 */ {0x0042, 0x8801},
+ /* 48760 1983 */ {0x000c, 0x8800},
+ /* 48783 1984 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 48807 1985 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 48831 1986 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 48857 1987 */ {0x0008, 0x8802},
+ /* 48882 1988 */ {0x0043, 0x8801},
+ /* 48907 1989 */ {0x0028, 0x8800},
+ /* 48930 1990 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 48954 1991 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 48978 1992 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 49004 1993 */ {0x0008, 0x8802},
+ /* 49029 1994 */ {0x0044, 0x8801},
+ /* 49054 1995 */ {0x0080, 0x8800},
+ /* 49077 1996 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 49101 1997 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 49125 1998 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 49151 1999 */ {0x0008, 0x8802},
+ /* 49176 2000 */ {0x0045, 0x8801},
+ /* 49201 2001 */ {0x0020, 0x8800},
+ /* 49224 2002 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 49248 2003 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 49272 2004 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 49298 2005 */ {0x0008, 0x8802},
+ /* 49323 2006 */ {0x0046, 0x8801},
+ /* 49348 2007 */ {0x0020, 0x8800},
+ /* 49371 2008 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 49395 2009 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 49419 2010 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 49445 2011 */ {0x0008, 0x8802},
+ /* 49470 2012 */ {0x0047, 0x8801},
+ /* 49495 2013 */ {0x0080, 0x8800},
+ /* 49518 2014 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 49542 2015 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 49566 2016 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 49592 2017 */ {0x0008, 0x8802},
+ /* 49617 2018 */ {0x0048, 0x8801},
+ /* 49642 2019 */ {0x004c, 0x8800},
+ /* 49665 2020 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 49689 2021 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 49713 2022 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 49739 2023 */ {0x0008, 0x8802},
+ /* 49764 2024 */ {0x0049, 0x8801},
+ /* 49789 2025 */ {0x0084, 0x8800},
+ /* 49812 2026 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 49836 2027 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 49860 2028 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 49886 2029 */ {0x0008, 0x8802},
+ /* 49911 2030 */ {0x004a, 0x8801},
+ /* 49936 2031 */ {0x0084, 0x8800},
+ /* 49959 2032 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 49983 2033 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 50007 2034 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 50033 2035 */ {0x0008, 0x8802},
+ /* 50058 2036 */ {0x004b, 0x8801},
+ /* 50083 2037 */ {0x0084, 0x8800},
+ /* 50106 2038 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* --------------------------------------- */
+ /* 50132 2039 */ {0x0012, 0x8700},
+ /* Clock speed 48Mhz/(2+2)/2= 6 Mhz */
+ /* 50157 2040 */ {0x0000, 0x8701},
+ /* CKx1 clock delay adj */
+ /* 50182 2041 */ {0x0000, 0x8701},
+ /* CKx1 clock delay adj */
+ /* 50207 2042 */ {0x0001, 0x870c},
+ /* CKOx2 output */
+ /* --------------------------------------- */
+ /* 50232 2043 */ {0x0080, 0x8600},
+ /* Line memory read counter (L) */
+ /* 50257 2044 */ {0x0001, 0x8606},
+ /* reserved */
+ /* 50282 2045 */ {0x0064, 0x8607},
+ /* Line memory read counter (H) 0x6480=25,728 */
+ /* 50307 2046 */ {0x002a, 0x8601},
+ /* CDSP sharp interpolation mode,
+ * line sel for color sep, edge enhance enab */
+ /* 50332 2047 */ {0x0000, 0x8602},
+ /* optical black level for user settng = 0 */
+ /* 50357 2048 */ {0x0080, 0x8600},
+ /* Line memory read counter (L) */
+ /* 50382 2049 */ {0x000a, 0x8603},
+ /* optical black level calc mode: auto; optical black offset = 10 */
+ /* 50407 2050 */ {0x00df, 0x865b},
+ /* Horiz offset for valid pixels (L)=0xdf */
+ /* 50432 2051 */ {0x0012, 0x865c},
+ /* Vert offset for valid lines (L)=0x12 */
+
+/* The following two lines seem to be the "wrong" resolution. */
+/* But perhaps these indicate the actual size of the sensor */
+/* rather than the size of the current video mode. */
+ /* 50457 2052 */ {0x0058, 0x865d},
+ /* Horiz valid pixels (*4) (L) = 352 */
+ /* 50482 2053 */ {0x0048, 0x865e},
+ /* Vert valid lines (*4) (L) = 288 */
+
+ /* 50507 2054 */ {0x0015, 0x8608},
+ /* A11 Coef ... */
+ /* 50532 2055 */ {0x0030, 0x8609},
+ /* 50557 2056 */ {0x00fb, 0x860a},
+ /* 50582 2057 */ {0x003e, 0x860b},
+ /* 50607 2058 */ {0x00ce, 0x860c},
+ /* 50632 2059 */ {0x00f4, 0x860d},
+ /* 50657 2060 */ {0x00eb, 0x860e},
+ /* 50682 2061 */ {0x00dc, 0x860f},
+ /* 50707 2062 */ {0x0039, 0x8610},
+ /* 50732 2063 */ {0x0001, 0x8611},
+ /* R offset for white balance ... */
+ /* 50757 2064 */ {0x0000, 0x8612},
+ /* 50782 2065 */ {0x0001, 0x8613},
+ /* 50807 2066 */ {0x0000, 0x8614},
+ /* 50832 2067 */ {0x005b, 0x8651},
+ /* R gain for white balance ... */
+ /* 50857 2068 */ {0x0040, 0x8652},
+ /* 50882 2069 */ {0x0060, 0x8653},
+ /* 50907 2070 */ {0x0040, 0x8654},
+ /* 50932 2071 */ {0x0000, 0x8655},
+ /* 50957 2072 */ {0x0001, 0x863f},
+ /* Fixed gamma correction enable, USB control,
+ * lum filter disable, lum noise clip disable */
+ /* 50982 2073 */ {0x00a1, 0x8656},
+ /* Window1 size 256x256, Windows2 size 64x64,
+ * gamma look-up disable, new edge enhancement enable */
+ /* 51007 2074 */ {0x0018, 0x8657},
+ /* Edge gain high thresh */
+ /* 51032 2075 */ {0x0020, 0x8658},
+ /* Edge gain low thresh */
+ /* 51057 2076 */ {0x000a, 0x8659},
+ /* Edge bandwidth high threshold */
+ /* 51082 2077 */ {0x0005, 0x865a},
+ /* Edge bandwidth low threshold */
+ /* -------------------------------- */
+ /* 51107 2078 */ {0x0030, 0x8112},
+ /* Video drop enable, ISO streaming enable */
+ /* 51130 2079 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 51154 2080 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 51180 2081 */ {0xa908, 0x8802},
+ /* 51205 2082 */ {0x0034, 0x8801},
+ /* SSI reg addr */
+ /* 51230 2083 */ {0x00ca, 0x8800},
+ /* SSI data to write */
+ /* 51253 2084 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 51277 2085 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 51301 2086 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 51327 2087 */ {0x1f08, 0x8802},
+ /* 51352 2088 */ {0x0006, 0x8801},
+ /* 51377 2089 */ {0x0080, 0x8800},
+ /* 51400 2090 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+
+/* ----- Read back coefs we wrote earlier. */
+ /* 51424 2091 */ /* READ { 0, 0x0000, 0x8608 } -> 0000: 15 */
+ /* 51448 2092 */ /* READ { 0, 0x0000, 0x8609 } -> 0000: 30 */
+ /* 51472 2093 */ /* READ { 0, 0x0000, 0x860a } -> 0000: fb */
+ /* 51496 2094 */ /* READ { 0, 0x0000, 0x860b } -> 0000: 3e */
+ /* 51520 2095 */ /* READ { 0, 0x0000, 0x860c } -> 0000: ce */
+ /* 51544 2096 */ /* READ { 0, 0x0000, 0x860d } -> 0000: f4 */
+ /* 51568 2097 */ /* READ { 0, 0x0000, 0x860e } -> 0000: eb */
+ /* 51592 2098 */ /* READ { 0, 0x0000, 0x860f } -> 0000: dc */
+ /* 51616 2099 */ /* READ { 0, 0x0000, 0x8610 } -> 0000: 39 */
+ /* 51640 2100 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 51664 2101 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
+ /* 51690 2102 */ {0xb008, 0x8802},
+ /* 51715 2103 */ {0x0006, 0x8801},
+ /* 51740 2104 */ {0x007d, 0x8800},
+ /* 51763 2105 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+
+#if 0
+ /* experimental. dark version. */
+ {0xba, 0x8705}, /* total pixel clocks per hsync cycle (L) */
+ {0x00, 0x8706}, /* total pixel clocks per hsync cycle (H in 2:0) */
+ {0x5a, 0x8707}, /* total pixel clocks per hsync blank period (L) */
+#elif 0
+ /* experimental. factory default. */
+ {0x8e, 0x8705}, /* total pixel clocks per hsync cycle (L) */
+ {0x03, 0x8706}, /* total pixel clocks per hsync cycle (H in 2:0) */
+ {0x5a, 0x8707}, /* total pixel clocks per hsync blank period (L) */
+#elif 0
+ /* experimental. light. */
+ {0xba, 0x8705}, /* total pixel clocks per hsync cycle (L) */
+ {0x01, 0x8706}, /* total pixel clocks per hsync cycle (H in 2:0) */
+ {0x10, 0x8707}, /* total pixel clocks per hsync blank period (L) */
+#endif
+
+#if 1
+ /* This chunk is seemingly redundant with */
+ /* earlier commands (A11 Coef...), but if I disable it, */
+ /* the image appears too dark. Maybe there was some kind of */
+ /* reset since the earlier commands, so this is necessary again. */
+ /* 51789 2106 */ {0x0015, 0x8608},
+ /* 51814 2107 */ {0x0030, 0x8609},
+ /* 51839 2108 */ {0xfffb, 0x860a},
+ /* 51864 2109 */ {0x003e, 0x860b},
+ /* 51889 2110 */ {0xffce, 0x860c},
+ /* 51914 2111 */ {0xfff4, 0x860d},
+ /* 51939 2112 */ {0xffeb, 0x860e},
+ /* 51964 2113 */ {0xffdc, 0x860f},
+ /* 51989 2114 */ {0x0039, 0x8610},
+ /* 52014 2115 */ {0x0018, 0x8657},
+#endif
+
+ /* 52039 2116 */ {0x0000, 0x8508},
+ /* Disable compression. */
+ /* Previous line was:
+ * 52039 2116 * { 0, 0x0021, 0x8508 }, * Enable compression. */
+ /* 52064 2117 */ {0x0032, 0x850b},
+ /* compression stuff */
+ /* 52089 2118 */ {0x0003, 0x8509},
+ /* compression stuff */
+ /* 52114 2119 */ {0x0011, 0x850a},
+ /* compression stuff */
+ /* 52139 2120 */ {0x0021, 0x850d},
+ /* compression stuff */
+ /* 52164 2121 */ {0x0010, 0x850c},
+ /* compression stuff */
+ /* 52189 2122 */ {0x0003, 0x8500},
+ /* *** Video mode: 160x120 */
+ /* 52214 2123 */ {0x0001, 0x8501},
+ /* Hardware-dominated snap control */
+ /* 52239 2124 */ {0x0061, 0x8656},
+ /* Window1 size 128x128, Windows2 size 128x128,
+ * gamma look-up disable, new edge enhancement enable */
+ /* 52264 2125 */ {0x0018, 0x8617},
+ /* Window1 start X (*2) */
+ /* 52289 2126 */ {0x0008, 0x8618},
+ /* Window1 start Y (*2) */
+ /* 52314 2127 */ {0x0061, 0x8656},
+ /* Window1 size 128x128, Windows2 size 128x128,
+ * gamma look-up disable, new edge enhancement enable */
+ /* 52339 2128 */ {0x0058, 0x8619},
+ /* Window2 start X (*2) */
+ /* 52364 2129 */ {0x0008, 0x861a},
+ /* Window2 start Y (*2) */
+ /* 52389 2130 */ {0x00ff, 0x8615},
+ /* High lum thresh for white balance */
+ /* 52414 2131 */ {0x0000, 0x8616},
+ /* Low lum thresh for white balance */
+ /* 52439 2132 */ {0x0012, 0x8700},
+ /* Clock speed 48Mhz/(2+2)/2= 6 Mhz */
+ /* 52464 2133 */ {0x0012, 0x8700},
+ /* Clock speed 48Mhz/(2+2)/2= 6 Mhz */
+ /* 52487 2134 */ /* READ { 0, 0x0000, 0x8656 } -> 0000: 61 */
+ /* 52513 2135 */ {0x0028, 0x8802},
+ /* 375 Khz SSI clock, SSI r/w sync with VSYNC */
+ /* 52536 2136 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 52560 2137 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 28 */
+ /* 52586 2138 */ {0x1f28, 0x8802},
+ /* 375 Khz SSI clock, SSI r/w sync with VSYNC */
+ /* 52611 2139 */ {0x0010, 0x8801},
+ /* SSI reg addr */
+ /* 52636 2140 */ {0x003e, 0x8800},
+ /* SSI data to write */
+ /* 52659 2141 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 52685 2142 */ {0x0028, 0x8802},
+ /* 52708 2143 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 52732 2144 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 28 */
+ /* 52758 2145 */ {0x1f28, 0x8802},
+ /* 52783 2146 */ {0x0000, 0x8801},
+ /* 52808 2147 */ {0x001f, 0x8800},
+ /* 52831 2148 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 52857 2149 */ {0x0001, 0x8602},
+ /* optical black level for user settning = 1 */
+
+#if 0
+ /* NOTE: Code like this case lets this driver (often) work */
+ /* in 352x288 resolution, apparently by slowing down the */
+ /* clock. */
+
+ /* 52464 2133 */ {0x002F, 0x8700},
+ /* Clock speed */
+#else
+ /* Original: */
+ /* 52882 2150 */ {0x0023, 0x8700},
+ /* Clock speed 48Mhz/(3+2)/4= 2.4 Mhz */
+#endif
+ /* 52907 2151 */ {0x000f, 0x8602},
+ /* optical black level for user settning = 15 */
+
+ /* 52932 2152 */ {0x0028, 0x8802},
+ /* 52955 2153 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 52979 2154 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 28 */
+ /* 53005 2155 */ {0x1f28, 0x8802},
+ /* 53030 2156 */ {0x0010, 0x8801},
+ /* 53055 2157 */ {0x007b, 0x8800},
+ /* 53078 2158 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* 53104 2159 */ {0x002f, 0x8651},
+ /* R gain for white balance ... */
+ /* 53129 2160 */ {0x0080, 0x8653},
+ /* 53152 2161 */ /* READ { 0, 0x0000, 0x8655 } -> 0000: 00 */
+ /* 53178 2162 */ {0x0000, 0x8655},
+
+ /* 53203 2163 */ {0x0030, 0x8112},
+ /* Video drop enable, ISO streaming enable */
+ /* 53228 2164 */ {0x0020, 0x8112},
+ /* Video drop enable, ISO streaming disable */
+ /* 53252 2165 */
+ /* UNKNOWN DIRECTION (URB_FUNCTION_SELECT_INTERFACE: (ALT=0) ) */
+ {}
+};
+
+#if 0
+/*
+ * Data to initialize the camera using the internal CCD
+ */
+static const __u16 spca508_open_data[][3] = {
+ /* line bmRequest,value,index */
+ {}
+};
+#endif
+
+/*
+ * Initialization data for Intel EasyPC Camera CS110
+ */
+static const __u16 spca508cs110_init_data[][3] = {
+ {0x0000, 0x870b}, /* Reset CTL3 */
+ {0x0003, 0x8111}, /* Soft Reset compression, memory, TG & CDSP */
+ {0x0000, 0x8111}, /* Normal operation on reset */
+ {0x0090, 0x8110},
+ /* External Clock 2x & Synchronous Serial Interface Output */
+ {0x0020, 0x8112}, /* Video Drop packet enable */
+ {0x0000, 0x8114}, /* Software GPIO output data */
+ {0x0001, 0x8114},
+ {0x0001, 0x8114},
+ {0x0001, 0x8114},
+ {0x0003, 0x8114},
+
+ /* Initial sequence Synchronous Serial Interface */
+ {0x000f, 0x8402}, /* Memory bank Address */
+ {0x0000, 0x8403}, /* Memory bank Address */
+ {0x00ba, 0x8804}, /* SSI Slave address */
+ {0x0010, 0x8802}, /* 93.75kHz SSI Clock Two DataByte */
+ {0x0010, 0x8802}, /* 93.75kHz SSI Clock two DataByte */
+
+ {0x0001, 0x8801},
+ {0x000a, 0x8805},/* a - NWG: Dunno what this is about */
+ {0x0000, 0x8800},
+ {0x0010, 0x8802},
+
+ {0x0002, 0x8801},
+ {0x0000, 0x8805},
+ {0x0000, 0x8800},
+ {0x0010, 0x8802},
+
+ {0x0003, 0x8801},
+ {0x0027, 0x8805},
+ {0x0001, 0x8800},
+ {0x0010, 0x8802},
+
+ {0x0004, 0x8801},
+ {0x0065, 0x8805},
+ {0x0001, 0x8800},
+ {0x0010, 0x8802},
+
+ {0x0005, 0x8801},
+ {0x0003, 0x8805},
+ {0x0000, 0x8800},
+ {0x0010, 0x8802},
+
+ {0x0006, 0x8801},
+ {0x001c, 0x8805},
+ {0x0000, 0x8800},
+ {0x0010, 0x8802},
+
+ {0x0007, 0x8801},
+ {0x002a, 0x8805},
+ {0x0000, 0x8800},
+ {0x0010, 0x8802},
+
+ {0x0002, 0x8704}, /* External input CKIx1 */
+ {0x0001, 0x8606}, /* 1 Line memory Read Counter (H) Result: (d)410 */
+ {0x009a, 0x8600}, /* Line memory Read Counter (L) */
+ {0x0001, 0x865b}, /* 1 Horizontal Offset for Valid Pixel(L) */
+ {0x0003, 0x865c}, /* 3 Vertical Offset for Valid Lines(L) */
+ {0x0058, 0x865d}, /* 58 Horizontal Valid Pixel Window(L) */
+
+ {0x0006, 0x8660}, /* Nibble data + input order */
+
+ {0x000a, 0x8602}, /* Optical black level set to 0x0a */
+/* 1945 */ {0x0000, 0x8603}, /* Optical black level Offset */
+
+/* 1962 * {0, 0x0000, 0x8611}, * 0 R Offset for white Balance */
+/* 1963 * {0, 0x0000, 0x8612}, * 1 Gr Offset for white Balance */
+/* 1964 * {0, 0x0000, 0x8613}, * 1f B Offset for white Balance */
+/* 1965 * {0, 0x0000, 0x8614}, * f0 Gb Offset for white Balance */
+
+ {0x0040, 0x8651}, /* 2b BLUE gain for white balance good at all 60 */
+ {0x0030, 0x8652}, /* 41 Gr Gain for white Balance (L) */
+ {0x0035, 0x8653}, /* 26 RED gain for white balance */
+ {0x0035, 0x8654}, /* 40Gb Gain for white Balance (L) */
+ {0x0041, 0x863f},
+ /* Fixed Gamma correction enabled (makes colours look better) */
+
+/* 2422 */ {0x0000, 0x8655},
+ /* High bits for white balance*****brightness control*** */
+ {}
+};
+
+static const __u16 spca508_sightcam_init_data[][3] = {
+/* This line seems to setup the frame/canvas */
+ /*368 */ {0x000f, 0x8402},
+
+/* Theese 6 lines are needed to startup the webcam */
+ /*398 */ {0x0090, 0x8110},
+ /*399 */ {0x0001, 0x8114},
+ /*400 */ {0x0001, 0x8114},
+ /*401 */ {0x0001, 0x8114},
+ /*402 */ {0x0003, 0x8114},
+ /*403 */ {0x0080, 0x8804},
+
+/* This part seems to make the pictures darker? (autobrightness?) */
+ /*436 */ {0x0001, 0x8801},
+ /*437 */ {0x0004, 0x8800},
+ /*439 */ {0x0003, 0x8801},
+ /*440 */ {0x00e0, 0x8800},
+ /*442 */ {0x0004, 0x8801},
+ /*443 */ {0x00b4, 0x8800},
+ /*445 */ {0x0005, 0x8801},
+ /*446 */ {0x0000, 0x8800},
+
+ /*448 */ {0x0006, 0x8801},
+ /*449 */ {0x00e0, 0x8800},
+ /*451 */ {0x0007, 0x8801},
+ /*452 */ {0x000c, 0x8800},
+
+/* This section is just needed, it probably
+ * does something like the previous section,
+ * but the cam won't start if it's not included.
+ */
+ /*484 */ {0x0014, 0x8801},
+ /*485 */ {0x0008, 0x8800},
+ /*487 */ {0x0015, 0x8801},
+ /*488 */ {0x0067, 0x8800},
+ /*490 */ {0x0016, 0x8801},
+ /*491 */ {0x0000, 0x8800},
+ /*493 */ {0x0017, 0x8801},
+ /*494 */ {0x0020, 0x8800},
+ /*496 */ {0x0018, 0x8801},
+ /*497 */ {0x0044, 0x8800},
+
+/* Makes the picture darker - and the
+ * cam won't start if not included
+ */
+ /*505 */ {0x001e, 0x8801},
+ /*506 */ {0x00ea, 0x8800},
+ /*508 */ {0x001f, 0x8801},
+ /*509 */ {0x0001, 0x8800},
+ /*511 */ {0x0003, 0x8801},
+ /*512 */ {0x00e0, 0x8800},
+
+/* seems to place the colors ontop of each other #1 */
+ /*517 */ {0x0006, 0x8704},
+ /*518 */ {0x0001, 0x870c},
+ /*519 */ {0x0016, 0x8600},
+ /*520 */ {0x0002, 0x8606},
+
+/* if not included the pictures becomes _very_ dark */
+ /*521 */ {0x0064, 0x8607},
+ /*522 */ {0x003a, 0x8601},
+ /*523 */ {0x0000, 0x8602},
+
+/* seems to place the colors ontop of each other #2 */
+ /*524 */ {0x0016, 0x8600},
+ /*525 */ {0x0018, 0x8617},
+ /*526 */ {0x0008, 0x8618},
+ /*527 */ {0x00a1, 0x8656},
+
+/* webcam won't start if not included */
+ /*528 */ {0x0007, 0x865b},
+ /*529 */ {0x0001, 0x865c},
+ /*530 */ {0x0058, 0x865d},
+ /*531 */ {0x0048, 0x865e},
+
+/* adjusts the colors */
+ /*541 */ {0x0049, 0x8651},
+ /*542 */ {0x0040, 0x8652},
+ /*543 */ {0x004c, 0x8653},
+ /*544 */ {0x0040, 0x8654},
+ {}
+};
+
+static const __u16 spca508_sightcam2_init_data[][3] = {
+#if 1
+/* 35 */ {0x0020, 0x8112},
+
+/* 36 */ {0x000f, 0x8402},
+/* 37 */ {0x0000, 0x8403},
+
+/* 38 */ {0x0008, 0x8201},
+/* 39 */ {0x0008, 0x8200},
+/* 40 */ {0x0001, 0x8200},
+/* 43 */ {0x0009, 0x8201},
+/* 44 */ {0x0008, 0x8200},
+/* 45 */ {0x0001, 0x8200},
+/* 48 */ {0x000a, 0x8201},
+/* 49 */ {0x0008, 0x8200},
+/* 50 */ {0x0001, 0x8200},
+/* 53 */ {0x000b, 0x8201},
+/* 54 */ {0x0008, 0x8200},
+/* 55 */ {0x0001, 0x8200},
+/* 58 */ {0x000c, 0x8201},
+/* 59 */ {0x0008, 0x8200},
+/* 60 */ {0x0001, 0x8200},
+/* 63 */ {0x000d, 0x8201},
+/* 64 */ {0x0008, 0x8200},
+/* 65 */ {0x0001, 0x8200},
+/* 68 */ {0x000e, 0x8201},
+/* 69 */ {0x0008, 0x8200},
+/* 70 */ {0x0001, 0x8200},
+/* 73 */ {0x0007, 0x8201},
+/* 74 */ {0x0008, 0x8200},
+/* 75 */ {0x0001, 0x8200},
+/* 78 */ {0x000f, 0x8201},
+/* 79 */ {0x0008, 0x8200},
+/* 80 */ {0x0001, 0x8200},
+
+/* 84 */ {0x0018, 0x8660},
+/* 85 */ {0x0010, 0x8201},
+
+/* 86 */ {0x0008, 0x8200},
+/* 87 */ {0x0001, 0x8200},
+/* 90 */ {0x0011, 0x8201},
+/* 91 */ {0x0008, 0x8200},
+/* 92 */ {0x0001, 0x8200},
+
+/* 95 */ {0x0000, 0x86b0},
+/* 96 */ {0x0034, 0x86b1},
+/* 97 */ {0x0000, 0x86b2},
+/* 98 */ {0x0049, 0x86b3},
+/* 99 */ {0x0000, 0x86b4},
+/* 100 */ {0x0000, 0x86b4},
+
+/* 101 */ {0x0012, 0x8201},
+/* 102 */ {0x0008, 0x8200},
+/* 103 */ {0x0001, 0x8200},
+/* 106 */ {0x0013, 0x8201},
+/* 107 */ {0x0008, 0x8200},
+/* 108 */ {0x0001, 0x8200},
+
+/* 111 */ {0x0001, 0x86b0},
+/* 112 */ {0x00aa, 0x86b1},
+/* 113 */ {0x0000, 0x86b2},
+/* 114 */ {0x00e4, 0x86b3},
+/* 115 */ {0x0000, 0x86b4},
+/* 116 */ {0x0000, 0x86b4},
+
+/* 118 */ {0x0018, 0x8660},
+
+/* 119 */ {0x0090, 0x8110},
+/* 120 */ {0x0001, 0x8114},
+/* 121 */ {0x0001, 0x8114},
+/* 122 */ {0x0001, 0x8114},
+/* 123 */ {0x0003, 0x8114},
+
+/* 124 */ {0x0080, 0x8804},
+/* 157 */ {0x0003, 0x8801},
+/* 158 */ {0x0012, 0x8800},
+/* 160 */ {0x0004, 0x8801},
+/* 161 */ {0x0005, 0x8800},
+/* 163 */ {0x0005, 0x8801},
+/* 164 */ {0x0000, 0x8800},
+/* 166 */ {0x0006, 0x8801},
+/* 167 */ {0x0000, 0x8800},
+/* 169 */ {0x0007, 0x8801},
+/* 170 */ {0x0000, 0x8800},
+/* 172 */ {0x0008, 0x8801},
+/* 173 */ {0x0005, 0x8800},
+/* 175 */ {0x000a, 0x8700},
+/* 176 */ {0x000e, 0x8801},
+/* 177 */ {0x0004, 0x8800},
+/* 179 */ {0x0005, 0x8801},
+/* 180 */ {0x0047, 0x8800},
+/* 182 */ {0x0006, 0x8801},
+/* 183 */ {0x0000, 0x8800},
+/* 185 */ {0x0007, 0x8801},
+/* 186 */ {0x00c0, 0x8800},
+/* 188 */ {0x0008, 0x8801},
+/* 189 */ {0x0003, 0x8800},
+/* 191 */ {0x0013, 0x8801},
+/* 192 */ {0x0001, 0x8800},
+/* 194 */ {0x0009, 0x8801},
+/* 195 */ {0x0000, 0x8800},
+/* 197 */ {0x000a, 0x8801},
+/* 198 */ {0x0000, 0x8800},
+/* 200 */ {0x000b, 0x8801},
+/* 201 */ {0x0000, 0x8800},
+/* 203 */ {0x000c, 0x8801},
+/* 204 */ {0x0000, 0x8800},
+/* 206 */ {0x000e, 0x8801},
+/* 207 */ {0x0004, 0x8800},
+/* 209 */ {0x000f, 0x8801},
+/* 210 */ {0x0000, 0x8800},
+/* 212 */ {0x0010, 0x8801},
+/* 213 */ {0x0006, 0x8800},
+/* 215 */ {0x0011, 0x8801},
+/* 216 */ {0x0006, 0x8800},
+/* 218 */ {0x0012, 0x8801},
+/* 219 */ {0x0000, 0x8800},
+/* 221 */ {0x0013, 0x8801},
+/* 222 */ {0x0001, 0x8800},
+
+/* 224 */ {0x000a, 0x8700},
+/* 225 */ {0x0000, 0x8702},
+/* 226 */ {0x0000, 0x8703},
+/* 227 */ {0x00c2, 0x8704},
+/* 228 */ {0x0001, 0x870c},
+
+/* 229 */ {0x0044, 0x8600},
+/* 230 */ {0x0002, 0x8606},
+/* 231 */ {0x0064, 0x8607},
+/* 232 */ {0x003a, 0x8601},
+/* 233 */ {0x0008, 0x8602},
+/* 234 */ {0x0044, 0x8600},
+/* 235 */ {0x0018, 0x8617},
+/* 236 */ {0x0008, 0x8618},
+/* 237 */ {0x00a1, 0x8656},
+/* 238 */ {0x0004, 0x865b},
+/* 239 */ {0x0002, 0x865c},
+/* 240 */ {0x0058, 0x865d},
+/* 241 */ {0x0048, 0x865e},
+/* 242 */ {0x0012, 0x8608},
+/* 243 */ {0x002c, 0x8609},
+/* 244 */ {0x0002, 0x860a},
+/* 245 */ {0x002c, 0x860b},
+/* 246 */ {0x00db, 0x860c},
+/* 247 */ {0x00f9, 0x860d},
+/* 248 */ {0x00f1, 0x860e},
+/* 249 */ {0x00e3, 0x860f},
+/* 250 */ {0x002c, 0x8610},
+/* 251 */ {0x006c, 0x8651},
+/* 252 */ {0x0041, 0x8652},
+/* 253 */ {0x0059, 0x8653},
+/* 254 */ {0x0040, 0x8654},
+/* 255 */ {0x00fa, 0x8611},
+/* 256 */ {0x00ff, 0x8612},
+/* 257 */ {0x00f8, 0x8613},
+/* 258 */ {0x0000, 0x8614},
+/* 259 */ {0x0001, 0x863f},
+/* 260 */ {0x0000, 0x8640},
+/* 261 */ {0x0026, 0x8641},
+/* 262 */ {0x0045, 0x8642},
+/* 263 */ {0x0060, 0x8643},
+/* 264 */ {0x0075, 0x8644},
+/* 265 */ {0x0088, 0x8645},
+/* 266 */ {0x009b, 0x8646},
+/* 267 */ {0x00b0, 0x8647},
+/* 268 */ {0x00c5, 0x8648},
+/* 269 */ {0x00d2, 0x8649},
+/* 270 */ {0x00dc, 0x864a},
+/* 271 */ {0x00e5, 0x864b},
+/* 272 */ {0x00eb, 0x864c},
+/* 273 */ {0x00f0, 0x864d},
+/* 274 */ {0x00f6, 0x864e},
+/* 275 */ {0x00fa, 0x864f},
+/* 276 */ {0x00ff, 0x8650},
+/* 277 */ {0x0060, 0x8657},
+/* 278 */ {0x0010, 0x8658},
+/* 279 */ {0x0018, 0x8659},
+/* 280 */ {0x0005, 0x865a},
+/* 281 */ {0x0018, 0x8660},
+/* 282 */ {0x0003, 0x8509},
+/* 283 */ {0x0011, 0x850a},
+/* 284 */ {0x0032, 0x850b},
+/* 285 */ {0x0010, 0x850c},
+/* 286 */ {0x0021, 0x850d},
+/* 287 */ {0x0001, 0x8500},
+/* 288 */ {0x0000, 0x8508},
+/* 289 */ {0x0012, 0x8608},
+/* 290 */ {0x002c, 0x8609},
+/* 291 */ {0x0002, 0x860a},
+/* 292 */ {0x0039, 0x860b},
+/* 293 */ {0x00d0, 0x860c},
+/* 294 */ {0x00f7, 0x860d},
+/* 295 */ {0x00ed, 0x860e},
+/* 296 */ {0x00db, 0x860f},
+/* 297 */ {0x0039, 0x8610},
+/* 298 */ {0x0012, 0x8657},
+/* 299 */ {0x000c, 0x8619},
+/* 300 */ {0x0004, 0x861a},
+/* 301 */ {0x00a1, 0x8656},
+/* 302 */ {0x00c8, 0x8615},
+/* 303 */ {0x0032, 0x8616},
+
+/* 306 */ {0x0030, 0x8112},
+/* 313 */ {0x0020, 0x8112},
+/* 314 */ {0x0020, 0x8112},
+/* 315 */ {0x000f, 0x8402},
+/* 316 */ {0x0000, 0x8403},
+
+/* 317 */ {0x0090, 0x8110},
+/* 318 */ {0x0001, 0x8114},
+/* 319 */ {0x0001, 0x8114},
+/* 320 */ {0x0001, 0x8114},
+/* 321 */ {0x0003, 0x8114},
+/* 322 */ {0x0080, 0x8804},
+
+/* 355 */ {0x0003, 0x8801},
+/* 356 */ {0x0012, 0x8800},
+/* 358 */ {0x0004, 0x8801},
+/* 359 */ {0x0005, 0x8800},
+/* 361 */ {0x0005, 0x8801},
+/* 362 */ {0x0047, 0x8800},
+/* 364 */ {0x0006, 0x8801},
+/* 365 */ {0x0000, 0x8800},
+/* 367 */ {0x0007, 0x8801},
+/* 368 */ {0x00c0, 0x8800},
+/* 370 */ {0x0008, 0x8801},
+/* 371 */ {0x0003, 0x8800},
+/* 373 */ {0x000a, 0x8700},
+/* 374 */ {0x000e, 0x8801},
+/* 375 */ {0x0004, 0x8800},
+/* 377 */ {0x0005, 0x8801},
+/* 378 */ {0x0047, 0x8800},
+/* 380 */ {0x0006, 0x8801},
+/* 381 */ {0x0000, 0x8800},
+/* 383 */ {0x0007, 0x8801},
+/* 384 */ {0x00c0, 0x8800},
+/* 386 */ {0x0008, 0x8801},
+/* 387 */ {0x0003, 0x8800},
+/* 389 */ {0x0013, 0x8801},
+/* 390 */ {0x0001, 0x8800},
+/* 392 */ {0x0009, 0x8801},
+/* 393 */ {0x0000, 0x8800},
+/* 395 */ {0x000a, 0x8801},
+/* 396 */ {0x0000, 0x8800},
+/* 398 */ {0x000b, 0x8801},
+/* 399 */ {0x0000, 0x8800},
+/* 401 */ {0x000c, 0x8801},
+/* 402 */ {0x0000, 0x8800},
+/* 404 */ {0x000e, 0x8801},
+/* 405 */ {0x0004, 0x8800},
+/* 407 */ {0x000f, 0x8801},
+/* 408 */ {0x0000, 0x8800},
+/* 410 */ {0x0010, 0x8801},
+/* 411 */ {0x0006, 0x8800},
+/* 413 */ {0x0011, 0x8801},
+/* 414 */ {0x0006, 0x8800},
+/* 416 */ {0x0012, 0x8801},
+/* 417 */ {0x0000, 0x8800},
+/* 419 */ {0x0013, 0x8801},
+/* 420 */ {0x0001, 0x8800},
+/* 422 */ {0x000a, 0x8700},
+/* 423 */ {0x0000, 0x8702},
+/* 424 */ {0x0000, 0x8703},
+/* 425 */ {0x00c2, 0x8704},
+/* 426 */ {0x0001, 0x870c},
+/* 427 */ {0x0044, 0x8600},
+/* 428 */ {0x0002, 0x8606},
+/* 429 */ {0x0064, 0x8607},
+/* 430 */ {0x003a, 0x8601},
+/* 431 */ {0x0008, 0x8602},
+/* 432 */ {0x0044, 0x8600},
+/* 433 */ {0x0018, 0x8617},
+/* 434 */ {0x0008, 0x8618},
+/* 435 */ {0x00a1, 0x8656},
+/* 436 */ {0x0004, 0x865b},
+/* 437 */ {0x0002, 0x865c},
+/* 438 */ {0x0058, 0x865d},
+/* 439 */ {0x0048, 0x865e},
+/* 440 */ {0x0012, 0x8608},
+/* 441 */ {0x002c, 0x8609},
+/* 442 */ {0x0002, 0x860a},
+/* 443 */ {0x002c, 0x860b},
+/* 444 */ {0x00db, 0x860c},
+/* 445 */ {0x00f9, 0x860d},
+/* 446 */ {0x00f1, 0x860e},
+/* 447 */ {0x00e3, 0x860f},
+/* 448 */ {0x002c, 0x8610},
+/* 449 */ {0x006c, 0x8651},
+/* 450 */ {0x0041, 0x8652},
+/* 451 */ {0x0059, 0x8653},
+/* 452 */ {0x0040, 0x8654},
+/* 453 */ {0x00fa, 0x8611},
+/* 454 */ {0x00ff, 0x8612},
+/* 455 */ {0x00f8, 0x8613},
+/* 456 */ {0x0000, 0x8614},
+/* 457 */ {0x0001, 0x863f},
+/* 458 */ {0x0000, 0x8640},
+/* 459 */ {0x0026, 0x8641},
+/* 460 */ {0x0045, 0x8642},
+/* 461 */ {0x0060, 0x8643},
+/* 462 */ {0x0075, 0x8644},
+/* 463 */ {0x0088, 0x8645},
+/* 464 */ {0x009b, 0x8646},
+/* 465 */ {0x00b0, 0x8647},
+/* 466 */ {0x00c5, 0x8648},
+/* 467 */ {0x00d2, 0x8649},
+/* 468 */ {0x00dc, 0x864a},
+/* 469 */ {0x00e5, 0x864b},
+/* 470 */ {0x00eb, 0x864c},
+/* 471 */ {0x00f0, 0x864d},
+/* 472 */ {0x00f6, 0x864e},
+/* 473 */ {0x00fa, 0x864f},
+/* 474 */ {0x00ff, 0x8650},
+/* 475 */ {0x0060, 0x8657},
+/* 476 */ {0x0010, 0x8658},
+/* 477 */ {0x0018, 0x8659},
+/* 478 */ {0x0005, 0x865a},
+/* 479 */ {0x0018, 0x8660},
+/* 480 */ {0x0003, 0x8509},
+/* 481 */ {0x0011, 0x850a},
+/* 482 */ {0x0032, 0x850b},
+/* 483 */ {0x0010, 0x850c},
+/* 484 */ {0x0021, 0x850d},
+/* 485 */ {0x0001, 0x8500},
+/* 486 */ {0x0000, 0x8508},
+
+/* 487 */ {0x0012, 0x8608},
+/* 488 */ {0x002c, 0x8609},
+/* 489 */ {0x0002, 0x860a},
+/* 490 */ {0x0039, 0x860b},
+/* 491 */ {0x00d0, 0x860c},
+/* 492 */ {0x00f7, 0x860d},
+/* 493 */ {0x00ed, 0x860e},
+/* 494 */ {0x00db, 0x860f},
+/* 495 */ {0x0039, 0x8610},
+/* 496 */ {0x0012, 0x8657},
+/* 497 */ {0x0064, 0x8619},
+
+/* This line starts it all, it is not needed here */
+/* since it has been build into the driver */
+/* jfm: don't start now */
+/* 590 * {0x0030, 0x8112}, */
+#endif
+ {}
+};
+
+/*
+ * Initialization data for Creative Webcam Vista
+ */
+static const __u16 spca508_vista_init_data[][3] = {
+ {0x0008, 0x8200}, /* Clear register */
+ {0x0000, 0x870b}, /* Reset CTL3 */
+ {0x0020, 0x8112}, /* Video Drop packet enable */
+ {0x0003, 0x8111}, /* Soft Reset compression, memory, TG & CDSP */
+ {0x0000, 0x8110}, /* Disable everything */
+ {0x0000, 0x8114}, /* Software GPIO output data */
+ {0x0000, 0x8114},
+
+ {0x0003, 0x8111},
+ {0x0000, 0x8111},
+ {0x0090, 0x8110}, /* Enable: SSI output, External 2X clock output */
+ {0x0020, 0x8112},
+ {0x0000, 0x8114},
+ {0x0001, 0x8114},
+ {0x0001, 0x8114},
+ {0x0001, 0x8114},
+ {0x0003, 0x8114},
+
+ {0x000f, 0x8402}, /* Memory bank Address */
+ {0x0000, 0x8403}, /* Memory bank Address */
+ {0x00ba, 0x8804}, /* SSI Slave address */
+ {0x0010, 0x8802}, /* 93.75kHz SSI Clock Two DataByte */
+
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+ /* READ { 0, 0x0001, 0x8802 } ->
+ 0000: 10 */
+ {0x0010, 0x8802}, /* Will write 2 bytes (DATA1+DATA2) */
+ {0x0020, 0x8801}, /* Register address for SSI read/write */
+ {0x0044, 0x8805}, /* DATA2 */
+ {0x0004, 0x8800}, /* DATA1 -> write triggered */
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+ /* READ { 0, 0x0001, 0x8802 } ->
+ 0000: 10 */
+ {0x0010, 0x8802},
+ {0x0009, 0x8801},
+ {0x0042, 0x8805},
+ {0x0001, 0x8800},
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+ /* READ { 0, 0x0001, 0x8802 } ->
+ 0000: 10 */
+ {0x0010, 0x8802},
+ {0x003c, 0x8801},
+ {0x0001, 0x8805},
+ {0x0000, 0x8800},
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+ /* READ { 0, 0x0001, 0x8802 } ->
+ 0000: 10 */
+ {0x0010, 0x8802},
+ {0x0001, 0x8801},
+ {0x000a, 0x8805},
+ {0x0000, 0x8800},
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+ /* READ { 0, 0x0001, 0x8802 } ->
+ 0000: 10 */
+ {0x0010, 0x8802},
+ {0x0002, 0x8801},
+ {0x0000, 0x8805},
+ {0x0000, 0x8800},
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+ /* READ { 0, 0x0001, 0x8802 } ->
+ 0000: 10 */
+ {0x0010, 0x8802},
+ {0x0003, 0x8801},
+ {0x0027, 0x8805},
+ {0x0001, 0x8800},
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+ /* READ { 0, 0x0001, 0x8802 } ->
+ 0000: 10 */
+ {0x0010, 0x8802},
+ {0x0004, 0x8801},
+ {0x0065, 0x8805},
+ {0x0001, 0x8800},
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+ /* READ { 0, 0x0001, 0x8802 } ->
+ 0000: 10 */
+ {0x0010, 0x8802},
+ {0x0005, 0x8801},
+ {0x0003, 0x8805},
+ {0x0000, 0x8800},
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+ /* READ { 0, 0x0001, 0x8802 } ->
+ 0000: 10 */
+ {0x0010, 0x8802},
+ {0x0006, 0x8801},
+ {0x001c, 0x8805},
+ {0x0000, 0x8800},
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+ /* READ { 0, 0x0001, 0x8802 } ->
+ 0000: 10 */
+ {0x0010, 0x8802},
+ {0x0007, 0x8801},
+ {0x002a, 0x8805},
+ {0x0000, 0x8800},
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+ /* READ { 0, 0x0001, 0x8802 } ->
+ 0000: 10 */
+ {0x0010, 0x8802},
+ {0x000e, 0x8801},
+ {0x0000, 0x8805},
+ {0x0000, 0x8800},
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+ /* READ { 0, 0x0001, 0x8802 } ->
+ 0000: 10 */
+ {0x0010, 0x8802},
+ {0x0028, 0x8801},
+ {0x002e, 0x8805},
+ {0x0000, 0x8800},
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+ /* READ { 0, 0x0001, 0x8802 } ->
+ 0000: 10 */
+ {0x0010, 0x8802},
+ {0x0039, 0x8801},
+ {0x0013, 0x8805},
+ {0x0000, 0x8800},
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+ /* READ { 0, 0x0001, 0x8802 } ->
+ 0000: 10 */
+ {0x0010, 0x8802},
+ {0x003b, 0x8801},
+ {0x000c, 0x8805},
+ {0x0000, 0x8800},
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+ /* READ { 0, 0x0001, 0x8802 } ->
+ 0000: 10 */
+ {0x0010, 0x8802},
+ {0x0035, 0x8801},
+ {0x0028, 0x8805},
+ {0x0000, 0x8800},
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+ /* READ { 0, 0x0001, 0x8802 } ->
+ 0000: 10 */
+ {0x0010, 0x8802},
+ {0x0009, 0x8801},
+ {0x0042, 0x8805},
+ {0x0001, 0x8800},
+ /* READ { 0, 0x0001, 0x8803 } ->
+ 0000: 00 */
+
+ {0x0050, 0x8703},
+ {0x0002, 0x8704}, /* External input CKIx1 */
+ {0x0001, 0x870C}, /* Select CKOx2 output */
+ {0x009A, 0x8600}, /* Line memory Read Counter (L) */
+ {0x0001, 0x8606}, /* 1 Line memory Read Counter (H) Result: (d)410 */
+ {0x0023, 0x8601},
+ {0x0010, 0x8602},
+ {0x000A, 0x8603},
+ {0x009A, 0x8600},
+ {0x0001, 0x865B}, /* 1 Horizontal Offset for Valid Pixel(L) */
+ {0x0003, 0x865C}, /* Vertical offset for valid lines (L) */
+ {0x0058, 0x865D}, /* Horizontal valid pixels window (L) */
+ {0x0048, 0x865E}, /* Vertical valid lines window (L) */
+ {0x0000, 0x865F},
+
+ {0x0006, 0x8660},
+ /* Enable nibble data input, select nibble input order */
+
+ {0x0013, 0x8608}, /* A11 Coeficients for color correction */
+ {0x0028, 0x8609},
+ /* Note: these values are confirmed at the end of array */
+ {0x0005, 0x860A}, /* ... */
+ {0x0025, 0x860B},
+ {0x00E1, 0x860C},
+ {0x00FA, 0x860D},
+ {0x00F4, 0x860E},
+ {0x00E8, 0x860F},
+ {0x0025, 0x8610}, /* A33 Coef. */
+ {0x00FC, 0x8611}, /* White balance offset: R */
+ {0x0001, 0x8612}, /* White balance offset: Gr */
+ {0x00FE, 0x8613}, /* White balance offset: B */
+ {0x0000, 0x8614}, /* White balance offset: Gb */
+
+ {0x0064, 0x8651}, /* R gain for white balance (L) */
+ {0x0040, 0x8652}, /* Gr gain for white balance (L) */
+ {0x0066, 0x8653}, /* B gain for white balance (L) */
+ {0x0040, 0x8654}, /* Gb gain for white balance (L) */
+ {0x0001, 0x863F}, /* Enable fixed gamma correction */
+
+ {0x00A1, 0x8656}, /* Size - Window1: 256x256, Window2: 128x128 */
+ /* UV division: UV no change, Enable New edge enhancement */
+ {0x0018, 0x8657}, /* Edge gain high threshold */
+ {0x0020, 0x8658}, /* Edge gain low threshold */
+ {0x000A, 0x8659}, /* Edge bandwidth high threshold */
+ {0x0005, 0x865A}, /* Edge bandwidth low threshold */
+ {0x0064, 0x8607}, /* UV filter enable */
+
+ {0x0016, 0x8660},
+ {0x0000, 0x86B0}, /* Bad pixels compensation address */
+ {0x00DC, 0x86B1}, /* X coord for bad pixels compensation (L) */
+ {0x0000, 0x86B2},
+ {0x0009, 0x86B3}, /* Y coord for bad pixels compensation (L) */
+ {0x0000, 0x86B4},
+
+ {0x0001, 0x86B0},
+ {0x00F5, 0x86B1},
+ {0x0000, 0x86B2},
+ {0x00C6, 0x86B3},
+ {0x0000, 0x86B4},
+
+ {0x0002, 0x86B0},
+ {0x001C, 0x86B1},
+ {0x0001, 0x86B2},
+ {0x00D7, 0x86B3},
+ {0x0000, 0x86B4},
+
+ {0x0003, 0x86B0},
+ {0x001C, 0x86B1},
+ {0x0001, 0x86B2},
+ {0x00D8, 0x86B3},
+ {0x0000, 0x86B4},
+
+ {0x0004, 0x86B0},
+ {0x001D, 0x86B1},
+ {0x0001, 0x86B2},
+ {0x00D8, 0x86B3},
+ {0x0000, 0x86B4},
+ {0x001E, 0x8660},
+
+ /* READ { 0, 0x0000, 0x8608 } ->
+ 0000: 13 */
+ /* READ { 0, 0x0000, 0x8609 } ->
+ 0000: 28 */
+ /* READ { 0, 0x0000, 0x8610 } ->
+ 0000: 05 */
+ /* READ { 0, 0x0000, 0x8611 } ->
+ 0000: 25 */
+ /* READ { 0, 0x0000, 0x8612 } ->
+ 0000: e1 */
+ /* READ { 0, 0x0000, 0x8613 } ->
+ 0000: fa */
+ /* READ { 0, 0x0000, 0x8614 } ->
+ 0000: f4 */
+ /* READ { 0, 0x0000, 0x8615 } ->
+ 0000: e8 */
+ /* READ { 0, 0x0000, 0x8616 } ->
+ 0000: 25 */
+ {}
+};
+
+static int reg_write(struct usb_device *dev,
+ __u16 index, __u16 value)
+{
+ int ret;
+
+ ret = usb_control_msg(dev,
+ usb_sndctrlpipe(dev, 0),
+ 0, /* request */
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value, index, NULL, 0, 500);
+ PDEBUG(D_USBO, "reg write i:0x%04x = 0x%02x",
+ index, value);
+ if (ret < 0)
+ PDEBUG(D_ERR|D_USBO, "reg write: error %d", ret);
+ return ret;
+}
+
+/* read 1 byte */
+/* returns: negative is error, pos or zero is data */
+static int reg_read(struct usb_device *dev,
+ __u16 index) /* wIndex */
+{
+ int ret;
+ __u8 data;
+
+ ret = usb_control_msg(dev,
+ usb_rcvctrlpipe(dev, 0),
+ 0, /* register */
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ (__u16) 0, /* value */
+ index,
+ &data, 1,
+ 500); /* timeout */
+ PDEBUG(D_USBI, "reg read i:%04x --> %02x", index, data);
+ if (ret < 0) {
+ PDEBUG(D_ERR|D_USBI, "reg_read err %d", ret);
+ return ret;
+ }
+ return data;
+}
+
+static int write_vector(struct gspca_dev *gspca_dev,
+ const __u16 data[][3])
+{
+ struct usb_device *dev = gspca_dev->dev;
+ int ret, i = 0;
+
+ while (data[i][1] != 0) {
+ ret = reg_write(dev, data[i][1], data[i][0]);
+ if (ret < 0)
+ return ret;
+ i++;
+ }
+ return 0;
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+ const struct usb_device_id *id)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+ struct cam *cam;
+ __u16 vendor;
+ __u16 product;
+ int data1, data2;
+
+ vendor = id->idVendor;
+ product = id->idProduct;
+ switch (vendor) {
+ case 0x0130: /* Clone webcam */
+/* switch (product) { */
+/* case 0x0130: */
+ sd->subtype = HamaUSBSightcam; /* same as Hama 0010 */
+/* break; */
+/* } */
+ break;
+ case 0x041e: /* Creative cameras */
+/* switch (product) { */
+/* case 0x4018: */
+ sd->subtype = CreativeVista;
+/* break; */
+/* } */
+ break;
+ case 0x0461: /* MicroInnovation */
+/* switch (product) { */
+/* case 0x0815: */
+ sd->subtype = MicroInnovationIC200;
+/* break; */
+/* } */
+ break;
+ case 0x0733: /* Rebadged ViewQuest (Intel) and ViewQuest cameras */
+/* switch (product) { */
+/* case 0x110: */
+ sd->subtype = ViewQuestVQ110;
+/* break; */
+/* } */
+ break;
+ case 0x0af9: /* Hama cameras */
+ switch (product) {
+ case 0x0010:
+ sd->subtype = HamaUSBSightcam;
+ break;
+ case 0x0011:
+ sd->subtype = HamaUSBSightcam2;
+ break;
+ }
+ break;
+ case 0x8086: /* Intel */
+/* switch (product) { */
+/* case 0x0110: */
+ sd->subtype = IntelEasyPCCamera;
+/* break; */
+/* } */
+ break;
+ }
+
+ /* Read from global register the USB product and vendor IDs, just to
+ * prove that we can communicate with the device. This works, which
+ * confirms at we are communicating properly and that the device
+ * is a 508. */
+ data1 = reg_read(dev, 0x8104);
+ data2 = reg_read(dev, 0x8105);
+ PDEBUG(D_PROBE, "Webcam Vendor ID: 0x%02x%02x", data2, data1);
+
+ data1 = reg_read(dev, 0x8106);
+ data2 = reg_read(dev, 0x8107);
+ PDEBUG(D_PROBE, "Webcam Product ID: 0x%02x%02x", data2, data1);
+
+ data1 = reg_read(dev, 0x8621);
+ PDEBUG(D_PROBE, "Window 1 average luminance: %d", data1);
+
+ cam = &gspca_dev->cam;
+ cam->dev_name = (char *) id->driver_info;
+ cam->epaddr = 0x01;
+ cam->cam_mode = sif_mode;
+ cam->nmodes = ARRAY_SIZE(sif_mode);
+ sd->brightness = BRIGHTNESS_DEF;
+
+ switch (sd->subtype) {
+ case ViewQuestVQ110:
+ if (write_vector(gspca_dev, spca508_init_data))
+ return -1;
+ break;
+ default:
+/* case MicroInnovationIC200: */
+/* case IntelEasyPCCamera: */
+ if (write_vector(gspca_dev, spca508cs110_init_data))
+ return -1;
+ break;
+ case HamaUSBSightcam:
+ if (write_vector(gspca_dev, spca508_sightcam_init_data))
+ return -1;
+ break;
+ case HamaUSBSightcam2:
+ if (write_vector(gspca_dev, spca508_sightcam2_init_data))
+ return -1;
+ break;
+ case CreativeVista:
+ if (write_vector(gspca_dev, spca508_vista_init_data))
+ return -1;
+ break;
+ }
+ return 0; /* success */
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+/* write_vector(gspca_dev, spca508_open_data); */
+ return 0;
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+ int mode;
+
+ mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
+ reg_write(gspca_dev->dev, 0x8500, mode);
+ switch (mode) {
+ case 0:
+ case 1:
+ reg_write(gspca_dev->dev, 0x8700, 0x28); /* clock */
+ break;
+ default:
+/* case 2: */
+/* case 3: */
+ reg_write(gspca_dev->dev, 0x8700, 0x23); /* clock */
+ break;
+ }
+ reg_write(gspca_dev->dev, 0x8112, 0x10 | 0x20);
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+ /* Video ISO disable, Video Drop Packet enable: */
+ reg_write(gspca_dev->dev, 0x8112, 0x20);
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+/* this function is called at close time */
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+/* convert YUVY per line to YUYV (YUV 4:2:2) */
+static void yuvy_decode(unsigned char *out,
+ unsigned char *in,
+ int width,
+ int height)
+{
+ unsigned char *Ui, *Vi, *yi, *yi1;
+ unsigned char *out1;
+ int i, j;
+
+ yi = in;
+ for (i = height / 2; --i >= 0; ) {
+ out1 = out + width * 2; /* next line */
+ Ui = yi + width;
+ Vi = Ui + width / 2;
+ yi1 = Vi + width / 2;
+ for (j = width / 2; --j >= 0; ) {
+ *out++ = 128 + *yi++;
+ *out++ = 128 + *Ui;
+ *out++ = 128 + *yi++;
+ *out++ = 128 + *Vi;
+
+ *out1++ = 128 + *yi1++;
+ *out1++ = 128 + *Ui++;
+ *out1++ = 128 + *yi1++;
+ *out1++ = 128 + *Vi++;
+ }
+ yi += width * 2;
+ out = out1;
+ }
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ struct gspca_frame *frame, /* target */
+ __u8 *data, /* isoc packet */
+ int len) /* iso packet length */
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ switch (data[0]) {
+ case 0: /* start of frame */
+ if (gspca_dev->last_packet_type == FIRST_PACKET) {
+ yuvy_decode(sd->tmpbuf2, sd->tmpbuf,
+ gspca_dev->width,
+ gspca_dev->height);
+ frame = gspca_frame_add(gspca_dev,
+ LAST_PACKET,
+ frame,
+ sd->tmpbuf2,
+ gspca_dev->width
+ * gspca_dev->height
+ * 2);
+ }
+ gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+ data, 0);
+ data += SPCA508_OFFSET_DATA;
+ len -= SPCA508_OFFSET_DATA;
+ if (len > 0)
+ memcpy(sd->tmpbuf, data, len);
+ else
+ len = 0;
+ sd->buflen = len;
+ return;
+ case 0xff: /* drop */
+/* gspca_dev->last_packet_type = DISCARD_PACKET; */
+ return;
+ }
+ data += 1;
+ len -= 1;
+ memcpy(&sd->tmpbuf[sd->buflen], data, len);
+ sd->buflen += len;
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ __u8 brightness = sd->brightness;
+
+ /* MX seem contrast */
+ reg_write(gspca_dev->dev, 0x8651, brightness);
+ reg_write(gspca_dev->dev, 0x8652, brightness);
+ reg_write(gspca_dev->dev, 0x8653, brightness);
+ reg_write(gspca_dev->dev, 0x8654, brightness);
+}
+
+static void getbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->brightness = reg_read(gspca_dev->dev, 0x8651);
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->brightness = val;
+ if (gspca_dev->streaming)
+ setbrightness(gspca_dev);
+ return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ getbrightness(gspca_dev);
+ *val = sd->brightness;
+ return 0;
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .ctrls = sd_ctrls,
+ .nctrls = ARRAY_SIZE(sd_ctrls),
+ .config = sd_config,
+ .open = sd_open,
+ .start = sd_start,
+ .stopN = sd_stopN,
+ .stop0 = sd_stop0,
+ .close = sd_close,
+ .pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static const __devinitdata struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x0130, 0x0130), DVNM("Clone Digital Webcam 11043")},
+ {USB_DEVICE(0x041e, 0x4018), DVNM("Creative Webcam Vista (PD1100)")},
+ {USB_DEVICE(0x0461, 0x0815), DVNM("Micro Innovation IC200")},
+ {USB_DEVICE(0x0733, 0x0110), DVNM("ViewQuest VQ110")},
+ {USB_DEVICE(0x0af9, 0x0010), DVNM("Hama USB Sightcam 100")},
+ {USB_DEVICE(0x0af9, 0x0011), DVNM("Hama USB Sightcam 100")},
+ {USB_DEVICE(0x8086, 0x0110), DVNM("Intel Easy PC Camera")},
+ {}
+};
+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,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+ if (usb_register(&sd_driver) < 0)
+ return -1;
+ PDEBUG(D_PROBE, "v%s registered", version);
+ return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+ usb_deregister(&sd_driver);
+ PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/linux/drivers/media/video/gspca/spca561.c b/linux/drivers/media/video/gspca/spca561.c
new file mode 100644
index 000000000..f0770ee59
--- /dev/null
+++ b/linux/drivers/media/video/gspca/spca561.c
@@ -0,0 +1,1045 @@
+/*
+ * Sunplus spca561 subdriver
+ *
+ * Copyright (C) 2004 Michel Xhaard mxhaard@magic.fr
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define MODULE_NAME "spca561"
+
+#include "gspca.h"
+
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 5)
+static const char version[] = "2.1.5";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("GSPCA/SPCA561 USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+
+ unsigned short contrast;
+ __u8 brightness;
+ __u8 autogain;
+
+ __u8 chip_revision;
+ signed char ag_cnt;
+#define AG_CNT_START 13
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+#define SD_BRIGHTNESS 0
+ {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+ .maximum = 63,
+ .step = 1,
+ .default_value = 32,
+ },
+ .set = sd_setbrightness,
+ .get = sd_getbrightness,
+ },
+#define SD_CONTRAST 1
+ {
+ {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = 0,
+ .maximum = 0x3fff,
+ .step = 1,
+ .default_value = 0x2000,
+ },
+ .set = sd_setcontrast,
+ .get = sd_getcontrast,
+ },
+#define SD_AUTOGAIN 2
+ {
+ {
+ .id = V4L2_CID_AUTOGAIN,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Auto Gain",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 1,
+ },
+ .set = sd_setautogain,
+ .get = sd_getautogain,
+ },
+};
+
+static struct v4l2_pix_format sif_mode[] = {
+ {160, 120, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
+ .bytesperline = 160,
+ .sizeimage = 160 * 120,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 3},
+ {176, 144, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
+ .bytesperline = 176,
+ .sizeimage = 176 * 144,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 2},
+ {320, 240, V4L2_PIX_FMT_SPCA561, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240 * 4 / 8,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 1},
+ {352, 288, V4L2_PIX_FMT_SPCA561, V4L2_FIELD_NONE,
+ .bytesperline = 352,
+ .sizeimage = 352 * 288 * 4 / 8,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0},
+};
+
+/*
+ * Initialization data
+ * I'm not very sure how to split initialization from open data
+ * chunks. For now, we'll consider everything as initialization
+ */
+/* Frame packet header offsets for the spca561 */
+#define SPCA561_OFFSET_SNAP 1
+#define SPCA561_OFFSET_TYPE 2
+#define SPCA561_OFFSET_COMPRESS 3
+#define SPCA561_OFFSET_FRAMSEQ 4
+#define SPCA561_OFFSET_GPIO 5
+#define SPCA561_OFFSET_USBBUFF 6
+#define SPCA561_OFFSET_WIN2GRAVE 7
+#define SPCA561_OFFSET_WIN2RAVE 8
+#define SPCA561_OFFSET_WIN2BAVE 9
+#define SPCA561_OFFSET_WIN2GBAVE 10
+#define SPCA561_OFFSET_WIN1GRAVE 11
+#define SPCA561_OFFSET_WIN1RAVE 12
+#define SPCA561_OFFSET_WIN1BAVE 13
+#define SPCA561_OFFSET_WIN1GBAVE 14
+#define SPCA561_OFFSET_FREQ 15
+#define SPCA561_OFFSET_VSYNC 16
+#define SPCA561_OFFSET_DATA 1
+#define SPCA561_INDEX_I2C_BASE 0x8800
+#define SPCA561_SNAPBIT 0x20
+#define SPCA561_SNAPCTRL 0x40
+enum {
+ Rev072A = 0,
+ Rev012A,
+};
+
+static void reg_w_val(struct usb_device *dev, __u16 index, __u16 value)
+{
+ int ret;
+
+ ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ 0, /* request */
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value, index, NULL, 0, 500);
+ PDEBUG(D_USBO, "reg write: 0x%02x:0x%02x", index, value);
+ if (ret < 0)
+ PDEBUG(D_ERR, "reg write: error %d", ret);
+}
+
+static void write_vector(struct gspca_dev *gspca_dev,
+ const __u16 data[][2])
+{
+ struct usb_device *dev = gspca_dev->dev;
+ int i;
+
+ i = 0;
+ while (data[i][1] != 0) {
+ reg_w_val(dev, data[i][1], data[i][0]);
+ i++;
+ }
+}
+
+static void reg_r(struct usb_device *dev,
+ __u16 index, __u8 *buffer, __u16 length)
+{
+ usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ 0, /* request */
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, /* value */
+ index, buffer, length, 500);
+}
+
+static void reg_w_buf(struct usb_device *dev,
+ __u16 index, const __u8 *buffer, __u16 len)
+{
+ __u8 tmpbuf[8];
+
+ memcpy(tmpbuf, buffer, len);
+ usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ 0, /* request */
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, /* value */
+ index, tmpbuf, len, 500);
+}
+
+static void i2c_init(struct gspca_dev *gspca_dev, __u8 mode)
+{
+ reg_w_val(gspca_dev->dev, 0x92, 0x8804);
+ reg_w_val(gspca_dev->dev, mode, 0x8802);
+}
+
+static void i2c_write(struct gspca_dev *gspca_dev, __u16 valeur, __u16 reg)
+{
+ int retry = 60;
+ __u8 DataLow;
+ __u8 DataHight;
+ __u8 Data;
+
+ DataLow = valeur;
+ DataHight = valeur >> 8;
+ reg_w_val(gspca_dev->dev, reg, 0x8801);
+ reg_w_val(gspca_dev->dev, DataLow, 0x8805);
+ reg_w_val(gspca_dev->dev, DataHight, 0x8800);
+ while (retry--) {
+ reg_r(gspca_dev->dev, 0x8803, &Data, 1);
+ if (!Data)
+ break;
+ }
+}
+
+static int i2c_read(struct gspca_dev *gspca_dev, __u16 reg, __u8 mode)
+{
+ int retry = 60;
+ __u8 value;
+ __u8 vallsb;
+ __u8 Data;
+
+ reg_w_val(gspca_dev->dev, 0x92, 0x8804);
+ reg_w_val(gspca_dev->dev, reg, 0x8801);
+ reg_w_val(gspca_dev->dev, (mode | 0x01), 0x8802);
+ while (retry--) {
+ reg_r(gspca_dev->dev, 0x8803, &Data, 1);
+ if (!Data)
+ break;
+ }
+ if (retry == 0)
+ return -1;
+ reg_r(gspca_dev->dev, 0x8800, &value, 1);
+ reg_r(gspca_dev->dev, 0x8805, &vallsb, 1);
+ return ((int) value << 8) | vallsb;
+}
+
+static const __u16 spca561_init_data[][2] = {
+ {0x0000, 0x8114}, /* Software GPIO output data */
+ {0x0001, 0x8114}, /* Software GPIO output data */
+ {0x0000, 0x8112}, /* Some kind of reset */
+ {0x0003, 0x8701}, /* PCLK clock delay adjustment */
+ {0x0001, 0x8703}, /* HSYNC from cmos inverted */
+ {0x0011, 0x8118}, /* Enable and conf sensor */
+ {0x0001, 0x8118}, /* Conf sensor */
+ {0x0092, 0x8804}, /* I know nothing about these */
+ {0x0010, 0x8802}, /* 0x88xx registers, so I won't */
+ /***************/
+ {0x000d, 0x8805}, /* sensor default setting */
+ {0x0001, 0x8801}, /* 1 <- 0x0d */
+ {0x0000, 0x8800},
+ {0x0018, 0x8805},
+ {0x0002, 0x8801}, /* 2 <- 0x18 */
+ {0x0000, 0x8800},
+ {0x0065, 0x8805},
+ {0x0004, 0x8801}, /* 4 <- 0x01 0x65 */
+ {0x0001, 0x8800},
+ {0x0021, 0x8805},
+ {0x0005, 0x8801}, /* 5 <- 0x21 */
+ {0x0000, 0x8800},
+ {0x00aa, 0x8805},
+ {0x0007, 0x8801}, /* 7 <- 0xaa */
+ {0x0000, 0x8800},
+ {0x0004, 0x8805},
+ {0x0020, 0x8801}, /* 0x20 <- 0x15 0x04 */
+ {0x0015, 0x8800},
+ {0x0002, 0x8805},
+ {0x0039, 0x8801}, /* 0x39 <- 0x02 */
+ {0x0000, 0x8800},
+ {0x0010, 0x8805},
+ {0x0035, 0x8801}, /* 0x35 <- 0x10 */
+ {0x0000, 0x8800},
+ {0x0049, 0x8805},
+ {0x0009, 0x8801}, /* 0x09 <- 0x10 0x49 */
+ {0x0010, 0x8800},
+ {0x000b, 0x8805},
+ {0x0028, 0x8801}, /* 0x28 <- 0x0b */
+ {0x0000, 0x8800},
+ {0x000f, 0x8805},
+ {0x003b, 0x8801}, /* 0x3b <- 0x0f */
+ {0x0000, 0x8800},
+ {0x0000, 0x8805},
+ {0x003c, 0x8801}, /* 0x3c <- 0x00 */
+ {0x0000, 0x8800},
+ /***************/
+ {0x0018, 0x8601}, /* Pixel/line selection for color separation */
+ {0x0000, 0x8602}, /* Optical black level for user setting */
+ {0x0060, 0x8604}, /* Optical black horizontal offset */
+ {0x0002, 0x8605}, /* Optical black vertical offset */
+ {0x0000, 0x8603}, /* Non-automatic optical black level */
+ {0x0002, 0x865b}, /* Horizontal offset for valid pixels */
+ {0x0000, 0x865f}, /* Vertical valid pixels window (x2) */
+ {0x00b0, 0x865d}, /* Horizontal valid pixels window (x2) */
+ {0x0090, 0x865e}, /* Vertical valid lines window (x2) */
+ {0x00e0, 0x8406}, /* Memory buffer threshold */
+ {0x0000, 0x8660}, /* Compensation memory stuff */
+ {0x0002, 0x8201}, /* Output address for r/w serial EEPROM */
+ {0x0008, 0x8200}, /* Clear valid bit for serial EEPROM */
+ {0x0001, 0x8200}, /* OprMode to be executed by hardware */
+ {0x0007, 0x8201}, /* Output address for r/w serial EEPROM */
+ {0x0008, 0x8200}, /* Clear valid bit for serial EEPROM */
+ {0x0001, 0x8200}, /* OprMode to be executed by hardware */
+ {0x0010, 0x8660}, /* Compensation memory stuff */
+ {0x0018, 0x8660}, /* Compensation memory stuff */
+
+ {0x0004, 0x8611}, /* R offset for white balance */
+ {0x0004, 0x8612}, /* Gr offset for white balance */
+ {0x0007, 0x8613}, /* B offset for white balance */
+ {0x0000, 0x8614}, /* Gb offset for white balance */
+ {0x008c, 0x8651}, /* R gain for white balance */
+ {0x008c, 0x8652}, /* Gr gain for white balance */
+ {0x00b5, 0x8653}, /* B gain for white balance */
+ {0x008c, 0x8654}, /* Gb gain for white balance */
+ {0x0002, 0x8502}, /* Maximum average bit rate stuff */
+
+ {0x0011, 0x8802},
+ {0x0087, 0x8700}, /* Set master clock (96Mhz????) */
+ {0x0081, 0x8702}, /* Master clock output enable */
+
+ {0x0000, 0x8500}, /* Set image type (352x288 no compression) */
+ /* Originally was 0x0010 (352x288 compression) */
+
+ {0x0002, 0x865b}, /* Horizontal offset for valid pixels */
+ {0x0003, 0x865c}, /* Vertical offset for valid lines */
+ /***************//* sensor active */
+ {0x0003, 0x8801}, /* 0x03 <- 0x01 0x21 //289 */
+ {0x0021, 0x8805},
+ {0x0001, 0x8800},
+ {0x0004, 0x8801}, /* 0x04 <- 0x01 0x65 //357 */
+ {0x0065, 0x8805},
+ {0x0001, 0x8800},
+ {0x0005, 0x8801}, /* 0x05 <- 0x2f */
+ {0x002f, 0x8805},
+ {0x0000, 0x8800},
+ {0x0006, 0x8801}, /* 0x06 <- 0 */
+ {0x0000, 0x8805},
+ {0x0000, 0x8800},
+ {0x000a, 0x8801}, /* 0x0a <- 2 */
+ {0x0002, 0x8805},
+ {0x0000, 0x8800},
+ {0x0009, 0x8801}, /* 0x09 <- 0x1061 */
+ {0x0061, 0x8805},
+ {0x0010, 0x8800},
+ {0x0035, 0x8801}, /* 0x35 <-0x14 */
+ {0x0014, 0x8805},
+ {0x0000, 0x8800},
+ {0x0030, 0x8112}, /* ISO and drop packet enable */
+ {0x0000, 0x8112}, /* Some kind of reset ???? */
+ {0x0009, 0x8118}, /* Enable sensor and set standby */
+ {0x0000, 0x8114}, /* Software GPIO output data */
+ {0x0000, 0x8114}, /* Software GPIO output data */
+ {0x0001, 0x8114}, /* Software GPIO output data */
+ {0x0000, 0x8112}, /* Some kind of reset ??? */
+ {0x0003, 0x8701},
+ {0x0001, 0x8703},
+ {0x0011, 0x8118},
+ {0x0001, 0x8118},
+ /***************/
+ {0x0092, 0x8804},
+ {0x0010, 0x8802},
+ {0x000d, 0x8805},
+ {0x0001, 0x8801},
+ {0x0000, 0x8800},
+ {0x0018, 0x8805},
+ {0x0002, 0x8801},
+ {0x0000, 0x8800},
+ {0x0065, 0x8805},
+ {0x0004, 0x8801},
+ {0x0001, 0x8800},
+ {0x0021, 0x8805},
+ {0x0005, 0x8801},
+ {0x0000, 0x8800},
+ {0x00aa, 0x8805},
+ {0x0007, 0x8801}, /* mode 0xaa */
+ {0x0000, 0x8800},
+ {0x0004, 0x8805},
+ {0x0020, 0x8801},
+ {0x0015, 0x8800}, /* mode 0x0415 */
+ {0x0002, 0x8805},
+ {0x0039, 0x8801},
+ {0x0000, 0x8800},
+ {0x0010, 0x8805},
+ {0x0035, 0x8801},
+ {0x0000, 0x8800},
+ {0x0049, 0x8805},
+ {0x0009, 0x8801},
+ {0x0010, 0x8800},
+ {0x000b, 0x8805},
+ {0x0028, 0x8801},
+ {0x0000, 0x8800},
+ {0x000f, 0x8805},
+ {0x003b, 0x8801},
+ {0x0000, 0x8800},
+ {0x0000, 0x8805},
+ {0x003c, 0x8801},
+ {0x0000, 0x8800},
+ {0x0002, 0x8502},
+ {0x0039, 0x8801},
+ {0x0000, 0x8805},
+ {0x0000, 0x8800},
+
+ {0x0087, 0x8700}, /* overwrite by start */
+ {0x0081, 0x8702},
+ {0x0000, 0x8500},
+/* {0x0010, 0x8500}, -- Previous line was this */
+ {0x0002, 0x865b},
+ {0x0003, 0x865c},
+ /***************/
+ {0x0003, 0x8801}, /* 0x121-> 289 */
+ {0x0021, 0x8805},
+ {0x0001, 0x8800},
+ {0x0004, 0x8801}, /* 0x165 -> 357 */
+ {0x0065, 0x8805},
+ {0x0001, 0x8800},
+ {0x0005, 0x8801}, /* 0x2f //blanking control colonne */
+ {0x002f, 0x8805},
+ {0x0000, 0x8800},
+ {0x0006, 0x8801}, /* 0x00 //blanking mode row */
+ {0x0000, 0x8805},
+ {0x0000, 0x8800},
+ {0x000a, 0x8801}, /* 0x01 //0x02 */
+ {0x0001, 0x8805},
+ {0x0000, 0x8800},
+ {0x0009, 0x8801}, /* 0x1061 - setexposure times && pixel clock
+ * 0001 0 | 000 0110 0001 */
+ {0x0061, 0x8805}, /* 61 31 */
+ {0x0008, 0x8800}, /* 08 */
+ {0x0035, 0x8801}, /* 0x14 - set gain general */
+ {0x001f, 0x8805}, /* 0x14 */
+ {0x0000, 0x8800},
+ {0x0030, 0x8112},
+ {}
+};
+
+static void sensor_reset(struct gspca_dev *gspca_dev)
+{
+ reg_w_val(gspca_dev->dev, 0x8631, 0xc8);
+ reg_w_val(gspca_dev->dev, 0x8634, 0xc8);
+ reg_w_val(gspca_dev->dev, 0x8112, 0x00);
+ reg_w_val(gspca_dev->dev, 0x8114, 0x00);
+ reg_w_val(gspca_dev->dev, 0x8118, 0x21);
+ i2c_init(gspca_dev, 0x14);
+ i2c_write(gspca_dev, 1, 0x0d);
+ i2c_write(gspca_dev, 0, 0x0d);
+}
+
+/******************** QC Express etch2 stuff ********************/
+static const __u16 Pb100_1map8300[][2] = {
+ /* reg, value */
+ {0x8320, 0x3304},
+
+ {0x8303, 0x0125}, /* image area */
+ {0x8304, 0x0169},
+ {0x8328, 0x000b},
+ {0x833c, 0x0001},
+
+ {0x832f, 0x0419},
+ {0x8307, 0x00aa},
+ {0x8301, 0x0003},
+ {0x8302, 0x000e},
+ {}
+};
+static const __u16 Pb100_2map8300[][2] = {
+ /* reg, value */
+ {0x8339, 0x0000},
+ {0x8307, 0x00aa},
+ {}
+};
+
+static const __u16 spca561_161rev12A_data1[][2] = {
+ {0x21, 0x8118},
+ {0x01, 0x8114},
+ {0x00, 0x8112},
+ {0x92, 0x8804},
+ {0x04, 0x8802}, /* windows uses 08 */
+ {}
+};
+static const __u16 spca561_161rev12A_data2[][2] = {
+ {0x21, 0x8118},
+ {0x10, 0x8500},
+ {0x07, 0x8601},
+ {0x07, 0x8602},
+ {0x04, 0x8501},
+ {0x21, 0x8118},
+
+ {0x07, 0x8201}, /* windows uses 02 */
+ {0x08, 0x8200},
+ {0x01, 0x8200},
+
+ {0x00, 0x8114},
+ {0x01, 0x8114}, /* windows uses 00 */
+
+ {0x90, 0x8604},
+ {0x00, 0x8605},
+ {0xb0, 0x8603},
+
+ /* sensor gains */
+ {0x00, 0x8610}, /* *red */
+ {0x00, 0x8611}, /* 3f *green */
+ {0x00, 0x8612}, /* green *blue */
+ {0x00, 0x8613}, /* blue *green */
+ {0x35, 0x8614}, /* green *red */
+ {0x35, 0x8615}, /* 40 *green */
+ {0x35, 0x8616}, /* 7a *blue */
+ {0x35, 0x8617}, /* 40 *green */
+
+ {0x0c, 0x8620}, /* 0c */
+ {0xc8, 0x8631}, /* c8 */
+ {0xc8, 0x8634}, /* c8 */
+ {0x23, 0x8635}, /* 23 */
+ {0x1f, 0x8636}, /* 1f */
+ {0xdd, 0x8637}, /* dd */
+ {0xe1, 0x8638}, /* e1 */
+ {0x1d, 0x8639}, /* 1d */
+ {0x21, 0x863a}, /* 21 */
+ {0xe3, 0x863b}, /* e3 */
+ {0xdf, 0x863c}, /* df */
+ {0xf0, 0x8505},
+ {0x32, 0x850a},
+ {}
+};
+
+static void sensor_mapwrite(struct gspca_dev *gspca_dev,
+ const __u16 sensormap[][2])
+{
+ int i = 0;
+ __u8 usbval[2];
+
+ while (sensormap[i][0]) {
+ usbval[0] = sensormap[i][1];
+ usbval[1] = sensormap[i][1] >> 8;
+ reg_w_buf(gspca_dev->dev, sensormap[i][0], usbval, 2);
+ i++;
+ }
+}
+static void init_161rev12A(struct gspca_dev *gspca_dev)
+{
+ sensor_reset(gspca_dev);
+ write_vector(gspca_dev, spca561_161rev12A_data1);
+ sensor_mapwrite(gspca_dev, Pb100_1map8300);
+ write_vector(gspca_dev, spca561_161rev12A_data2);
+ sensor_mapwrite(gspca_dev, Pb100_2map8300);
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+ const struct usb_device_id *id)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+ struct cam *cam;
+ __u16 vendor, product;
+ __u8 data1, data2;
+
+ /* Read frm global register the USB product and vendor IDs, just to
+ * prove that we can communicate with the device. This works, which
+ * confirms at we are communicating properly and that the device
+ * is a 561. */
+ reg_r(dev, 0x8104, &data1, 1);
+ reg_r(dev, 0x8105, &data2, 1);
+ vendor = (data2 << 8) | data1;
+ reg_r(dev, 0x8106, &data1, 1);
+ reg_r(dev, 0x8107, &data2, 1);
+ product = (data2 << 8) | data1;
+ if (vendor != id->idVendor || product != id->idProduct) {
+ PDEBUG(D_PROBE, "Bad vendor / product from device");
+ return -EINVAL;
+ }
+ switch (product) {
+ case 0x0928:
+ case 0x0929:
+ case 0x092a:
+ case 0x092b:
+ case 0x092c:
+ case 0x092d:
+ case 0x092e:
+ case 0x092f:
+ case 0x403b:
+ sd->chip_revision = Rev012A;
+ break;
+ default:
+/* case 0x0561:
+ case 0x0815: * ?? in spca508.c
+ case 0x401a:
+ case 0x7004:
+ case 0x7e50:
+ case 0xa001:
+ case 0xcdee: */
+ sd->chip_revision = Rev072A;
+ break;
+ }
+ cam = &gspca_dev->cam;
+ cam->dev_name = (char *) id->driver_info;
+ cam->epaddr = 0x01;
+ gspca_dev->nbalt = 7 + 1; /* choose alternate 7 first */
+ cam->cam_mode = sif_mode;
+ cam->nmodes = sizeof sif_mode / sizeof sif_mode[0];
+ sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
+ sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
+ sd->autogain = sd_ctrls[SD_AUTOGAIN].qctrl.default_value;
+ return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ switch (sd->chip_revision) {
+ case Rev072A:
+ PDEBUG(D_STREAM, "Chip revision id: 072a");
+ write_vector(gspca_dev, spca561_init_data);
+ break;
+ default:
+/* case Rev012A: */
+ PDEBUG(D_STREAM, "Chip revision id: 012a");
+ init_161rev12A(gspca_dev);
+ break;
+ }
+ return 0;
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+ __u8 lowb;
+ int expotimes;
+
+ switch (sd->chip_revision) {
+ case Rev072A:
+ lowb = sd->contrast >> 8;
+ reg_w_val(dev, lowb, 0x8651);
+ reg_w_val(dev, lowb, 0x8652);
+ reg_w_val(dev, lowb, 0x8653);
+ reg_w_val(dev, lowb, 0x8654);
+ break;
+ case Rev012A: {
+ __u8 Reg8391[] =
+ { 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00 };
+
+ /* Write camera sensor settings */
+ expotimes = (sd->contrast >> 5) & 0x07ff;
+ Reg8391[0] = expotimes & 0xff; /* exposure */
+ Reg8391[1] = 0x18 | (expotimes >> 8);
+ Reg8391[2] = sd->brightness; /* gain */
+ reg_w_buf(dev, 0x8391, Reg8391, 8);
+ reg_w_buf(dev, 0x8390, Reg8391, 8);
+ break;
+ }
+ }
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+ int Clck;
+ __u8 Reg8307[] = { 0xaa, 0x00 };
+ int mode;
+
+ mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
+ switch (sd->chip_revision) {
+ case Rev072A:
+ switch (mode) {
+ default:
+/* case 0:
+ case 1: */
+ Clck = 0x25;
+ break;
+ case 2:
+ Clck = 0x22;
+ break;
+ case 3:
+ Clck = 0x21;
+ break;
+ }
+ reg_w_val(dev, 0x8500, mode); /* mode */
+ reg_w_val(dev, 0x8700, Clck); /* 0x27 clock */
+ reg_w_val(dev, 0x8112, 0x10 | 0x20);
+ break;
+ default:
+/* case Rev012A: */
+ switch (mode) {
+ case 0:
+ case 1:
+ Clck = 0x8a;
+ break;
+ case 2:
+ Clck = 0x85;
+ break;
+ default:
+ Clck = 0x83;
+ break;
+ }
+ if (mode <= 1) {
+ /* Use compression on 320x240 and above */
+ reg_w_val(dev, 0x8500, 0x10 | mode);
+ } else {
+ /* I couldn't get the compression to work below 320x240
+ * Fortunately at these resolutions the bandwidth
+ * is sufficient to push raw frames at ~20fps */
+ reg_w_val(dev, 0x8500, mode);
+ } /* -- qq@kuku.eu.org */
+ reg_w_buf(dev, 0x8307, Reg8307, 2);
+ reg_w_val(dev, 0x8700, Clck); /* 0x8f 0x85 0x27 clock */
+ reg_w_val(dev, 0x8112, 0x1e | 0x20);
+ reg_w_val(dev, 0x850b, 0x03);
+ setcontrast(gspca_dev);
+ break;
+ }
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+ reg_w_val(gspca_dev->dev, 0x8112, 0x20);
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+/* this function is called at close time */
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+ reg_w_val(gspca_dev->dev, 0x8114, 0);
+}
+
+static void setautogain(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int expotimes = 0;
+ int pixelclk = 0;
+ int gainG = 0;
+ __u8 R, Gr, Gb, B;
+ int y;
+ __u8 luma_mean = 110;
+ __u8 luma_delta = 20;
+ __u8 spring = 4;
+
+ switch (sd->chip_revision) {
+ case Rev072A:
+ reg_r(gspca_dev->dev, 0x8621, &Gr, 1);
+ reg_r(gspca_dev->dev, 0x8622, &R, 1);
+ reg_r(gspca_dev->dev, 0x8623, &B, 1);
+ reg_r(gspca_dev->dev, 0x8624, &Gb, 1);
+ y = (77 * R + 75 * (Gr + Gb) + 29 * B) >> 8;
+ /* u= (128*B-(43*(Gr+Gb+R))) >> 8; */
+ /* v= (128*R-(53*(Gr+Gb))-21*B) >> 8; */
+ /* PDEBUG(D_CONF,"reading Y %d U %d V %d ",y,u,v); */
+
+ if (y < luma_mean - luma_delta ||
+ y > luma_mean + luma_delta) {
+ expotimes = i2c_read(gspca_dev, 0x09, 0x10);
+ pixelclk = 0x0800;
+ expotimes = expotimes & 0x07ff;
+ /* PDEBUG(D_PACK,
+ "Exposition Times 0x%03X Clock 0x%04X ",
+ expotimes,pixelclk); */
+ gainG = i2c_read(gspca_dev, 0x35, 0x10);
+ /* PDEBUG(D_PACK,
+ "reading Gain register %d", gainG); */
+
+ expotimes += (luma_mean - y) >> spring;
+ gainG += (luma_mean - y) / 50;
+ /* PDEBUG(D_PACK,
+ "compute expotimes %d gain %d",
+ expotimes,gainG); */
+
+ if (gainG > 0x3f)
+ gainG = 0x3f;
+ else if (gainG < 4)
+ gainG = 3;
+ i2c_write(gspca_dev, gainG, 0x35);
+
+ if (expotimes >= 0x0256)
+ expotimes = 0x0256;
+ else if (expotimes < 4)
+ expotimes = 3;
+ i2c_write(gspca_dev, expotimes | pixelclk, 0x09);
+ }
+ break;
+ case Rev012A:
+ /* sensor registers is access and memory mapped to 0x8300 */
+ /* readind all 0x83xx block the sensor */
+ /*
+ * The data from the header seem wrong where is the luma
+ * and chroma mean value
+ * at the moment set exposure in contrast set
+ */
+ break;
+ }
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ struct gspca_frame *frame, /* target */
+ __u8 *data, /* isoc packet */
+ int len) /* iso packet length */
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ switch (data[0]) {
+ case 0: /* start of frame */
+ frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+ data, 0);
+ if (sd->ag_cnt >= 0) {
+ if (--sd->ag_cnt < 0) {
+ sd->ag_cnt = AG_CNT_START;
+ setautogain(gspca_dev);
+ }
+ }
+ data += SPCA561_OFFSET_DATA;
+ len -= SPCA561_OFFSET_DATA;
+ if (data[1] & 0x10) {
+ /* compressed bayer */
+ gspca_frame_add(gspca_dev, FIRST_PACKET,
+ frame, data, len);
+ } else {
+ /* raw bayer (with a header, which we skip) */
+ data += 20;
+ len -= 20;
+ gspca_frame_add(gspca_dev, FIRST_PACKET,
+ frame, data, len);
+ }
+ return;
+ case 0xff: /* drop */
+/* gspca_dev->last_packet_type = DISCARD_PACKET; */
+ return;
+ }
+ data++;
+ len--;
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ __u8 value;
+
+ switch (sd->chip_revision) {
+ case Rev072A:
+ value = sd->brightness;
+ reg_w_val(gspca_dev->dev, value, 0x8611);
+ reg_w_val(gspca_dev->dev, value, 0x8612);
+ reg_w_val(gspca_dev->dev, value, 0x8613);
+ reg_w_val(gspca_dev->dev, value, 0x8614);
+ break;
+ default:
+/* case Rev012A: */
+ setcontrast(gspca_dev);
+ break;
+ }
+}
+
+static void getbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ __u8 value;
+ __u16 tot;
+
+ switch (sd->chip_revision) {
+ case Rev072A:
+ tot = 0;
+ reg_r(gspca_dev->dev, 0x8611, &value, 1);
+ tot += value;
+ reg_r(gspca_dev->dev, 0x8612, &value, 1);
+ tot += value;
+ reg_r(gspca_dev->dev, 0x8613, &value, 1);
+ tot += value;
+ reg_r(gspca_dev->dev, 0x8614, &value, 1);
+ tot += value;
+ sd->brightness = tot >> 2;
+ break;
+ default:
+/* case Rev012A: */
+ /* no way to read sensor settings */
+ break;
+ }
+}
+
+static void getcontrast(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ __u8 value;
+ __u16 tot;
+
+ switch (sd->chip_revision) {
+ case Rev072A:
+ tot = 0;
+ reg_r(gspca_dev->dev, 0x8651, &value, 1);
+ tot += value;
+ reg_r(gspca_dev->dev, 0x8652, &value, 1);
+ tot += value;
+ reg_r(gspca_dev->dev, 0x8653, &value, 1);
+ tot += value;
+ reg_r(gspca_dev->dev, 0x8654, &value, 1);
+ tot += value;
+ sd->contrast = tot << 6;
+ break;
+ default:
+/* case Rev012A: */
+ /* no way to read sensor settings */
+ break;
+ }
+ PDEBUG(D_CONF, "get contrast %d", sd->contrast);
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->brightness = val;
+ if (gspca_dev->streaming)
+ setbrightness(gspca_dev);
+ return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ getbrightness(gspca_dev);
+ *val = sd->brightness;
+ return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->contrast = val;
+ if (gspca_dev->streaming)
+ setcontrast(gspca_dev);
+ return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ getcontrast(gspca_dev);
+ *val = sd->contrast;
+ return 0;
+}
+
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->autogain = val;
+ if (val)
+ sd->ag_cnt = AG_CNT_START;
+ else
+ sd->ag_cnt = -1;
+ return 0;
+}
+
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->autogain;
+ return 0;
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .ctrls = sd_ctrls,
+ .nctrls = ARRAY_SIZE(sd_ctrls),
+ .config = sd_config,
+ .open = sd_open,
+ .start = sd_start,
+ .stopN = sd_stopN,
+ .stop0 = sd_stop0,
+ .close = sd_close,
+ .pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static const __devinitdata struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x041e, 0x401a), DVNM("Creative Webcam Vista (PD1100)")},
+ {USB_DEVICE(0x041e, 0x403b), DVNM("Creative Webcam Vista (VF0010)")},
+ {USB_DEVICE(0x0458, 0x7004), DVNM("Genius VideoCAM Express V2")},
+ {USB_DEVICE(0x046d, 0x0928), DVNM("Logitech QC Express Etch2")},
+ {USB_DEVICE(0x046d, 0x0929), DVNM("Labtec Webcam Elch2")},
+ {USB_DEVICE(0x046d, 0x092a), DVNM("Logitech QC for Notebook")},
+ {USB_DEVICE(0x046d, 0x092b), DVNM("Labtec Webcam Plus")},
+ {USB_DEVICE(0x046d, 0x092c), DVNM("Logitech QC chat Elch2")},
+ {USB_DEVICE(0x046d, 0x092d), DVNM("Logitech QC Elch2")},
+ {USB_DEVICE(0x046d, 0x092e), DVNM("Logitech QC Elch2")},
+ {USB_DEVICE(0x046d, 0x092f), DVNM("Logitech QC Elch2")},
+ {USB_DEVICE(0x04fc, 0x0561), DVNM("Flexcam 100")},
+ {USB_DEVICE(0x060b, 0xa001), DVNM("Maxell Compact Pc PM3")},
+ {USB_DEVICE(0x10fd, 0x7e50), DVNM("FlyCam Usb 100")},
+ {USB_DEVICE(0xabcd, 0xcdee), DVNM("Petcam")},
+ {}
+};
+
+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,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+ if (usb_register(&sd_driver) < 0)
+ return -1;
+ PDEBUG(D_PROBE, "v%s registered", version);
+ return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+ usb_deregister(&sd_driver);
+ PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/linux/drivers/media/video/gspca/stk014.c b/linux/drivers/media/video/gspca/stk014.c
new file mode 100644
index 000000000..d676cd16a
--- /dev/null
+++ b/linux/drivers/media/video/gspca/stk014.c
@@ -0,0 +1,596 @@
+/*
+ * Syntek DV4000 (STK014) subdriver
+ *
+ * Copyright (C) 2008 Jean-Francois Moine (http://moinejf.free.fr)
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define MODULE_NAME "stk014"
+
+#include "gspca.h"
+#include "jpeg.h"
+
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 5)
+static const char version[] = "2.1.5";
+
+MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>");
+MODULE_DESCRIPTION("Syntek DV4000 (STK014) USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+
+ unsigned char brightness;
+ unsigned char contrast;
+ unsigned char colors;
+ unsigned char lightfreq;
+};
+
+/* global parameters */
+static int sd_quant = 7; /* <= 4 KO - 7: good (enough!) */
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+ {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+#define BRIGHTNESS_DEF 127
+ .default_value = BRIGHTNESS_DEF,
+ },
+ .set = sd_setbrightness,
+ .get = sd_getbrightness,
+ },
+ {
+ {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+#define CONTRAST_DEF 127
+ .default_value = CONTRAST_DEF,
+ },
+ .set = sd_setcontrast,
+ .get = sd_getcontrast,
+ },
+ {
+ {
+ .id = V4L2_CID_SATURATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Color",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+#define COLOR_DEF 127
+ .default_value = COLOR_DEF,
+ },
+ .set = sd_setcolors,
+ .get = sd_getcolors,
+ },
+ {
+ {
+ .id = V4L2_CID_POWER_LINE_FREQUENCY,
+ .type = V4L2_CTRL_TYPE_MENU,
+ .name = "Light frequency filter",
+ .minimum = 1,
+ .maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */
+ .step = 1,
+#define FREQ_DEF 1
+ .default_value = FREQ_DEF,
+ },
+ .set = sd_setfreq,
+ .get = sd_getfreq,
+ },
+};
+
+static struct v4l2_pix_format vga_mode[] = {
+ {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 1},
+ {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 0},
+};
+
+/* -- read a register -- */
+static int reg_r(struct gspca_dev *gspca_dev,
+ __u16 index, __u8 *buf)
+{
+ struct usb_device *dev = gspca_dev->dev;
+ int ret;
+
+ ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ 0x00,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0x00,
+ index,
+ buf, 1,
+ 500);
+ if (ret < 0)
+ PDEBUG(D_ERR, "reg_r err %d", ret);
+ return ret;
+}
+
+/* -- write a register -- */
+static int reg_w(struct gspca_dev *gspca_dev,
+ __u16 index, __u16 value)
+{
+ struct usb_device *dev = gspca_dev->dev;
+ int ret;
+
+ ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ 0x01,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value,
+ index,
+ NULL,
+ 0,
+ 500);
+ if (ret < 0)
+ PDEBUG(D_ERR, "reg_w err %d", ret);
+ return ret;
+}
+
+/* -- get a value -- */
+static int rcv_val(struct gspca_dev *gspca_dev,
+ int ads,
+ int len)
+{
+ struct usb_device *dev = gspca_dev->dev;
+ int alen, ret;
+ unsigned char bulk_buf[4];
+
+ reg_w(gspca_dev, 0x634, (ads >> 16) & 0xff);
+ reg_w(gspca_dev, 0x635, (ads >> 8) & 0xff);
+ reg_w(gspca_dev, 0x636, ads & 0xff);
+ reg_w(gspca_dev, 0x637, 0);
+ reg_w(gspca_dev, 0x638, len & 0xff);
+ reg_w(gspca_dev, 0x639, len >> 8);
+ reg_w(gspca_dev, 0x63a, 0);
+ reg_w(gspca_dev, 0x63b, 0);
+ reg_w(gspca_dev, 0x630, 5);
+ if (len > sizeof bulk_buf)
+ return -1;
+ ret = usb_bulk_msg(dev,
+ usb_rcvbulkpipe(dev, 5),
+ bulk_buf,
+ len,
+ &alen,
+ 500); /* timeout in milliseconds */
+ return ret;
+}
+
+/* -- send a value -- */
+static int snd_val(struct gspca_dev *gspca_dev,
+ int ads,
+ unsigned int val)
+{
+ struct usb_device *dev = gspca_dev->dev;
+ int alen, ret;
+ __u8 value, seq;
+ unsigned char bulk_buf[4];
+
+ if (ads == 0x003f08) {
+ ret = reg_r(gspca_dev, 0x0704, &value);
+ if (ret < 0)
+ goto ko;
+ ret = reg_r(gspca_dev, 0x0705, &seq);
+ if (ret < 0)
+ goto ko;
+ ret = reg_r(gspca_dev, 0x0650, &value);
+ if (ret < 0)
+ goto ko;
+ reg_w(gspca_dev, 0x654, seq);
+ } else
+ reg_w(gspca_dev, 0x654, (ads >> 16) & 0xff);
+ reg_w(gspca_dev, 0x655, (ads >> 8) & 0xff);
+ reg_w(gspca_dev, 0x656, ads & 0xff);
+ reg_w(gspca_dev, 0x657, 0);
+ reg_w(gspca_dev, 0x658, 0x04); /* size */
+ reg_w(gspca_dev, 0x659, 0);
+ reg_w(gspca_dev, 0x65a, 0);
+ reg_w(gspca_dev, 0x65b, 0);
+ reg_w(gspca_dev, 0x650, 5);
+ bulk_buf[0] = (val >> 24) & 0xff;
+ bulk_buf[1] = (val >> 16) & 0xff;
+ bulk_buf[2] = (val >> 8) & 0xff;
+ bulk_buf[3] = val & 0xff;
+ ret = usb_bulk_msg(dev,
+ usb_sndbulkpipe(dev, 6),
+ bulk_buf,
+ 4,
+ &alen,
+ 500); /* timeout in milliseconds */
+ if (ret < 0)
+ goto ko;
+ if (ads == 0x003f08) {
+ seq += 4;
+ seq &= 0x3f;
+ reg_w(gspca_dev, 0x705, seq);
+ }
+ return ret;
+ko:
+ PDEBUG(D_ERR, "snd_val err %d", ret);
+ return ret;
+}
+
+/* set a camera parameter */
+static int set_par(struct gspca_dev *gspca_dev,
+ int parval)
+{
+ return snd_val(gspca_dev, 0x003f08, parval);
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int parval;
+
+ parval = 0x06000000 /* whiteness */
+ + (sd->brightness << 16);
+ set_par(gspca_dev, parval);
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int parval;
+
+ parval = 0x07000000 /* contrast */
+ + (sd->contrast << 16);
+ set_par(gspca_dev, parval);
+}
+
+static void setcolors(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int parval;
+
+ parval = 0x08000000 /* saturation */
+ + (sd->colors << 16);
+ set_par(gspca_dev, parval);
+}
+
+static void setfreq(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ set_par(gspca_dev, sd->lightfreq == 1
+ ? 0x33640000 /* 50 Hz */
+ : 0x33780000); /* 60 Hz */
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+ const struct usb_device_id *id)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct cam *cam = &gspca_dev->cam;
+
+ cam->dev_name = (char *) id->driver_info;
+ cam->epaddr = 0x02;
+ gspca_dev->cam.cam_mode = vga_mode;
+ gspca_dev->cam.nmodes = sizeof vga_mode / sizeof vga_mode[0];
+ sd->brightness = BRIGHTNESS_DEF;
+ sd->contrast = CONTRAST_DEF;
+ sd->colors = COLOR_DEF;
+ sd->lightfreq = FREQ_DEF;
+ return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+ __u8 value;
+ int ret;
+
+ /* check if the device responds */
+ usb_set_interface(gspca_dev->dev, gspca_dev->iface, 1);
+ ret = reg_r(gspca_dev, 0x0740, &value);
+ if (ret < 0)
+ return ret;
+ if (value != 0xff) {
+ PDEBUG(D_ERR|D_STREAM, "init reg: 0x%02x", value);
+ return -1;
+ }
+ return 0;
+}
+
+/* -- start the camera -- */
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+ __u8 dum;
+ int ret, value;
+
+ /* work on alternate 1 */
+ usb_set_interface(gspca_dev->dev, gspca_dev->iface, 1);
+
+ set_par(gspca_dev, 0x10000000);
+ set_par(gspca_dev, 0x00000000);
+ set_par(gspca_dev, 0x8002e001);
+ set_par(gspca_dev, 0x14000000);
+ if (gspca_dev->width > 320)
+ value = 0x8002e001; /* 640x480 */
+ else
+ value = 0x4001f000; /* 320x240 */
+ set_par(gspca_dev, value);
+ ret = usb_set_interface(gspca_dev->dev,
+ gspca_dev->iface,
+ gspca_dev->alt);
+ if (ret < 0) {
+ PDEBUG(D_ERR|D_STREAM, "set intf %d %d failed",
+ gspca_dev->iface, gspca_dev->alt);
+ goto out;
+ }
+ ret = reg_r(gspca_dev, 0x0630, &dum);
+ if (ret < 0)
+ goto out;
+ rcv_val(gspca_dev, 0x000020, 4); /* << (value ff ff ff ff) */
+ ret = reg_r(gspca_dev, 0x0650, &dum);
+ if (ret < 0)
+ goto out;
+ snd_val(gspca_dev, 0x000020, 0xffffffff);
+ reg_w(gspca_dev, 0x0620, 0);
+ reg_w(gspca_dev, 0x0630, 0);
+ reg_w(gspca_dev, 0x0640, 0);
+ reg_w(gspca_dev, 0x0650, 0);
+ reg_w(gspca_dev, 0x0660, 0);
+ setbrightness(gspca_dev); /* whiteness */
+ setcontrast(gspca_dev); /* contrast */
+ setcolors(gspca_dev); /* saturation */
+ set_par(gspca_dev, 0x09800000); /* Red ? */
+ set_par(gspca_dev, 0x0a800000); /* Green ? */
+ set_par(gspca_dev, 0x0b800000); /* Blue ? */
+ set_par(gspca_dev, 0x0d030000); /* Gamma ? */
+ setfreq(gspca_dev); /* light frequency */
+
+ /* start the video flow */
+ set_par(gspca_dev, 0x01000000);
+ set_par(gspca_dev, 0x01000000);
+ PDEBUG(D_STREAM, "camera started alt: 0x%02x", gspca_dev->alt);
+ return;
+out:
+ PDEBUG(D_ERR|D_STREAM, "camera start err %d", ret);
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+ struct usb_device *dev = gspca_dev->dev;
+ __u8 value;
+
+ set_par(gspca_dev, 0x02000000);
+ set_par(gspca_dev, 0x02000000);
+ usb_set_interface(dev, gspca_dev->iface, 1);
+ reg_r(gspca_dev, 0x0630, &value);
+ rcv_val(gspca_dev, 0x000020, 4); /* << (value ff ff ff ff) */
+ reg_r(gspca_dev, 0x0650, &value);
+ snd_val(gspca_dev, 0x000020, 0xffffffff);
+ reg_w(gspca_dev, 0x0620, 0);
+ reg_w(gspca_dev, 0x0630, 0);
+ reg_w(gspca_dev, 0x0640, 0);
+ reg_w(gspca_dev, 0x0650, 0);
+ reg_w(gspca_dev, 0x0660, 0);
+ PDEBUG(D_STREAM, "camera stopped");
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ struct gspca_frame *frame, /* target */
+ __u8 *data, /* isoc packet */
+ int len) /* iso packet length */
+{
+ static unsigned char ffd9[] = {0xff, 0xd9};
+
+ /* a frame starts with:
+ * - 0xff 0xfe
+ * - 0x08 0x00 - length (little endian ?!)
+ * - 4 bytes = size of whole frame (BE - including header)
+ * - 0x00 0x0c
+ * - 0xff 0xd8
+ * - .. JPEG image with escape sequences (ff 00)
+ * (without ending - ff d9)
+ */
+ if (data[0] == 0xff && data[1] == 0xfe) {
+ frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+ ffd9, 2);
+
+ /* put the JPEG 411 header */
+ jpeg_put_header(gspca_dev, frame, sd_quant, 0x22);
+
+ /* beginning of the frame */
+#define STKHDRSZ 12
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+ data + STKHDRSZ, len - STKHDRSZ);
+#undef STKHDRSZ
+ return;
+ }
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->brightness = val;
+ if (gspca_dev->streaming)
+ setbrightness(gspca_dev);
+ return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->brightness;
+ return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->contrast = val;
+ if (gspca_dev->streaming)
+ setcontrast(gspca_dev);
+ return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->contrast;
+ return 0;
+}
+
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->colors = val;
+ if (gspca_dev->streaming)
+ setcolors(gspca_dev);
+ return 0;
+}
+
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->colors;
+ return 0;
+}
+
+static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->lightfreq = val;
+ if (gspca_dev->streaming)
+ setfreq(gspca_dev);
+ return 0;
+}
+
+static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->lightfreq;
+ return 0;
+}
+
+static int sd_querymenu(struct gspca_dev *gspca_dev,
+ struct v4l2_querymenu *menu)
+{
+ switch (menu->id) {
+ case V4L2_CID_POWER_LINE_FREQUENCY:
+ switch (menu->index) {
+ case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
+ strcpy((char *) menu->name, "50 Hz");
+ return 0;
+ case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
+ strcpy((char *) menu->name, "60 Hz");
+ return 0;
+ }
+ break;
+ }
+ return -EINVAL;
+}
+
+/* sub-driver description */
+static struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .ctrls = sd_ctrls,
+ .nctrls = sizeof sd_ctrls / sizeof sd_ctrls[0],
+ .config = sd_config,
+ .open = sd_open,
+ .start = sd_start,
+ .stopN = sd_stopN,
+ .stop0 = sd_stop0,
+ .close = sd_close,
+ .pkt_scan = sd_pkt_scan,
+ .querymenu = sd_querymenu,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static __devinitdata struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x05e1, 0x0893), DVNM("Syntek DV4000")},
+ {}
+};
+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,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+ if (usb_register(&sd_driver) < 0)
+ return -1;
+ info("v%s registered", version);
+ return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+ usb_deregister(&sd_driver);
+ info("deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
+
+module_param_named(quant, sd_quant, int, 0644);
+MODULE_PARM_DESC(quant, "Quantization index (0..8)");
diff --git a/linux/drivers/media/video/gspca/sunplus.c b/linux/drivers/media/video/gspca/sunplus.c
new file mode 100644
index 000000000..6e02726ee
--- /dev/null
+++ b/linux/drivers/media/video/gspca/sunplus.c
@@ -0,0 +1,1701 @@
+/*
+ * Sunplus spca504(abc) spca533 spca536 library
+ * Copyright (C) 2005 Michel Xhaard mxhaard@magic.fr
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define MODULE_NAME "sunplus"
+
+#include "gspca.h"
+#include "jpeg.h"
+
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 5)
+static const char version[] = "2.1.5";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("GSPCA/SPCA5xx USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+
+ __u8 packet[ISO_MAX_SIZE + 128];
+ /* !! no more than 128 ff in an ISO packet */
+
+ unsigned char brightness;
+ unsigned char contrast;
+ unsigned char colors;
+ unsigned char autogain;
+
+ char qindex;
+ char bridge;
+#define BRIDGE_SPCA504 0
+#define BRIDGE_SPCA504B 1
+#define BRIDGE_SPCA504C 2
+#define BRIDGE_SPCA533 3
+#define BRIDGE_SPCA536 4
+ char subtype;
+#define AiptekMiniPenCam13 1
+#define LogitechClickSmart420 2
+#define LogitechClickSmart820 3
+#define MegapixV4 4
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+#define SD_BRIGHTNESS 0
+ {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+ .maximum = 0xff,
+ .step = 1,
+ .default_value = 0,
+ },
+ .set = sd_setbrightness,
+ .get = sd_getbrightness,
+ },
+#define SD_CONTRAST 1
+ {
+ {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = 0,
+ .maximum = 0xff,
+ .step = 1,
+ .default_value = 0x20,
+ },
+ .set = sd_setcontrast,
+ .get = sd_getcontrast,
+ },
+#define SD_COLOR 2
+ {
+ {
+ .id = V4L2_CID_SATURATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Color",
+ .minimum = 0,
+ .maximum = 0xff,
+ .step = 1,
+ .default_value = 0x1a,
+ },
+ .set = sd_setcolors,
+ .get = sd_getcolors,
+ },
+#define SD_AUTOGAIN 3
+ {
+ {
+ .id = V4L2_CID_AUTOGAIN,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Auto Gain",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 1,
+ },
+ .set = sd_setautogain,
+ .get = sd_getautogain,
+ },
+};
+
+static struct v4l2_pix_format vga_mode[] = {
+ {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 2},
+ {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 1},
+};
+
+static struct v4l2_pix_format custom_mode[] = {
+ {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 2},
+ {464, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 464,
+ .sizeimage = 464 * 480 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 1},
+};
+
+static struct v4l2_pix_format vga_mode2[] = {
+ {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 176,
+ .sizeimage = 176 * 144 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 4},
+ {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 3},
+ {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 352,
+ .sizeimage = 352 * 288 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 2},
+ {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 1},
+};
+
+#define SPCA50X_OFFSET_DATA 10
+#define SPCA504_PCCAM600_OFFSET_SNAPSHOT 3
+#define SPCA504_PCCAM600_OFFSET_COMPRESS 4
+#define SPCA504_PCCAM600_OFFSET_MODE 5
+#define SPCA504_PCCAM600_OFFSET_DATA 14
+ /* Frame packet header offsets for the spca533 */
+#define SPCA533_OFFSET_DATA 16
+#define SPCA533_OFFSET_FRAMSEQ 15
+/* Frame packet header offsets for the spca536 */
+#define SPCA536_OFFSET_DATA 4
+#define SPCA536_OFFSET_FRAMSEQ 1
+
+/* Initialisation data for the Creative PC-CAM 600 */
+static const __u16 spca504_pccam600_init_data[][3] = {
+/* {0xa0, 0x0000, 0x0503}, * capture mode */
+ {0x00, 0x0000, 0x2000},
+ {0x00, 0x0013, 0x2301},
+ {0x00, 0x0003, 0x2000},
+ {0x00, 0x0001, 0x21ac},
+ {0x00, 0x0001, 0x21a6},
+ {0x00, 0x0000, 0x21a7}, /* brightness */
+ {0x00, 0x0020, 0x21a8}, /* contrast */
+ {0x00, 0x0001, 0x21ac}, /* sat/hue */
+ {0x00, 0x0000, 0x21ad}, /* hue */
+ {0x00, 0x001a, 0x21ae}, /* saturation */
+ {0x00, 0x0002, 0x21a3}, /* gamma */
+#if 0
+ {0xb0, 0x0000, 0x0000}, /* reset auto exposure */
+ {0x0c, 0x0000, 0x0000}, /* reset auto whiteness */
+ {0x0c, 0x0004, 0x0000}, /* enable auto whiteness */
+ {0x30, 0x020f, 0x0001}, /* exposure compensation */
+ {0x30, 0x01f7, 0x0002}, /* whiteness balance */
+#endif
+ {0x30, 0x0154, 0x0008},
+ {0x30, 0x0004, 0x0006},
+ {0x30, 0x0258, 0x0009},
+ {0x30, 0x0004, 0x0000},
+ {0x30, 0x0093, 0x0004},
+ {0x30, 0x0066, 0x0005},
+ {0x00, 0x0000, 0x2000},
+ {0x00, 0x0013, 0x2301},
+ {0x00, 0x0003, 0x2000},
+ {0x00, 0x0013, 0x2301},
+ {0x00, 0x0003, 0x2000},
+ {}
+};
+
+/* Creative PC-CAM 600 specific open data, sent before using the
+ * generic initialisation data from spca504_open_data.
+ */
+static const __u16 spca504_pccam600_open_data[][3] = {
+ {0x00, 0x0001, 0x2501},
+ {0x20, 0x0500, 0x0001}, /* snapshot mode */
+ {0x00, 0x0003, 0x2880},
+ {0x00, 0x0001, 0x2881},
+ {}
+};
+
+/* Initialisation data for the logitech clicksmart 420 */
+static const __u16 spca504A_clicksmart420_init_data[][3] = {
+/* {0xa0, 0x0000, 0x0503}, * capture mode */
+ {0x00, 0x0000, 0x2000},
+ {0x00, 0x0013, 0x2301},
+ {0x00, 0x0003, 0x2000},
+ {0x00, 0x0001, 0x21ac},
+ {0x00, 0x0001, 0x21a6},
+ {0x00, 0x0000, 0x21a7}, /* brightness */
+ {0x00, 0x0020, 0x21a8}, /* contrast */
+ {0x00, 0x0001, 0x21ac}, /* sat/hue */
+ {0x00, 0x0000, 0x21ad}, /* hue */
+ {0x00, 0x001a, 0x21ae}, /* saturation */
+ {0x00, 0x0002, 0x21a3}, /* gamma */
+#if 1
+ {0x30, 0x0004, 0x000a},
+ {0xb0, 0x0001, 0x0000},
+#endif
+
+#if 0
+ {0xb0, 0x0000, 0x0000}, /* reset auto exposure */
+ {0x0c, 0x0000, 0x0000}, /* reset auto whiteness */
+ {0x0c, 0x0004, 0x0000}, /* enable auto whiteness */
+ {0x30, 0x020f, 0x0001}, /* exposure compensation */
+ {0x30, 0x01f7, 0x0002}, /* whiteness balance */
+#endif
+
+#if 1
+ {0x0a1, 0x0080, 0x0001},
+ {0x30, 0x0049, 0x0000},
+ {0x30, 0x0060, 0x0005},
+ {0x0c, 0x0004, 0x0000},
+ {0x00, 0x0000, 0x0000},
+ {0x00, 0x0000, 0x2000},
+ {0x00, 0x0013, 0x2301},
+ {0x00, 0x0003, 0x2000},
+ {0x00, 0x0000, 0x2000},
+#endif
+
+#if 0
+ {0x30, 0x0154, 0x0008},
+ {0x30, 0x0004, 0x0006},
+ {0x30, 0x0258, 0x0009},
+ {0x30, 0x0004, 0x0000},
+ {0x30, 0x0093, 0x0004},
+ {0x30, 0x0066, 0x0005},
+ {0x00, 0x0000, 0x2000},
+ {0x00, 0x0013, 0x2301},
+ {0x00, 0x0003, 0x2000},
+ {0x00, 0x0013, 0x2301},
+ {0x00, 0x0003, 0x2000},
+#endif
+ {}
+};
+
+/* clicksmart 420 open data ? */
+static const __u16 spca504A_clicksmart420_open_data[][3] = {
+ {0x00, 0x0001, 0x2501},
+ {0x20, 0x0502, 0x0000},
+ {0x06, 0x0000, 0x0000},
+ {0x00, 0x0004, 0x2880},
+ {0x00, 0x0001, 0x2881},
+/* look like setting a qTable */
+ {0x00, 0x0006, 0x2800},
+ {0x00, 0x0004, 0x2801},
+ {0x00, 0x0004, 0x2802},
+ {0x00, 0x0006, 0x2803},
+ {0x00, 0x000a, 0x2804},
+ {0x00, 0x0010, 0x2805},
+ {0x00, 0x0014, 0x2806},
+ {0x00, 0x0018, 0x2807},
+ {0x00, 0x0005, 0x2808},
+ {0x00, 0x0005, 0x2809},
+ {0x00, 0x0006, 0x280a},
+ {0x00, 0x0008, 0x280b},
+ {0x00, 0x000a, 0x280c},
+ {0x00, 0x0017, 0x280d},
+ {0x00, 0x0018, 0x280e},
+ {0x00, 0x0016, 0x280f},
+
+ {0x00, 0x0006, 0x2810},
+ {0x00, 0x0005, 0x2811},
+ {0x00, 0x0006, 0x2812},
+ {0x00, 0x000a, 0x2813},
+ {0x00, 0x0010, 0x2814},
+ {0x00, 0x0017, 0x2815},
+ {0x00, 0x001c, 0x2816},
+ {0x00, 0x0016, 0x2817},
+ {0x00, 0x0006, 0x2818},
+ {0x00, 0x0007, 0x2819},
+ {0x00, 0x0009, 0x281a},
+ {0x00, 0x000c, 0x281b},
+ {0x00, 0x0014, 0x281c},
+ {0x00, 0x0023, 0x281d},
+ {0x00, 0x0020, 0x281e},
+ {0x00, 0x0019, 0x281f},
+
+ {0x00, 0x0007, 0x2820},
+ {0x00, 0x0009, 0x2821},
+ {0x00, 0x000f, 0x2822},
+ {0x00, 0x0016, 0x2823},
+ {0x00, 0x001b, 0x2824},
+ {0x00, 0x002c, 0x2825},
+ {0x00, 0x0029, 0x2826},
+ {0x00, 0x001f, 0x2827},
+ {0x00, 0x000a, 0x2828},
+ {0x00, 0x000e, 0x2829},
+ {0x00, 0x0016, 0x282a},
+ {0x00, 0x001a, 0x282b},
+ {0x00, 0x0020, 0x282c},
+ {0x00, 0x002a, 0x282d},
+ {0x00, 0x002d, 0x282e},
+ {0x00, 0x0025, 0x282f},
+
+ {0x00, 0x0014, 0x2830},
+ {0x00, 0x001a, 0x2831},
+ {0x00, 0x001f, 0x2832},
+ {0x00, 0x0023, 0x2833},
+ {0x00, 0x0029, 0x2834},
+ {0x00, 0x0030, 0x2835},
+ {0x00, 0x0030, 0x2836},
+ {0x00, 0x0028, 0x2837},
+ {0x00, 0x001d, 0x2838},
+ {0x00, 0x0025, 0x2839},
+ {0x00, 0x0026, 0x283a},
+ {0x00, 0x0027, 0x283b},
+ {0x00, 0x002d, 0x283c},
+ {0x00, 0x0028, 0x283d},
+ {0x00, 0x0029, 0x283e},
+ {0x00, 0x0028, 0x283f},
+
+ {0x00, 0x0007, 0x2840},
+ {0x00, 0x0007, 0x2841},
+ {0x00, 0x000a, 0x2842},
+ {0x00, 0x0013, 0x2843},
+ {0x00, 0x0028, 0x2844},
+ {0x00, 0x0028, 0x2845},
+ {0x00, 0x0028, 0x2846},
+ {0x00, 0x0028, 0x2847},
+ {0x00, 0x0007, 0x2848},
+ {0x00, 0x0008, 0x2849},
+ {0x00, 0x000a, 0x284a},
+ {0x00, 0x001a, 0x284b},
+ {0x00, 0x0028, 0x284c},
+ {0x00, 0x0028, 0x284d},
+ {0x00, 0x0028, 0x284e},
+ {0x00, 0x0028, 0x284f},
+
+ {0x00, 0x000a, 0x2850},
+ {0x00, 0x000a, 0x2851},
+ {0x00, 0x0016, 0x2852},
+ {0x00, 0x0028, 0x2853},
+ {0x00, 0x0028, 0x2854},
+ {0x00, 0x0028, 0x2855},
+ {0x00, 0x0028, 0x2856},
+ {0x00, 0x0028, 0x2857},
+ {0x00, 0x0013, 0x2858},
+ {0x00, 0x001a, 0x2859},
+ {0x00, 0x0028, 0x285a},
+ {0x00, 0x0028, 0x285b},
+ {0x00, 0x0028, 0x285c},
+ {0x00, 0x0028, 0x285d},
+ {0x00, 0x0028, 0x285e},
+ {0x00, 0x0028, 0x285f},
+
+ {0x00, 0x0028, 0x2860},
+ {0x00, 0x0028, 0x2861},
+ {0x00, 0x0028, 0x2862},
+ {0x00, 0x0028, 0x2863},
+ {0x00, 0x0028, 0x2864},
+ {0x00, 0x0028, 0x2865},
+ {0x00, 0x0028, 0x2866},
+ {0x00, 0x0028, 0x2867},
+ {0x00, 0x0028, 0x2868},
+ {0x00, 0x0028, 0x2869},
+ {0x00, 0x0028, 0x286a},
+ {0x00, 0x0028, 0x286b},
+ {0x00, 0x0028, 0x286c},
+ {0x00, 0x0028, 0x286d},
+ {0x00, 0x0028, 0x286e},
+ {0x00, 0x0028, 0x286f},
+
+ {0x00, 0x0028, 0x2870},
+ {0x00, 0x0028, 0x2871},
+ {0x00, 0x0028, 0x2872},
+ {0x00, 0x0028, 0x2873},
+ {0x00, 0x0028, 0x2874},
+ {0x00, 0x0028, 0x2875},
+ {0x00, 0x0028, 0x2876},
+ {0x00, 0x0028, 0x2877},
+ {0x00, 0x0028, 0x2878},
+ {0x00, 0x0028, 0x2879},
+ {0x00, 0x0028, 0x287a},
+ {0x00, 0x0028, 0x287b},
+ {0x00, 0x0028, 0x287c},
+ {0x00, 0x0028, 0x287d},
+ {0x00, 0x0028, 0x287e},
+ {0x00, 0x0028, 0x287f},
+
+ {0xa0, 0x0000, 0x0503},
+ {}
+};
+
+static const __u8 qtable_creative_pccam[2][64] = {
+ { /* Q-table Y-components */
+ 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
+ 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
+ 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11,
+ 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13,
+ 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17,
+ 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c,
+ 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e,
+ 0x16, 0x1c, 0x1d, 0x1d, 0x22, 0x1e, 0x1f, 0x1e},
+ { /* Q-table C-components */
+ 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e,
+ 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e,
+ 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+ 0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+ 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+ 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+ 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+ 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
+};
+
+/* FIXME: This Q-table is identical to the Creative PC-CAM one,
+ * except for one byte. Possibly a typo?
+ * NWG: 18/05/2003.
+ */
+static const __u8 qtable_spca504_default[2][64] = {
+ { /* Q-table Y-components */
+ 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
+ 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
+ 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11,
+ 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13,
+ 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17,
+ 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c,
+ 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e,
+ 0x16, 0x1c, 0x1d, 0x1d, 0x1d /* 0x22 */ , 0x1e, 0x1f, 0x1e,
+ },
+ { /* Q-table C-components */
+ 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e,
+ 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e,
+ 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+ 0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+ 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+ 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+ 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+ 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
+};
+
+static void spca5xxRegRead(struct usb_device *dev,
+ __u16 req,
+ __u16 index,
+ __u8 *buffer, __u16 length)
+{
+ usb_control_msg(dev,
+ usb_rcvctrlpipe(dev, 0),
+ req,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, /* value */
+ index, buffer, length,
+ 500);
+}
+
+static void spca5xxRegWrite(struct usb_device *dev,
+ __u16 req,
+ __u16 value,
+ __u16 index,
+ __u8 *buffer, __u16 length)
+{
+ usb_control_msg(dev,
+ usb_sndctrlpipe(dev, 0),
+ req,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value, index, buffer, length,
+ 500);
+}
+
+static int reg_write(struct usb_device *dev,
+ __u16 req, __u16 index, __u16 value)
+{
+ int ret;
+
+ ret = usb_control_msg(dev,
+ usb_sndctrlpipe(dev, 0),
+ req,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value, index, NULL, 0, 500);
+ PDEBUG(D_PACK, "reg write: 0x%02x,0x%02x:0x%02x, 0x%x",
+ req, index, value, ret);
+ if (ret < 0)
+ PDEBUG(D_ERR, "reg write: error %d", ret);
+ return ret;
+}
+
+static int reg_read_info(struct usb_device *dev,
+ __u16 value) /* wValue */
+{
+ int ret;
+ __u8 data;
+
+ ret = usb_control_msg(dev,
+ usb_rcvctrlpipe(dev, 0),
+ 0x20, /* request */
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value,
+ 0, /* index */
+ &data, 1,
+ 500); /* timeout */
+ if (ret < 0) {
+ PDEBUG(D_ERR, "reg_read_info err %d", ret);
+ return 0;
+ }
+ return data;
+}
+
+/* returns: negative is error, pos or zero is data */
+static int reg_read(struct usb_device *dev,
+ __u16 req, /* bRequest */
+ __u16 index, /* wIndex */
+ __u16 length) /* wLength (1 or 2 only) */
+{
+ int ret;
+ __u8 buf[2];
+
+ buf[1] = 0;
+ ret = usb_control_msg(dev,
+ usb_rcvctrlpipe(dev, 0),
+ req,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, /* value */
+ index,
+ buf, length,
+ 500);
+ if (ret < 0) {
+ PDEBUG(D_ERR, "reg_read err %d", ret);
+ return -1;
+ }
+ return (buf[1] << 8) + buf[0];
+}
+
+static int write_vector(struct gspca_dev *gspca_dev,
+ const __u16 data[][3])
+{
+ struct usb_device *dev = gspca_dev->dev;
+ int ret, i = 0;
+
+ while (data[i][0] != 0 || data[i][1] != 0 || data[i][2] != 0) {
+ ret = reg_write(dev, data[i][0], data[i][2], data[i][1]);
+ if (ret < 0) {
+ PDEBUG(D_ERR,
+ "Register write failed for 0x%x,0x%x,0x%x",
+ data[i][0], data[i][1], data[i][2]);
+ return ret;
+ }
+ i++;
+ }
+ return 0;
+}
+
+static int spca50x_setup_qtable(struct gspca_dev *gspca_dev,
+ unsigned int request,
+ unsigned int ybase,
+ unsigned int cbase,
+ const __u8 qtable[2][64])
+{
+ struct usb_device *dev = gspca_dev->dev;
+ int i, err;
+
+ /* loop over y components */
+ for (i = 0; i < 64; i++) {
+ err = reg_write(dev, request, ybase + i, qtable[0][i]);
+ if (err < 0)
+ return err;
+ }
+
+ /* loop over c components */
+ for (i = 0; i < 64; i++) {
+ err = reg_write(dev, request, cbase + i, qtable[1][i]);
+ if (err < 0)
+ return err;
+ }
+ return 0;
+}
+
+static void spca504_acknowledged_command(struct gspca_dev *gspca_dev,
+ __u16 req, __u16 idx, __u16 val)
+{
+ struct usb_device *dev = gspca_dev->dev;
+ __u8 notdone;
+
+ reg_write(dev, req, idx, val);
+ notdone = reg_read(dev, 0x01, 0x0001, 1);
+ reg_write(dev, req, idx, val);
+
+ PDEBUG(D_FRAM, "before wait 0x%x", notdone);
+
+ msleep(200);
+ notdone = reg_read(dev, 0x01, 0x0001, 1);
+ PDEBUG(D_FRAM, "after wait 0x%x", notdone);
+}
+
+static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev,
+ __u16 req,
+ __u16 idx, __u16 val, __u8 stat, __u8 count)
+{
+ struct usb_device *dev = gspca_dev->dev;
+ __u8 status;
+ __u8 endcode;
+
+ reg_write(dev, req, idx, val);
+ status = reg_read(dev, 0x01, 0x0001, 1);
+ endcode = stat;
+ PDEBUG(D_FRAM, "Status 0x%x Need 0x%x", status, stat);
+ if (!count)
+ return;
+ count = 200;
+ while (--count > 0) {
+ msleep(10);
+ /* gsmart mini2 write a each wait setting 1 ms is enought */
+/* reg_write(dev, req, idx, val); */
+ status = reg_read(dev, 0x01, 0x0001, 1);
+ if (status == endcode) {
+ PDEBUG(D_FRAM, "status 0x%x after wait 0x%x",
+ status, 200 - count);
+ break;
+ }
+ }
+}
+
+static int spca504B_PollingDataReady(struct usb_device *dev)
+{
+ __u8 DataReady;
+ int count = 10;
+
+ while (--count > 0) {
+ spca5xxRegRead(dev, 0x21, 0, &DataReady, 1);
+ if ((DataReady & 0x01) == 0)
+ break;
+ msleep(10);
+ }
+ return DataReady;
+}
+
+static void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev)
+{
+ struct usb_device *dev = gspca_dev->dev;
+ __u8 DataReady;
+ int count = 50;
+
+ while (--count > 0) {
+ spca5xxRegRead(dev, 0x21, 1, &DataReady, 1);
+
+ if (DataReady) {
+ DataReady = 0;
+ spca5xxRegWrite(dev, 0x21, 0, 1, &DataReady, 1);
+ spca5xxRegRead(dev, 0x21, 1, &DataReady, 1);
+ spca504B_PollingDataReady(dev);
+ break;
+ }
+ msleep(10);
+ }
+}
+
+static void spca50x_GetFirmware(struct gspca_dev *gspca_dev)
+{
+ struct usb_device *dev = gspca_dev->dev;
+ __u8 FW[5];
+ __u8 ProductInfo[64];
+
+ spca5xxRegRead(dev, 0x20, 0, FW, 5);
+ PDEBUG(D_STREAM, "FirmWare : %d %d %d %d %d ",
+ FW[0], FW[1], FW[2], FW[3], FW[4]);
+ spca5xxRegRead(dev, 0x23, 0, ProductInfo, 64);
+ spca5xxRegRead(dev, 0x23, 1, ProductInfo, 64);
+}
+
+static void spca504B_SetSizeType(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+ __u8 Size;
+ __u8 Type;
+ int rc;
+
+ Size = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
+ Type = 0;
+ switch (sd->bridge) {
+ case BRIDGE_SPCA533:
+ spca5xxRegWrite(dev, 0x31, 0, 0, NULL, 0);
+ spca504B_WaitCmdStatus(gspca_dev);
+ rc = spca504B_PollingDataReady(dev);
+ spca50x_GetFirmware(gspca_dev);
+ Type = 2;
+ spca5xxRegWrite(dev, 0x24, 0, 8, &Type, 1);
+ spca5xxRegRead(dev, 0x24, 8, &Type, 1);
+
+ spca5xxRegWrite(dev, 0x25, 0, 4, &Size, 1);
+ spca5xxRegRead(dev, 0x25, 4, &Size, 1);
+ rc = spca504B_PollingDataReady(dev);
+
+ /* Init the cam width height with some values get on init ? */
+ spca5xxRegWrite(dev, 0x31, 0, 4, NULL, 0);
+ spca504B_WaitCmdStatus(gspca_dev);
+ rc = spca504B_PollingDataReady(dev);
+ break;
+ default:
+/* case BRIDGE_SPCA504B: */
+/* case BRIDGE_SPCA536: */
+ Type = 6;
+ spca5xxRegWrite(dev, 0x25, 0, 4, &Size, 1);
+ spca5xxRegRead(dev, 0x25, 4, &Size, 1);
+ spca5xxRegWrite(dev, 0x27, 0, 0, &Type, 1);
+ spca5xxRegRead(dev, 0x27, 0, &Type, 1);
+ rc = spca504B_PollingDataReady(dev);
+ break;
+ case BRIDGE_SPCA504:
+ Size += 3;
+ if (sd->subtype == AiptekMiniPenCam13) {
+ /* spca504a aiptek */
+ spca504A_acknowledged_command(gspca_dev,
+ 0x08, Size, 0,
+ 0x80 | (Size & 0x0f), 1);
+ spca504A_acknowledged_command(gspca_dev,
+ 1, 3, 0, 0x9f, 0);
+ } else {
+ spca504_acknowledged_command(gspca_dev, 0x08, Size, 0);
+ }
+ break;
+ case BRIDGE_SPCA504C:
+ /* capture mode */
+ reg_write(dev, 0xa0, (0x0500 | (Size & 0x0f)), 0x0);
+ reg_write(dev, 0x20, 0x01, 0x0500 | (Size & 0x0f));
+ break;
+ }
+}
+
+static void spca504_wait_status(struct gspca_dev *gspca_dev)
+{
+ struct usb_device *dev = gspca_dev->dev;
+ int cnt;
+
+ cnt = 256;
+ while (--cnt > 0) {
+ /* With this we get the status, when return 0 it's all ok */
+ if (reg_read(dev, 0x06, 0x00, 1) == 0)
+ return;
+ msleep(10);
+ }
+}
+
+static void spca504B_setQtable(struct gspca_dev *gspca_dev)
+{
+ struct usb_device *dev = gspca_dev->dev;
+ __u8 Data = 3;
+
+ spca5xxRegWrite(dev, 0x26, 0, 0, &Data, 1);
+ spca5xxRegRead(dev, 0x26, 0, &Data, 1);
+ spca504B_PollingDataReady(dev);
+}
+
+static void sp5xx_initContBrigHueRegisters(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+ int pollreg = 1;
+
+ switch (sd->bridge) {
+ case BRIDGE_SPCA504:
+ case BRIDGE_SPCA504C:
+ pollreg = 0;
+ /* fall thru */
+ default:
+/* case BRIDGE_SPCA533: */
+/* case BRIDGE_SPCA504B: */
+ spca5xxRegWrite(dev, 0, 0, 0x21a7, NULL, 0); /* brightness */
+ spca5xxRegWrite(dev, 0, 0x20, 0x21a8, NULL, 0); /* contrast */
+ spca5xxRegWrite(dev, 0, 0, 0x21ad, NULL, 0); /* hue */
+ spca5xxRegWrite(dev, 0, 1, 0x21ac, NULL, 0); /* sat/hue */
+ spca5xxRegWrite(dev, 0, 0x20, 0x21ae, NULL, 0); /* saturation */
+ spca5xxRegWrite(dev, 0, 0, 0x21a3, NULL, 0); /* gamma */
+ break;
+ case BRIDGE_SPCA536:
+ spca5xxRegWrite(dev, 0, 0, 0x20f0, NULL, 0);
+ spca5xxRegWrite(dev, 0, 0x21, 0x20f1, NULL, 0);
+ spca5xxRegWrite(dev, 0, 0x40, 0x20f5, NULL, 0);
+ spca5xxRegWrite(dev, 0, 1, 0x20f4, NULL, 0);
+ spca5xxRegWrite(dev, 0, 0x40, 0x20f6, NULL, 0);
+ spca5xxRegWrite(dev, 0, 0, 0x2089, NULL, 0);
+ break;
+ }
+ if (pollreg)
+ spca504B_PollingDataReady(dev);
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+ const struct usb_device_id *id)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+ struct cam *cam;
+ __u16 vendor;
+ __u16 product;
+ __u8 fw;
+
+ vendor = id->idVendor;
+ product = id->idProduct;
+ switch (vendor) {
+ case 0x041e: /* Creative cameras */
+/* switch (product) { */
+/* case 0x400b: */
+/* case 0x4012: */
+/* case 0x4013: */
+/* sd->bridge = BRIDGE_SPCA504C; */
+/* break; */
+/* } */
+ break;
+ case 0x0458: /* Genius KYE cameras */
+/* switch (product) { */
+/* case 0x7006: */
+ sd->bridge = BRIDGE_SPCA504B;
+/* break; */
+/* } */
+ break;
+ case 0x046d: /* Logitech Labtec */
+ switch (product) {
+ case 0x0905:
+ sd->subtype = LogitechClickSmart820;
+ sd->bridge = BRIDGE_SPCA533;
+ break;
+ case 0x0960:
+ sd->subtype = LogitechClickSmart420;
+ sd->bridge = BRIDGE_SPCA504C;
+ break;
+ }
+ break;
+ case 0x0471: /* Philips */
+/* switch (product) { */
+/* case 0x0322: */
+ sd->bridge = BRIDGE_SPCA504B;
+/* break; */
+/* } */
+ break;
+ case 0x04a5: /* Benq */
+ switch (product) {
+ case 0x3003:
+ sd->bridge = BRIDGE_SPCA504B;
+ break;
+ case 0x3008:
+ case 0x300a:
+ sd->bridge = BRIDGE_SPCA533;
+ break;
+ }
+ break;
+ case 0x04f1: /* JVC */
+/* switch (product) { */
+/* case 0x1001: */
+ sd->bridge = BRIDGE_SPCA504B;
+/* break; */
+/* } */
+ break;
+ case 0x04fc: /* SunPlus */
+ switch (product) {
+ case 0x500c:
+ sd->bridge = BRIDGE_SPCA504B;
+ break;
+ case 0x504a:
+/* try to get the firmware as some cam answer 2.0.1.2.2
+ * and should be a spca504b then overwrite that setting */
+ spca5xxRegRead(dev, 0x20, 0, &fw, 1);
+ if (fw == 1) {
+ sd->subtype = AiptekMiniPenCam13;
+ sd->bridge = BRIDGE_SPCA504;
+ } else if (fw == 2) {
+ sd->bridge = BRIDGE_SPCA504B;
+ } else
+ return -ENODEV;
+ break;
+ case 0x504b:
+ sd->bridge = BRIDGE_SPCA504B;
+ break;
+ case 0x5330:
+ sd->bridge = BRIDGE_SPCA533;
+ break;
+ case 0x5360:
+ sd->bridge = BRIDGE_SPCA536;
+ break;
+ case 0xffff:
+ sd->bridge = BRIDGE_SPCA504B;
+ break;
+ }
+ break;
+ case 0x052b: /* ?? Megapix */
+/* switch (product) { */
+/* case 0x1513: */
+ sd->subtype = MegapixV4;
+ sd->bridge = BRIDGE_SPCA533;
+/* break; */
+/* } */
+ break;
+ case 0x0546: /* Polaroid */
+ switch (product) {
+ case 0x3155:
+ sd->bridge = BRIDGE_SPCA533;
+ break;
+ case 0x3191:
+ case 0x3273:
+ sd->bridge = BRIDGE_SPCA504B;
+ break;
+ }
+ break;
+ case 0x055f: /* Mustek cameras */
+ switch (product) {
+ case 0xc211:
+ sd->bridge = BRIDGE_SPCA536;
+ break;
+ case 0xc230:
+ case 0xc232:
+ sd->bridge = BRIDGE_SPCA533;
+ break;
+ case 0xc360:
+ sd->bridge = BRIDGE_SPCA536;
+ break;
+ case 0xc420:
+ sd->bridge = BRIDGE_SPCA504;
+ break;
+ case 0xc430:
+ case 0xc440:
+ sd->bridge = BRIDGE_SPCA533;
+ break;
+ case 0xc520:
+ sd->bridge = BRIDGE_SPCA504;
+ break;
+ case 0xc530:
+ case 0xc540:
+ case 0xc630:
+ case 0xc650:
+ sd->bridge = BRIDGE_SPCA533;
+ break;
+ }
+ break;
+ case 0x05da: /* Digital Dream cameras */
+/* switch (product) { */
+/* case 0x1018: */
+ sd->bridge = BRIDGE_SPCA504B;
+/* break; */
+/* } */
+ break;
+ case 0x06d6: /* Trust */
+/* switch (product) { */
+/* case 0x0031: */
+ sd->bridge = BRIDGE_SPCA533; /* SPCA533A */
+/* break; */
+/* } */
+ break;
+ case 0x0733: /* Rebadged ViewQuest (Intel) and ViewQuest cameras */
+ switch (product) {
+ case 0x1311:
+ case 0x1314:
+ case 0x2211:
+ case 0x2221:
+ sd->bridge = BRIDGE_SPCA533;
+ break;
+ case 0x3261:
+ case 0x3281:
+ sd->bridge = BRIDGE_SPCA536;
+ break;
+ }
+ break;
+ case 0x08ca: /* Aiptek */
+ switch (product) {
+ case 0x0104:
+ case 0x0106:
+ sd->bridge = BRIDGE_SPCA533;
+ break;
+ case 0x2008:
+ sd->bridge = BRIDGE_SPCA504B;
+ break;
+ case 0x2010:
+ sd->bridge = BRIDGE_SPCA533;
+ break;
+ case 0x2016:
+ case 0x2018:
+ sd->bridge = BRIDGE_SPCA504B;
+ break;
+ case 0x2020:
+ case 0x2022:
+ sd->bridge = BRIDGE_SPCA533;
+ break;
+ case 0x2024:
+ sd->bridge = BRIDGE_SPCA536;
+ break;
+ case 0x2028:
+ sd->bridge = BRIDGE_SPCA533;
+ break;
+ case 0x2040:
+ case 0x2042:
+ case 0x2060:
+ sd->bridge = BRIDGE_SPCA536;
+ break;
+ }
+ break;
+ case 0x0d64: /* SunPlus */
+/* switch (product) { */
+/* case 0x0303: */
+ sd->bridge = BRIDGE_SPCA536;
+/* break; */
+/* } */
+ break;
+ }
+
+ cam = &gspca_dev->cam;
+ cam->dev_name = (char *) id->driver_info;
+ cam->epaddr = 0x01;
+
+ switch (sd->bridge) {
+ default:
+/* case BRIDGE_SPCA504B: */
+/* case BRIDGE_SPCA504: */
+/* case BRIDGE_SPCA536: */
+ cam->cam_mode = vga_mode;
+ cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+ break;
+ case BRIDGE_SPCA533:
+ cam->cam_mode = custom_mode;
+ cam->nmodes = sizeof custom_mode / sizeof custom_mode[0];
+ break;
+ case BRIDGE_SPCA504C:
+ cam->cam_mode = vga_mode2;
+ cam->nmodes = sizeof vga_mode2 / sizeof vga_mode2[0];
+ break;
+ }
+ sd->qindex = 5; /* set the quantization table */
+ sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
+ sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
+ sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value;
+ return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+ int rc;
+ __u8 Data;
+ __u8 i;
+ __u8 info[6];
+ int err_code;
+
+ switch (sd->bridge) {
+ case BRIDGE_SPCA504B:
+ spca5xxRegWrite(dev, 0x1d, 0, 0, NULL, 0);
+ spca5xxRegWrite(dev, 0, 1, 0x2306, NULL, 0);
+ spca5xxRegWrite(dev, 0, 0, 0x0d04, NULL, 0);
+ spca5xxRegWrite(dev, 0, 0, 0x2000, NULL, 0);
+ spca5xxRegWrite(dev, 0, 0x13, 0x2301, NULL, 0);
+ spca5xxRegWrite(dev, 0, 0, 0x2306, NULL, 0);
+ /* fall thru */
+ case BRIDGE_SPCA533:
+ rc = spca504B_PollingDataReady(dev);
+ spca50x_GetFirmware(gspca_dev);
+ break;
+ case BRIDGE_SPCA536:
+ spca50x_GetFirmware(gspca_dev);
+ spca5xxRegRead(dev, 0x00, 0x5002, &Data, 1);
+ Data = 0;
+ spca5xxRegWrite(dev, 0x24, 0, 0, &Data, 1);
+ spca5xxRegRead(dev, 0x24, 0, &Data, 1);
+ rc = spca504B_PollingDataReady(dev);
+ spca5xxRegWrite(dev, 0x34, 0, 0, NULL, 0);
+ spca504B_WaitCmdStatus(gspca_dev);
+ break;
+ case BRIDGE_SPCA504C: /* pccam600 */
+ PDEBUG(D_STREAM, "Opening SPCA504 (PC-CAM 600)");
+ reg_write(dev, 0xe0, 0x0000, 0x0000);
+ reg_write(dev, 0xe0, 0x0000, 0x0001); /* reset */
+ spca504_wait_status(gspca_dev);
+ if (sd->subtype == LogitechClickSmart420)
+ write_vector(gspca_dev,
+ spca504A_clicksmart420_open_data);
+ else
+ write_vector(gspca_dev, spca504_pccam600_open_data);
+ err_code = spca50x_setup_qtable(gspca_dev,
+ 0x00, 0x2800,
+ 0x2840, qtable_creative_pccam);
+ if (err_code < 0) {
+ PDEBUG(D_ERR|D_STREAM, "spca50x_setup_qtable failed");
+ return err_code;
+ }
+ break;
+ default:
+/* case BRIDGE_SPCA504: */
+ PDEBUG(D_STREAM, "Opening SPCA504");
+ if (sd->subtype == AiptekMiniPenCam13) {
+ /*****************************/
+ for (i = 0; i < 6; i++)
+ info[i] = reg_read_info(dev, i);
+ PDEBUG(D_STREAM,
+ "Read info: %d %d %d %d %d %d."
+ " Should be 1,0,2,2,0,0",
+ info[0], info[1], info[2],
+ info[3], info[4], info[5]);
+ /* spca504a aiptek */
+ /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
+ spca504A_acknowledged_command(gspca_dev, 0x24,
+ 8, 3, 0x9e, 1);
+ /* Twice sequencial need status 0xff->0x9e->0x9d */
+ spca504A_acknowledged_command(gspca_dev, 0x24,
+ 8, 3, 0x9e, 0);
+
+ spca504A_acknowledged_command(gspca_dev, 0x24,
+ 0, 0, 0x9d, 1);
+ /******************************/
+ /* spca504a aiptek */
+ spca504A_acknowledged_command(gspca_dev, 0x08,
+ 6, 0, 0x86, 1);
+/* reg_write (dev, 0, 0x2000, 0); */
+/* reg_write (dev, 0, 0x2883, 1); */
+/* spca504A_acknowledged_command (gspca_dev, 0x08,
+ 6, 0, 0x86, 1); */
+/* spca504A_acknowledged_command (gspca_dev, 0x24,
+ 0, 0, 0x9D, 1); */
+ reg_write(dev, 0x0, 0x270c, 0x5); /* L92 sno1t.txt */
+ reg_write(dev, 0x0, 0x2310, 0x5);
+ spca504A_acknowledged_command(gspca_dev, 0x01,
+ 0x0f, 0, 0xff, 0);
+ }
+ /* setup qtable */
+ reg_write(dev, 0, 0x2000, 0);
+ reg_write(dev, 0, 0x2883, 1);
+ err_code = spca50x_setup_qtable(gspca_dev,
+ 0x00, 0x2800,
+ 0x2840,
+ qtable_spca504_default);
+ if (err_code < 0) {
+ PDEBUG(D_ERR, "spca50x_setup_qtable failed");
+ return err_code;
+ }
+ break;
+ }
+ return 0;
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+ int rc;
+ int enable;
+ __u8 i;
+ __u8 info[6];
+
+ if (sd->bridge == BRIDGE_SPCA504B)
+ spca504B_setQtable(gspca_dev);
+ spca504B_SetSizeType(gspca_dev);
+ switch (sd->bridge) {
+ default:
+/* case BRIDGE_SPCA504B: */
+/* case BRIDGE_SPCA533: */
+/* case BRIDGE_SPCA536: */
+ if (sd->subtype == MegapixV4 ||
+ sd->subtype == LogitechClickSmart820) {
+ spca5xxRegWrite(dev, 0xf0, 0, 0, NULL, 0);
+ spca504B_WaitCmdStatus(gspca_dev);
+ spca5xxRegRead(dev, 0xf0, 4, NULL, 0);
+ spca504B_WaitCmdStatus(gspca_dev);
+ } else {
+ spca5xxRegWrite(dev, 0x31, 0, 4, NULL, 0);
+ spca504B_WaitCmdStatus(gspca_dev);
+ rc = spca504B_PollingDataReady(dev);
+ }
+ break;
+ case BRIDGE_SPCA504:
+ if (sd->subtype == AiptekMiniPenCam13) {
+ for (i = 0; i < 6; i++)
+ info[i] = reg_read_info(dev, i);
+ PDEBUG(D_STREAM,
+ "Read info: %d %d %d %d %d %d."
+ " Should be 1,0,2,2,0,0",
+ info[0], info[1], info[2],
+ info[3], info[4], info[5]);
+ /* spca504a aiptek */
+ /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
+ spca504A_acknowledged_command(gspca_dev, 0x24,
+ 8, 3, 0x9e, 1);
+ /* Twice sequencial need status 0xff->0x9e->0x9d */
+ spca504A_acknowledged_command(gspca_dev, 0x24,
+ 8, 3, 0x9e, 0);
+ spca504A_acknowledged_command(gspca_dev, 0x24,
+ 0, 0, 0x9d, 1);
+ } else {
+ spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
+ for (i = 0; i < 6; i++)
+ info[i] = reg_read_info(dev, i);
+ PDEBUG(D_STREAM,
+ "Read info: %d %d %d %d %d %d."
+ " Should be 1,0,2,2,0,0",
+ info[0], info[1], info[2],
+ info[3], info[4], info[5]);
+ spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
+ spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
+ }
+ spca504B_SetSizeType(gspca_dev);
+ reg_write(dev, 0x0, 0x270c, 0x5); /* L92 sno1t.txt */
+ reg_write(dev, 0x0, 0x2310, 0x5);
+ break;
+ case BRIDGE_SPCA504C:
+ if (sd->subtype == LogitechClickSmart420) {
+ write_vector(gspca_dev,
+ spca504A_clicksmart420_init_data);
+ } else {
+ write_vector(gspca_dev, spca504_pccam600_init_data);
+ }
+ enable = (sd->autogain ? 0x4 : 0x1);
+ reg_write(dev, 0x0c, 0x0000, enable); /* auto exposure */
+ reg_write(dev, 0xb0, 0x0000, enable); /* auto whiteness */
+
+ /* set default exposure compensation and whiteness balance */
+ reg_write(dev, 0x30, 0x0001, 800); /* ~ 20 fps */
+ reg_write(dev, 0x30, 0x0002, 1600);
+ spca504B_SetSizeType(gspca_dev);
+ break;
+ }
+ sp5xx_initContBrigHueRegisters(gspca_dev);
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+
+ switch (sd->bridge) {
+ default:
+/* case BRIDGE_SPCA533: */
+/* case BRIDGE_SPCA536: */
+/* case BRIDGE_SPCA504B: */
+ spca5xxRegWrite(dev, 0x31, 0, 0, NULL, 0);
+ spca504B_WaitCmdStatus(gspca_dev);
+ spca504B_PollingDataReady(dev);
+ break;
+ case BRIDGE_SPCA504:
+ case BRIDGE_SPCA504C:
+ reg_write(dev, 0x00, 0x2000, 0x0000);
+
+ if (sd->subtype == AiptekMiniPenCam13) {
+ /* spca504a aiptek */
+/* spca504A_acknowledged_command(gspca_dev, 0x08,
+ 6, 0, 0x86, 1); */
+ spca504A_acknowledged_command(gspca_dev, 0x24,
+ 0x00, 0x00, 0x9d, 1);
+ spca504A_acknowledged_command(gspca_dev, 0x01,
+ 0x0f, 0x00, 0xff, 1);
+ } else {
+ spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
+ reg_write(dev, 0x01, 0x000f, 0x0);
+ }
+ break;
+ }
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ struct gspca_frame *frame, /* target */
+ __u8 *data, /* isoc packet */
+ int len) /* iso packet length */
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int i, sof = 0;
+ unsigned char *s, *d;
+ static unsigned char ffd9[] = {0xff, 0xd9};
+
+/* frames are jpeg 4.1.1 without 0xff escape */
+ switch (sd->bridge) {
+ case BRIDGE_SPCA533:
+ if (data[0] == 0xff) {
+ if (data[1] != 0x01) { /* drop packet */
+/* gspca_dev->last_packet_type = DISCARD_PACKET; */
+ return;
+ }
+ sof = 1;
+ data += SPCA533_OFFSET_DATA;
+ len -= SPCA533_OFFSET_DATA;
+ } else {
+ data += 1;
+ len -= 1;
+ }
+ break;
+ case BRIDGE_SPCA536:
+ if (data[0] == 0xff) {
+ sof = 1;
+ data += SPCA536_OFFSET_DATA;
+ len -= SPCA536_OFFSET_DATA;
+ } else {
+ data += 2;
+ len -= 2;
+ }
+ break;
+ default:
+/* case BRIDGE_SPCA504: */
+/* case BRIDGE_SPCA504B: */
+ switch (data[0]) {
+ case 0xfe: /* start of frame */
+ sof = 1;
+ data += SPCA50X_OFFSET_DATA;
+ len -= SPCA50X_OFFSET_DATA;
+ break;
+ case 0xff: /* drop packet */
+/* gspca_dev->last_packet_type = DISCARD_PACKET; */
+ return;
+ default:
+ data += 1;
+ len -= 1;
+ break;
+ }
+ break;
+ case BRIDGE_SPCA504C:
+ switch (data[0]) {
+ case 0xfe: /* start of frame */
+ sof = 1;
+ data += SPCA504_PCCAM600_OFFSET_DATA;
+ len -= SPCA504_PCCAM600_OFFSET_DATA;
+ break;
+ case 0xff: /* drop packet */
+/* gspca_dev->last_packet_type = DISCARD_PACKET; */
+ return;
+ default:
+ data += 1;
+ len -= 1;
+ break;
+ }
+ break;
+ }
+ if (sof) { /* start of frame */
+ frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+ ffd9, 2);
+
+ /* put the JPEG header in the new frame */
+ jpeg_put_header(gspca_dev, frame,
+ ((struct sd *) gspca_dev)->qindex,
+ 0x22);
+ }
+
+ /* add 0x00 after 0xff */
+ for (i = len; --i >= 0; )
+ if (data[i] == 0xff)
+ break;
+ if (i < 0) { /* no 0xff */
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+ return;
+ }
+ s = data;
+ d = sd->packet;
+ for (i = 0; i < len; i++) {
+ *d++ = *s++;
+ if (s[-1] == 0xff)
+ *d++ = 0x00;
+ }
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+ sd->packet, d - sd->packet);
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+
+ switch (sd->bridge) {
+ default:
+/* case BRIDGE_SPCA533: */
+/* case BRIDGE_SPCA504B: */
+/* case BRIDGE_SPCA504: */
+/* case BRIDGE_SPCA504C: */
+ reg_write(dev, 0x0, 0x21a7, sd->brightness);
+ break;
+ case BRIDGE_SPCA536:
+ reg_write(dev, 0x0, 0x20f0, sd->brightness);
+ break;
+ }
+}
+
+static void getbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+ __u16 brightness = 0;
+
+ switch (sd->bridge) {
+ default:
+/* case BRIDGE_SPCA533: */
+/* case BRIDGE_SPCA504B: */
+/* case BRIDGE_SPCA504: */
+/* case BRIDGE_SPCA504C: */
+ brightness = reg_read(dev, 0x0, 0x21a7, 2);
+ break;
+ case BRIDGE_SPCA536:
+ brightness = reg_read(dev, 0x0, 0x20f0, 2);
+ break;
+ }
+ sd->brightness = ((brightness & 0xff) - 128) % 255;
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+
+ switch (sd->bridge) {
+ default:
+/* case BRIDGE_SPCA533: */
+/* case BRIDGE_SPCA504B: */
+/* case BRIDGE_SPCA504: */
+/* case BRIDGE_SPCA504C: */
+ reg_write(dev, 0x0, 0x21a8, sd->contrast);
+ break;
+ case BRIDGE_SPCA536:
+ reg_write(dev, 0x0, 0x20f1, sd->contrast);
+ break;
+ }
+}
+
+static void getcontrast(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+
+ switch (sd->bridge) {
+ default:
+/* case BRIDGE_SPCA533: */
+/* case BRIDGE_SPCA504B: */
+/* case BRIDGE_SPCA504: */
+/* case BRIDGE_SPCA504C: */
+ sd->contrast = reg_read(dev, 0x0, 0x21a8, 2);
+ break;
+ case BRIDGE_SPCA536:
+ sd->contrast = reg_read(dev, 0x0, 0x20f1, 2);
+ break;
+ }
+}
+
+static void setcolors(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+
+ switch (sd->bridge) {
+ default:
+/* case BRIDGE_SPCA533: */
+/* case BRIDGE_SPCA504B: */
+/* case BRIDGE_SPCA504: */
+/* case BRIDGE_SPCA504C: */
+ reg_write(dev, 0x0, 0x21ae, sd->colors);
+ break;
+ case BRIDGE_SPCA536:
+ reg_write(dev, 0x0, 0x20f6, sd->colors);
+ break;
+ }
+}
+
+static void getcolors(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+
+ switch (sd->bridge) {
+ default:
+/* case BRIDGE_SPCA533: */
+/* case BRIDGE_SPCA504B: */
+/* case BRIDGE_SPCA504: */
+/* case BRIDGE_SPCA504C: */
+ sd->colors = reg_read(dev, 0x0, 0x21ae, 2) >> 1;
+ break;
+ case BRIDGE_SPCA536:
+ sd->colors = reg_read(dev, 0x0, 0x20f6, 2) >> 1;
+ break;
+ }
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->brightness = val;
+ if (gspca_dev->streaming)
+ setbrightness(gspca_dev);
+ return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ getbrightness(gspca_dev);
+ *val = sd->brightness;
+ return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->contrast = val;
+ if (gspca_dev->streaming)
+ setcontrast(gspca_dev);
+ return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ getcontrast(gspca_dev);
+ *val = sd->contrast;
+ return 0;
+}
+
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->colors = val;
+ if (gspca_dev->streaming)
+ setcolors(gspca_dev);
+ return 0;
+}
+
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ getcolors(gspca_dev);
+ *val = sd->colors;
+ return 0;
+}
+
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->autogain = val;
+ return 0;
+}
+
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->autogain;
+ return 0;
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .ctrls = sd_ctrls,
+ .nctrls = ARRAY_SIZE(sd_ctrls),
+ .config = sd_config,
+ .open = sd_open,
+ .start = sd_start,
+ .stopN = sd_stopN,
+ .stop0 = sd_stop0,
+ .close = sd_close,
+ .pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static const __devinitdata struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x041e, 0x400b), DVNM("Creative PC-CAM 600")},
+ {USB_DEVICE(0x041e, 0x4012), DVNM("PC-Cam350")},
+ {USB_DEVICE(0x041e, 0x4013), DVNM("Creative Pccam750")},
+ {USB_DEVICE(0x0458, 0x7006), DVNM("Genius Dsc 1.3 Smart")},
+ {USB_DEVICE(0x046d, 0x0905), DVNM("Logitech ClickSmart 820")},
+ {USB_DEVICE(0x046d, 0x0960), DVNM("Logitech ClickSmart 420")},
+ {USB_DEVICE(0x0471, 0x0322), DVNM("Philips DMVC1300K")},
+ {USB_DEVICE(0x04a5, 0x3003), DVNM("Benq DC 1300")},
+ {USB_DEVICE(0x04a5, 0x3008), DVNM("Benq DC 1500")},
+ {USB_DEVICE(0x04a5, 0x300a), DVNM("Benq DC3410")},
+ {USB_DEVICE(0x04f1, 0x1001), DVNM("JVC GC A50")},
+ {USB_DEVICE(0x04fc, 0x500c), DVNM("Sunplus CA500C")},
+ {USB_DEVICE(0x04fc, 0x504a), DVNM("Aiptek Mini PenCam 1.3")},
+ {USB_DEVICE(0x04fc, 0x504b), DVNM("Maxell MaxPocket LE 1.3")},
+ {USB_DEVICE(0x04fc, 0x5330), DVNM("Digitrex 2110")},
+ {USB_DEVICE(0x04fc, 0x5360), DVNM("Sunplus Generic")},
+ {USB_DEVICE(0x04fc, 0xffff), DVNM("Pure DigitalDakota")},
+ {USB_DEVICE(0x052b, 0x1513), DVNM("Megapix V4")},
+ {USB_DEVICE(0x0546, 0x3155), DVNM("Polaroid PDC3070")},
+ {USB_DEVICE(0x0546, 0x3191), DVNM("Polaroid Ion 80")},
+ {USB_DEVICE(0x0546, 0x3273), DVNM("Polaroid PDC2030")},
+ {USB_DEVICE(0x055f, 0xc211), DVNM("Kowa Bs888e Microcamera")},
+ {USB_DEVICE(0x055f, 0xc230), DVNM("Mustek Digicam 330K")},
+ {USB_DEVICE(0x055f, 0xc232), DVNM("Mustek MDC3500")},
+ {USB_DEVICE(0x055f, 0xc360), DVNM("Mustek DV4000 Mpeg4 ")},
+ {USB_DEVICE(0x055f, 0xc420), DVNM("Mustek gSmart Mini 2")},
+ {USB_DEVICE(0x055f, 0xc430), DVNM("Mustek Gsmart LCD 2")},
+ {USB_DEVICE(0x055f, 0xc440), DVNM("Mustek DV 3000")},
+ {USB_DEVICE(0x055f, 0xc520), DVNM("Mustek gSmart Mini 3")},
+ {USB_DEVICE(0x055f, 0xc530), DVNM("Mustek Gsmart LCD 3")},
+ {USB_DEVICE(0x055f, 0xc540), DVNM("Gsmart D30")},
+ {USB_DEVICE(0x055f, 0xc630), DVNM("Mustek MDC4000")},
+ {USB_DEVICE(0x055f, 0xc650), DVNM("Mustek MDC5500Z")},
+ {USB_DEVICE(0x05da, 0x1018), DVNM("Digital Dream Enigma 1.3")},
+ {USB_DEVICE(0x06d6, 0x0031), DVNM("Trust 610 LCD PowerC@m Zoom")},
+ {USB_DEVICE(0x0733, 0x1311), DVNM("Digital Dream Epsilon 1.3")},
+ {USB_DEVICE(0x0733, 0x1314), DVNM("Mercury 2.1MEG Deluxe Classic Cam")},
+ {USB_DEVICE(0x0733, 0x2211), DVNM("Jenoptik jdc 21 LCD")},
+ {USB_DEVICE(0x0733, 0x2221), DVNM("Mercury Digital Pro 3.1p")},
+ {USB_DEVICE(0x0733, 0x3261), DVNM("Concord 3045 spca536a")},
+ {USB_DEVICE(0x0733, 0x3281), DVNM("Cyberpix S550V")},
+ {USB_DEVICE(0x08ca, 0x0104), DVNM("Aiptek PocketDVII 1.3")},
+ {USB_DEVICE(0x08ca, 0x0106), DVNM("Aiptek Pocket DV3100+")},
+ {USB_DEVICE(0x08ca, 0x2008), DVNM("Aiptek Mini PenCam 2 M")},
+ {USB_DEVICE(0x08ca, 0x2010), DVNM("Aiptek PocketCam 3M")},
+ {USB_DEVICE(0x08ca, 0x2016), DVNM("Aiptek PocketCam 2 Mega")},
+ {USB_DEVICE(0x08ca, 0x2018), DVNM("Aiptek Pencam SD 2M")},
+ {USB_DEVICE(0x08ca, 0x2020), DVNM("Aiptek Slim 3000F")},
+ {USB_DEVICE(0x08ca, 0x2022), DVNM("Aiptek Slim 3200")},
+ {USB_DEVICE(0x08ca, 0x2024), DVNM("Aiptek DV3500 Mpeg4 ")},
+ {USB_DEVICE(0x08ca, 0x2028), DVNM("Aiptek PocketCam4M")},
+ {USB_DEVICE(0x08ca, 0x2040), DVNM("Aiptek PocketDV4100M")},
+ {USB_DEVICE(0x08ca, 0x2042), DVNM("Aiptek PocketDV5100")},
+ {USB_DEVICE(0x08ca, 0x2060), DVNM("Aiptek PocketDV5300")},
+ {USB_DEVICE(0x0d64, 0x0303), DVNM("Sunplus FashionCam DXG")},
+ {}
+};
+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,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+ if (usb_register(&sd_driver) < 0)
+ return -1;
+ PDEBUG(D_PROBE, "v%s registered", version);
+ return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+ usb_deregister(&sd_driver);
+ PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/linux/drivers/media/video/gspca/t613.c b/linux/drivers/media/video/gspca/t613.c
new file mode 100644
index 000000000..78ee480e2
--- /dev/null
+++ b/linux/drivers/media/video/gspca/t613.c
@@ -0,0 +1,1086 @@
+/*
+ *Notes: * t613 + tas5130A
+ * * Focus to light do not balance well as in win.
+ * Quality in win is not good, but its kinda better.
+ * * Fix some "extraneous bytes", most of apps will show the image anyway
+ * * Gamma table, is there, but its really doing something?
+ * * 7~8 Fps, its ok, max on win its 10.
+ * Costantino Leandro
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define MODULE_NAME "t613"
+#include "gspca.h"
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 5)
+static const char version[] = "2.1.5";
+
+#define MAX_GAMMA 0x10 /* 0 to 15 */
+
+/* From LUVCVIEW */
+#define V4L2_CID_EFFECTS (V4L2_CID_PRIVATE_BASE + 3)
+
+MODULE_AUTHOR("Leandro Costantino <le_costantino@pixartargentina.com.ar>");
+MODULE_DESCRIPTION("GSPCA/T613 (JPEG Compliance) USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+
+ unsigned char brightness;
+ unsigned char contrast;
+ unsigned char colors;
+ unsigned char autogain;
+ unsigned char gamma;
+ unsigned char sharpness;
+ unsigned char freq;
+ unsigned char whitebalance;
+ unsigned char mirror;
+ unsigned char effect;
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setlowlight(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getlowlight(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setflip(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getflip(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_seteffect(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_geteffect(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_querymenu(struct gspca_dev *gspca_dev,
+ struct v4l2_querymenu *menu);
+
+static struct ctrl sd_ctrls[] = {
+#define SD_BRIGHTNESS 0
+ {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+ .maximum = 0x0f,
+ .step = 1,
+ .default_value = 0x09,
+ },
+ .set = sd_setbrightness,
+ .get = sd_getbrightness,
+ },
+#define SD_CONTRAST 1
+ {
+ {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = 0,
+ .maximum = 0x0d,
+ .step = 1,
+ .default_value = 0x07,
+ },
+ .set = sd_setcontrast,
+ .get = sd_getcontrast,
+ },
+#define SD_COLOR 2
+ {
+ {
+ .id = V4L2_CID_SATURATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Color",
+ .minimum = 0,
+ .maximum = 0x0f,
+ .step = 1,
+ .default_value = 0x05,
+ },
+ .set = sd_setcolors,
+ .get = sd_getcolors,
+ },
+#define SD_GAMMA 3
+ {
+ {
+ .id = V4L2_CID_GAMMA, /* (gamma on win) */
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Gamma (Untested)",
+ .minimum = 0,
+ .maximum = MAX_GAMMA,
+ .step = 1,
+ .default_value = 0x09,
+ },
+ .set = sd_setgamma,
+ .get = sd_getgamma,
+ },
+#define SD_AUTOGAIN 4
+ {
+ {
+ .id = V4L2_CID_GAIN, /* here, i activate only the lowlight,
+ * some apps dont bring up the
+ * backligth_compensation control) */
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Low Light",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0x01,
+ },
+ .set = sd_setlowlight,
+ .get = sd_getlowlight,
+ },
+#define SD_MIRROR 5
+ {
+ {
+ .id = V4L2_CID_HFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Mirror Image",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ .set = sd_setflip,
+ .get = sd_getflip
+ },
+#define SD_LIGHTFREQ 6
+ {
+ {
+ .id = V4L2_CID_POWER_LINE_FREQUENCY,
+ .type = V4L2_CTRL_TYPE_MENU,
+ .name = "Light Frequency Filter",
+ .minimum = 1, /* 1 -> 0x50, 2->0x60 */
+ .maximum = 2,
+ .step = 1,
+ .default_value = 1,
+ },
+ .set = sd_setfreq,
+ .get = sd_getfreq},
+
+#define SD_WHITE_BALANCE 7
+ {
+ {
+ .id = V4L2_CID_WHITE_BALANCE_TEMPERATURE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "White Balance",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 1,
+ },
+ .set = sd_setwhitebalance,
+ .get = sd_getwhitebalance
+ },
+#define SD_SHARPNESS 8 /* (aka definition on win) */
+ {
+ {
+ .id = V4L2_CID_SHARPNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Sharpness",
+ .minimum = 0,
+ .maximum = MAX_GAMMA, /* 0 to 16 */
+ .step = 1,
+ .default_value = 0x06,
+ },
+ .set = sd_setsharpness,
+ .get = sd_getsharpness,
+ },
+#define SD_EFFECTS 9
+ {
+ {
+ .id = V4L2_CID_EFFECTS,
+ .type = V4L2_CTRL_TYPE_MENU,
+ .name = "Webcam Effects",
+ .minimum = 0,
+ .maximum = 4,
+ .step = 1,
+ .default_value = 0,
+ },
+ .set = sd_seteffect,
+ .get = sd_geteffect
+ },
+};
+
+static char *effects_control[] = {
+ "Normal",
+ "Emboss", /* disabled */
+ "Monochrome",
+ "Sepia",
+ "Sketch",
+ "Sun Effect", /* disabled */
+ "Negative",
+};
+
+static struct v4l2_pix_format vga_mode_t16[] = {
+ {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 160,
+ .sizeimage = 160 * 120 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 4},
+ {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 176,
+ .sizeimage = 176 * 144 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 3},
+ {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 2},
+ {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 352,
+ .sizeimage = 352 * 288 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 1},
+ {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 0},
+};
+
+#define T16_OFFSET_DATA 631
+#define MAX_EFFECTS 7
+/* easily done by soft, this table could be removed,
+ * i keep it here just in case */
+static const __u8 effects_table[MAX_EFFECTS][6] = {
+ {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x00}, /* Normal */
+ {0xa8, 0xc8, 0xc6, 0x52, 0xc0, 0x04}, /* Repujar */
+ {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x20}, /* Monochrome */
+ {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x80}, /* Sepia */
+ {0xa8, 0xc8, 0xc6, 0x52, 0xc0, 0x02}, /* Croquis */
+ {0xa8, 0xc8, 0xc6, 0xd2, 0xc0, 0x10}, /* Sun Effect */
+ {0xa8, 0xc8, 0xc6, 0xd2, 0xc0, 0x40}, /* Negative */
+};
+
+static const __u8 gamma_table[MAX_GAMMA][34] = {
+ {0x90, 0x00, 0x91, 0x3e, 0x92, 0x69, 0x93, 0x85,
+ 0x94, 0x95, 0x95, 0xa1, 0x96, 0xae, 0x97, 0xb9,
+ 0x98, 0xc2, 0x99, 0xcb, 0x9a, 0xd4, 0x9b, 0xdb,
+ 0x9c, 0xe3, 0x9d, 0xea, 0x9e, 0xf1, 0x9f, 0xf8,
+ 0xa0, 0xff},
+ {0x90, 0x00, 0x91, 0x33, 0x92, 0x5A, 0x93, 0x75,
+ 0x94, 0x85, 0x95, 0x93, 0x96, 0xA1, 0x97, 0xAD,
+ 0x98, 0xB7, 0x99, 0xC2, 0x9A, 0xCB, 0x9B, 0xD4,
+ 0x9C, 0xDE, 0x9D, 0xE7, 0x9E, 0xF0, 0x9F, 0xF7,
+ 0xa0, 0xff},
+ {0x90, 0x00, 0x91, 0x2F, 0x92, 0x51, 0x93, 0x6B,
+ 0x94, 0x7C, 0x95, 0x8A, 0x96, 0x99, 0x97, 0xA6,
+ 0x98, 0xB1, 0x99, 0xBC, 0x9A, 0xC6, 0x9B, 0xD0,
+ 0x9C, 0xDB, 0x9D, 0xE4, 0x9E, 0xED, 0x9F, 0xF6,
+ 0xa0, 0xff},
+ {0x90, 0x00, 0x91, 0x29, 0x92, 0x48, 0x93, 0x60,
+ 0x94, 0x72, 0x95, 0x81, 0x96, 0x90, 0x97, 0x9E,
+ 0x98, 0xAA, 0x99, 0xB5, 0x9A, 0xBF, 0x9B, 0xCB,
+ 0x9C, 0xD6, 0x9D, 0xE1, 0x9E, 0xEB, 0x9F, 0xF5,
+ 0xa0, 0xff},
+ {0x90, 0x00, 0x91, 0x23, 0x92, 0x3F, 0x93, 0x55,
+ 0x94, 0x68, 0x95, 0x77, 0x96, 0x86, 0x97, 0x95,
+ 0x98, 0xA2, 0x99, 0xAD, 0x9A, 0xB9, 0x9B, 0xC6,
+ 0x9C, 0xD2, 0x9D, 0xDE, 0x9E, 0xE9, 0x9F, 0xF4,
+ 0xa0, 0xff},
+ {0x90, 0x00, 0x91, 0x1B, 0x92, 0x33, 0x93, 0x48,
+ 0x94, 0x59, 0x95, 0x69, 0x96, 0x79, 0x97, 0x87,
+ 0x98, 0x96, 0x99, 0xA3, 0x9A, 0xB1, 0x9B, 0xBE,
+ 0x9C, 0xCC, 0x9D, 0xDA, 0x9E, 0xE7, 0x9F, 0xF3,
+ 0xa0, 0xff},
+ {0x90, 0x00, 0x91, 0x02, 0x92, 0x10, 0x93, 0x20,
+ 0x94, 0x32, 0x95, 0x40, 0x96, 0x57, 0x97, 0x67,
+ 0x98, 0x77, 0x99, 0x88, 0x9a, 0x99, 0x9b, 0xaa,
+ 0x9c, 0xbb, 0x9d, 0xcc, 0x9e, 0xdd, 0x9f, 0xee,
+ 0xa0, 0xff},
+ {0x90, 0x00, 0x91, 0x02, 0x92, 0x14, 0x93, 0x26,
+ 0x94, 0x38, 0x95, 0x4A, 0x96, 0x60, 0x97, 0x70,
+ 0x98, 0x80, 0x99, 0x90, 0x9A, 0xA0, 0x9B, 0xB0,
+ 0x9C, 0xC0, 0x9D, 0xD0, 0x9E, 0xE0, 0x9F, 0xF0,
+ 0xa0, 0xff},
+ {0x90, 0x00, 0x91, 0x10, 0x92, 0x22, 0x93, 0x35,
+ 0x94, 0x47, 0x95, 0x5A, 0x96, 0x69, 0x97, 0x79,
+ 0x98, 0x88, 0x99, 0x97, 0x9A, 0xA7, 0x9B, 0xB6,
+ 0x9C, 0xC4, 0x9D, 0xD3, 0x9E, 0xE0, 0x9F, 0xF0,
+ 0xa0, 0xff},
+ {0x90, 0x00, 0x91, 0x10, 0x92, 0x26, 0x93, 0x40,
+ 0x94, 0x54, 0x95, 0x65, 0x96, 0x75, 0x97, 0x84,
+ 0x98, 0x93, 0x99, 0xa1, 0x9a, 0xb0, 0x9b, 0xbd,
+ 0x9c, 0xca, 0x9d, 0xd6, 0x9e, 0xe0, 0x9f, 0xf0,
+ 0xa0, 0xff},
+ {0x90, 0x00, 0x91, 0x18, 0x92, 0x2B, 0x93, 0x44,
+ 0x94, 0x60, 0x95, 0x70, 0x96, 0x80, 0x97, 0x8E,
+ 0x98, 0x9C, 0x99, 0xAA, 0x9A, 0xB7, 0x9B, 0xC4,
+ 0x9C, 0xD0, 0x9D, 0xD8, 0x9E, 0xE2, 0x9F, 0xF0,
+ 0xa0, 0xff},
+ {0x90, 0x00, 0x91, 0x1A, 0x92, 0x34, 0x93, 0x52,
+ 0x94, 0x66, 0x95, 0x7E, 0x96, 0x8D, 0x97, 0x9B,
+ 0x98, 0xA8, 0x99, 0xB4, 0x9A, 0xC0, 0x9B, 0xCB,
+ 0x9C, 0xD6, 0x9D, 0xE1, 0x9E, 0xEB, 0x9F, 0xF5,
+ 0xa0, 0xff},
+ {0x90, 0x00, 0x91, 0x3F, 0x92, 0x5A, 0x93, 0x6E,
+ 0x94, 0x7F, 0x95, 0x8E, 0x96, 0x9C, 0x97, 0xA8,
+ 0x98, 0xB4, 0x99, 0xBF, 0x9A, 0xC9, 0x9B, 0xD3,
+ 0x9C, 0xDC, 0x9D, 0xE5, 0x9E, 0xEE, 0x9F, 0xF6,
+ 0xA0, 0xFF},
+ {0x90, 0x00, 0x91, 0x54, 0x92, 0x6F, 0x93, 0x83,
+ 0x94, 0x93, 0x95, 0xA0, 0x96, 0xAD, 0x97, 0xB7,
+ 0x98, 0xC2, 0x99, 0xCB, 0x9A, 0xD4, 0x9B, 0xDC,
+ 0x9C, 0xE4, 0x9D, 0xEB, 0x9E, 0xF2, 0x9F, 0xF9,
+ 0xa0, 0xff},
+ {0x90, 0x00, 0x91, 0x6E, 0x92, 0x88, 0x93, 0x9A,
+ 0x94, 0xA8, 0x95, 0xB3, 0x96, 0xBD, 0x97, 0xC6,
+ 0x98, 0xCF, 0x99, 0xD6, 0x9A, 0xDD, 0x9B, 0xE3,
+ 0x9C, 0xE9, 0x9D, 0xEF, 0x9E, 0xF4, 0x9F, 0xFA,
+ 0xa0, 0xff},
+ {0x90, 0x00, 0x91, 0x93, 0x92, 0xA8, 0x93, 0xB7,
+ 0x94, 0xC1, 0x95, 0xCA, 0x96, 0xD2, 0x97, 0xD8,
+ 0x98, 0xDE, 0x99, 0xE3, 0x9A, 0xE8, 0x9B, 0xED,
+ 0x9C, 0xF1, 0x9D, 0xF5, 0x9E, 0xF8, 0x9F, 0xFC,
+ 0xA0, 0xFF}
+};
+
+static const __u8 tas5130a_sensor_init[][8] = {
+ {0x62, 0x08, 0x63, 0x70, 0x64, 0x1d, 0x60, 0x09},
+ {0x62, 0x20, 0x63, 0x01, 0x64, 0x02, 0x60, 0x09},
+ {0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09},
+ {0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09},
+ {},
+};
+
+static void t16RegRead(struct usb_device *dev,
+ __u16 index, __u8 *buffer, __u16 length)
+{
+ usb_control_msg(dev,
+ usb_rcvctrlpipe(dev, 0),
+ 0, /* request */
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, /* value */
+ index, buffer, length, 500);
+}
+
+static void t16RegWrite(struct usb_device *dev,
+ __u16 value,
+ __u16 index,
+ const __u8 *buffer, __u16 len)
+{
+ if (buffer == NULL) {
+ usb_control_msg(dev,
+ usb_sndctrlpipe(dev, 0),
+ 0,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+ value, index,
+ NULL, 0, 500);
+ return;
+ }
+ if (len < 16) {
+ __u8 tmpbuf[16];
+
+ memcpy(tmpbuf, buffer, len);
+ usb_control_msg(dev,
+ usb_sndctrlpipe(dev, 0),
+ 0,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+ value, index,
+ tmpbuf, len, 500);
+ } else {
+ __u8 *tmpbuf;
+
+ tmpbuf = kmalloc(len, GFP_KERNEL);
+ memcpy(tmpbuf, buffer, len);
+ usb_control_msg(dev,
+ usb_sndctrlpipe(dev, 0),
+ 0,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+ value, index,
+ tmpbuf, len, 500);
+ kfree(tmpbuf);
+ }
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+ const struct usb_device_id *id)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct cam *cam;
+#if 0
+ __u16 vendor;
+ __u16 product;
+
+ vendor = id->idVendor;
+ product = id->idProduct;
+ switch (vendor) {
+ case 0x17a1:
+ /* t613 + tas5130A */
+ /* Currently one sensor supported... */
+ break;
+ }
+#endif
+
+ cam = &gspca_dev->cam;
+ cam->dev_name = (char *) id->driver_info;
+ cam->epaddr = 0x01;
+
+ cam->cam_mode = vga_mode_t16;
+ cam->nmodes = ARRAY_SIZE(vga_mode_t16);
+
+ sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
+ sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
+ sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value;
+ sd->gamma = sd_ctrls[SD_GAMMA].qctrl.default_value;
+ sd->mirror = sd_ctrls[SD_MIRROR].qctrl.default_value;
+ sd->freq = sd_ctrls[SD_LIGHTFREQ].qctrl.default_value;
+ sd->whitebalance = sd_ctrls[SD_WHITE_BALANCE].qctrl.default_value;
+ sd->sharpness = sd_ctrls[SD_SHARPNESS].qctrl.default_value;
+ sd->effect = sd_ctrls[SD_EFFECTS].qctrl.default_value;
+ return 0;
+}
+
+static int init_default_parameters(struct gspca_dev *gspca_dev)
+{
+ struct usb_device *dev = gspca_dev->dev;
+
+ /* some of this registers are not really neded, because
+ * they are overriden by setbrigthness, setcontrast, etc,
+ * but wont hurt anyway, and can help someone with similar webcam
+ * to see the initial parameters.*/
+ int i = 0;
+ __u8 test_byte;
+
+ static const __u8 read_indexs[] =
+ { 0x06, 0x07, 0x0a, 0x0b, 0x66, 0x80, 0x81, 0x8e, 0x8f, 0xa5,
+ 0xa6, 0xa8, 0xbb, 0xbc, 0xc6, 0x00, 0x00 };
+ static const __u8 n1[6] =
+ {0x08, 0x03, 0x09, 0x03, 0x12, 0x04};
+ static const __u8 n2[2] =
+ {0x08, 0x00};
+ static const __u8 nset[6] =
+ { 0x61, 0x68, 0x62, 0xff, 0x60, 0x07 };
+ static const __u8 n3[6] =
+ {0x61, 0x68, 0x65, 0x0a, 0x60, 0x04};
+ static const __u8 n4[0x46] =
+ {0x09, 0x01, 0x12, 0x04, 0x66, 0x8a, 0x80, 0x3c,
+ 0x81, 0x22, 0x84, 0x50, 0x8a, 0x78, 0x8b, 0x68,
+ 0x8c, 0x88, 0x8e, 0x33, 0x8f, 0x24, 0xaa, 0xb1,
+ 0xa2, 0x60, 0xa5, 0x30, 0xa6, 0x3a, 0xa8, 0xe8,
+ 0xae, 0x05, 0xb1, 0x00, 0xbb, 0x04, 0xbc, 0x48,
+ 0xbe, 0x36, 0xc6, 0x88, 0xe9, 0x00, 0xc5, 0xc0,
+ 0x65, 0x0a, 0xbb, 0x86, 0xaf, 0x58, 0xb0, 0x68,
+ 0x87, 0x40, 0x89, 0x2b, 0x8d, 0xff, 0x83, 0x40,
+ 0xac, 0x84, 0xad, 0x86, 0xaf, 0x46};
+#if 0
+ static const __u8 nset1[50] = {
+ 0x80, 0x3c, 0x81, 0x68, 0x83, 0xa0, 0x84, 0x20, 0x8a, 0x5c,
+ 0x8b, 0x4c, 0x8c, 0x88, 0x8e, 0xb4,
+ 0x8f, 0x24, 0xa1, 0xb1, 0xa2, 0x30, 0xa5, 0x18, 0xa6, 0x4a,
+ 0xae, 0x03, 0xb1, 0x44, 0xb2, 0x08,
+ 0xb7, 0x06, 0xb9, 0xe7, 0xbb, 0xc4, 0xbc, 0x4a, 0xbe, 0x36,
+ 0xbf, 0xff, 0xc2, 0x88, 0xc5, 0xc0,
+ 0xc6, 0xd2
+ };
+#endif
+ static const __u8 nset4[18] = {
+ 0xe0, 0x60, 0xe1, 0xa8, 0xe2, 0xe0, 0xe3, 0x60, 0xe4, 0xa8,
+ 0xe5, 0xe0, 0xe6, 0x60, 0xe7, 0xa8,
+ 0xe8, 0xe0
+ };
+ /* ojo puede ser 0xe6 en vez de 0xe9 */
+ static const __u8 nset2[20] = {
+ 0xd0, 0xbb, 0xd1, 0x28, 0xd2, 0x10, 0xd3, 0x10, 0xd4, 0xbb,
+ 0xd5, 0x28, 0xd6, 0x1e, 0xd7, 0x27,
+ 0xd8, 0xc8, 0xd9, 0xfc
+ };
+ static const __u8 missing[8] =
+ { 0x87, 0x20, 0x88, 0x20, 0x89, 0x20, 0x80, 0x38 };
+ static const __u8 nset3[18] = {
+ 0xc7, 0x60, 0xc8, 0xa8, 0xc9, 0xe0, 0xca, 0x60, 0xcb, 0xa8,
+ 0xcc, 0xe0, 0xcd, 0x60, 0xce, 0xa8,
+ 0xcf, 0xe0
+ };
+ static const __u8 nset5[4] =
+ { 0x8f, 0x24, 0xc3, 0x00 }; /* bright */
+ static const __u8 nset6[34] = {
+ 0x90, 0x00, 0x91, 0x1c, 0x92, 0x30, 0x93, 0x43, 0x94, 0x54,
+ 0x95, 0x65, 0x96, 0x75, 0x97, 0x84,
+ 0x98, 0x93, 0x99, 0xa1, 0x9a, 0xb0, 0x9b, 0xbd, 0x9c, 0xca,
+ 0x9d, 0xd8, 0x9e, 0xe5, 0x9f, 0xf2,
+ 0xa0, 0xff
+ }; /* Gamma */
+ static const __u8 nset7[4] =
+ { 0x66, 0xca, 0xa8, 0xf8 }; /* 50/60 Hz */
+ static const __u8 nset9[4] =
+ { 0x0b, 0x04, 0x0a, 0x78 };
+ static const __u8 nset8[6] =
+ { 0xa8, 0xf0, 0xc6, 0x88, 0xc0, 0x00 };
+ static const __u8 nset10[6] =
+ { 0x0c, 0x03, 0xab, 0x10, 0x81, 0x20 };
+
+ t16RegWrite(dev, 0x01, 0x0000, n1, 0x06);
+ t16RegWrite(dev, 0x01, 0x0000, nset, 0x06);
+ t16RegRead(dev, 0x0063, &test_byte, 1);
+ t16RegWrite(dev, 0x01, 0x0000, n2, 0x02);
+
+ while (read_indexs[i] != 0x00) {
+ t16RegRead(dev, read_indexs[i], &test_byte, 1);
+ PDEBUG(D_CONF, "Reg 0x%x => 0x%x", read_indexs[i],
+ test_byte);
+ i++;
+ }
+
+ t16RegWrite(dev, 0x01, 0x0000, n3, 0x06);
+ t16RegWrite(dev, 0x01, 0x0000, n4, 0x46);
+ t16RegRead(dev, 0x0080, &test_byte, 1);
+ t16RegWrite(dev, 0x00, 0x2c80, NULL, 0);
+ t16RegWrite(dev, 0x01, 0x0000, nset2, 0x14);
+ t16RegWrite(dev, 0x01, 0x0000, nset3, 0x12);
+ t16RegWrite(dev, 0x01, 0x0000, nset4, 0x12);
+ t16RegWrite(dev, 0x00, 0x3880, NULL, 0);
+ t16RegWrite(dev, 0x00, 0x3880, NULL, 0);
+ t16RegWrite(dev, 0x00, 0x338e, NULL, 0);
+ t16RegWrite(dev, 0x01, 0x0000, nset5, 0x04);
+ t16RegWrite(dev, 0x00, 0x00a9, NULL, 0);
+ t16RegWrite(dev, 0x01, 0x0000, nset6, 0x22);
+ t16RegWrite(dev, 0x00, 0x86bb, NULL, 0);
+ t16RegWrite(dev, 0x00, 0x4aa6, NULL, 0);
+
+ t16RegWrite(dev, 0x01, 0x0000, missing, 0x08);
+
+ t16RegWrite(dev, 0x00, 0x2087, NULL, 0);
+ t16RegWrite(dev, 0x00, 0x2088, NULL, 0);
+ t16RegWrite(dev, 0x00, 0x2089, NULL, 0);
+
+ t16RegWrite(dev, 0x01, 0x0000, nset7, 0x04);
+ t16RegWrite(dev, 0x01, 0x0000, nset10, 0x06);
+ t16RegWrite(dev, 0x01, 0x0000, nset8, 0x06);
+ t16RegWrite(dev, 0x01, 0x0000, nset9, 0x04);
+
+ t16RegWrite(dev, 0x00, 0x2880, NULL, 0);
+ t16RegWrite(dev, 0x01, 0x0000, nset2, 0x14);
+ t16RegWrite(dev, 0x01, 0x0000, nset3, 0x12);
+ t16RegWrite(dev, 0x01, 0x0000, nset4, 0x12);
+
+ return 0;
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+ unsigned int brightness;
+ __u8 set6[4] = { 0x8f, 0x26, 0xc3, 0x80 };
+ brightness = sd->brightness;
+
+ if (brightness < 7) {
+ set6[3] = 0x70 - (brightness * 0xa);
+ } else {
+ set6[1] = 0x24;
+ set6[3] = 0x00 + ((brightness - 7) * 0xa);
+ }
+
+ t16RegWrite(dev, 0x01, 0x0000, set6, 4);
+}
+
+static void setflip(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+
+ __u8 flipcmd[8] =
+ { 0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09 };
+
+ if (sd->mirror == 1)
+ flipcmd[3] = 0x01;
+
+ t16RegWrite(dev, 0x01, 0x0000, flipcmd, 8);
+}
+
+static void seteffect(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+
+ t16RegWrite(dev, 0x01, 0x0000, effects_table[sd->effect], 0x06);
+ if (sd->effect == 1 || sd->effect == 5) {
+ PDEBUG(D_CONF,
+ "This effect have been disabled for webcam \"safety\"");
+ return;
+ }
+
+ if (sd->effect == 1 || sd->effect == 4)
+ t16RegWrite(dev, 0x00, 0x4aa6, NULL, 0);
+ else
+ t16RegWrite(dev, 0x00, 0xfaa6, NULL, 0);
+}
+
+static void setwhitebalance(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+
+ __u8 white_balance[8] =
+ { 0x87, 0x20, 0x88, 0x20, 0x89, 0x20, 0x80, 0x38 };
+
+ if (sd->whitebalance == 1)
+ white_balance[7] = 0x3c;
+
+ t16RegWrite(dev, 0x01, 0x0000, white_balance, 8);
+}
+
+static void setlightfreq(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+ __u8 freq[4] = { 0x66, 0x40, 0xa8, 0xe8 };
+
+ if (sd->freq == 2) /* 60hz */
+ freq[1] = 0x00;
+
+ t16RegWrite(dev, 0x1, 0x0000, freq, 0x4);
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+ unsigned int contrast = sd->contrast;
+ __u16 reg_to_write = 0x00;
+
+ if (contrast < 7)
+ reg_to_write = 0x8ea9 - (0x200 * contrast);
+ else
+ reg_to_write = (0x00a9 + ((contrast - 7) * 0x200));
+
+ t16RegWrite(dev, 0x00, reg_to_write, NULL, 0);
+}
+
+static void setcolors(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+ __u16 reg_to_write;
+
+ reg_to_write = 0xc0bb + sd->colors * 0x100;
+ t16RegWrite(dev, 0x00, reg_to_write, NULL, 0);
+}
+
+static void setgamma(struct gspca_dev *gspca_dev)
+{
+#if 0
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+
+ PDEBUG(D_CONF, "Gamma: %d", sd->gamma);
+
+ t16RegWrite(dev, 0x01, 0x0000, gamma_table[sd->gamma], 34);
+#endif
+}
+
+static void setsharpness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+ __u16 reg_to_write;
+
+ reg_to_write = 0x0aa6 + 0x1000 * sd->sharpness;
+
+ t16RegWrite(dev, 0x00, reg_to_write, NULL, 0);
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->brightness = val;
+ if (gspca_dev->streaming)
+ setbrightness(gspca_dev);
+ return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->brightness;
+ return *val;
+}
+
+static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->whitebalance = val;
+ if (gspca_dev->streaming)
+ setwhitebalance(gspca_dev);
+ return 0;
+}
+
+static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->whitebalance;
+ return *val;
+}
+
+static int sd_setflip(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->mirror = val;
+ if (gspca_dev->streaming)
+ setflip(gspca_dev);
+ return 0;
+}
+
+static int sd_getflip(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->mirror;
+ return *val;
+}
+
+static int sd_seteffect(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->effect = val;
+ if (gspca_dev->streaming)
+ seteffect(gspca_dev);
+ return 0;
+}
+
+static int sd_geteffect(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->effect;
+ return *val;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->contrast = val;
+ if (gspca_dev->streaming)
+ setcontrast(gspca_dev);
+ return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->contrast;
+ return *val;
+}
+
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->colors = val;
+ if (gspca_dev->streaming)
+ setcolors(gspca_dev);
+ return 0;
+}
+
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->colors;
+ return 0;
+}
+
+static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->gamma = val;
+ if (gspca_dev->streaming)
+ setgamma(gspca_dev);
+ return 0;
+}
+
+static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ *val = sd->gamma;
+ return 0;
+}
+
+static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->freq = val;
+ if (gspca_dev->streaming)
+ setlightfreq(gspca_dev);
+ return 0;
+}
+
+static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->freq;
+ return 0;
+}
+
+static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->sharpness = val;
+ if (gspca_dev->streaming)
+ setsharpness(gspca_dev);
+ return 0;
+}
+
+static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->sharpness;
+ return 0;
+}
+
+/* Low Light set here......*/
+static int sd_setlowlight(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+
+ sd->autogain = val;
+ if (val != 0)
+ t16RegWrite(dev, 0x00, 0xf48e, NULL, 0);
+ else
+ t16RegWrite(dev, 0x00, 0xb48e, NULL, 0);
+ return 0;
+}
+
+static int sd_getlowlight(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->autogain;
+ return 0;
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+ struct usb_device *dev = gspca_dev->dev;
+ int mode;
+ __u8 test_byte;
+
+ static const __u8 t1[] = { 0x66, 0x00, 0xa8, 0xe8 };
+ __u8 t2[] = { 0x07, 0x00, 0x0d, 0x60, 0x0e, 0x80 };
+ static const __u8 t3[] =
+ { 0xb3, 0x07, 0xb4, 0x00, 0xb5, 0x88, 0xb6, 0x02, 0xb7, 0x06,
+ 0xb8, 0x00, 0xb9, 0xe7, 0xba, 0x01 };
+ static const __u8 t4[] = { 0x0b, 0x04, 0x0a, 0x40 };
+
+ mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode]. priv;
+ switch (mode) {
+ case 1: /* 352x288 */
+ t2[1] = 0x40;
+ break;
+ case 2: /* 320x240 */
+ t2[1] = 0x10;
+ break;
+ case 3: /* 176x144 */
+ t2[1] = 0x50;
+ break;
+ case 4: /* 160x120 */
+ t2[1] = 0x20;
+ break;
+ default: /* 640x480 (0x00) */
+ break;
+ }
+
+ t16RegWrite(dev, 0x01, 0x0000, tas5130a_sensor_init[0], 0x8);
+ t16RegWrite(dev, 0x01, 0x0000, tas5130a_sensor_init[1], 0x8);
+ t16RegWrite(dev, 0x01, 0x0000, tas5130a_sensor_init[2], 0x8);
+ t16RegWrite(dev, 0x01, 0x0000, tas5130a_sensor_init[3], 0x8);
+ t16RegWrite(dev, 0x00, 0x3c80, NULL, 0);
+ /* just in case and to keep sync with logs (for mine) */
+ t16RegWrite(dev, 0x01, 0x0000, tas5130a_sensor_init[3], 0x8);
+ t16RegWrite(dev, 0x00, 0x3c80, NULL, 0);
+ /* just in case and to keep sync with logs (for mine) */
+ t16RegWrite(dev, 0x01, 0x0000, t1, 4);
+ t16RegWrite(dev, 0x01, 0x0000, t2, 6);
+ t16RegRead(dev, 0x0012, &test_byte, 0x01);
+ t16RegWrite(dev, 0x01, 0x0000, t3, 0x10);
+ t16RegWrite(dev, 0x00, 0x0013, NULL, 0);
+ t16RegWrite(dev, 0x01, 0x0000, t4, 0x4);
+ /* restart on each start, just in case, sometimes regs goes wrong
+ * when using controls from app */
+ setbrightness(gspca_dev);
+ setcontrast(gspca_dev);
+ setcolors(gspca_dev);
+#if 0
+ seteffect(gspca_dev);
+ setflip(gspca_dev);
+#endif
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ struct gspca_frame *frame, /* target */
+ __u8 *data, /* isoc packet */
+ int len) /* iso packet length */
+{
+ int sof = 0;
+ static __u8 ffd9[] = { 0xff, 0xd9 };
+
+ if (data[0] == 0x5a) {
+ /* Control Packet, after this came the header again,
+ * but extra bytes came in the packet before this,
+ * sometimes an EOF arrives, sometimes not... */
+ return;
+ }
+
+ if (data[len - 1] == 0xff && data[len] == 0xd9) {
+ /* Just in case, i have seen packets with the marker,
+ * other's do not include it... */
+ data += 2;
+ len -= 4;
+ } else if (data[2] == 0xff && data[3] == 0xd8) {
+ sof = 1;
+ data += 2;
+ len -= 2;
+ } else {
+ data += 2;
+ len -= 2;
+ }
+
+ if (sof) {
+ /* extra bytes....., could be processed too but would be
+ * a waste of time, right now leave the application and
+ * libjpeg do it for ourserlves.. */
+ frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+ ffd9, 2);
+ gspca_frame_add(gspca_dev, FIRST_PACKET, frame, data, len);
+ return;
+ }
+
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+}
+
+static int sd_querymenu(struct gspca_dev *gspca_dev,
+ struct v4l2_querymenu *menu)
+{
+ switch (menu->id) {
+ case V4L2_CID_POWER_LINE_FREQUENCY:
+ switch (menu->index) {
+ case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
+ strcpy((char *) menu->name, "50 Hz");
+ return 0;
+ case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
+ strcpy((char *) menu->name, "60 Hz");
+ return 0;
+ }
+ break;
+ case V4L2_CID_EFFECTS:
+ if ((unsigned) menu->index < ARRAY_SIZE(effects_control)) {
+ strncpy((char *) menu->name,
+ effects_control[menu->index], 32);
+ return 0;
+ }
+ break;
+ }
+ return -EINVAL;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+ init_default_parameters(gspca_dev);
+ return 0;
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .ctrls = sd_ctrls,
+ .nctrls = ARRAY_SIZE(sd_ctrls),
+ .config = sd_config,
+ .open = sd_open,
+ .start = sd_start,
+ .stopN = sd_stopN,
+ .stop0 = sd_stop0,
+ .close = sd_close,
+ .pkt_scan = sd_pkt_scan,
+ .querymenu = sd_querymenu,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static const __devinitdata struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x17a1, 0x0128), DVNM("XPX Webcam")},
+ {}
+};
+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,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+ if (usb_register(&sd_driver) < 0)
+ return -1;
+ PDEBUG(D_PROBE, "v%s registered", version);
+ return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+ usb_deregister(&sd_driver);
+ PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/linux/drivers/media/video/gspca/tv8532.c b/linux/drivers/media/video/gspca/tv8532.c
new file mode 100644
index 000000000..b9837841c
--- /dev/null
+++ b/linux/drivers/media/video/gspca/tv8532.c
@@ -0,0 +1,727 @@
+/*
+ * Quickcam cameras initialization data
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#define MODULE_NAME "tv8532"
+
+#include "gspca.h"
+
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 5)
+static const char version[] = "2.1.5";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("TV8532 USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+
+ int buflen; /* current length of tmpbuf */
+ __u8 tmpbuf[352 * 288 + 10 * 288]; /* no protection... */
+ __u8 tmpbuf2[352 * 288]; /* no protection... */
+
+ unsigned short brightness;
+ unsigned short contrast;
+
+ char packet;
+ char synchro;
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+#define SD_BRIGHTNESS 0
+ {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 1,
+ .maximum = 0x2ff,
+ .step = 1,
+ .default_value = 0x18f,
+ },
+ .set = sd_setbrightness,
+ .get = sd_getbrightness,
+ },
+#define SD_CONTRAST 1
+ {
+ {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = 0,
+ .maximum = 0xffff,
+ .step = 1,
+ .default_value = 0x7fff,
+ },
+ .set = sd_setcontrast,
+ .get = sd_getcontrast,
+ },
+};
+
+static struct v4l2_pix_format sif_mode[] = {
+ {176, 144, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+ .bytesperline = 176,
+ .sizeimage = 176 * 144,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 1},
+ {352, 288, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+ .bytesperline = 352,
+ .sizeimage = 352 * 288,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0},
+};
+
+/*
+ * Initialization data: this is the first set-up data written to the
+ * device (before the open data).
+ */
+#define TESTCLK 0x10 /* reg 0x2c -> 0x12 //10 */
+#define TESTCOMP 0x90 /* reg 0x28 -> 0x80 */
+#define TESTLINE 0x81 /* reg 0x29 -> 0x81 */
+#define QCIFLINE 0x41 /* reg 0x29 -> 0x81 */
+#define TESTPTL 0x14 /* reg 0x2D -> 0x14 */
+#define TESTPTH 0x01 /* reg 0x2E -> 0x01 */
+#define TESTPTBL 0x12 /* reg 0x2F -> 0x0a */
+#define TESTPTBH 0x01 /* reg 0x30 -> 0x01 */
+#define ADWIDTHL 0xe8 /* reg 0x0c -> 0xe8 */
+#define ADWIDTHH 0x03 /* reg 0x0d -> 0x03 */
+#define ADHEIGHL 0x90 /* reg 0x0e -> 0x91 //93 */
+#define ADHEIGHH 0x01 /* reg 0x0f -> 0x01 */
+#define EXPOL 0x8f /* reg 0x1c -> 0x8f */
+#define EXPOH 0x01 /* reg 0x1d -> 0x01 */
+#define ADCBEGINL 0x44 /* reg 0x10 -> 0x46 //47 */
+#define ADCBEGINH 0x00 /* reg 0x11 -> 0x00 */
+#define ADRBEGINL 0x0a /* reg 0x14 -> 0x0b //0x0c */
+#define ADRBEGINH 0x00 /* reg 0x15 -> 0x00 */
+#define TV8532_CMD_UPDATE 0x84
+
+#define TV8532_EEprom_Add 0x03
+#define TV8532_EEprom_DataL 0x04
+#define TV8532_EEprom_DataM 0x05
+#define TV8532_EEprom_DataH 0x06
+#define TV8532_EEprom_TableLength 0x07
+#define TV8532_EEprom_Write 0x08
+#define TV8532_PART_CTRL 0x00
+#define TV8532_CTRL 0x01
+#define TV8532_CMD_EEprom_Open 0x30
+#define TV8532_CMD_EEprom_Close 0x29
+#define TV8532_UDP_UPDATE 0x31
+#define TV8532_GPIO 0x39
+#define TV8532_GPIO_OE 0x3B
+#define TV8532_REQ_RegWrite 0x02
+#define TV8532_REQ_RegRead 0x03
+
+#define TV8532_ADWIDTH_L 0x0C
+#define TV8532_ADWIDTH_H 0x0D
+#define TV8532_ADHEIGHT_L 0x0E
+#define TV8532_ADHEIGHT_H 0x0F
+#define TV8532_EXPOSURE 0x1C
+#define TV8532_QUANT_COMP 0x28
+#define TV8532_MODE_PACKET 0x29
+#define TV8532_SETCLK 0x2C
+#define TV8532_POINT_L 0x2D
+#define TV8532_POINT_H 0x2E
+#define TV8532_POINTB_L 0x2F
+#define TV8532_POINTB_H 0x30
+#define TV8532_BUDGET_L 0x2A
+#define TV8532_BUDGET_H 0x2B
+#define TV8532_VID_L 0x34
+#define TV8532_VID_H 0x35
+#define TV8532_PID_L 0x36
+#define TV8532_PID_H 0x37
+#define TV8532_DeviceID 0x83
+#define TV8532_AD_SLOPE 0x91
+#define TV8532_AD_BITCTRL 0x94
+#define TV8532_AD_COLBEGIN_L 0x10
+#define TV8532_AD_COLBEGIN_H 0x11
+#define TV8532_AD_ROWBEGIN_L 0x14
+#define TV8532_AD_ROWBEGIN_H 0x15
+
+static const __u32 tv_8532_eeprom_data[] = {
+/* add dataL dataM dataH */
+ 0x00010001, 0x01018011, 0x02050014, 0x0305001c,
+ 0x040d001e, 0x0505001f, 0x06050519, 0x0705011b,
+ 0x0805091e, 0x090d892e, 0x0a05892f, 0x0b050dd9,
+ 0x0c0509f1, 0
+};
+
+static void reg_r(struct usb_device *dev,
+ __u16 index, __u8 *buffer)
+{
+ usb_control_msg(dev,
+ usb_rcvctrlpipe(dev, 0),
+ TV8532_REQ_RegRead,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, /* value */
+ index, buffer, sizeof(__u8),
+ 500);
+}
+
+static void reg_w(struct usb_device *dev,
+ __u16 index, __u8 *buffer, __u16 length)
+{
+ usb_control_msg(dev,
+ usb_sndctrlpipe(dev, 0),
+ TV8532_REQ_RegWrite,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, /* value */
+ index, buffer, length, 500);
+}
+
+static void tv_8532WriteEEprom(struct gspca_dev *gspca_dev)
+{
+ int i = 0;
+ __u8 reg, data0, data1, data2, datacmd;
+ struct usb_device *dev = gspca_dev->dev;
+
+ datacmd = 0xb0;;
+ reg_w(dev, TV8532_GPIO, &datacmd, 1);
+ datacmd = TV8532_CMD_EEprom_Open;
+ reg_w(dev, TV8532_CTRL, &datacmd, 1);
+/* msleep(1); */
+ while (tv_8532_eeprom_data[i]) {
+ reg = (tv_8532_eeprom_data[i] & 0xff000000) >> 24;
+ reg_w(dev, TV8532_EEprom_Add, &reg, 1);
+ /* msleep(1); */
+ data0 = (tv_8532_eeprom_data[i] & 0x000000ff);
+ reg_w(dev, TV8532_EEprom_DataL, &data0, 1);
+ /* msleep(1); */
+ data1 = (tv_8532_eeprom_data[i] & 0x0000FF00) >> 8;
+ reg_w(dev, TV8532_EEprom_DataM, &data1, 1);
+ /* msleep(1); */
+ data2 = (tv_8532_eeprom_data[i] & 0x00FF0000) >> 16;
+ reg_w(dev, TV8532_EEprom_DataH, &data2, 1);
+ /* msleep(1); */
+ datacmd = 0;
+ reg_w(dev, TV8532_EEprom_Write, &datacmd, 1);
+ /* msleep(10); */
+ i++;
+ }
+ datacmd = i;
+ reg_w(dev, TV8532_EEprom_TableLength, &datacmd, 1);
+/* msleep(1); */
+ datacmd = TV8532_CMD_EEprom_Close;
+ reg_w(dev, TV8532_CTRL, &datacmd, 1);
+ msleep(10);
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+ const struct usb_device_id *id)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct cam *cam;
+
+ tv_8532WriteEEprom(gspca_dev);
+
+ cam = &gspca_dev->cam;
+ cam->dev_name = (char *) id->driver_info;
+ cam->epaddr = 1;
+ cam->cam_mode = sif_mode;
+ cam->nmodes = sizeof sif_mode / sizeof sif_mode[0];
+
+ sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
+ sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
+ return 0;
+}
+
+static void tv_8532ReadRegisters(struct gspca_dev *gspca_dev)
+{
+ struct usb_device *dev = gspca_dev->dev;
+ __u8 data;
+/* __u16 vid, pid; */
+
+ reg_r(dev, 0x0001, &data);
+ PDEBUG(D_USBI, "register 0x01-> %x", data);
+ reg_r(dev, 0x0002, &data);
+ PDEBUG(D_USBI, "register 0x02-> %x", data);
+ reg_r(dev, TV8532_ADWIDTH_L, &data);
+ reg_r(dev, TV8532_ADWIDTH_H, &data);
+ reg_r(dev, TV8532_QUANT_COMP, &data);
+ reg_r(dev, TV8532_MODE_PACKET, &data);
+ reg_r(dev, TV8532_SETCLK, &data);
+ reg_r(dev, TV8532_POINT_L, &data);
+ reg_r(dev, TV8532_POINT_H, &data);
+ reg_r(dev, TV8532_POINTB_L, &data);
+ reg_r(dev, TV8532_POINTB_H, &data);
+ reg_r(dev, TV8532_BUDGET_L, &data);
+ reg_r(dev, TV8532_BUDGET_H, &data);
+ reg_r(dev, TV8532_VID_L, &data);
+ reg_r(dev, TV8532_VID_H, &data);
+ reg_r(dev, TV8532_PID_L, &data);
+ reg_r(dev, TV8532_PID_H, &data);
+ reg_r(dev, TV8532_DeviceID, &data);
+ reg_r(dev, TV8532_AD_COLBEGIN_L, &data);
+ reg_r(dev, TV8532_AD_COLBEGIN_H, &data);
+ reg_r(dev, TV8532_AD_ROWBEGIN_L, &data);
+ reg_r(dev, TV8532_AD_ROWBEGIN_H, &data);
+}
+
+static void tv_8532_setReg(struct gspca_dev *gspca_dev)
+{
+ struct usb_device *dev = gspca_dev->dev;
+ __u8 data;
+ __u8 value[2] = { 0, 0 };
+
+ data = ADCBEGINL;
+ reg_w(dev, TV8532_AD_COLBEGIN_L, &data, 1); /* 0x10 */
+ data = ADCBEGINH; /* also digital gain */
+ reg_w(dev, TV8532_AD_COLBEGIN_H, &data, 1);
+ data = TV8532_CMD_UPDATE;
+ reg_w(dev, TV8532_PART_CTRL, &data, 1); /* 0x00<-0x84 */
+
+ data = 0x0a;
+ reg_w(dev, TV8532_GPIO_OE, &data, 1);
+ /******************************************************/
+ data = ADHEIGHL;
+ reg_w(dev, TV8532_ADHEIGHT_L, &data, 1); /* 0e */
+ data = ADHEIGHH;
+ reg_w(dev, TV8532_ADHEIGHT_H, &data, 1); /* 0f */
+ value[0] = EXPOL;
+ value[1] = EXPOH; /* 350d 0x014c; */
+ reg_w(dev, TV8532_EXPOSURE, value, 2); /* 1c */
+ data = ADCBEGINL;
+ reg_w(dev, TV8532_AD_COLBEGIN_L, &data, 1); /* 0x10 */
+ data = ADCBEGINH; /* also digital gain */
+ reg_w(dev, TV8532_AD_COLBEGIN_H, &data, 1);
+ data = ADRBEGINL;
+ reg_w(dev, TV8532_AD_ROWBEGIN_L, &data, 1); /* 0x14 */
+
+ data = 0x00;
+ reg_w(dev, TV8532_AD_SLOPE, &data, 1); /* 0x91 */
+ data = 0x02;
+ reg_w(dev, TV8532_AD_BITCTRL, &data, 1); /* 0x94 */
+
+
+ data = TV8532_CMD_EEprom_Close;
+ reg_w(dev, TV8532_CTRL, &data, 1); /* 0x01 */
+
+ data = 0x00;
+ reg_w(dev, TV8532_AD_SLOPE, &data, 1); /* 0x91 */
+ data = TV8532_CMD_UPDATE;
+ reg_w(dev, TV8532_PART_CTRL, &data, 1); /* 0x00<-0x84 */
+}
+
+static void tv_8532_PollReg(struct gspca_dev *gspca_dev)
+{
+ struct usb_device *dev = gspca_dev->dev;
+ __u8 data;
+ int i;
+
+ /* strange polling from tgc */
+ for (i = 0; i < 10; i++) {
+ data = TESTCLK; /* 0x48; //0x08; */
+ reg_w(dev, TV8532_SETCLK, &data, 1); /* 0x2c */
+ data = TV8532_CMD_UPDATE;
+ reg_w(dev, TV8532_PART_CTRL, &data, 1);
+ data = 0x01;
+ reg_w(dev, TV8532_UDP_UPDATE, &data, 1); /* 0x31 */
+ }
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+ struct usb_device *dev = gspca_dev->dev;
+ __u8 data;
+ __u8 dataStart;
+ __u8 value[2];
+
+ data = 0x32;
+ reg_w(dev, TV8532_AD_SLOPE, &data, 1);
+ data = 0;
+ reg_w(dev, TV8532_AD_BITCTRL, &data, 1);
+ tv_8532ReadRegisters(gspca_dev);
+ data = 0x0b;
+ reg_w(dev, TV8532_GPIO_OE, &data, 1);
+ value[0] = ADHEIGHL;
+ value[1] = ADHEIGHH; /* 401d 0x0169; */
+ reg_w(dev, TV8532_ADHEIGHT_L, value, 2); /* 0e */
+ value[0] = EXPOL;
+ value[1] = EXPOH; /* 350d 0x014c; */
+ reg_w(dev, TV8532_EXPOSURE, value, 2); /* 1c */
+ data = ADWIDTHL; /* 0x20; */
+ reg_w(dev, TV8532_ADWIDTH_L, &data, 1); /* 0x0c */
+ data = ADWIDTHH;
+ reg_w(dev, TV8532_ADWIDTH_H, &data, 1); /* 0x0d */
+
+ /*******************************************************************/
+ data = TESTCOMP; /* 0x72 compressed mode */
+ reg_w(dev, TV8532_QUANT_COMP, &data, 1); /* 0x28 */
+ data = TESTLINE; /* 0x84; // CIF | 4 packet */
+ reg_w(dev, TV8532_MODE_PACKET, &data, 1); /* 0x29 */
+
+ /************************************************/
+ data = TESTCLK; /* 0x48; //0x08; */
+ reg_w(dev, TV8532_SETCLK, &data, 1); /* 0x2c */
+ data = TESTPTL; /* 0x38; */
+ reg_w(dev, TV8532_POINT_L, &data, 1); /* 0x2d */
+ data = TESTPTH; /* 0x04; */
+ reg_w(dev, TV8532_POINT_H, &data, 1); /* 0x2e */
+ dataStart = TESTPTBL; /* 0x04; */
+ reg_w(dev, TV8532_POINTB_L, &dataStart, 1); /* 0x2f */
+ data = TESTPTBH; /* 0x04; */
+ reg_w(dev, TV8532_POINTB_H, &data, 1); /* 0x30 */
+ data = TV8532_CMD_UPDATE;
+ reg_w(dev, TV8532_PART_CTRL, &data, 1); /* 0x00<-0x84 */
+ /*************************************************/
+ data = 0x01;
+ reg_w(dev, TV8532_UDP_UPDATE, &data, 1); /* 0x31 */
+ msleep(200);
+ data = 0x00;
+ reg_w(dev, TV8532_UDP_UPDATE, &data, 1); /* 0x31 */
+ /*************************************************/
+ tv_8532_setReg(gspca_dev);
+ /*************************************************/
+ data = 0x0b;
+ reg_w(dev, TV8532_GPIO_OE, &data, 1);
+ /*************************************************/
+ tv_8532_setReg(gspca_dev);
+ /*************************************************/
+ tv_8532_PollReg(gspca_dev);
+ return 0;
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ __u8 value[2];
+ __u8 data;
+ int brightness = sd->brightness;
+
+ value[1] = (brightness >> 8) & 0xff;
+ value[0] = (brightness) & 0xff;
+ reg_w(gspca_dev->dev, TV8532_EXPOSURE, value, 2); /* 1c */
+ data = TV8532_CMD_UPDATE;
+ reg_w(gspca_dev->dev, TV8532_PART_CTRL, &data, 1);
+}
+
+/* -- start the camera -- */
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+ struct usb_device *dev = gspca_dev->dev;
+ __u8 data;
+ __u8 value[2];
+
+ data = 0x32;
+ reg_w(dev, TV8532_AD_SLOPE, &data, 1);
+ data = 0;
+ reg_w(dev, TV8532_AD_BITCTRL, &data, 1);
+ tv_8532ReadRegisters(gspca_dev);
+ data = 0x0b;
+ reg_w(dev, TV8532_GPIO_OE, &data, 1);
+ value[0] = ADHEIGHL;
+ value[1] = ADHEIGHH; /* 401d 0x0169; */
+ reg_w(dev, TV8532_ADHEIGHT_L, value, 2); /* 0e */
+/* value[0] = EXPOL; value[1] =EXPOH; * 350d 0x014c; */
+/* reg_w(dev,TV8532_REQ_RegWrite,0,TV8532_EXPOSURE,value,2); * 1c */
+ setbrightness(gspca_dev);
+
+ data = ADWIDTHL; /* 0x20; */
+ reg_w(dev, TV8532_ADWIDTH_L, &data, 1); /* 0x0c */
+ data = ADWIDTHH;
+ reg_w(dev, TV8532_ADWIDTH_H, &data, 1); /* 0x0d */
+
+ /************************************************/
+ data = TESTCOMP; /* 0x72 compressed mode */
+ reg_w(dev, TV8532_QUANT_COMP, &data, 1); /* 0x28 */
+ if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
+ /* 176x144 */
+ data = QCIFLINE; /* 0x84; // CIF | 4 packet */
+ reg_w(dev, TV8532_MODE_PACKET, &data, 1); /* 0x29 */
+ } else {
+ /* 352x288 */
+ data = TESTLINE; /* 0x84; // CIF | 4 packet */
+ reg_w(dev, TV8532_MODE_PACKET, &data, 1); /* 0x29 */
+ }
+ /************************************************/
+ data = TESTCLK; /* 0x48; //0x08; */
+ reg_w(dev, TV8532_SETCLK, &data, 1); /* 0x2c */
+ data = TESTPTL; /* 0x38; */
+ reg_w(dev, TV8532_POINT_L, &data, 1); /* 0x2d */
+ data = TESTPTH; /* 0x04; */
+ reg_w(dev, TV8532_POINT_H, &data, 1); /* 0x2e */
+ data = TESTPTBL; /* 0x04; */
+ reg_w(dev, TV8532_POINTB_L, &data, 1); /* 0x2f */
+ data = TESTPTBH; /* 0x04; */
+ reg_w(dev, TV8532_POINTB_H, &data, 1); /* 0x30 */
+ data = TV8532_CMD_UPDATE;
+ reg_w(dev, TV8532_PART_CTRL, &data, 1); /* 0x00<-0x84 */
+ /************************************************/
+ data = 0x01;
+ reg_w(dev, TV8532_UDP_UPDATE, &data, 1); /* 0x31 */
+ msleep(200);
+ data = 0x00;
+ reg_w(dev, TV8532_UDP_UPDATE, &data, 1); /* 0x31 */
+ /************************************************/
+ tv_8532_setReg(gspca_dev);
+ /************************************************/
+ data = 0x0b;
+ reg_w(dev, TV8532_GPIO_OE, &data, 1);
+ /************************************************/
+ tv_8532_setReg(gspca_dev);
+ /************************************************/
+ tv_8532_PollReg(gspca_dev);
+ data = 0x00;
+ reg_w(dev, TV8532_UDP_UPDATE, &data, 1); /* 0x31 */
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+ struct usb_device *dev = gspca_dev->dev;
+ __u8 data;
+
+ data = 0x0b;
+ reg_w(dev, TV8532_GPIO_OE, &data, 1);
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+static void tv8532_preprocess(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+/* we should received a whole frame with header and EOL marker
+ * in gspca_dev->tmpbuf and return a GBRG pattern in gspca_dev->tmpbuf2
+ * sequence 2bytes header the Alternate pixels bayer GB 4 bytes
+ * Alternate pixels bayer RG 4 bytes EOL */
+ int width = gspca_dev->width;
+ int height = gspca_dev->height;
+ unsigned char *dst = sd->tmpbuf2;
+ unsigned char *data = sd->tmpbuf;
+ int i;
+
+ /* precompute where is the good bayer line */
+ if (((data[3] + data[width + 7]) >> 1)
+ + (data[4] >> 2)
+ + (data[width + 6] >> 1) >= ((data[2] + data[width + 6]) >> 1)
+ + (data[3] >> 2)
+ + (data[width + 5] >> 1))
+ data += 3;
+ else
+ data += 2;
+ for (i = 0; i < height / 2; i++) {
+ memcpy(dst, data, width);
+ data += width + 3;
+ dst += width;
+ memcpy(dst, data, width);
+ data += width + 7;
+ dst += width;
+ }
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ struct gspca_frame *frame, /* target */
+ __u8 *data, /* isoc packet */
+ int len) /* iso packet length */
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (data[0] != 0x80) {
+ sd->packet++;
+ if (sd->buflen + len > sizeof sd->tmpbuf) {
+ if (gspca_dev->last_packet_type != DISCARD_PACKET) {
+ PDEBUG(D_PACK, "buffer overflow");
+ gspca_dev->last_packet_type = DISCARD_PACKET;
+ }
+ return;
+ }
+ memcpy(&sd->tmpbuf[sd->buflen], data, len);
+ sd->buflen += len;
+ return;
+ }
+
+ /* here we detect 0x80 */
+ /* counter is limited so we need few header for a frame :) */
+
+ /* header 0x80 0x80 0x80 0x80 0x80 */
+ /* packet 00 63 127 145 00 */
+ /* sof 0 1 1 0 0 */
+
+ /* update sequence */
+ if (sd->packet == 63 || sd->packet == 127)
+ sd->synchro = 1;
+
+ /* is there a frame start ? */
+ if (sd->packet >= (gspca_dev->height >> 1) - 1) {
+ PDEBUG(D_PACK, "SOF > %d packet %d", sd->synchro,
+ sd->packet);
+ if (!sd->synchro) { /* start of frame */
+ if (gspca_dev->last_packet_type == FIRST_PACKET) {
+ tv8532_preprocess(gspca_dev);
+ frame = gspca_frame_add(gspca_dev,
+ LAST_PACKET,
+ frame, sd->tmpbuf2,
+ gspca_dev->width *
+ gspca_dev->width);
+ }
+ gspca_frame_add(gspca_dev, FIRST_PACKET,
+ frame, data, 0);
+ memcpy(sd->tmpbuf, data, len);
+ sd->buflen = len;
+ sd->packet = 0;
+ return;
+ }
+ if (gspca_dev->last_packet_type != DISCARD_PACKET) {
+ PDEBUG(D_PACK,
+ "Warning wrong TV8532 frame detection %d",
+ sd->packet);
+ gspca_dev->last_packet_type = DISCARD_PACKET;
+ }
+ return;
+ }
+
+ if (!sd->synchro) {
+ /* Drop packet frame corrupt */
+ PDEBUG(D_PACK, "DROP SOF %d packet %d",
+ sd->synchro, sd->packet);
+ sd->packet = 0;
+ gspca_dev->last_packet_type = DISCARD_PACKET;
+ return;
+ }
+ sd->synchro = 1;
+ sd->packet++;
+ memcpy(&sd->tmpbuf[sd->buflen], data, len);
+ sd->buflen += len;
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+#if 0
+ __u8 value[2];
+ __u8 data;
+
+ value[0] = (gspca_dev->contrast) & 0xff;
+ value[1] = (gspca_dev->contrast >> 8) & 0xff;
+ reg_w(gspca_dev->dev, 0x0020, &value[1], 1);
+ reg_w(gspca_dev->dev, 0x0022, &value[1], 1);
+ reg_w(gspca_dev->dev, 0x0024, &value[1], 1);
+ reg_w(gspca_dev->dev, 0x0026, &value[1], 1);
+ data = TV8532_CMD_UPDATE;
+ reg_w(gspca_dev->dev, TV8532_PART_CTRL, &data, 1);
+#endif
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->brightness = val;
+ if (gspca_dev->streaming)
+ setbrightness(gspca_dev);
+ return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->brightness;
+ return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->contrast = val;
+ if (gspca_dev->streaming)
+ setcontrast(gspca_dev);
+ return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->contrast;
+ return 0;
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .ctrls = sd_ctrls,
+ .nctrls = ARRAY_SIZE(sd_ctrls),
+ .config = sd_config,
+ .open = sd_open,
+ .start = sd_start,
+ .stopN = sd_stopN,
+ .stop0 = sd_stop0,
+ .close = sd_close,
+ .pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static const __devinitdata struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x046d, 0x0920), DVNM("QC Express")},
+ {USB_DEVICE(0x046d, 0x0921), DVNM("Labtec Webcam")},
+ {USB_DEVICE(0x0545, 0x808b), DVNM("Veo Stingray")},
+ {USB_DEVICE(0x0545, 0x8333), DVNM("Veo Stingray")},
+ {USB_DEVICE(0x0923, 0x010f), DVNM("ICM532 cams")},
+ {}
+};
+
+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,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+ if (usb_register(&sd_driver) < 0)
+ return -1;
+ PDEBUG(D_PROBE, "v%s registered", version);
+ return 0;
+}
+
+static void __exit sd_mod_exit(void)
+{
+ usb_deregister(&sd_driver);
+ PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/linux/drivers/media/video/gspca/vc032x.c b/linux/drivers/media/video/gspca/vc032x.c
new file mode 100644
index 000000000..1129cbeb8
--- /dev/null
+++ b/linux/drivers/media/video/gspca/vc032x.c
@@ -0,0 +1,2029 @@
+/*
+ * Z-star vc0321 library
+ * Copyright (C) 2006 Koninski Artur takeshi87@o2.pl
+ * Copyright (C) 2006 Michel Xhaard
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define MODULE_NAME "vc032x"
+
+#include "gspca.h"
+
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 5)
+static const char version[] = "2.1.5";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("GSPCA/VC032X USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+
+ unsigned char autogain;
+ unsigned char lightfreq;
+
+ char qindex;
+ char bridge;
+#define BRIDGE_VC0321 0
+#define BRIDGE_VC0323 1
+ char sensor;
+#define SENSOR_HV7131R 0
+#define SENSOR_MI1320 1
+#define SENSOR_MI1310_SOC 2
+#define SENSOR_OV7660 3
+#define SENSOR_OV7670 4
+#define SENSOR_PO3130NC 5
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+#define SD_AUTOGAIN 0
+ {
+ {
+ .id = V4L2_CID_AUTOGAIN,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Auto Gain",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 1,
+ },
+ .set = sd_setautogain,
+ .get = sd_getautogain,
+ },
+#define SD_FREQ 1
+ {
+ {
+ .id = V4L2_CID_POWER_LINE_FREQUENCY,
+ .type = V4L2_CTRL_TYPE_MENU,
+ .name = "Light frequency filter",
+ .minimum = 0,
+ .maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */
+ .step = 1,
+ .default_value = 1,
+ },
+ .set = sd_setfreq,
+ .get = sd_getfreq,
+ },
+};
+
+static struct v4l2_pix_format vc0321_mode[] = {
+ {320, 240, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
+ .bytesperline = 320 * 2,
+ .sizeimage = 320 * 240 * 2,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 1},
+ {640, 480, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
+ .bytesperline = 640 * 2,
+ .sizeimage = 640 * 480 * 2,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0},
+};
+static struct v4l2_pix_format vc0323_mode[] = {
+ {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 1},
+ {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 0},
+};
+
+#if 0
+static const __u8 mi1310soc_gamma[17] = {
+ 0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
+ 0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff
+};
+static const __u8 mi1310soc_matrix[9] = {
+ 0x56, 0xf0, 0xf6, 0xf3, 0x57, 0xf6, 0xf3, 0xef, 0x58
+};
+#endif
+static const __u8 mi1310_socinitVGA_JPG[][4] = {
+ {0xb0, 0x03, 0x19, 0xcc},
+ {0xb0, 0x04, 0x02, 0xcc},
+ {0xb3, 0x00, 0x64, 0xcc},
+ {0xb3, 0x00, 0x65, 0xcc},
+ {0xb3, 0x05, 0x00, 0xcc},
+ {0xb3, 0x06, 0x00, 0xcc},
+ {0xb3, 0x08, 0x01, 0xcc},
+ {0xb3, 0x09, 0x0c, 0xcc},
+ {0xb3, 0x34, 0x02, 0xcc},
+ {0xb3, 0x35, 0xdd, 0xcc},
+ {0xb3, 0x02, 0x00, 0xcc},
+ {0xb3, 0x03, 0x0a, 0xcc},
+ {0xb3, 0x04, 0x05, 0xcc},
+ {0xb3, 0x20, 0x00, 0xcc},
+ {0xb3, 0x21, 0x00, 0xcc},
+ {0xb3, 0x22, 0x03, 0xcc},
+ {0xb3, 0x23, 0xc0, 0xcc},
+ {0xb3, 0x14, 0x00, 0xcc},
+ {0xb3, 0x15, 0x00, 0xcc},
+ {0xb3, 0x16, 0x04, 0xcc},
+ {0xb3, 0x17, 0xff, 0xcc},
+ {0xb3, 0x00, 0x65, 0xcc},
+ {0xb8, 0x00, 0x00, 0xcc},
+ {0xbc, 0x00, 0xd0, 0xcc},
+ {0xbc, 0x01, 0x01, 0xcc},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0xc8, 0x9f, 0x0b, 0xbb},
+ {0x5b, 0x00, 0x01, 0xbb},
+ {0x2f, 0xde, 0x20, 0xbb},
+ {0xf0, 0x00, 0x00, 0xbb},
+ {0x20, 0x03, 0x02, 0xbb},
+ {0xf0, 0x00, 0x01, 0xbb},
+ {0x05, 0x00, 0x07, 0xbb},
+ {0x34, 0x00, 0x00, 0xbb},
+ {0x35, 0xff, 0x00, 0xbb},
+ {0xdc, 0x07, 0x02, 0xbb},
+ {0xdd, 0x3c, 0x18, 0xbb},
+ {0xde, 0x92, 0x6d, 0xbb},
+ {0xdf, 0xcd, 0xb1, 0xbb},
+ {0xe0, 0xff, 0xe7, 0xbb},
+ {0x06, 0xf0, 0x0d, 0xbb},
+ {0x06, 0x70, 0x0e, 0xbb},
+ {0x4c, 0x00, 0x01, 0xbb},
+ {0x4d, 0x00, 0x01, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x2e, 0x0c, 0x55, 0xbb},
+ {0x21, 0xb6, 0x6e, 0xbb},
+ {0x36, 0x30, 0x10, 0xbb},
+ {0x37, 0x00, 0xc1, 0xbb},
+ {0xf0, 0x00, 0x00, 0xbb},
+ {0x07, 0x00, 0x84, 0xbb},
+ {0x08, 0x02, 0x4a, 0xbb},
+ {0x05, 0x01, 0x10, 0xbb},
+ {0x06, 0x00, 0x39, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x58, 0x02, 0x67, 0xbb},
+ {0x57, 0x02, 0x00, 0xbb},
+ {0x5a, 0x02, 0x67, 0xbb},
+ {0x59, 0x02, 0x00, 0xbb},
+ {0x5c, 0x12, 0x0d, 0xbb},
+ {0x5d, 0x16, 0x11, 0xbb},
+ {0x39, 0x06, 0x18, 0xbb},
+ {0x3a, 0x06, 0x18, 0xbb},
+ {0x3b, 0x06, 0x18, 0xbb},
+ {0x3c, 0x06, 0x18, 0xbb},
+ {0x64, 0x7b, 0x5b, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x36, 0x30, 0x10, 0xbb},
+ {0x37, 0x00, 0xc0, 0xbb},
+ {0xbc, 0x0e, 0x00, 0xcc},
+ {0xbc, 0x0f, 0x05, 0xcc},
+ {0xbc, 0x10, 0xc0, 0xcc},
+ {0xbc, 0x11, 0x03, 0xcc},
+ {0xb6, 0x00, 0x00, 0xcc},
+ {0xb6, 0x03, 0x02, 0xcc},
+ {0xb6, 0x02, 0x80, 0xcc},
+ {0xb6, 0x05, 0x01, 0xcc},
+ {0xb6, 0x04, 0xe0, 0xcc},
+ {0xb6, 0x12, 0xf8, 0xcc},
+ {0xb6, 0x13, 0x25, 0xcc},
+ {0xb6, 0x18, 0x02, 0xcc},
+ {0xb6, 0x17, 0x58, 0xcc},
+ {0xb6, 0x16, 0x00, 0xcc},
+ {0xb6, 0x22, 0x12, 0xcc},
+ {0xb6, 0x23, 0x0b, 0xcc},
+ {0xbf, 0xc0, 0x39, 0xcc},
+ {0xbf, 0xc1, 0x04, 0xcc},
+ {0xbf, 0xcc, 0x00, 0xcc},
+ {0xbc, 0x02, 0x18, 0xcc},
+ {0xbc, 0x03, 0x50, 0xcc},
+ {0xbc, 0x04, 0x18, 0xcc},
+ {0xbc, 0x05, 0x00, 0xcc},
+ {0xbc, 0x06, 0x00, 0xcc},
+ {0xbc, 0x08, 0x30, 0xcc},
+ {0xbc, 0x09, 0x40, 0xcc},
+ {0xbc, 0x0a, 0x10, 0xcc},
+ {0xbc, 0x0b, 0x00, 0xcc},
+ {0xbc, 0x0c, 0x00, 0xcc},
+ {0xb3, 0x5c, 0x01, 0xcc},
+ {0xf0, 0x00, 0x01, 0xbb},
+ {0x80, 0x00, 0x03, 0xbb},
+ {0x81, 0xc7, 0x14, 0xbb},
+ {0x82, 0xeb, 0xe8, 0xbb},
+ {0x83, 0xfe, 0xf4, 0xbb},
+ {0x84, 0xcd, 0x10, 0xbb},
+ {0x85, 0xf3, 0xee, 0xbb},
+ {0x86, 0xff, 0xf1, 0xbb},
+ {0x87, 0xcd, 0x10, 0xbb},
+ {0x88, 0xf3, 0xee, 0xbb},
+ {0x89, 0x01, 0xf1, 0xbb},
+ {0x8a, 0xe5, 0x17, 0xbb},
+ {0x8b, 0xe8, 0xe2, 0xbb},
+ {0x8c, 0xf7, 0xed, 0xbb},
+ {0x8d, 0x00, 0xff, 0xbb},
+ {0x8e, 0xec, 0x10, 0xbb},
+ {0x8f, 0xf0, 0xed, 0xbb},
+ {0x90, 0xf9, 0xf2, 0xbb},
+ {0x91, 0x00, 0x00, 0xbb},
+ {0x92, 0xe9, 0x0d, 0xbb},
+ {0x93, 0xf4, 0xf2, 0xbb},
+ {0x94, 0xfb, 0xf5, 0xbb},
+ {0x95, 0x00, 0xff, 0xbb},
+ {0xb6, 0x0f, 0x08, 0xbb},
+ {0xb7, 0x3d, 0x16, 0xbb},
+ {0xb8, 0x0c, 0x04, 0xbb},
+ {0xb9, 0x1c, 0x07, 0xbb},
+ {0xba, 0x0a, 0x03, 0xbb},
+ {0xbb, 0x1b, 0x09, 0xbb},
+ {0xbc, 0x17, 0x0d, 0xbb},
+ {0xbd, 0x23, 0x1d, 0xbb},
+ {0xbe, 0x00, 0x28, 0xbb},
+ {0xbf, 0x11, 0x09, 0xbb},
+ {0xc0, 0x16, 0x15, 0xbb},
+ {0xc1, 0x00, 0x1b, 0xbb},
+ {0xc2, 0x0e, 0x07, 0xbb},
+ {0xc3, 0x14, 0x10, 0xbb},
+ {0xc4, 0x00, 0x17, 0xbb},
+ {0x06, 0x74, 0x8e, 0xbb},
+ {0xf0, 0x00, 0x01, 0xbb},
+ {0x06, 0xf4, 0x8e, 0xbb},
+ {0x00, 0x00, 0x50, 0xdd},
+ {0x06, 0x74, 0x8e, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x24, 0x50, 0x20, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x34, 0x0c, 0x50, 0xbb},
+ {0xb3, 0x01, 0x41, 0xcc},
+ {0xf0, 0x00, 0x00, 0xbb},
+ {0x03, 0x03, 0xc0, 0xbb},
+ {},
+};
+static const __u8 mi1310_socinitQVGA_JPG[][4] = {
+ {0xb0, 0x03, 0x19, 0xcc}, {0xb0, 0x04, 0x02, 0xcc},
+ {0xb3, 0x00, 0x64, 0xcc}, {0xb3, 0x00, 0x65, 0xcc},
+ {0xb3, 0x05, 0x00, 0xcc}, {0xb3, 0x06, 0x00, 0xcc},
+ {0xb3, 0x08, 0x01, 0xcc}, {0xb3, 0x09, 0x0c, 0xcc},
+ {0xb3, 0x34, 0x02, 0xcc}, {0xb3, 0x35, 0xdd, 0xcc},
+ {0xb3, 0x02, 0x00, 0xcc}, {0xb3, 0x03, 0x0a, 0xcc},
+ {0xb3, 0x04, 0x05, 0xcc}, {0xb3, 0x20, 0x00, 0xcc},
+ {0xb3, 0x21, 0x00, 0xcc}, {0xb3, 0x22, 0x03, 0xcc},
+ {0xb3, 0x23, 0xc0, 0xcc}, {0xb3, 0x14, 0x00, 0xcc},
+ {0xb3, 0x15, 0x00, 0xcc}, {0xb3, 0x16, 0x04, 0xcc},
+ {0xb3, 0x17, 0xff, 0xcc}, {0xb3, 0x00, 0x65, 0xcc},
+ {0xb8, 0x00, 0x00, 0xcc}, {0xbc, 0x00, 0xf0, 0xcc},
+ {0xbc, 0x01, 0x01, 0xcc}, {0xf0, 0x00, 0x02, 0xbb},
+ {0xc8, 0x9f, 0x0b, 0xbb}, {0x5b, 0x00, 0x01, 0xbb},
+ {0x2f, 0xde, 0x20, 0xbb}, {0xf0, 0x00, 0x00, 0xbb},
+ {0x20, 0x03, 0x02, 0xbb}, {0xf0, 0x00, 0x01, 0xbb},
+ {0x05, 0x00, 0x07, 0xbb}, {0x34, 0x00, 0x00, 0xbb},
+ {0x35, 0xff, 0x00, 0xbb}, {0xdc, 0x07, 0x02, 0xbb},
+ {0xdd, 0x3c, 0x18, 0xbb}, {0xde, 0x92, 0x6d, 0xbb},
+ {0xdf, 0xcd, 0xb1, 0xbb}, {0xe0, 0xff, 0xe7, 0xbb},
+ {0x06, 0xf0, 0x0d, 0xbb}, {0x06, 0x70, 0x0e, 0xbb},
+ {0x4c, 0x00, 0x01, 0xbb}, {0x4d, 0x00, 0x01, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb}, {0x2e, 0x0c, 0x55, 0xbb},
+ {0x21, 0xb6, 0x6e, 0xbb}, {0x36, 0x30, 0x10, 0xbb},
+ {0x37, 0x00, 0xc1, 0xbb}, {0xf0, 0x00, 0x00, 0xbb},
+ {0x07, 0x00, 0x84, 0xbb}, {0x08, 0x02, 0x4a, 0xbb},
+ {0x05, 0x01, 0x10, 0xbb}, {0x06, 0x00, 0x39, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb}, {0x58, 0x02, 0x67, 0xbb},
+ {0x57, 0x02, 0x00, 0xbb}, {0x5a, 0x02, 0x67, 0xbb},
+ {0x59, 0x02, 0x00, 0xbb}, {0x5c, 0x12, 0x0d, 0xbb},
+ {0x5d, 0x16, 0x11, 0xbb}, {0x39, 0x06, 0x18, 0xbb},
+ {0x3a, 0x06, 0x18, 0xbb}, {0x3b, 0x06, 0x18, 0xbb},
+ {0x3c, 0x06, 0x18, 0xbb}, {0x64, 0x7b, 0x5b, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb}, {0x36, 0x30, 0x10, 0xbb},
+ {0x37, 0x00, 0xc0, 0xbb}, {0xbc, 0x0e, 0x00, 0xcc},
+ {0xbc, 0x0f, 0x05, 0xcc}, {0xbc, 0x10, 0xc0, 0xcc},
+ {0xbc, 0x11, 0x03, 0xcc}, {0xb6, 0x00, 0x00, 0xcc},
+ {0xb6, 0x03, 0x01, 0xcc}, {0xb6, 0x02, 0x40, 0xcc},
+ {0xb6, 0x05, 0x00, 0xcc}, {0xb6, 0x04, 0xf0, 0xcc},
+ {0xb6, 0x12, 0xf8, 0xcc}, {0xb6, 0x13, 0x25, 0xcc},
+ {0xb6, 0x18, 0x00, 0xcc}, {0xb6, 0x17, 0x96, 0xcc},
+ {0xb6, 0x16, 0x00, 0xcc}, {0xb6, 0x22, 0x12, 0xcc},
+ {0xb6, 0x23, 0x0b, 0xcc}, {0xbf, 0xc0, 0x39, 0xcc},
+ {0xbf, 0xc1, 0x04, 0xcc}, {0xbf, 0xcc, 0x00, 0xcc},
+ {0xb3, 0x5c, 0x01, 0xcc}, {0xf0, 0x00, 0x01, 0xbb},
+ {0x80, 0x00, 0x03, 0xbb}, {0x81, 0xc7, 0x14, 0xbb},
+ {0x82, 0xeb, 0xe8, 0xbb}, {0x83, 0xfe, 0xf4, 0xbb},
+ {0x84, 0xcd, 0x10, 0xbb}, {0x85, 0xf3, 0xee, 0xbb},
+ {0x86, 0xff, 0xf1, 0xbb}, {0x87, 0xcd, 0x10, 0xbb},
+ {0x88, 0xf3, 0xee, 0xbb}, {0x89, 0x01, 0xf1, 0xbb},
+ {0x8a, 0xe5, 0x17, 0xbb}, {0x8b, 0xe8, 0xe2, 0xbb},
+ {0x8c, 0xf7, 0xed, 0xbb}, {0x8d, 0x00, 0xff, 0xbb},
+ {0x8e, 0xec, 0x10, 0xbb}, {0x8f, 0xf0, 0xed, 0xbb},
+ {0x90, 0xf9, 0xf2, 0xbb}, {0x91, 0x00, 0x00, 0xbb},
+ {0x92, 0xe9, 0x0d, 0xbb}, {0x93, 0xf4, 0xf2, 0xbb},
+ {0x94, 0xfb, 0xf5, 0xbb}, {0x95, 0x00, 0xff, 0xbb},
+ {0xb6, 0x0f, 0x08, 0xbb}, {0xb7, 0x3d, 0x16, 0xbb},
+ {0xb8, 0x0c, 0x04, 0xbb}, {0xb9, 0x1c, 0x07, 0xbb},
+ {0xba, 0x0a, 0x03, 0xbb}, {0xbb, 0x1b, 0x09, 0xbb},
+ {0xbc, 0x17, 0x0d, 0xbb}, {0xbd, 0x23, 0x1d, 0xbb},
+ {0xbe, 0x00, 0x28, 0xbb}, {0xbf, 0x11, 0x09, 0xbb},
+ {0xc0, 0x16, 0x15, 0xbb}, {0xc1, 0x00, 0x1b, 0xbb},
+ {0xc2, 0x0e, 0x07, 0xbb}, {0xc3, 0x14, 0x10, 0xbb},
+ {0xc4, 0x00, 0x17, 0xbb}, {0x06, 0x74, 0x8e, 0xbb},
+ {0xf0, 0x00, 0x01, 0xbb}, {0x06, 0xf4, 0x8e, 0xbb},
+ {0x00, 0x00, 0x50, 0xdd}, {0x06, 0x74, 0x8e, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb}, {0x24, 0x50, 0x20, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb}, {0x34, 0x0c, 0x50, 0xbb},
+ {0xb3, 0x01, 0x41, 0xcc}, {0xf0, 0x00, 0x00, 0xbb},
+ {0x03, 0x03, 0xc0, 0xbb},
+ {},
+};
+
+static const __u8 mi1320_gamma[17] = {
+ 0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
+ 0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff
+};
+static const __u8 mi1320_matrix[9] = {
+ 0x54, 0xda, 0x06, 0xf1, 0x50, 0xf4, 0xf7, 0xea, 0x52
+};
+static const __u8 mi1320_initVGA_data[][4] = {
+ {0xb3, 0x01, 0x01, 0xcc}, {0x00, 0x00, 0x33, 0xdd},
+ {0xb0, 0x03, 0x19, 0xcc}, {0x00, 0x00, 0x33, 0xdd},
+ {0xb0, 0x04, 0x02, 0xcc}, {0x00, 0x00, 0x33, 0xdd},
+ {0xb3, 0x00, 0x64, 0xcc}, {0xb3, 0x00, 0x65, 0xcc},
+ {0xb0, 0x16, 0x03, 0xcc}, {0xb3, 0x05, 0x00, 0xcc},
+ {0xb3, 0x06, 0x00, 0xcc}, {0xb3, 0x08, 0x01, 0xcc},
+ {0xb3, 0x09, 0x0c, 0xcc}, {0xb3, 0x34, 0x02, 0xcc},
+ {0xb3, 0x35, 0xc8, 0xcc}, {0xb3, 0x02, 0x00, 0xcc},
+ {0xb3, 0x03, 0x0a, 0xcc}, {0xb3, 0x04, 0x05, 0xcc},
+ {0xb3, 0x20, 0x00, 0xcc}, {0xb3, 0x21, 0x00, 0xcc},
+ {0xb3, 0x22, 0x03, 0xcc}, {0xb3, 0x23, 0xc0, 0xcc},
+ {0xb3, 0x14, 0x00, 0xcc}, {0xb3, 0x15, 0x00, 0xcc},
+ {0xb3, 0x16, 0x04, 0xcc}, {0xb3, 0x17, 0xff, 0xcc},
+ {0xb3, 0x00, 0x67, 0xcc}, {0xbc, 0x00, 0xd0, 0xcc},
+ {0xbc, 0x01, 0x01, 0xcc}, {0xf0, 0x00, 0x00, 0xbb},
+ {0x0d, 0x00, 0x09, 0xbb}, {0x00, 0x01, 0x00, 0xdd},
+ {0x0d, 0x00, 0x08, 0xbb}, {0xf0, 0x00, 0x01, 0xbb},
+ {0xa1, 0x05, 0x00, 0xbb}, {0xa4, 0x03, 0xc0, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb}, {0x00, 0x00, 0x10, 0xdd},
+ {0xc8, 0x9f, 0x0b, 0xbb}, {0x00, 0x00, 0x10, 0xdd},
+ {0xf0, 0x00, 0x00, 0xbb}, {0x00, 0x00, 0x10, 0xdd},
+ {0x20, 0x01, 0x00, 0xbb}, {0x00, 0x00, 0x10, 0xdd},
+ {0xf0, 0x00, 0x01, 0xbb}, {0x9d, 0x3c, 0xa0, 0xbb},
+ {0x47, 0x30, 0x30, 0xbb}, {0xf0, 0x00, 0x00, 0xbb},
+ {0x0a, 0x80, 0x11, 0xbb}, {0x35, 0x00, 0x22, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb}, {0x9d, 0xc5, 0x05, 0xbb},
+ {0xdc, 0x0f, 0xfc, 0xbb}, {0xf0, 0x00, 0x01, 0xbb},
+ {0x06, 0x74, 0x0e, 0xbb}, {0x80, 0x00, 0x06, 0xbb},
+ {0x81, 0x04, 0x00, 0xbb}, {0x82, 0x01, 0x02, 0xbb},
+ {0x83, 0x03, 0x02, 0xbb}, {0x84, 0x05, 0x00, 0xbb},
+ {0x85, 0x01, 0x00, 0xbb}, {0x86, 0x03, 0x02, 0xbb},
+ {0x87, 0x05, 0x00, 0xbb}, {0x88, 0x01, 0x00, 0xbb},
+ {0x89, 0x02, 0x02, 0xbb}, {0x8a, 0xfd, 0x04, 0xbb},
+ {0x8b, 0xfc, 0xfd, 0xbb}, {0x8c, 0xff, 0xfd, 0xbb},
+ {0x8d, 0x00, 0x00, 0xbb}, {0x8e, 0xfe, 0x05, 0xbb},
+ {0x8f, 0xfc, 0xfd, 0xbb}, {0x90, 0xfe, 0xfd, 0xbb},
+ {0x91, 0x00, 0x00, 0xbb}, {0x92, 0xfe, 0x03, 0xbb},
+ {0x93, 0xfd, 0xfe, 0xbb}, {0x94, 0xff, 0xfd, 0xbb},
+ {0x95, 0x00, 0x00, 0xbb}, {0xb6, 0x07, 0x05, 0xbb},
+ {0xb7, 0x13, 0x06, 0xbb}, {0xb8, 0x08, 0x06, 0xbb},
+ {0xb9, 0x14, 0x08, 0xbb}, {0xba, 0x06, 0x05, 0xbb},
+ {0xbb, 0x13, 0x06, 0xbb}, {0xbc, 0x03, 0x01, 0xbb},
+ {0xbd, 0x03, 0x04, 0xbb}, {0xbe, 0x00, 0x02, 0xbb},
+ {0xbf, 0x03, 0x01, 0xbb}, {0xc0, 0x02, 0x04, 0xbb},
+ {0xc1, 0x00, 0x04, 0xbb}, {0xc2, 0x02, 0x01, 0xbb},
+ {0xc3, 0x01, 0x03, 0xbb}, {0xc4, 0x00, 0x04, 0xbb},
+ {0xf0, 0x00, 0x00, 0xbb}, {0x05, 0x01, 0x13, 0xbb},
+ {0x06, 0x00, 0x11, 0xbb}, {0x07, 0x00, 0x85, 0xbb},
+ {0x08, 0x00, 0x27, 0xbb}, {0x20, 0x01, 0x03, 0xbb},
+ {0x21, 0x80, 0x00, 0xbb}, {0x22, 0x0d, 0x0f, 0xbb},
+ {0x24, 0x80, 0x00, 0xbb}, {0x59, 0x00, 0xff, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb}, {0x39, 0x03, 0x0d, 0xbb},
+ {0x3a, 0x06, 0x1b, 0xbb}, {0x3b, 0x00, 0x95, 0xbb},
+ {0x3c, 0x04, 0xdb, 0xbb}, {0x57, 0x02, 0x00, 0xbb},
+ {0x58, 0x02, 0x66, 0xbb}, {0x59, 0x00, 0xff, 0xbb},
+ {0x5a, 0x01, 0x33, 0xbb}, {0x5c, 0x12, 0x0d, 0xbb},
+ {0x5d, 0x16, 0x11, 0xbb}, {0x64, 0x5e, 0x1c, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb}, {0x2f, 0xd1, 0x00, 0xbb},
+ {0x5b, 0x00, 0x01, 0xbb}, {0xf0, 0x00, 0x02, 0xbb},
+ {0x36, 0x68, 0x10, 0xbb}, {0x00, 0x00, 0x30, 0xdd},
+ {0x37, 0x82, 0x00, 0xbb}, {0xbc, 0x0e, 0x00, 0xcc},
+ {0xbc, 0x0f, 0x05, 0xcc}, {0xbc, 0x10, 0xc0, 0xcc},
+ {0xbc, 0x11, 0x03, 0xcc}, {0xb6, 0x00, 0x00, 0xcc},
+ {0xb6, 0x03, 0x05, 0xcc}, {0xb6, 0x02, 0x00, 0xcc},
+ {0xb6, 0x05, 0x04, 0xcc}, {0xb6, 0x04, 0x00, 0xcc},
+ {0xb6, 0x12, 0xf8, 0xcc}, {0xb6, 0x13, 0x29, 0xcc},
+ {0xb6, 0x18, 0x0a, 0xcc}, {0xb6, 0x17, 0x00, 0xcc},
+ {0xb6, 0x16, 0x00, 0xcc}, {0xb6, 0x22, 0x12, 0xcc},
+ {0xb6, 0x23, 0x0b, 0xcc}, {0xbf, 0xc0, 0x26, 0xcc},
+ {0xbf, 0xc1, 0x02, 0xcc}, {0xbf, 0xcc, 0x04, 0xcc},
+ {0xbc, 0x02, 0x18, 0xcc}, {0xbc, 0x03, 0x50, 0xcc},
+ {0xbc, 0x04, 0x18, 0xcc}, {0xbc, 0x05, 0x00, 0xcc},
+ {0xbc, 0x06, 0x00, 0xcc}, {0xbc, 0x08, 0x30, 0xcc},
+ {0xbc, 0x09, 0x40, 0xcc}, {0xbc, 0x0a, 0x10, 0xcc},
+ {0xbc, 0x0b, 0x00, 0xcc}, {0xbc, 0x0c, 0x00, 0xcc},
+ {0xb3, 0x5c, 0x01, 0xcc}, {0xb3, 0x01, 0x41, 0xcc},
+ {}
+};
+static const __u8 mi1320_initQVGA_data[][4] = {
+ {0xb3, 0x01, 0x01, 0xcc}, {0x00, 0x00, 0x33, 0xdd},
+ {0xb0, 0x03, 0x19, 0xcc}, {0x00, 0x00, 0x33, 0xdd},
+ {0xb0, 0x04, 0x02, 0xcc}, {0x00, 0x00, 0x33, 0xdd},
+ {0xb3, 0x00, 0x64, 0xcc}, {0xb3, 0x00, 0x65, 0xcc},
+ {0xb0, 0x16, 0x03, 0xcc}, {0xb3, 0x05, 0x01, 0xcc},
+ {0xb3, 0x06, 0x01, 0xcc}, {0xb3, 0x08, 0x01, 0xcc},
+ {0xb3, 0x09, 0x0c, 0xcc}, {0xb3, 0x34, 0x02, 0xcc},
+ {0xb3, 0x35, 0xc8, 0xcc}, {0xb3, 0x02, 0x00, 0xcc},
+ {0xb3, 0x03, 0x0a, 0xcc}, {0xb3, 0x04, 0x05, 0xcc},
+ {0xb3, 0x20, 0x00, 0xcc}, {0xb3, 0x21, 0x00, 0xcc},
+ {0xb3, 0x22, 0x01, 0xcc}, {0xb3, 0x23, 0xe0, 0xcc},
+ {0xb3, 0x14, 0x00, 0xcc}, {0xb3, 0x15, 0x00, 0xcc},
+ {0xb3, 0x16, 0x02, 0xcc}, {0xb3, 0x17, 0x7f, 0xcc},
+ {0xb3, 0x00, 0x65, 0xcc}, {0xb8, 0x00, 0x00, 0xcc},
+ {0xbc, 0x00, 0xd0, 0xcc}, {0xbc, 0x01, 0x01, 0xcc},
+ {0xf0, 0x00, 0x00, 0xbb}, {0x0d, 0x00, 0x09, 0xbb},
+ {0x00, 0x01, 0x00, 0xdd}, {0x0d, 0x00, 0x08, 0xbb},
+ {0xf0, 0x00, 0x00, 0xbb}, {0x02, 0x00, 0x64, 0xbb},
+ {0x05, 0x01, 0x78, 0xbb}, {0x06, 0x00, 0x11, 0xbb},
+ {0x07, 0x01, 0x42, 0xbb}, {0x08, 0x00, 0x11, 0xbb},
+ {0x20, 0x01, 0x00, 0xbb}, {0x21, 0x80, 0x00, 0xbb},
+ {0x22, 0x0d, 0x0f, 0xbb}, {0x24, 0x80, 0x00, 0xbb},
+ {0x59, 0x00, 0xff, 0xbb}, {0xf0, 0x00, 0x01, 0xbb},
+ {0x9d, 0x3c, 0xa0, 0xbb}, {0x47, 0x30, 0x30, 0xbb},
+ {0xf0, 0x00, 0x00, 0xbb}, {0x0a, 0x80, 0x11, 0xbb},
+ {0x35, 0x00, 0x22, 0xbb}, {0xf0, 0x00, 0x02, 0xbb},
+ {0x9d, 0xc5, 0x05, 0xbb}, {0xdc, 0x0f, 0xfc, 0xbb},
+ {0xf0, 0x00, 0x01, 0xbb}, {0x06, 0x74, 0x0e, 0xbb},
+ {0x80, 0x00, 0x06, 0xbb}, {0x81, 0x04, 0x00, 0xbb},
+ {0x82, 0x01, 0x02, 0xbb}, {0x83, 0x03, 0x02, 0xbb},
+ {0x84, 0x05, 0x00, 0xbb}, {0x85, 0x01, 0x00, 0xbb},
+ {0x86, 0x03, 0x02, 0xbb}, {0x87, 0x05, 0x00, 0xbb},
+ {0x88, 0x01, 0x00, 0xbb}, {0x89, 0x02, 0x02, 0xbb},
+ {0x8a, 0xfd, 0x04, 0xbb}, {0x8b, 0xfc, 0xfd, 0xbb},
+ {0x8c, 0xff, 0xfd, 0xbb}, {0x8d, 0x00, 0x00, 0xbb},
+ {0x8e, 0xfe, 0x05, 0xbb}, {0x8f, 0xfc, 0xfd, 0xbb},
+ {0x90, 0xfe, 0xfd, 0xbb}, {0x91, 0x00, 0x00, 0xbb},
+ {0x92, 0xfe, 0x03, 0xbb}, {0x93, 0xfd, 0xfe, 0xbb},
+ {0x94, 0xff, 0xfd, 0xbb}, {0x95, 0x00, 0x00, 0xbb},
+ {0xb6, 0x07, 0x05, 0xbb}, {0xb7, 0x13, 0x06, 0xbb},
+ {0xb8, 0x08, 0x06, 0xbb}, {0xb9, 0x14, 0x08, 0xbb},
+ {0xba, 0x06, 0x05, 0xbb}, {0xbb, 0x13, 0x06, 0xbb},
+ {0xbc, 0x03, 0x01, 0xbb}, {0xbd, 0x03, 0x04, 0xbb},
+ {0xbe, 0x00, 0x02, 0xbb}, {0xbf, 0x03, 0x01, 0xbb},
+ {0xc0, 0x02, 0x04, 0xbb}, {0xc1, 0x00, 0x04, 0xbb},
+ {0xc2, 0x02, 0x01, 0xbb}, {0xc3, 0x01, 0x03, 0xbb},
+ {0xc4, 0x00, 0x04, 0xbb}, {0xf0, 0x00, 0x02, 0xbb},
+ {0xc8, 0x00, 0x00, 0xbb}, {0x2e, 0x00, 0x00, 0xbb},
+ {0x2e, 0x0c, 0x5b, 0xbb}, {0x2f, 0xd1, 0x00, 0xbb},
+ {0x39, 0x03, 0xca, 0xbb}, {0x3a, 0x06, 0x80, 0xbb},
+ {0x3b, 0x01, 0x52, 0xbb}, {0x3c, 0x05, 0x40, 0xbb},
+ {0x57, 0x01, 0x9c, 0xbb}, {0x58, 0x01, 0xee, 0xbb},
+ {0x59, 0x00, 0xf0, 0xbb}, {0x5a, 0x01, 0x20, 0xbb},
+ {0x5c, 0x1d, 0x17, 0xbb}, {0x5d, 0x22, 0x1c, 0xbb},
+ {0x64, 0x1e, 0x1c, 0xbb}, {0x5b, 0x00, 0x01, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb}, {0x36, 0x68, 0x10, 0xbb},
+ {0x00, 0x00, 0x30, 0xdd}, {0x37, 0x81, 0x00, 0xbb},
+ {0xbc, 0x02, 0x18, 0xcc}, {0xbc, 0x03, 0x50, 0xcc},
+ {0xbc, 0x04, 0x18, 0xcc}, {0xbc, 0x05, 0x00, 0xcc},
+ {0xbc, 0x06, 0x00, 0xcc}, {0xbc, 0x08, 0x30, 0xcc},
+ {0xbc, 0x09, 0x40, 0xcc}, {0xbc, 0x0a, 0x10, 0xcc},
+ {0xbc, 0x0b, 0x00, 0xcc}, {0xbc, 0x0c, 0x00, 0xcc},
+ {0xbf, 0xc0, 0x26, 0xcc}, {0xbf, 0xc1, 0x02, 0xcc},
+ {0xbf, 0xcc, 0x04, 0xcc}, {0xb3, 0x5c, 0x01, 0xcc},
+ {0xb3, 0x01, 0x41, 0xcc},
+ {}
+};
+
+static const __u8 po3130_gamma[17] = {
+ 0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
+ 0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff
+};
+static const __u8 po3130_matrix[9] = {
+ 0x5f, 0xec, 0xf5, 0xf1, 0x5a, 0xf5, 0xf1, 0xec, 0x63
+};
+
+static const __u8 po3130_initVGA_data[][4] = {
+ {0xb0, 0x4d, 0x00, 0xcc}, {0xb3, 0x01, 0x01, 0xcc},
+ {0x00, 0x00, 0x50, 0xdd}, {0xb0, 0x03, 0x01, 0xcc},
+ {0xb3, 0x00, 0x04, 0xcc}, {0xb3, 0x00, 0x24, 0xcc},
+ {0xb3, 0x00, 0x25, 0xcc}, {0xb3, 0x08, 0x01, 0xcc},
+ {0xb3, 0x09, 0x0c, 0xcc}, {0xb3, 0x05, 0x00, 0xcc},
+ {0xb3, 0x06, 0x01, 0xcc}, {0xb3, 0x03, 0x1a, 0xcc},
+ {0xb3, 0x04, 0x15, 0xcc}, {0xb3, 0x20, 0x00, 0xcc},
+ {0xb3, 0x21, 0x00, 0xcc}, {0xb3, 0x22, 0x01, 0xcc},
+ {0xb3, 0x23, 0xe8, 0xcc}, {0xb8, 0x08, 0xe8, 0xcc},
+ {0xb3, 0x14, 0x00, 0xcc}, {0xb3, 0x15, 0x00, 0xcc},
+ {0xb3, 0x16, 0x02, 0xcc}, {0xb3, 0x17, 0x7f, 0xcc},
+ {0xb3, 0x34, 0x01, 0xcc}, {0xb3, 0x35, 0xf6, 0xcc},
+ {0xb3, 0x00, 0x27, 0xcc}, {0xbc, 0x00, 0x71, 0xcc},
+ {0xb8, 0x00, 0x21, 0xcc}, {0xb8, 0x27, 0x20, 0xcc},
+ {0xb8, 0x01, 0x79, 0xcc}, {0xb8, 0x81, 0x09, 0xcc},
+ {0xb8, 0x2c, 0x50, 0xcc}, {0xb8, 0x2d, 0xf8, 0xcc},
+ {0xb8, 0x2e, 0xf8, 0xcc}, {0xb8, 0x2f, 0xf8, 0xcc},
+ {0xb8, 0x30, 0x50, 0xcc}, {0xb8, 0x31, 0xf8, 0xcc},
+ {0xb8, 0x32, 0xf8, 0xcc}, {0xb8, 0x33, 0xf8, 0xcc},
+ {0xb8, 0x34, 0x50, 0xcc}, {0xb8, 0x35, 0x00, 0xcc},
+ {0xb8, 0x36, 0x00, 0xcc}, {0xb8, 0x37, 0x00, 0xcc},
+ {0x00, 0x1e, 0xc6, 0xaa}, {0x00, 0x20, 0x44, 0xaa},
+ {0x00, 0xad, 0x02, 0xaa}, {0x00, 0xae, 0x2c, 0xaa},
+ {0x00, 0x12, 0x08, 0xaa}, {0x00, 0x17, 0x41, 0xaa},
+ {0x00, 0x19, 0x41, 0xaa}, {0x00, 0x1e, 0x06, 0xaa},
+ {0x00, 0x21, 0x00, 0xaa}, {0x00, 0x36, 0xc0, 0xaa},
+ {0x00, 0x37, 0xc8, 0xaa}, {0x00, 0x3b, 0x36, 0xaa},
+ {0x00, 0x4b, 0xfe, 0xaa}, {0x00, 0x51, 0x1c, 0xaa},
+ {0x00, 0x52, 0x01, 0xaa}, {0x00, 0x55, 0x0a, 0xaa},
+ {0x00, 0x59, 0x02, 0xaa}, {0x00, 0x5a, 0x04, 0xaa},
+ {0x00, 0x5c, 0x10, 0xaa}, {0x00, 0x5d, 0x10, 0xaa},
+ {0x00, 0x5e, 0x10, 0xaa}, {0x00, 0x5f, 0x10, 0xaa},
+ {0x00, 0x61, 0x00, 0xaa}, {0x00, 0x62, 0x18, 0xaa},
+ {0x00, 0x63, 0x30, 0xaa}, {0x00, 0x70, 0x68, 0xaa},
+ {0x00, 0x80, 0x71, 0xaa}, {0x00, 0x81, 0x08, 0xaa},
+ {0x00, 0x82, 0x00, 0xaa}, {0x00, 0x83, 0x55, 0xaa},
+ {0x00, 0x84, 0x06, 0xaa}, {0x00, 0x85, 0x06, 0xaa},
+ {0x00, 0x86, 0x13, 0xaa}, {0x00, 0x87, 0x18, 0xaa},
+ {0x00, 0xaa, 0x3f, 0xaa}, {0x00, 0xab, 0x44, 0xaa},
+ {0x00, 0xb0, 0x68, 0xaa}, {0x00, 0xb5, 0x10, 0xaa},
+ {0x00, 0xb8, 0x20, 0xaa}, {0x00, 0xb9, 0xa0, 0xaa},
+ {0x00, 0xbc, 0x04, 0xaa}, {0x00, 0x8b, 0x40, 0xaa},
+ {0x00, 0x8c, 0x91, 0xaa}, {0x00, 0x8d, 0x8f, 0xaa},
+ {0x00, 0x8e, 0x91, 0xaa}, {0x00, 0x8f, 0x43, 0xaa},
+ {0x00, 0x90, 0x92, 0xaa}, {0x00, 0x91, 0x89, 0xaa},
+ {0x00, 0x92, 0x9d, 0xaa}, {0x00, 0x93, 0x46, 0xaa},
+ {0x00, 0xd6, 0x22, 0xaa}, {0x00, 0x73, 0x00, 0xaa},
+ {0x00, 0x74, 0x10, 0xaa}, {0x00, 0x75, 0x20, 0xaa},
+ {0x00, 0x76, 0x2b, 0xaa}, {0x00, 0x77, 0x36, 0xaa},
+ {0x00, 0x78, 0x49, 0xaa}, {0x00, 0x79, 0x5a, 0xaa},
+ {0x00, 0x7a, 0x7f, 0xaa}, {0x00, 0x7b, 0x9b, 0xaa},
+ {0x00, 0x7c, 0xba, 0xaa}, {0x00, 0x7d, 0xd4, 0xaa},
+ {0x00, 0x7e, 0xea, 0xaa}, {0x00, 0xd6, 0x62, 0xaa},
+ {0x00, 0x73, 0x00, 0xaa}, {0x00, 0x74, 0x10, 0xaa},
+ {0x00, 0x75, 0x20, 0xaa}, {0x00, 0x76, 0x2b, 0xaa},
+ {0x00, 0x77, 0x36, 0xaa}, {0x00, 0x78, 0x49, 0xaa},
+ {0x00, 0x79, 0x5a, 0xaa}, {0x00, 0x7a, 0x7f, 0xaa},
+ {0x00, 0x7b, 0x9b, 0xaa}, {0x00, 0x7c, 0xba, 0xaa},
+ {0x00, 0x7d, 0xd4, 0xaa}, {0x00, 0x7e, 0xea, 0xaa},
+ {0x00, 0xd6, 0xa2, 0xaa}, {0x00, 0x73, 0x00, 0xaa},
+ {0x00, 0x74, 0x10, 0xaa}, {0x00, 0x75, 0x20, 0xaa},
+ {0x00, 0x76, 0x2b, 0xaa}, {0x00, 0x77, 0x36, 0xaa},
+ {0x00, 0x78, 0x49, 0xaa}, {0x00, 0x79, 0x5a, 0xaa},
+ {0x00, 0x7a, 0x7f, 0xaa}, {0x00, 0x7b, 0x9b, 0xaa},
+ {0x00, 0x7c, 0xba, 0xaa}, {0x00, 0x7d, 0xd4, 0xaa},
+ {0x00, 0x7e, 0xea, 0xaa},
+ {0x00, 0x4c, 0x07, 0xaa},
+ {0x00, 0x4b, 0xe0, 0xaa}, {0x00, 0x4e, 0x77, 0xaa},
+ {0x00, 0x59, 0x02, 0xaa}, {0x00, 0x4d, 0x0a, 0xaa},
+/* {0x00, 0xd1, 0x00, 0xaa}, {0x00, 0x20, 0xc4, 0xaa},
+ {0xb8, 0x8e, 0x00, 0xcc}, {0xb8, 0x8f, 0xff, 0xcc}, */
+ {0x00, 0xd1, 0x3c, 0xaa}, {0x00, 0x20, 0xc4, 0xaa},
+ {0xb8, 0x8e, 0x00, 0xcc}, {0xb8, 0x8f, 0xff, 0xcc},
+ {0xb8, 0xfe, 0x00, 0xcc}, {0xb8, 0xff, 0x28, 0xcc},
+ {0xb9, 0x00, 0x28, 0xcc}, {0xb9, 0x01, 0x28, 0xcc},
+ {0xb9, 0x02, 0x28, 0xcc}, {0xb9, 0x03, 0x00, 0xcc},
+ {0xb9, 0x04, 0x00, 0xcc}, {0xb9, 0x05, 0x3c, 0xcc},
+ {0xb9, 0x06, 0x3c, 0xcc}, {0xb9, 0x07, 0x3c, 0xcc},
+ {0xb9, 0x08, 0x3c, 0xcc}, {0x00, 0x05, 0x00, 0xaa},
+ {0xb3, 0x5c, 0x00, 0xcc}, {0xb3, 0x01, 0x41, 0xcc},
+ {}
+};
+static const __u8 po3130_rundata[][4] = {
+ {0x00, 0x47, 0x45, 0xaa}, {0x00, 0x48, 0x9b, 0xaa},
+ {0x00, 0x49, 0x3a, 0xaa}, {0x00, 0x4a, 0x01, 0xaa},
+ {0x00, 0x44, 0x40, 0xaa},
+/* {0x00, 0xd5, 0x7c, 0xaa}, */
+ {0x00, 0xad, 0x04, 0xaa}, {0x00, 0xae, 0x00, 0xaa},
+ {0x00, 0xb0, 0x78, 0xaa}, {0x00, 0x98, 0x02, 0xaa},
+ {0x00, 0x94, 0x25, 0xaa}, {0x00, 0x95, 0x25, 0xaa},
+ {0x00, 0x59, 0x68, 0xaa}, {0x00, 0x44, 0x20, 0xaa},
+ {0x00, 0x17, 0x50, 0xaa}, {0x00, 0x19, 0x50, 0xaa},
+ {0x00, 0xd1, 0x3c, 0xaa}, {0x00, 0xd1, 0x3c, 0xaa},
+ {0x00, 0x1e, 0x06, 0xaa}, {0x00, 0x1e, 0x06, 0xaa},
+ {}
+};
+
+static const __u8 po3130_initQVGA_data[][4] = {
+ {0xb0, 0x4d, 0x00, 0xcc}, {0xb3, 0x01, 0x01, 0xcc},
+ {0x00, 0x00, 0x50, 0xdd}, {0xb0, 0x03, 0x09, 0xcc},
+ {0xb3, 0x00, 0x04, 0xcc}, {0xb3, 0x00, 0x24, 0xcc},
+ {0xb3, 0x00, 0x25, 0xcc}, {0xb3, 0x08, 0x01, 0xcc},
+ {0xb3, 0x09, 0x0c, 0xcc}, {0xb3, 0x05, 0x00, 0xcc},
+ {0xb3, 0x06, 0x01, 0xcc}, {0xb3, 0x03, 0x1a, 0xcc},
+ {0xb3, 0x04, 0x15, 0xcc}, {0xb3, 0x20, 0x00, 0xcc},
+ {0xb3, 0x21, 0x00, 0xcc}, {0xb3, 0x22, 0x01, 0xcc},
+ {0xb3, 0x23, 0xe0, 0xcc}, {0xb8, 0x08, 0xe0, 0xcc},
+ {0xb3, 0x14, 0x00, 0xcc}, {0xb3, 0x15, 0x00, 0xcc},
+ {0xb3, 0x16, 0x02, 0xcc}, {0xb3, 0x17, 0x7f, 0xcc},
+ {0xb3, 0x34, 0x01, 0xcc}, {0xb3, 0x35, 0xf6, 0xcc},
+ {0xb3, 0x00, 0x27, 0xcc}, {0xbc, 0x00, 0xd1, 0xcc},
+ {0xb8, 0x00, 0x21, 0xcc}, {0xb8, 0x27, 0x20, 0xcc},
+ {0xb8, 0x01, 0x79, 0xcc}, {0xb8, 0x81, 0x09, 0xcc},
+ {0xb8, 0x2c, 0x50, 0xcc}, {0xb8, 0x2d, 0xf8, 0xcc},
+ {0xb8, 0x2e, 0xf8, 0xcc}, {0xb8, 0x2f, 0xf8, 0xcc},
+ {0xb8, 0x30, 0x50, 0xcc}, {0xb8, 0x31, 0xf8, 0xcc},
+ {0xb8, 0x32, 0xf8, 0xcc}, {0xb8, 0x33, 0xf8, 0xcc},
+ {0xb8, 0x34, 0x50, 0xcc}, {0xb8, 0x35, 0x00, 0xcc},
+ {0xb8, 0x36, 0x00, 0xcc}, {0xb8, 0x37, 0x00, 0xcc},
+ {0x00, 0x1e, 0xc6, 0xaa}, {0x00, 0x20, 0x44, 0xaa},
+ {0x00, 0xad, 0x02, 0xaa}, {0x00, 0xae, 0x2c, 0xaa},
+ {0x00, 0x12, 0x08, 0xaa}, {0x00, 0x17, 0x41, 0xaa},
+ {0x00, 0x19, 0x41, 0xaa}, {0x00, 0x1e, 0x06, 0xaa},
+ {0x00, 0x21, 0x00, 0xaa}, {0x00, 0x36, 0xc0, 0xaa},
+ {0x00, 0x37, 0xc8, 0xaa}, {0x00, 0x3b, 0x36, 0xaa},
+ {0x00, 0x4b, 0xfe, 0xaa}, {0x00, 0x51, 0x1c, 0xaa},
+ {0x00, 0x52, 0x01, 0xaa}, {0x00, 0x55, 0x0a, 0xaa},
+ {0x00, 0x59, 0x6f, 0xaa}, {0x00, 0x5a, 0x04, 0xaa},
+ {0x00, 0x5c, 0x10, 0xaa}, {0x00, 0x5d, 0x10, 0xaa},
+ {0x00, 0x5e, 0x10, 0xaa}, {0x00, 0x5f, 0x10, 0xaa},
+ {0x00, 0x61, 0x00, 0xaa}, {0x00, 0x62, 0x18, 0xaa},
+ {0x00, 0x63, 0x30, 0xaa}, {0x00, 0x70, 0x68, 0xaa},
+ {0x00, 0x80, 0x71, 0xaa}, {0x00, 0x81, 0x08, 0xaa},
+ {0x00, 0x82, 0x00, 0xaa}, {0x00, 0x83, 0x55, 0xaa},
+ {0x00, 0x84, 0x06, 0xaa}, {0x00, 0x85, 0x06, 0xaa},
+ {0x00, 0x86, 0x13, 0xaa}, {0x00, 0x87, 0x18, 0xaa},
+ {0x00, 0xaa, 0x3f, 0xaa}, {0x00, 0xab, 0x44, 0xaa},
+ {0x00, 0xb0, 0x68, 0xaa}, {0x00, 0xb5, 0x10, 0xaa},
+ {0x00, 0xb8, 0x20, 0xaa}, {0x00, 0xb9, 0xa0, 0xaa},
+ {0x00, 0xbc, 0x04, 0xaa}, {0x00, 0x8b, 0x40, 0xaa},
+ {0x00, 0x8c, 0x91, 0xaa}, {0x00, 0x8d, 0x8f, 0xaa},
+ {0x00, 0x8e, 0x91, 0xaa}, {0x00, 0x8f, 0x43, 0xaa},
+ {0x00, 0x90, 0x92, 0xaa}, {0x00, 0x91, 0x89, 0xaa},
+ {0x00, 0x92, 0x9d, 0xaa}, {0x00, 0x93, 0x46, 0xaa},
+ {0x00, 0xd6, 0x22, 0xaa}, {0x00, 0x73, 0x00, 0xaa},
+ {0x00, 0x74, 0x10, 0xaa}, {0x00, 0x75, 0x20, 0xaa},
+ {0x00, 0x76, 0x2b, 0xaa}, {0x00, 0x77, 0x36, 0xaa},
+ {0x00, 0x78, 0x49, 0xaa}, {0x00, 0x79, 0x5a, 0xaa},
+ {0x00, 0x7a, 0x7f, 0xaa}, {0x00, 0x7b, 0x9b, 0xaa},
+ {0x00, 0x7c, 0xba, 0xaa}, {0x00, 0x7d, 0xd4, 0xaa},
+ {0x00, 0x7e, 0xea, 0xaa}, {0x00, 0xd6, 0x62, 0xaa},
+ {0x00, 0x73, 0x00, 0xaa}, {0x00, 0x74, 0x10, 0xaa},
+ {0x00, 0x75, 0x20, 0xaa}, {0x00, 0x76, 0x2b, 0xaa},
+ {0x00, 0x77, 0x36, 0xaa}, {0x00, 0x78, 0x49, 0xaa},
+ {0x00, 0x79, 0x5a, 0xaa}, {0x00, 0x7a, 0x7f, 0xaa},
+ {0x00, 0x7b, 0x9b, 0xaa}, {0x00, 0x7c, 0xba, 0xaa},
+ {0x00, 0x7d, 0xd4, 0xaa}, {0x00, 0x7e, 0xea, 0xaa},
+ {0x00, 0xd6, 0xa2, 0xaa}, {0x00, 0x73, 0x00, 0xaa},
+ {0x00, 0x74, 0x10, 0xaa}, {0x00, 0x75, 0x20, 0xaa},
+ {0x00, 0x76, 0x2b, 0xaa}, {0x00, 0x77, 0x36, 0xaa},
+ {0x00, 0x78, 0x49, 0xaa}, {0x00, 0x79, 0x5a, 0xaa},
+ {0x00, 0x7a, 0x7f, 0xaa}, {0x00, 0x7b, 0x9b, 0xaa},
+ {0x00, 0x7c, 0xba, 0xaa}, {0x00, 0x7d, 0xd4, 0xaa},
+ {0x00, 0x7e, 0xea, 0xaa}, {0x00, 0x4c, 0x07, 0xaa},
+ {0x00, 0x4b, 0xe0, 0xaa}, {0x00, 0x4e, 0x77, 0xaa},
+ {0x00, 0x59, 0x66, 0xaa}, {0x00, 0x4d, 0x0a, 0xaa},
+ {0x00, 0xd1, 0x00, 0xaa}, {0x00, 0x20, 0xc4, 0xaa},
+ {0xb8, 0x8e, 0x00, 0xcc}, {0xb8, 0x8f, 0xff, 0xcc},
+ {0xb8, 0xfe, 0x00, 0xcc}, {0xb8, 0xff, 0x28, 0xcc},
+ {0xb9, 0x00, 0x28, 0xcc}, {0xb9, 0x01, 0x28, 0xcc},
+ {0xb9, 0x02, 0x28, 0xcc}, {0xb9, 0x03, 0x00, 0xcc},
+ {0xb9, 0x04, 0x00, 0xcc}, {0xb9, 0x05, 0x3c, 0xcc},
+ {0xb9, 0x06, 0x3c, 0xcc}, {0xb9, 0x07, 0x3c, 0xcc},
+ {0xb9, 0x08, 0x3c, 0xcc}, {0xbc, 0x02, 0x18, 0xcc},
+ {0xbc, 0x03, 0x50, 0xcc}, {0xbc, 0x04, 0x18, 0xcc},
+ {0xbc, 0x05, 0x00, 0xcc}, {0xbc, 0x06, 0x00, 0xcc},
+ {0xbc, 0x08, 0x30, 0xcc}, {0xbc, 0x09, 0x40, 0xcc},
+ {0xbc, 0x0a, 0x10, 0xcc}, {0xbc, 0x0b, 0x00, 0xcc},
+ {0xbc, 0x0c, 0x00, 0xcc}, {0x00, 0x05, 0x00, 0xaa},
+ {0xb3, 0x5c, 0x00, 0xcc}, {0xb3, 0x01, 0x41, 0xcc},
+ {}
+};
+
+static const __u8 hv7131r_gamma[17] = {
+/* 0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
+ * 0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff */
+ 0x04, 0x1a, 0x36, 0x55, 0x6f, 0x87, 0x9d, 0xb0, 0xc1,
+ 0xcf, 0xda, 0xe4, 0xec, 0xf3, 0xf8, 0xfd, 0xff
+};
+static const __u8 hv7131r_matrix[9] = {
+ 0x5f, 0xec, 0xf5, 0xf1, 0x5a, 0xf5, 0xf1, 0xec, 0x63
+};
+static const __u8 hv7131r_initVGA_data[][4] = {
+ {0xb0, 0x4d, 0x00, 0xcc}, {0xb3, 0x01, 0x01, 0xcc},
+ {0x00, 0x00, 0x50, 0xdd}, {0xb0, 0x03, 0x01, 0xcc},
+ {0xb3, 0x00, 0x24, 0xcc},
+ {0xb3, 0x00, 0x25, 0xcc}, {0xb3, 0x08, 0x01, 0xcc},
+ {0xb3, 0x09, 0x0c, 0xcc}, {0xb3, 0x05, 0x00, 0xcc},
+ {0xb3, 0x06, 0x01, 0xcc},
+ {0xb3, 0x01, 0x45, 0xcc}, {0xb3, 0x03, 0x0b, 0xcc},
+ {0xb3, 0x04, 0x05, 0xcc}, {0xb3, 0x20, 0x00, 0xcc},
+ {0xb3, 0x21, 0x00, 0xcc},
+ {0xb3, 0x22, 0x01, 0xcc}, {0xb3, 0x23, 0xe0, 0xcc},
+ {0xb3, 0x14, 0x00, 0xcc}, {0xb3, 0x15, 0x00, 0xcc},
+ {0xb3, 0x16, 0x02, 0xcc},
+ {0xb3, 0x17, 0x7f, 0xcc}, {0xb3, 0x34, 0x01, 0xcc},
+ {0xb3, 0x35, 0x91, 0xcc}, {0xb3, 0x00, 0x27, 0xcc},
+ {0xbc, 0x00, 0x73, 0xcc},
+ {0xb8, 0x00, 0x23, 0xcc}, {0x00, 0x01, 0x0c, 0xaa},
+ {0x00, 0x14, 0x01, 0xaa}, {0x00, 0x15, 0xe6, 0xaa},
+ {0x00, 0x16, 0x02, 0xaa},
+ {0x00, 0x17, 0x86, 0xaa}, {0x00, 0x23, 0x00, 0xaa},
+ {0x00, 0x25, 0x09, 0xaa}, {0x00, 0x26, 0x27, 0xaa},
+ {0x00, 0x27, 0xc0, 0xaa},
+ {0xb8, 0x2c, 0x60, 0xcc}, {0xb8, 0x2d, 0xf8, 0xcc},
+ {0xb8, 0x2e, 0xf8, 0xcc}, {0xb8, 0x2f, 0xf8, 0xcc},
+ {0xb8, 0x30, 0x50, 0xcc},
+ {0xb8, 0x31, 0xf8, 0xcc}, {0xb8, 0x32, 0xf8, 0xcc},
+ {0xb8, 0x33, 0xf8, 0xcc}, {0xb8, 0x34, 0x65, 0xcc},
+ {0xb8, 0x35, 0x00, 0xcc},
+ {0xb8, 0x36, 0x00, 0xcc}, {0xb8, 0x37, 0x00, 0xcc},
+ {0xb8, 0x27, 0x20, 0xcc}, {0xb8, 0x01, 0x7d, 0xcc},
+ {0xb8, 0x81, 0x09, 0xcc},
+ {0xb3, 0x01, 0x41, 0xcc}, {0xb8, 0xfe, 0x00, 0xcc},
+ {0xb8, 0xff, 0x28, 0xcc}, {0xb9, 0x00, 0x28, 0xcc},
+ {0xb9, 0x01, 0x28, 0xcc},
+ {0xb9, 0x02, 0x28, 0xcc}, {0xb9, 0x03, 0x00, 0xcc},
+ {0xb9, 0x04, 0x00, 0xcc}, {0xb9, 0x05, 0x3c, 0xcc},
+ {0xb9, 0x06, 0x3c, 0xcc},
+ {0xb9, 0x07, 0x3c, 0xcc}, {0xb9, 0x08, 0x3c, 0xcc},
+ {0xb8, 0x8e, 0x00, 0xcc}, {0xb8, 0x8f, 0xff, 0xcc},
+ {0x00, 0x30, 0x18, 0xaa},
+ {}
+};
+
+static const __u8 hv7131r_initQVGA_data[][4] = {
+ {0xb0, 0x4d, 0x00, 0xcc}, {0xb3, 0x01, 0x01, 0xcc},
+ {0x00, 0x00, 0x50, 0xdd}, {0xb0, 0x03, 0x01, 0xcc},
+ {0xb3, 0x00, 0x24, 0xcc},
+ {0xb3, 0x00, 0x25, 0xcc}, {0xb3, 0x08, 0x01, 0xcc},
+ {0xb3, 0x09, 0x0c, 0xcc}, {0xb3, 0x05, 0x00, 0xcc},
+ {0xb3, 0x06, 0x01, 0xcc},
+ {0xb3, 0x03, 0x0b, 0xcc}, {0xb3, 0x04, 0x05, 0xcc},
+ {0xb3, 0x20, 0x00, 0xcc}, {0xb3, 0x21, 0x00, 0xcc},
+ {0xb3, 0x22, 0x01, 0xcc},
+ {0xb3, 0x23, 0xe0, 0xcc}, {0xb3, 0x14, 0x00, 0xcc},
+ {0xb3, 0x15, 0x00, 0xcc}, {0xb3, 0x16, 0x02, 0xcc},
+ {0xb3, 0x17, 0x7f, 0xcc},
+ {0xb3, 0x34, 0x01, 0xcc}, {0xb3, 0x35, 0x91, 0xcc},
+ {0xb3, 0x00, 0x27, 0xcc}, {0xbc, 0x00, 0xd1, 0xcc},
+ {0xb8, 0x00, 0x21, 0xcc},
+ {0x00, 0x01, 0x0c, 0xaa}, {0x00, 0x14, 0x01, 0xaa},
+ {0x00, 0x15, 0xe6, 0xaa}, {0x00, 0x16, 0x02, 0xaa},
+ {0x00, 0x17, 0x86, 0xaa},
+ {0x00, 0x23, 0x00, 0xaa}, {0x00, 0x25, 0x01, 0xaa},
+ {0x00, 0x26, 0xd4, 0xaa}, {0x00, 0x27, 0xc0, 0xaa},
+ {0xbc, 0x02, 0x08, 0xcc},
+ {0xbc, 0x03, 0x70, 0xcc}, {0xbc, 0x04, 0x08, 0xcc},
+ {0xbc, 0x05, 0x00, 0xcc}, {0xbc, 0x06, 0x00, 0xcc},
+ {0xbc, 0x08, 0x3c, 0xcc},
+ {0xbc, 0x09, 0x40, 0xcc}, {0xbc, 0x0a, 0x04, 0xcc},
+ {0xbc, 0x0b, 0x00, 0xcc}, {0xbc, 0x0c, 0x00, 0xcc},
+ {0xb8, 0xfe, 0x02, 0xcc},
+ {0xb8, 0xff, 0x07, 0xcc}, {0xb9, 0x00, 0x14, 0xcc},
+ {0xb9, 0x01, 0x14, 0xcc}, {0xb9, 0x02, 0x14, 0xcc},
+ {0xb9, 0x03, 0x00, 0xcc},
+ {0xb9, 0x04, 0x02, 0xcc}, {0xb9, 0x05, 0x05, 0xcc},
+ {0xb9, 0x06, 0x0f, 0xcc}, {0xb9, 0x07, 0x0f, 0xcc},
+ {0xb9, 0x08, 0x0f, 0xcc},
+ {0xb8, 0x2c, 0x60, 0xcc}, {0xb8, 0x2d, 0xf8, 0xcc},
+ {0xb8, 0x2e, 0xf8, 0xcc}, {0xb8, 0x2f, 0xf8, 0xcc},
+ {0xb8, 0x30, 0x50, 0xcc},
+ {0xb8, 0x31, 0xf8, 0xcc}, {0xb8, 0x32, 0xf8, 0xcc},
+ {0xb8, 0x33, 0xf8, 0xcc},
+ {0xb8, 0x34, 0x65, 0xcc}, {0xb8, 0x35, 0x00, 0xcc},
+ {0xb8, 0x36, 0x00, 0xcc}, {0xb8, 0x37, 0x00, 0xcc},
+ {0xb8, 0x27, 0x20, 0xcc},
+ {0xb8, 0x01, 0x7d, 0xcc}, {0xb8, 0x81, 0x09, 0xcc},
+ {0xb3, 0x01, 0x41, 0xcc}, {0xb8, 0xfe, 0x00, 0xcc},
+ {0xb8, 0xff, 0x28, 0xcc},
+ {0xb9, 0x00, 0x28, 0xcc}, {0xb9, 0x01, 0x28, 0xcc},
+ {0xb9, 0x02, 0x28, 0xcc}, {0xb9, 0x03, 0x00, 0xcc},
+ {0xb9, 0x04, 0x00, 0xcc},
+ {0xb9, 0x05, 0x3c, 0xcc}, {0xb9, 0x06, 0x3c, 0xcc},
+ {0xb9, 0x07, 0x3c, 0xcc}, {0xb9, 0x08, 0x3c, 0xcc},
+ {0xb8, 0x8e, 0x00, 0xcc},
+ {0xb8, 0x8f, 0xff, 0xcc}, {0x00, 0x30, 0x18, 0xaa},
+ {}
+};
+
+static const __u8 ov7660_gamma[17] = {
+ 0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
+ 0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff
+};
+static const __u8 ov7660_matrix[9] = {
+ 0x5a, 0xf0, 0xf6, 0xf3, 0x57, 0xf6, 0xf3, 0xef, 0x62
+};
+static const __u8 ov7660_initVGA_data[][4] = {
+ {0xb0, 0x4d, 0x00, 0xcc}, {0xb3, 0x01, 0x01, 0xcc},
+ {0x00, 0x00, 0x50, 0xdd},
+ {0xb0, 0x03, 0x01, 0xcc},
+ {0xb3, 0x00, 0x21, 0xcc}, {0xb3, 0x00, 0x26, 0xcc},
+ {0xb3, 0x05, 0x01, 0xcc},
+ {0xb3, 0x06, 0x03, 0xcc},
+ {0xb3, 0x03, 0x1f, 0xcc}, {0xb3, 0x04, 0x05, 0xcc},
+ {0xb3, 0x05, 0x00, 0xcc},
+ {0xb3, 0x06, 0x01, 0xcc},
+ {0xb3, 0x15, 0x00, 0xcc},/* 0xb315 <-0 href startl */
+ {0xb3, 0x16, 0x02, 0xcc}, {0xb3, 0x17, 0x7f, 0xcc},
+ {0xb3, 0x21, 0x00, 0xcc},
+ {0xb3, 0x23, 0xe0, 0xcc}, {0xb3, 0x1d, 0x01, 0xcc},
+ {0xb3, 0x1f, 0x02, 0xcc},
+ {0xb3, 0x34, 0x01, 0xcc},
+ {0xb3, 0x35, 0xa1, 0xcc}, {0xb3, 0x00, 0x26, 0xcc},
+ {0xb8, 0x00, 0x33, 0xcc}, /* 13 */
+ {0xb8, 0x01, 0x7d, 0xcc},
+ {0xbc, 0x00, 0x73, 0xcc}, {0xb8, 0x81, 0x09, 0xcc},
+ {0xb8, 0x27, 0x20, 0xcc},
+ {0xb8, 0x8f, 0x50, 0xcc},
+ {0x00, 0x01, 0x80, 0xaa}, {0x00, 0x02, 0x80, 0xaa},
+ {0x00, 0x12, 0x80, 0xaa},
+ {0x00, 0x12, 0x05, 0xaa},
+ {0x00, 0x1e, 0x01, 0xaa},
+ {0x00, 0x3d, 0x40, 0xaa}, /* 0x3d <-40 gamma 01 */
+ {0x00, 0x41, 0x00, 0xaa}, /* edge 00 */
+ {0x00, 0x0d, 0x48, 0xaa}, {0x00, 0x0e, 0x04, 0xaa},
+ {0x00, 0x13, 0xa7, 0xaa},
+ {0x00, 0x40, 0xc1, 0xaa}, {0x00, 0x35, 0x00, 0xaa},
+ {0x00, 0x36, 0x00, 0xaa},
+ {0x00, 0x3c, 0x68, 0xaa}, {0x00, 0x1b, 0x05, 0xaa},
+ {0x00, 0x39, 0x43, 0xaa},
+ {0x00, 0x8d, 0xcf, 0xaa},
+ {0x00, 0x8b, 0xcc, 0xaa}, {0x00, 0x8c, 0xcc, 0xaa},
+ {0x00, 0x0f, 0x62, 0xaa},
+ {0x00, 0x35, 0x84, 0xaa},
+ {0x00, 0x3b, 0x08, 0xaa}, /* 0 * Nightframe 1/4 + 50Hz -> 0xC8 */
+ {0x00, 0x3a, 0x00, 0xaa}, /* mx change yuyv format 00, 04, 01; 08, 0c*/
+ {0x00, 0x14, 0x2a, 0xaa}, /* agc ampli */
+ {0x00, 0x9e, 0x40, 0xaa}, {0xb8, 0x8f, 0x50, 0xcc},
+ {0x00, 0x01, 0x80, 0xaa},
+ {0x00, 0x02, 0x80, 0xaa},
+ {0xb8, 0xfe, 0x00, 0xcc}, {0xb8, 0xff, 0x28, 0xcc},
+ {0xb9, 0x00, 0x28, 0xcc},
+ {0xb9, 0x01, 0x28, 0xcc}, {0xb9, 0x02, 0x28, 0xcc},
+ {0xb9, 0x03, 0x00, 0xcc},
+ {0xb9, 0x04, 0x00, 0xcc},
+ {0xb9, 0x05, 0x3c, 0xcc}, {0xb9, 0x06, 0x3c, 0xcc},
+ {0xb9, 0x07, 0x3c, 0xcc},
+ {0xb9, 0x08, 0x3c, 0xcc},
+
+ {0xb8, 0x8e, 0x00, 0xcc}, {0xb8, 0x8f, 0xff, 0xcc},
+
+ {0x00, 0x29, 0x3c, 0xaa}, {0xb3, 0x01, 0x45, 0xcc},
+ {}
+};
+static const __u8 ov7660_initQVGA_data[][4] = {
+ {0xb0, 0x4d, 0x00, 0xcc}, {0xb3, 0x01, 0x01, 0xcc},
+ {0x00, 0x00, 0x50, 0xdd}, {0xb0, 0x03, 0x01, 0xcc},
+ {0xb3, 0x00, 0x21, 0xcc}, {0xb3, 0x00, 0x26, 0xcc},
+ {0xb3, 0x05, 0x01, 0xcc}, {0xb3, 0x06, 0x03, 0xcc},
+ {0xb3, 0x03, 0x1f, 0xcc}, {0xb3, 0x04, 0x05, 0xcc},
+ {0xb3, 0x05, 0x00, 0xcc}, {0xb3, 0x06, 0x01, 0xcc},
+ {0xb3, 0x15, 0x00, 0xcc},/* 0xb315 <-0 href startl */
+ {0xb3, 0x16, 0x02, 0xcc}, {0xb3, 0x17, 0x7f, 0xcc},
+ {0xb3, 0x21, 0x00, 0xcc},
+ {0xb3, 0x23, 0xe0, 0xcc}, {0xb3, 0x1d, 0x01, 0xcc},
+ {0xb3, 0x1f, 0x02, 0xcc}, {0xb3, 0x34, 0x01, 0xcc},
+ {0xb3, 0x35, 0xa1, 0xcc}, {0xb3, 0x00, 0x26, 0xcc},
+ {0xb8, 0x00, 0x33, 0xcc}, /* 13 */
+ {0xb8, 0x01, 0x7d, 0xcc},
+/* sizer */
+ {0xbc, 0x00, 0xd3, 0xcc},
+ {0xb8, 0x81, 0x09, 0xcc}, {0xb8, 0x81, 0x09, 0xcc},
+ {0xb8, 0x27, 0x20, 0xcc}, {0xb8, 0x8f, 0x50, 0xcc},
+ {0x00, 0x01, 0x80, 0xaa}, {0x00, 0x02, 0x80, 0xaa},
+ {0x00, 0x12, 0x80, 0xaa}, {0x00, 0x12, 0x05, 0xaa},
+ {0x00, 0x1e, 0x01, 0xaa},
+ {0x00, 0x3d, 0x40, 0xaa}, /* 0x3d <-40 gamma 01 */
+ {0x00, 0x41, 0x00, 0xaa}, /* edge 00 */
+ {0x00, 0x0d, 0x48, 0xaa}, {0x00, 0x0e, 0x04, 0xaa},
+ {0x00, 0x13, 0xa7, 0xaa},
+ {0x00, 0x40, 0xc1, 0xaa}, {0x00, 0x35, 0x00, 0xaa},
+ {0x00, 0x36, 0x00, 0xaa},
+ {0x00, 0x3c, 0x68, 0xaa}, {0x00, 0x1b, 0x05, 0xaa},
+ {0x00, 0x39, 0x43, 0xaa}, {0x00, 0x8d, 0xcf, 0xaa},
+ {0x00, 0x8b, 0xcc, 0xaa}, {0x00, 0x8c, 0xcc, 0xaa},
+ {0x00, 0x0f, 0x62, 0xaa}, {0x00, 0x35, 0x84, 0xaa},
+ {0x00, 0x3b, 0x08, 0xaa}, /* 0 * Nightframe 1/4 + 50Hz -> 0xC8 */
+ {0x00, 0x3a, 0x00, 0xaa}, /* mx change yuyv format 00, 04, 01; 08, 0c*/
+ {0x00, 0x14, 0x2a, 0xaa}, /* agc ampli */
+ {0x00, 0x9e, 0x40, 0xaa}, {0xb8, 0x8f, 0x50, 0xcc},
+ {0x00, 0x01, 0x80, 0xaa},
+ {0x00, 0x02, 0x80, 0xaa},
+/* sizer filters */
+ {0xbc, 0x02, 0x08, 0xcc},
+ {0xbc, 0x03, 0x70, 0xcc},
+ {0xb8, 0x35, 0x00, 0xcc},
+ {0xb8, 0x36, 0x00, 0xcc},
+ {0xb8, 0x37, 0x00, 0xcc},
+ {0xbc, 0x04, 0x08, 0xcc},
+ {0xbc, 0x05, 0x00, 0xcc},
+ {0xbc, 0x06, 0x00, 0xcc},
+ {0xbc, 0x08, 0x3c, 0xcc},
+ {0xbc, 0x09, 0x40, 0xcc},
+ {0xbc, 0x0a, 0x04, 0xcc},
+ {0xbc, 0x0b, 0x00, 0xcc},
+ {0xbc, 0x0c, 0x00, 0xcc},
+/* */
+ {0xb8, 0xfe, 0x00, 0xcc},
+ {0xb8, 0xff, 0x28, 0xcc},
+/* */
+ {0xb9, 0x00, 0x28, 0xcc}, {0xb9, 0x01, 0x28, 0xcc},
+ {0xb9, 0x02, 0x28, 0xcc}, {0xb9, 0x03, 0x00, 0xcc},
+ {0xb9, 0x04, 0x00, 0xcc}, {0xb9, 0x05, 0x3c, 0xcc},
+ {0xb9, 0x06, 0x3c, 0xcc}, {0xb9, 0x07, 0x3c, 0xcc},
+ {0xb9, 0x08, 0x3c, 0xcc},
+/* */
+ {0xb8, 0x8e, 0x00, 0xcc},
+ {0xb8, 0x8f, 0xff, 0xcc}, /* ff */
+ {0x00, 0x29, 0x3c, 0xaa},
+ {0xb3, 0x01, 0x45, 0xcc}, /* 45 */
+ {0x00, 0x00, 0x00, 0x00}
+};
+
+static const __u8 ov7660_50HZ[][4] = {
+ {0x00, 0x3b, 0x08, 0xaa},
+ {0x00, 0x9d, 0x40, 0xaa},
+ {0x00, 0x13, 0xa7, 0xaa},
+ {0x00, 0x00, 0x00, 0x00}
+};
+
+static const __u8 ov7660_60HZ[][4] = {
+ {0x00, 0x3b, 0x00, 0xaa},
+ {0x00, 0x9e, 0x40, 0xaa},
+ {0x00, 0x13, 0xa7, 0xaa},
+ {}
+};
+
+static const __u8 ov7660_NoFliker[][4] = {
+ {0x00, 0x13, 0x87, 0xaa},
+ {}
+};
+
+static const __u8 ov7670_initVGA_JPG[][4] = {
+ {0xb3, 0x01, 0x05, 0xcc},
+ {0x00, 0x00, 0x30, 0xdd}, {0xb0, 0x03, 0x19, 0xcc},
+ {0x00, 0x00, 0x10, 0xdd},
+ {0xb0, 0x04, 0x02, 0xcc}, {0x00, 0x00, 0x10, 0xdd},
+ {0xb3, 0x00, 0x66, 0xcc}, {0xb3, 0x00, 0x67, 0xcc},
+ {0xb3, 0x35, 0xa1, 0xcc}, {0xb3, 0x34, 0x01, 0xcc},
+ {0xb3, 0x05, 0x01, 0xcc}, {0xb3, 0x06, 0x01, 0xcc},
+ {0xb3, 0x08, 0x01, 0xcc}, {0xb3, 0x09, 0x0c, 0xcc},
+ {0xb3, 0x02, 0x02, 0xcc}, {0xb3, 0x03, 0x1f, 0xcc},
+ {0xb3, 0x14, 0x00, 0xcc}, {0xb3, 0x15, 0x00, 0xcc},
+ {0xb3, 0x16, 0x02, 0xcc}, {0xb3, 0x17, 0x7f, 0xcc},
+ {0xb3, 0x04, 0x05, 0xcc}, {0xb3, 0x20, 0x00, 0xcc},
+ {0xb3, 0x21, 0x00, 0xcc}, {0xb3, 0x22, 0x01, 0xcc},
+ {0xb3, 0x23, 0xe0, 0xcc}, {0xbc, 0x00, 0x41, 0xcc},
+ {0xbc, 0x01, 0x01, 0xcc}, {0x00, 0x12, 0x80, 0xaa},
+ {0x00, 0x00, 0x20, 0xdd}, {0x00, 0x12, 0x00, 0xaa},
+ {0x00, 0x11, 0x40, 0xaa}, {0x00, 0x6b, 0x0a, 0xaa},
+ {0x00, 0x3a, 0x04, 0xaa}, {0x00, 0x40, 0xc0, 0xaa},
+ {0x00, 0x8c, 0x00, 0xaa}, {0x00, 0x7a, 0x29, 0xaa},
+ {0x00, 0x7b, 0x0e, 0xaa}, {0x00, 0x7c, 0x1a, 0xaa},
+ {0x00, 0x7d, 0x31, 0xaa}, {0x00, 0x7e, 0x53, 0xaa},
+ {0x00, 0x7f, 0x60, 0xaa}, {0x00, 0x80, 0x6b, 0xaa},
+ {0x00, 0x81, 0x73, 0xaa}, {0x00, 0x82, 0x7b, 0xaa},
+ {0x00, 0x83, 0x82, 0xaa}, {0x00, 0x84, 0x89, 0xaa},
+ {0x00, 0x85, 0x96, 0xaa}, {0x00, 0x86, 0xa1, 0xaa},
+ {0x00, 0x87, 0xb7, 0xaa}, {0x00, 0x88, 0xcc, 0xaa},
+ {0x00, 0x89, 0xe1, 0xaa}, {0x00, 0x13, 0xe0, 0xaa},
+ {0x00, 0x00, 0x00, 0xaa}, {0x00, 0x10, 0x00, 0xaa},
+ {0x00, 0x0d, 0x40, 0xaa}, {0x00, 0x14, 0x28, 0xaa},
+ {0x00, 0xa5, 0x05, 0xaa}, {0x00, 0xab, 0x07, 0xaa},
+ {0x00, 0x24, 0x95, 0xaa}, {0x00, 0x25, 0x33, 0xaa},
+ {0x00, 0x26, 0xe3, 0xaa}, {0x00, 0x9f, 0x88, 0xaa},
+ {0x00, 0xa0, 0x78, 0xaa}, {0x00, 0x55, 0x90, 0xaa},
+ {0x00, 0xa1, 0x03, 0xaa}, {0x00, 0xa6, 0xe0, 0xaa},
+ {0x00, 0xa7, 0xd8, 0xaa}, {0x00, 0xa8, 0xf0, 0xaa},
+ {0x00, 0xa9, 0x90, 0xaa}, {0x00, 0xaa, 0x14, 0xaa},
+ {0x00, 0x13, 0xe5, 0xaa}, {0x00, 0x0e, 0x61, 0xaa},
+ {0x00, 0x0f, 0x4b, 0xaa}, {0x00, 0x16, 0x02, 0xaa},
+ {0x00, 0x1e, 0x07, 0xaa}, {0x00, 0x21, 0x02, 0xaa},
+ {0x00, 0x22, 0x91, 0xaa}, {0x00, 0x29, 0x07, 0xaa},
+ {0x00, 0x33, 0x0b, 0xaa}, {0x00, 0x35, 0x0b, 0xaa},
+ {0x00, 0x37, 0x1d, 0xaa}, {0x00, 0x38, 0x71, 0xaa},
+ {0x00, 0x39, 0x2a, 0xaa}, {0x00, 0x3c, 0x78, 0xaa},
+ {0x00, 0x4d, 0x40, 0xaa}, {0x00, 0x4e, 0x20, 0xaa},
+ {0x00, 0x74, 0x19, 0xaa}, {0x00, 0x8d, 0x4f, 0xaa},
+ {0x00, 0x8e, 0x00, 0xaa}, {0x00, 0x8f, 0x00, 0xaa},
+ {0x00, 0x90, 0x00, 0xaa}, {0x00, 0x91, 0x00, 0xaa},
+ {0x00, 0x96, 0x00, 0xaa}, {0x00, 0x9a, 0x80, 0xaa},
+ {0x00, 0xb0, 0x84, 0xaa}, {0x00, 0xb1, 0x0c, 0xaa},
+ {0x00, 0xb2, 0x0e, 0xaa}, {0x00, 0xb3, 0x82, 0xaa},
+ {0x00, 0xb8, 0x0a, 0xaa}, {0x00, 0x43, 0x14, 0xaa},
+ {0x00, 0x44, 0xf0, 0xaa}, {0x00, 0x45, 0x45, 0xaa},
+ {0x00, 0x46, 0x63, 0xaa}, {0x00, 0x47, 0x2d, 0xaa},
+ {0x00, 0x48, 0x46, 0xaa}, {0x00, 0x59, 0x88, 0xaa},
+ {0x00, 0x5a, 0xa0, 0xaa}, {0x00, 0x5b, 0xc6, 0xaa},
+ {0x00, 0x5c, 0x7d, 0xaa}, {0x00, 0x5d, 0x5f, 0xaa},
+ {0x00, 0x5e, 0x19, 0xaa}, {0x00, 0x6c, 0x0a, 0xaa},
+ {0x00, 0x6d, 0x55, 0xaa}, {0x00, 0x6e, 0x11, 0xaa},
+ {0x00, 0x6f, 0x9e, 0xaa}, {0x00, 0x69, 0x00, 0xaa},
+ {0x00, 0x6a, 0x40, 0xaa}, {0x00, 0x01, 0x40, 0xaa},
+ {0x00, 0x02, 0x40, 0xaa}, {0x00, 0x13, 0xe7, 0xaa},
+ {0x00, 0x5f, 0xf0, 0xaa}, {0x00, 0x60, 0xf0, 0xaa},
+ {0x00, 0x61, 0xf0, 0xaa}, {0x00, 0x27, 0xa0, 0xaa},
+ {0x00, 0x28, 0x80, 0xaa}, {0x00, 0x2c, 0x90, 0xaa},
+ {0x00, 0x4f, 0x66, 0xaa}, {0x00, 0x50, 0x66, 0xaa},
+ {0x00, 0x51, 0x00, 0xaa}, {0x00, 0x52, 0x22, 0xaa},
+ {0x00, 0x53, 0x5e, 0xaa}, {0x00, 0x54, 0x80, 0xaa},
+ {0x00, 0x58, 0x9e, 0xaa}, {0x00, 0x41, 0x08, 0xaa},
+ {0x00, 0x3f, 0x00, 0xaa}, {0x00, 0x75, 0x85, 0xaa},
+ {0x00, 0x76, 0xe1, 0xaa}, {0x00, 0x4c, 0x00, 0xaa},
+ {0x00, 0x77, 0x0a, 0xaa}, {0x00, 0x3d, 0x88, 0xaa},
+ {0x00, 0x4b, 0x09, 0xaa}, {0x00, 0xc9, 0x60, 0xaa},
+ {0x00, 0x41, 0x38, 0xaa}, {0x00, 0x62, 0x30, 0xaa},
+ {0x00, 0x63, 0x30, 0xaa}, {0x00, 0x64, 0x08, 0xaa},
+ {0x00, 0x94, 0x07, 0xaa}, {0x00, 0x95, 0x0b, 0xaa},
+ {0x00, 0x65, 0x00, 0xaa}, {0x00, 0x66, 0x05, 0xaa},
+ {0x00, 0x56, 0x50, 0xaa}, {0x00, 0x34, 0x11, 0xaa},
+ {0x00, 0xa4, 0x88, 0xaa}, {0x00, 0x96, 0x00, 0xaa},
+ {0x00, 0x97, 0x30, 0xaa}, {0x00, 0x98, 0x20, 0xaa},
+ {0x00, 0x99, 0x30, 0xaa}, {0x00, 0x9a, 0x84, 0xaa},
+ {0x00, 0x9b, 0x29, 0xaa}, {0x00, 0x9c, 0x03, 0xaa},
+ {0x00, 0x78, 0x04, 0xaa}, {0x00, 0x79, 0x01, 0xaa},
+ {0x00, 0xc8, 0xf0, 0xaa}, {0x00, 0x79, 0x0f, 0xaa},
+ {0x00, 0xc8, 0x00, 0xaa}, {0x00, 0x79, 0x10, 0xaa},
+ {0x00, 0xc8, 0x7e, 0xaa}, {0x00, 0x79, 0x0a, 0xaa},
+ {0x00, 0xc8, 0x80, 0xaa}, {0x00, 0x79, 0x0b, 0xaa},
+ {0x00, 0xc8, 0x01, 0xaa}, {0x00, 0x79, 0x0c, 0xaa},
+ {0x00, 0xc8, 0x0f, 0xaa}, {0x00, 0x79, 0x0d, 0xaa},
+ {0x00, 0xc8, 0x20, 0xaa}, {0x00, 0x79, 0x09, 0xaa},
+ {0x00, 0xc8, 0x80, 0xaa}, {0x00, 0x79, 0x02, 0xaa},
+ {0x00, 0xc8, 0xc0, 0xaa}, {0x00, 0x79, 0x03, 0xaa},
+ {0x00, 0xc8, 0x40, 0xaa}, {0x00, 0x79, 0x05, 0xaa},
+ {0x00, 0xc8, 0x30, 0xaa}, {0x00, 0x79, 0x26, 0xaa},
+ {0x00, 0x11, 0x40, 0xaa}, {0x00, 0x3a, 0x04, 0xaa},
+ {0x00, 0x12, 0x00, 0xaa}, {0x00, 0x40, 0xc0, 0xaa},
+ {0x00, 0x8c, 0x00, 0xaa}, {0x00, 0x17, 0x14, 0xaa},
+ {0x00, 0x18, 0x02, 0xaa}, {0x00, 0x32, 0x92, 0xaa},
+ {0x00, 0x19, 0x02, 0xaa}, {0x00, 0x1a, 0x7a, 0xaa},
+ {0x00, 0x03, 0x0a, 0xaa}, {0x00, 0x0c, 0x00, 0xaa},
+ {0x00, 0x3e, 0x00, 0xaa}, {0x00, 0x70, 0x3a, 0xaa},
+ {0x00, 0x71, 0x35, 0xaa}, {0x00, 0x72, 0x11, 0xaa},
+ {0x00, 0x73, 0xf0, 0xaa}, {0x00, 0xa2, 0x02, 0xaa},
+ {0x00, 0xb1, 0x00, 0xaa}, {0x00, 0xb1, 0x0c, 0xaa},
+ {0x00, 0x1e, 0x37, 0xaa}, {0x00, 0xaa, 0x14, 0xaa},
+ {0x00, 0x24, 0x80, 0xaa}, {0x00, 0x25, 0x74, 0xaa},
+ {0x00, 0x26, 0xd3, 0xaa}, {0x00, 0x0d, 0x00, 0xaa},
+ {0x00, 0x14, 0x18, 0xaa}, {0x00, 0x9d, 0x99, 0xaa},
+ {0x00, 0x9e, 0x7f, 0xaa}, {0x00, 0x64, 0x08, 0xaa},
+ {0x00, 0x94, 0x07, 0xaa}, {0x00, 0x95, 0x06, 0xaa},
+ {0x00, 0x66, 0x05, 0xaa}, {0x00, 0x41, 0x08, 0xaa},
+ {0x00, 0x3f, 0x00, 0xaa}, {0x00, 0x75, 0x07, 0xaa},
+ {0x00, 0x76, 0xe1, 0xaa}, {0x00, 0x4c, 0x00, 0xaa},
+ {0x00, 0x77, 0x00, 0xaa}, {0x00, 0x3d, 0xc2, 0xaa},
+ {0x00, 0x4b, 0x09, 0xaa}, {0x00, 0xc9, 0x60, 0xaa},
+ {0x00, 0x41, 0x38, 0xaa}, {0xb6, 0x00, 0x00, 0xcc},
+ {0xb6, 0x03, 0x02, 0xcc}, {0xb6, 0x02, 0x80, 0xcc},
+ {0xb6, 0x05, 0x01, 0xcc}, {0xb6, 0x04, 0xe0, 0xcc},
+ {0xb6, 0x12, 0xf8, 0xcc}, {0xb6, 0x13, 0x13, 0xcc},
+ {0xb6, 0x18, 0x02, 0xcc}, {0xb6, 0x17, 0x58, 0xcc},
+ {0xb6, 0x16, 0x00, 0xcc}, {0xb6, 0x22, 0x12, 0xcc},
+ {0xb6, 0x23, 0x0b, 0xcc}, {0xbf, 0xc0, 0x39, 0xcc},
+ {0xbf, 0xc1, 0x04, 0xcc}, {0xbf, 0xcc, 0x00, 0xcc},
+ {0xb3, 0x5c, 0x01, 0xcc}, {0xb3, 0x01, 0x45, 0xcc},
+ {0x00, 0x77, 0x05, 0xaa},
+ {},
+};
+
+static const __u8 ov7670_initQVGA_JPG[][4] = {
+ {0xb3, 0x01, 0x05, 0xcc}, {0x00, 0x00, 0x30, 0xdd},
+ {0xb0, 0x03, 0x19, 0xcc}, {0x00, 0x00, 0x10, 0xdd},
+ {0xb0, 0x04, 0x02, 0xcc}, {0x00, 0x00, 0x10, 0xdd},
+ {0xb3, 0x00, 0x66, 0xcc}, {0xb3, 0x00, 0x67, 0xcc},
+ {0xb3, 0x35, 0xa1, 0xcc}, {0xb3, 0x34, 0x01, 0xcc},
+ {0xb3, 0x05, 0x01, 0xcc}, {0xb3, 0x06, 0x01, 0xcc},
+ {0xb3, 0x08, 0x01, 0xcc}, {0xb3, 0x09, 0x0c, 0xcc},
+ {0xb3, 0x02, 0x02, 0xcc}, {0xb3, 0x03, 0x1f, 0xcc},
+ {0xb3, 0x14, 0x00, 0xcc}, {0xb3, 0x15, 0x00, 0xcc},
+ {0xb3, 0x16, 0x02, 0xcc}, {0xb3, 0x17, 0x7f, 0xcc},
+ {0xb3, 0x04, 0x05, 0xcc}, {0xb3, 0x20, 0x00, 0xcc},
+ {0xb3, 0x21, 0x00, 0xcc}, {0xb3, 0x22, 0x01, 0xcc},
+ {0xb3, 0x23, 0xe0, 0xcc}, {0xbc, 0x00, 0xd1, 0xcc},
+ {0xbc, 0x01, 0x01, 0xcc}, {0x00, 0x12, 0x80, 0xaa},
+ {0x00, 0x00, 0x20, 0xdd}, {0x00, 0x12, 0x00, 0xaa},
+ {0x00, 0x11, 0x40, 0xaa}, {0x00, 0x6b, 0x0a, 0xaa},
+ {0x00, 0x3a, 0x04, 0xaa}, {0x00, 0x40, 0xc0, 0xaa},
+ {0x00, 0x8c, 0x00, 0xaa}, {0x00, 0x7a, 0x29, 0xaa},
+ {0x00, 0x7b, 0x0e, 0xaa}, {0x00, 0x7c, 0x1a, 0xaa},
+ {0x00, 0x7d, 0x31, 0xaa}, {0x00, 0x7e, 0x53, 0xaa},
+ {0x00, 0x7f, 0x60, 0xaa}, {0x00, 0x80, 0x6b, 0xaa},
+ {0x00, 0x81, 0x73, 0xaa}, {0x00, 0x82, 0x7b, 0xaa},
+ {0x00, 0x83, 0x82, 0xaa}, {0x00, 0x84, 0x89, 0xaa},
+ {0x00, 0x85, 0x96, 0xaa}, {0x00, 0x86, 0xa1, 0xaa},
+ {0x00, 0x87, 0xb7, 0xaa}, {0x00, 0x88, 0xcc, 0xaa},
+ {0x00, 0x89, 0xe1, 0xaa}, {0x00, 0x13, 0xe0, 0xaa},
+ {0x00, 0x00, 0x00, 0xaa}, {0x00, 0x10, 0x00, 0xaa},
+ {0x00, 0x0d, 0x40, 0xaa}, {0x00, 0x14, 0x28, 0xaa},
+ {0x00, 0xa5, 0x05, 0xaa}, {0x00, 0xab, 0x07, 0xaa},
+ {0x00, 0x24, 0x95, 0xaa}, {0x00, 0x25, 0x33, 0xaa},
+ {0x00, 0x26, 0xe3, 0xaa}, {0x00, 0x9f, 0x88, 0xaa},
+ {0x00, 0xa0, 0x78, 0xaa}, {0x00, 0x55, 0x90, 0xaa},
+ {0x00, 0xa1, 0x03, 0xaa}, {0x00, 0xa6, 0xe0, 0xaa},
+ {0x00, 0xa7, 0xd8, 0xaa}, {0x00, 0xa8, 0xf0, 0xaa},
+ {0x00, 0xa9, 0x90, 0xaa}, {0x00, 0xaa, 0x14, 0xaa},
+ {0x00, 0x13, 0xe5, 0xaa}, {0x00, 0x0e, 0x61, 0xaa},
+ {0x00, 0x0f, 0x4b, 0xaa}, {0x00, 0x16, 0x02, 0xaa},
+ {0x00, 0x1e, 0x07, 0xaa}, {0x00, 0x21, 0x02, 0xaa},
+ {0x00, 0x22, 0x91, 0xaa}, {0x00, 0x29, 0x07, 0xaa},
+ {0x00, 0x33, 0x0b, 0xaa}, {0x00, 0x35, 0x0b, 0xaa},
+ {0x00, 0x37, 0x1d, 0xaa}, {0x00, 0x38, 0x71, 0xaa},
+ {0x00, 0x39, 0x2a, 0xaa}, {0x00, 0x3c, 0x78, 0xaa},
+ {0x00, 0x4d, 0x40, 0xaa}, {0x00, 0x4e, 0x20, 0xaa},
+ {0x00, 0x74, 0x19, 0xaa}, {0x00, 0x8d, 0x4f, 0xaa},
+ {0x00, 0x8e, 0x00, 0xaa}, {0x00, 0x8f, 0x00, 0xaa},
+ {0x00, 0x90, 0x00, 0xaa}, {0x00, 0x91, 0x00, 0xaa},
+ {0x00, 0x96, 0x00, 0xaa}, {0x00, 0x9a, 0x80, 0xaa},
+ {0x00, 0xb0, 0x84, 0xaa}, {0x00, 0xb1, 0x0c, 0xaa},
+ {0x00, 0xb2, 0x0e, 0xaa}, {0x00, 0xb3, 0x82, 0xaa},
+ {0x00, 0xb8, 0x0a, 0xaa}, {0x00, 0x43, 0x14, 0xaa},
+ {0x00, 0x44, 0xf0, 0xaa}, {0x00, 0x45, 0x45, 0xaa},
+ {0x00, 0x46, 0x63, 0xaa}, {0x00, 0x47, 0x2d, 0xaa},
+ {0x00, 0x48, 0x46, 0xaa}, {0x00, 0x59, 0x88, 0xaa},
+ {0x00, 0x5a, 0xa0, 0xaa}, {0x00, 0x5b, 0xc6, 0xaa},
+ {0x00, 0x5c, 0x7d, 0xaa}, {0x00, 0x5d, 0x5f, 0xaa},
+ {0x00, 0x5e, 0x19, 0xaa}, {0x00, 0x6c, 0x0a, 0xaa},
+ {0x00, 0x6d, 0x55, 0xaa}, {0x00, 0x6e, 0x11, 0xaa},
+ {0x00, 0x6f, 0x9e, 0xaa}, {0x00, 0x69, 0x00, 0xaa},
+ {0x00, 0x6a, 0x40, 0xaa}, {0x00, 0x01, 0x40, 0xaa},
+ {0x00, 0x02, 0x40, 0xaa}, {0x00, 0x13, 0xe7, 0xaa},
+ {0x00, 0x5f, 0xf0, 0xaa}, {0x00, 0x60, 0xf0, 0xaa},
+ {0x00, 0x61, 0xf0, 0xaa}, {0x00, 0x27, 0xa0, 0xaa},
+ {0x00, 0x28, 0x80, 0xaa}, {0x00, 0x2c, 0x90, 0xaa},
+ {0x00, 0x4f, 0x66, 0xaa}, {0x00, 0x50, 0x66, 0xaa},
+ {0x00, 0x51, 0x00, 0xaa}, {0x00, 0x52, 0x22, 0xaa},
+ {0x00, 0x53, 0x5e, 0xaa}, {0x00, 0x54, 0x80, 0xaa},
+ {0x00, 0x58, 0x9e, 0xaa}, {0x00, 0x41, 0x08, 0xaa},
+ {0x00, 0x3f, 0x00, 0xaa}, {0x00, 0x75, 0x85, 0xaa},
+ {0x00, 0x76, 0xe1, 0xaa}, {0x00, 0x4c, 0x00, 0xaa},
+ {0x00, 0x77, 0x0a, 0xaa}, {0x00, 0x3d, 0x88, 0xaa},
+ {0x00, 0x4b, 0x09, 0xaa}, {0x00, 0xc9, 0x60, 0xaa},
+ {0x00, 0x41, 0x38, 0xaa}, {0x00, 0x62, 0x30, 0xaa},
+ {0x00, 0x63, 0x30, 0xaa}, {0x00, 0x64, 0x08, 0xaa},
+ {0x00, 0x94, 0x07, 0xaa}, {0x00, 0x95, 0x0b, 0xaa},
+ {0x00, 0x65, 0x00, 0xaa}, {0x00, 0x66, 0x05, 0xaa},
+ {0x00, 0x56, 0x50, 0xaa}, {0x00, 0x34, 0x11, 0xaa},
+ {0x00, 0xa4, 0x88, 0xaa}, {0x00, 0x96, 0x00, 0xaa},
+ {0x00, 0x97, 0x30, 0xaa}, {0x00, 0x98, 0x20, 0xaa},
+ {0x00, 0x99, 0x30, 0xaa}, {0x00, 0x9a, 0x84, 0xaa},
+ {0x00, 0x9b, 0x29, 0xaa}, {0x00, 0x9c, 0x03, 0xaa},
+ {0x00, 0x78, 0x04, 0xaa}, {0x00, 0x79, 0x01, 0xaa},
+ {0x00, 0xc8, 0xf0, 0xaa}, {0x00, 0x79, 0x0f, 0xaa},
+ {0x00, 0xc8, 0x00, 0xaa}, {0x00, 0x79, 0x10, 0xaa},
+ {0x00, 0xc8, 0x7e, 0xaa}, {0x00, 0x79, 0x0a, 0xaa},
+ {0x00, 0xc8, 0x80, 0xaa}, {0x00, 0x79, 0x0b, 0xaa},
+ {0x00, 0xc8, 0x01, 0xaa}, {0x00, 0x79, 0x0c, 0xaa},
+ {0x00, 0xc8, 0x0f, 0xaa}, {0x00, 0x79, 0x0d, 0xaa},
+ {0x00, 0xc8, 0x20, 0xaa}, {0x00, 0x79, 0x09, 0xaa},
+ {0x00, 0xc8, 0x80, 0xaa}, {0x00, 0x79, 0x02, 0xaa},
+ {0x00, 0xc8, 0xc0, 0xaa}, {0x00, 0x79, 0x03, 0xaa},
+ {0x00, 0xc8, 0x40, 0xaa}, {0x00, 0x79, 0x05, 0xaa},
+ {0x00, 0xc8, 0x30, 0xaa}, {0x00, 0x79, 0x26, 0xaa},
+ {0x00, 0x11, 0x40, 0xaa}, {0x00, 0x3a, 0x04, 0xaa},
+ {0x00, 0x12, 0x00, 0xaa}, {0x00, 0x40, 0xc0, 0xaa},
+ {0x00, 0x8c, 0x00, 0xaa}, {0x00, 0x17, 0x14, 0xaa},
+ {0x00, 0x18, 0x02, 0xaa}, {0x00, 0x32, 0x92, 0xaa},
+ {0x00, 0x19, 0x02, 0xaa}, {0x00, 0x1a, 0x7a, 0xaa},
+ {0x00, 0x03, 0x0a, 0xaa}, {0x00, 0x0c, 0x00, 0xaa},
+ {0x00, 0x3e, 0x00, 0xaa}, {0x00, 0x70, 0x3a, 0xaa},
+ {0x00, 0x71, 0x35, 0xaa}, {0x00, 0x72, 0x11, 0xaa},
+ {0x00, 0x73, 0xf0, 0xaa}, {0x00, 0xa2, 0x02, 0xaa},
+ {0x00, 0xb1, 0x00, 0xaa}, {0x00, 0xb1, 0x0c, 0xaa},
+ {0x00, 0x1e, 0x37, 0xaa}, {0x00, 0xaa, 0x14, 0xaa},
+ {0x00, 0x24, 0x80, 0xaa}, {0x00, 0x25, 0x74, 0xaa},
+ {0x00, 0x26, 0xd3, 0xaa}, {0x00, 0x0d, 0x00, 0xaa},
+ {0x00, 0x14, 0x18, 0xaa}, {0x00, 0x9d, 0x99, 0xaa},
+ {0x00, 0x9e, 0x7f, 0xaa}, {0x00, 0x64, 0x08, 0xaa},
+ {0x00, 0x94, 0x07, 0xaa}, {0x00, 0x95, 0x06, 0xaa},
+ {0x00, 0x66, 0x05, 0xaa}, {0x00, 0x41, 0x08, 0xaa},
+ {0x00, 0x3f, 0x00, 0xaa}, {0x00, 0x75, 0x07, 0xaa},
+ {0x00, 0x76, 0xe1, 0xaa}, {0x00, 0x4c, 0x00, 0xaa},
+ {0x00, 0x77, 0x00, 0xaa}, {0x00, 0x3d, 0xc2, 0xaa},
+ {0x00, 0x4b, 0x09, 0xaa}, {0x00, 0xc9, 0x60, 0xaa},
+ {0x00, 0x41, 0x38, 0xaa}, {0xb6, 0x00, 0x00, 0xcc},
+ {0xb6, 0x03, 0x01, 0xcc}, {0xb6, 0x02, 0x40, 0xcc},
+ {0xb6, 0x05, 0x00, 0xcc}, {0xb6, 0x04, 0xf0, 0xcc},
+ {0xb6, 0x12, 0xf8, 0xcc}, {0xb6, 0x13, 0x21, 0xcc},
+ {0xb6, 0x18, 0x00, 0xcc}, {0xb6, 0x17, 0x96, 0xcc},
+ {0xb6, 0x16, 0x00, 0xcc}, {0xb6, 0x22, 0x12, 0xcc},
+ {0xb6, 0x23, 0x0b, 0xcc}, {0xbf, 0xc0, 0x39, 0xcc},
+ {0xbf, 0xc1, 0x04, 0xcc}, {0xbf, 0xcc, 0x00, 0xcc},
+ {0xbc, 0x02, 0x18, 0xcc}, {0xbc, 0x03, 0x50, 0xcc},
+ {0xbc, 0x04, 0x18, 0xcc}, {0xbc, 0x05, 0x00, 0xcc},
+ {0xbc, 0x06, 0x00, 0xcc}, {0xbc, 0x08, 0x30, 0xcc},
+ {0xbc, 0x09, 0x40, 0xcc}, {0xbc, 0x0a, 0x10, 0xcc},
+ {0xbc, 0x0b, 0x00, 0xcc}, {0xbc, 0x0c, 0x00, 0xcc},
+ {0xb3, 0x5c, 0x01, 0xcc}, {0xb3, 0x01, 0x45, 0xcc},
+ {0x00, 0x77, 0x05, 0xaa },
+ {},
+};
+#if 0
+static const __u8 ov7670_initQVGA_JPG[][4] = {
+ {0xb3, 0x00, 0x00, 0xcc},
+ {0xb0, 0x16, 0x0d, 0xcc},
+ {0x00, 0x00, 0x50, 0xdd}, {0xb0, 0x16, 0x00, 0xcc},
+ {0x00, 0x00, 0x50, 0xdd}, {0xb0, 0x03, 0x19, 0xcc},
+ {0x00, 0x00, 0x50, 0xdd}, {0xb3, 0x49, 0x11, 0xcc},
+ {0xb3, 0x49, 0x00, 0xcc}, {0xb0, 0x16, 0x00, 0xcc},
+
+ {0xb3, 0x01, 0x05, 0xcc}, {0x00, 0x00, 0x50, 0xdd},
+ {0xb0, 0x03, 0x19, 0xcc}, {0xb0, 0x04, 0x02, 0xcc},
+ {0x00, 0x00, 0x50, 0xdd}, {0xb3, 0x00, 0x66, 0xcc},
+ {0xb3, 0x00, 0x67, 0xcc}, {0xb3, 0x35, 0xa1, 0xcc},
+ {0xb3, 0x34, 0x01, 0xcc}, {0xb3, 0x05, 0x01, 0xcc},
+ {0xb3, 0x06, 0x01, 0xcc}, {0xb3, 0x08, 0x01, 0xcc},
+ {0xb3, 0x09, 0x0c, 0xcc}, {0xb3, 0x02, 0x02, 0xcc},
+ {0xb3, 0x03, 0x1f, 0xcc}, {0xb3, 0x14, 0x00, 0xcc},
+ {0xb3, 0x15, 0x00, 0xcc}, {0xb3, 0x16, 0x02, 0xcc},
+ {0xb3, 0x17, 0x7f, 0xcc}, {0xb3, 0x04, 0x05, 0xcc},
+ {0xb3, 0x20, 0x00, 0xcc}, {0xb3, 0x21, 0x00, 0xcc},
+ {0xb3, 0x22, 0x01, 0xcc}, {0xb3, 0x23, 0xe0, 0xcc},
+ {0xbc, 0x00, 0xd1, 0xcc}, /* set QVGA */
+ {0xbc, 0x01, 0x01, 0xcc},/* */
+ {0x00, 0x12, 0x80, 0xaa},/* OV sensor reset */
+ {0x00, 0x00, 0x50, 0xdd},/* wait sometimes */
+ {0, 0x12, 0x00, 0xaa},
+ {0, 0x11, 0x40, 0xaa}, {0, 0x6b, 0x0a, 0xaa},
+ {0, 0x3a, 0x04, 0xaa}, {0, 0x40, 0xc0, 0xaa},
+ {0, 0x8c, 0x00, 0xaa}, {0, 0x7a, 0x29, 0xaa},
+ {0, 0x7b, 0x0e, 0xaa}, {0, 0x7c, 0x1a, 0xaa},
+ {0, 0x7d, 0x31, 0xaa}, {0, 0x7e, 0x53, 0xaa},
+ {0, 0x7f, 0x60, 0xaa}, {0, 0x80, 0x6b, 0xaa},
+ {0, 0x81, 0x73, 0xaa}, {0, 0x82, 0x7b, 0xaa},
+ {0, 0x83, 0x82, 0xaa}, {0, 0x84, 0x89, 0xaa},
+ {0, 0x85, 0x96, 0xaa}, {0, 0x86, 0xa1, 0xaa},
+ {0, 0x87, 0xb7, 0xaa}, {0, 0x88, 0xcc, 0xaa},
+ {0, 0x89, 0xe1, 0xaa}, {0, 0x13, 0xe0, 0xaa},
+ {0, 0x00, 0x00, 0xaa}, {0, 0x10, 0x00, 0xaa},
+ {0, 0x0d, 0x40, 0xaa}, {0, 0x14, 0x28, 0xaa},
+ {0, 0xa5, 0x05, 0xaa}, {0, 0xab, 0x07, 0xaa},
+ {0, 0x24, 0x95, 0xaa}, {0, 0x25, 0x33, 0xaa},
+ {0, 0x26, 0xe3, 0xaa}, {0, 0x9f, 0x88, 0xaa},
+ {0, 0xa0, 0x78, 0xaa}, {0, 0x55, 0x90, 0xaa},
+ {0, 0xa1, 0x03, 0xaa}, {0, 0xa6, 0xe0, 0xaa},
+ {0, 0xa7, 0xd8, 0xaa}, {0, 0xa8, 0xf0, 0xaa},
+ {0, 0xa9, 0x90, 0xaa}, {0, 0xaa, 0x14, 0xaa},
+ {0, 0x13, 0xe5, 0xaa}, {0, 0x0e, 0x61, 0xaa},
+ {0, 0x0f, 0x4b, 0xaa}, {0, 0x16, 0x02, 0xaa},
+ {0, 0x1e, 0x07, 0xaa}, {0, 0x21, 0x02, 0xaa},
+ {0, 0x22, 0x91, 0xaa}, {0, 0x29, 0x07, 0xaa},
+ {0, 0x33, 0x0b, 0xaa}, {0, 0x35, 0x0b, 0xaa},
+ {0, 0x37, 0x1d, 0xaa}, {0, 0x38, 0x71, 0xaa},
+ {0, 0x39, 0x2a, 0xaa}, {0, 0x3c, 0x78, 0xaa},
+ {0, 0x4d, 0x40, 0xaa}, {0, 0x4e, 0x20, 0xaa},
+ {0, 0x74, 0x19, 0xaa}, {0, 0x8d, 0x4f, 0xaa},
+ {0, 0x8e, 0x00, 0xaa}, {0, 0x8f, 0x00, 0xaa},
+ {0, 0x90, 0x00, 0xaa}, {0, 0x91, 0x00, 0xaa},
+ {0, 0x96, 0x00, 0xaa}, {0, 0x9a, 0x80, 0xaa},
+ {0, 0xb0, 0x84, 0xaa}, {0, 0xb1, 0x0c, 0xaa},
+ {0, 0xb2, 0x0e, 0xaa}, {0, 0xb3, 0x82, 0xaa},
+ {0, 0xb8, 0x0a, 0xaa}, {0, 0x43, 0x14, 0xaa},
+ {0, 0x44, 0xf0, 0xaa}, {0, 0x45, 0x45, 0xaa},
+ {0, 0x46, 0x63, 0xaa}, {0, 0x47, 0x2d, 0xaa},
+ {0, 0x48, 0x46, 0xaa}, {0, 0x59, 0x88, 0xaa},
+ {0, 0x5a, 0xa0, 0xaa}, {0, 0x5b, 0xc6, 0xaa},
+ {0, 0x5c, 0x7d, 0xaa}, {0, 0x5d, 0x5f, 0xaa},
+ {0, 0x5e, 0x19, 0xaa}, {0, 0x6c, 0x0a, 0xaa},
+ {0, 0x6d, 0x55, 0xaa}, {0, 0x6e, 0x11, 0xaa},
+ {0, 0x6f, 0x9e, 0xaa}, {0, 0x69, 0x00, 0xaa},
+ {0, 0x6a, 0x40, 0xaa}, {0, 0x01, 0x40, 0xaa},
+ {0, 0x02, 0x40, 0xaa}, {0, 0x13, 0xe7, 0xaa},
+ {0, 0x5f, 0xf0, 0xaa}, {0, 0x60, 0xf0, 0xaa},
+ {0, 0x61, 0xf0, 0xaa}, {0, 0x27, 0xa0, 0xaa},
+ {0, 0x28, 0x80, 0xaa}, {0, 0x2c, 0x90, 0xaa},
+ {0, 0x4f, 0x66, 0xaa}, {0, 0x50, 0x66, 0xaa},
+ {0, 0x51, 0x00, 0xaa}, {0, 0x52, 0x22, 0xaa},
+ {0, 0x53, 0x5e, 0xaa}, {0, 0x54, 0x80, 0xaa},
+ {0, 0x58, 0x9e, 0xaa}, {0, 0x41, 0x08, 0xaa},
+ {0, 0x3f, 0x00, 0xaa}, {0, 0x75, 0x85, 0xaa},
+ {0, 0x76, 0xe1, 0xaa}, {0, 0x4c, 0x00, 0xaa},
+ {0, 0x77, 0x0a, 0xaa}, {0, 0x3d, 0x88, 0xaa},
+ {0, 0x4b, 0x09, 0xaa}, {0, 0xc9, 0x60, 0xaa},
+ {0, 0x41, 0x38, 0xaa}, {0, 0x62, 0x30, 0xaa},
+ {0, 0x63, 0x30, 0xaa}, {0, 0x64, 0x08, 0xaa},
+ {0, 0x94, 0x07, 0xaa}, {0, 0x95, 0x0b, 0xaa},
+ {0, 0x65, 0x00, 0xaa}, {0, 0x66, 0x05, 0xaa},
+ {0, 0x56, 0x50, 0xaa}, {0, 0x34, 0x11, 0xaa},
+ {0, 0xa4, 0x88, 0xaa}, {0, 0x96, 0x00, 0xaa},
+ {0, 0x97, 0x30, 0xaa}, {0, 0x98, 0x20, 0xaa},
+ {0, 0x99, 0x30, 0xaa}, {0, 0x9a, 0x84, 0xaa},
+ {0, 0x9b, 0x29, 0xaa}, {0, 0x9c, 0x03, 0xaa},
+ {0, 0x78, 0x04, 0xaa}, {0, 0x79, 0x01, 0xaa},
+ {0, 0xc8, 0xf0, 0xaa}, {0, 0x79, 0x0f, 0xaa},
+ {0, 0xc8, 0x00, 0xaa}, {0, 0x79, 0x10, 0xaa},
+ {0, 0xc8, 0x7e, 0xaa}, {0, 0x79, 0x0a, 0xaa},
+ {0, 0xc8, 0x80, 0xaa}, {0, 0x79, 0x0b, 0xaa},
+ {0, 0xc8, 0x01, 0xaa}, {0, 0x79, 0x0c, 0xaa},
+ {0, 0xc8, 0x0f, 0xaa}, {0, 0x79, 0x0d, 0xaa},
+ {0, 0xc8, 0x20, 0xaa}, {0, 0x79, 0x09, 0xaa},
+ {0, 0xc8, 0x80, 0xaa}, {0, 0x79, 0x02, 0xaa},
+ {0, 0xc8, 0xc0, 0xaa}, {0, 0x79, 0x03, 0xaa},
+ {0, 0xc8, 0x40, 0xaa}, {0, 0x79, 0x05, 0xaa},
+ {0, 0xc8, 0x30, 0xaa}, {0, 0x79, 0x26, 0xaa},
+ {0, 0x11, 0x40, 0xaa}, {0, 0x3a, 0x04, 0xaa},
+ {0, 0x12, 0x00, 0xaa}, {0, 0x40, 0xc0, 0xaa},
+ {0, 0x8c, 0x00, 0xaa}, {0, 0x17, 0x14, 0xaa},
+ {0, 0x18, 0x02, 0xaa}, {0, 0x32, 0x92, 0xaa},
+ {0, 0x19, 0x02, 0xaa}, {0, 0x1a, 0x7a, 0xaa},
+ {0, 0x03, 0x0a, 0xaa}, {0, 0x0c, 0x00, 0xaa},
+ {0, 0x3e, 0x00, 0xaa}, {0, 0x70, 0x3a, 0xaa},
+ {0, 0x71, 0x35, 0xaa}, {0, 0x72, 0x11, 0xaa},
+ {0, 0x73, 0xf0, 0xaa}, {0, 0xa2, 0x02, 0xaa},
+ {0, 0xb1, 0x00, 0xaa}, {0, 0xb1, 0x0c, 0xaa},
+ {0, 0x1e, 0x37, 0xaa}, {0, 0xaa, 0x14, 0xaa},
+ {0, 0x24, 0x80, 0xaa}, {0, 0x25, 0x74, 0xaa},
+ {0, 0x26, 0xd3, 0xaa}, {0, 0x0d, 0x00, 0xaa},
+ {0, 0x14, 0x18, 0xaa}, {0, 0x9d, 0x99, 0xaa},
+ {0, 0x9e, 0x7f, 0xaa}, {0, 0x64, 0x08, 0xaa},
+ {0, 0x94, 0x07, 0xaa}, {0, 0x95, 0x06, 0xaa},
+ {0, 0x66, 0x05, 0xaa}, {0, 0x41, 0x08, 0xaa},
+ {0, 0x3f, 0x00, 0xaa}, {0, 0x75, 0x07, 0xaa},
+ {0, 0x76, 0xe1, 0xaa}, {0, 0x4c, 0x00, 0xaa},
+ {0, 0x77, 0x00, 0xaa}, {0, 0x3d, 0xc2, 0xaa},
+ {0, 0x4b, 0x09, 0xaa}, {0, 0xc9, 0x60, 0xaa},
+ {0, 0x41, 0x38, 0xaa},
+ {0xb6, 0x00, 0x00, 0xcc}, {0xb6, 0x03, 0x01, 0xcc},
+ {0xb6, 0x02, 0x40, 0xcc},
+ {0xb6, 0x05, 0x00, 0xcc}, {0xb6, 0x04, 0xf0, 0xcc},
+ {0xb6, 0x12, 0xf8, 0xcc}, {0xb6, 0x13, 0x21, 0xcc},
+ {0xb6, 0x18, 0x00, 0xcc}, {0xb6, 0x17, 0x96, 0xcc},
+ {0xb6, 0x16, 0x00, 0xcc}, {0xb6, 0x22, 0x12, 0xcc},
+ {0xb6, 0x23, 0x0b, 0xcc},
+ {0xbf, 0xc0, 0x39, 0xcc},/* set jpeg */
+ {0xbf, 0xc1, 0x04, 0xcc},/* */
+ {0xbf, 0xcc, 0x00, 0xcc},/* */
+ {0xbc, 0x02, 0x18, 0xcc}, {0xbc, 0x03, 0x50, 0xcc},
+ {0xbc, 0x04, 0x18, 0xcc}, {0xbc, 0x05, 0x00, 0xcc},
+ {0xbc, 0x06, 0x00, 0xcc}, {0xbc, 0x08, 0x30, 0xcc},
+ {0xbc, 0x09, 0x40, 0xcc}, {0xbc, 0x0a, 0x10, 0xcc},
+ {0xbc, 0x0b, 0x00, 0xcc}, {0xbc, 0x0c, 0x00, 0xcc},
+ {0xb3, 0x5c, 0x01, 0xcc}, {0xb3, 0x01, 0x45, 0xcc},
+ {0, 0x77, 0x05, 0xaa}, {0xb6, 0x12, 0xf8, 0xcc},
+ {0xb6, 0x13, 0x20, 0xcc},
+ {0, 0x24, 0x6c, 0xaa},
+ {0, 0x25, 0x5c, 0xaa}, {0, 0x56, 0x50, 0xaa},
+ {0, 0x4f, 0xa8, 0xaa}, {0, 0x50, 0xa5, 0xaa},
+ {0, 0x51, 0x02, 0xaa}, {0, 0x52, 0x22, 0xaa},
+ {0, 0x53, 0x86, 0xaa}, {0, 0x54, 0xaa, 0xaa},
+ {0, 0x7a, 0x19, 0xaa}, {0, 0x7b, 0x0c, 0xaa},
+ {0, 0x7c, 0x18, 0xaa}, {0, 0x7d, 0x2f, 0xaa},
+ {0, 0x7e, 0x54, 0xaa}, {0, 0x7f, 0x64, 0xaa},
+ {0, 0x80, 0x71, 0xaa}, {0, 0x81, 0x7d, 0xaa},
+ {0, 0x82, 0x88, 0xaa}, {0, 0x83, 0x91, 0xaa},
+ {0, 0x84, 0x98, 0xaa}, {0, 0x85, 0xa7, 0xaa},
+ {0, 0x86, 0xb4, 0xaa}, {0, 0x87, 0xcb, 0xaa},
+ {0, 0x88, 0xde, 0xaa}, {0, 0x89, 0xed, 0xaa},
+ {0, 0x75, 0x86, 0xaa}, {0, 0x92, 0x00, 0xaa},
+ {0, 0x3b, 0, 0xbb},
+ {0, 0x3b, 0x00, 0xaa},
+ {0, 0x13, 0, 0xbb}, {0, 0x13, 0xe7, 0xaa},
+ {0, 0x2d, 0x00, 0xaa}, {0, 0x2e, 0x00, 0xaa},
+ {0, 0x04, 0x00, 0xaa}, {0, 0x10, 0x00, 0xaa},
+ {0, 0x3b, 0, 0xbb}, {0, 0x3b, 0x80, 0xaa},
+ {0, 0x13, 0, 0xbb},
+ {0, 0x13, 0xe7, 0xaa},
+ {0, 0x1e, 0x27, 0xaa},
+ {0, 0x1e, 0x27, 0xaa},
+ {0, 0x3b, 0xc8, 0xaa},
+ {}
+};
+#endif
+
+struct sensor_info {
+ int sensorId;
+ __u8 I2cAdd;
+ __u8 IdAdd;
+ __u16 VpId;
+ __u8 m1;
+ __u8 m2;
+ __u8 op;
+ };
+
+static const struct sensor_info sensor_info_data[] = {
+/* sensorId, I2cAdd, IdAdd, VpId, m1, m2, op */
+ {SENSOR_HV7131R, 0x80 | 0x11, 0x00, 0x0209, 0x24, 0x25, 0x01},
+ {SENSOR_OV7660, 0x80 | 0x21, 0x0a, 0x7660, 0x26, 0x26, 0x05},
+ {SENSOR_PO3130NC, 0x80 | 0x76, 0x00, 0x3130, 0x24, 0x25, 0x01},
+ {SENSOR_MI1320, 0x80 | 0xc8, 0x00, 0x148c, 0x64, 0x65, 0x01},
+ {SENSOR_OV7670, 0x80 | 0x21, 0x0a, 0x7673, 0x66, 0x67, 0x05},
+ {SENSOR_MI1310_SOC, 0x80 | 0x5d, 0x00, 0x143a, 0x24, 0x25, 0x01},
+};
+
+static void reg_r(struct usb_device *dev,
+ __u16 req,
+ __u16 index,
+ __u8 *buffer, __u16 length)
+{
+ usb_control_msg(dev,
+ usb_rcvctrlpipe(dev, 0),
+ req,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 1, /* value */
+ index, buffer, length,
+ 500);
+}
+
+static void reg_w(struct usb_device *dev,
+ __u16 req,
+ __u16 value,
+ __u16 index)
+{
+ usb_control_msg(dev,
+ usb_sndctrlpipe(dev, 0),
+ req,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value, index, NULL, 0,
+ 500);
+}
+
+static void vc032x_read_sensor_register(struct usb_device *dev,
+ __u16 address, __u16 *value)
+{
+ __u8 ldata, mdata, hdata;
+ __u8 tmpvalue = 0;
+ int retry = 50;
+ ldata = 0;
+ mdata = 0;
+ hdata = 0;
+ *value = 0;
+
+ reg_r(dev, 0xa1, 0xb33f, &tmpvalue, 1);
+ /*PDEBUG(D_PROBE, " I2c Bus Busy Wait 0x%02X ", tmpvalue); */
+ if (!(tmpvalue & 0x02)) {
+ PDEBUG(D_ERR, "I2c Bus Busy Wait %d", tmpvalue & 0x02);
+ return;
+ }
+ reg_w(dev, 0xa0, address, 0xb33a);
+ reg_w(dev, 0xa0, 0x02, 0xb339);
+
+ tmpvalue = 0;
+ reg_r(dev, 0xa1, 0xb33b, &tmpvalue, 1);
+ while (retry-- && tmpvalue) {
+ reg_r(dev, 0xa1, 0xb33b, &tmpvalue, 1);
+/* PDEBUG(D_PROBE, "Read again 0xb33b %d", tmpvalue); */
+ msleep(1);
+ }
+ reg_r(dev, 0xa1, 0xb33e, &hdata, 1);
+ reg_r(dev, 0xa1, 0xb33d, &mdata, 1);
+ reg_r(dev, 0xa1, 0xb33c, &ldata, 1);
+ PDEBUG(D_PROBE, "Read Sensor h (0x%02X) m (0x%02X) l (0x%02X)",
+ hdata, mdata, ldata);
+ tmpvalue = 0;
+ reg_r(dev, 0xa1, 0xb334, &tmpvalue, 1);
+ if (tmpvalue == 0x02)
+ *value = (ldata << 8) + mdata;
+ else
+ *value = ldata;
+}
+static int vc032x_probe_sensor(struct gspca_dev *gspca_dev)
+{
+ struct usb_device *dev = gspca_dev->dev;
+ int i;
+ __u8 data;
+ __u16 value;
+ const struct sensor_info *ptsensor_info;
+
+ reg_r(dev, 0xa1, 0xbfcf, &data, 1);
+ PDEBUG(D_PROBE, "check sensor header %d", data);
+ for (i = 0; i < ARRAY_SIZE(sensor_info_data); i++) {
+ ptsensor_info = &sensor_info_data[i];
+ reg_w(dev, 0xa0, 0x02, 0xb334);
+ reg_w(dev, 0xa0, ptsensor_info->m1, 0xb300);
+ reg_w(dev, 0xa0, ptsensor_info->m2, 0xb300);
+ reg_w(dev, 0xa0, 0x01, 0xb308);
+ reg_w(dev, 0xa0, 0x0c, 0xb309);
+ reg_w(dev, 0xa0, ptsensor_info->I2cAdd, 0xb335);
+/* PDEBUG(D_PROBE,
+ "check sensor VC032X -> %d Add -> ox%02X!",
+ i, ptsensor_info->I2cAdd); */
+ reg_w(dev, 0xa0, ptsensor_info->op, 0xb301);
+ vc032x_read_sensor_register(dev, ptsensor_info->IdAdd, &value);
+ if (value == ptsensor_info->VpId) {
+/* PDEBUG(D_PROBE, "find sensor VC032X -> ox%04X!",
+ ptsensor_info->VpId); */
+ return ptsensor_info->sensorId;
+ }
+ }
+ return -1;
+}
+
+static __u8 i2c_write(struct usb_device *dev,
+ __u8 reg, const __u8 *val, __u8 size)
+{
+ __u8 retbyte;
+
+ if (size > 3 || size < 1)
+ return -EINVAL;
+ reg_r(dev, 0xa1, 0xb33f, &retbyte, 1);
+ reg_w(dev, 0xa0, size, 0xb334);
+ reg_w(dev, 0xa0, reg, 0xb33a);
+ switch (size) {
+ case 1:
+ reg_w(dev, 0xa0, val[0], 0xb336);
+ break;
+ case 2:
+ reg_w(dev, 0xa0, val[0], 0xb336);
+ reg_w(dev, 0xa0, val[1], 0xb337);
+ break;
+ case 3:
+ reg_w(dev, 0xa0, val[0], 0xb336);
+ reg_w(dev, 0xa0, val[1], 0xb337);
+ reg_w(dev, 0xa0, val[2], 0xb338);
+ break;
+ default:
+ reg_w(dev, 0xa0, 0x01, 0xb334);
+ return -EINVAL;
+ }
+ reg_w(dev, 0xa0, 0x01, 0xb339);
+ reg_r(dev, 0xa1, 0xb33b, &retbyte, 1);
+ return retbyte == 0;
+}
+
+static void put_tab_to_reg(struct gspca_dev *gspca_dev,
+ const __u8 *tab, __u8 tabsize, __u16 addr)
+{
+ int j;
+ __u16 ad = addr;
+
+ for (j = 0; j < tabsize; j++)
+ reg_w(gspca_dev->dev, 0xa0, tab[j], ad++);
+}
+
+static void usb_exchange(struct gspca_dev *gspca_dev,
+ const __u8 data[][4])
+{
+ struct usb_device *dev = gspca_dev->dev;
+ int i = 0;
+
+ for (;;) {
+ switch (data[i][3]) {
+ default:
+ return;
+ case 0xcc: /* normal write */
+ reg_w(dev, 0xa0, data[i][2],
+ ((data[i][0])<<8) | data[i][1]);
+ break;
+ case 0xaa: /* i2c op */
+ i2c_write(dev, data[i][1], &data[i][2], 1);
+ break;
+ case 0xbb: /* i2c op */
+ i2c_write(dev, data[i][0], &data[i][1], 2);
+ break;
+ case 0xdd:
+ msleep(data[i][2] + 10);
+ break;
+ }
+ i++;
+ }
+ /*not reached*/
+}
+
+/*
+ "GammaT"=hex:04,17,31,4f,6a,83,99,ad,bf,ce,da,e5,ee,f5,fb,ff,ff
+ "MatrixT"=hex:60,f9,e5,e7,50,05,f3,e6,66
+ */
+
+static void vc0321_reset(struct gspca_dev *gspca_dev)
+{
+ reg_w(gspca_dev->dev, 0xa0, 0x00, 0xb04d);
+ reg_w(gspca_dev->dev, 0xa0, 0x01, 0xb301);
+ msleep(100);
+ reg_w(gspca_dev->dev, 0xa0, 0x01, 0xb003);
+ msleep(100);
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+ const struct usb_device_id *id)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+ struct cam *cam;
+ __u8 tmp2[4];
+ int sensor;
+ __u16 vendor;
+ __u16 product;
+
+ vendor = id->idVendor;
+ product = id->idProduct;
+ switch (vendor) {
+ case 0x046d: /* Logitech Labtec */
+/* switch (product) { */
+/* case 0x0892: */
+/* case 0x0896: */
+ sd->bridge = BRIDGE_VC0321;
+/* break; */
+/* } */
+ break;
+ case 0x0ac8: /* Vimicro z-star */
+ switch (product) {
+ case 0x0321:
+ case 0x0328:
+ case 0xc001:
+ case 0xc002:
+ sd->bridge = BRIDGE_VC0321;
+ break;
+ case 0x0323:
+ sd->bridge = BRIDGE_VC0323;
+ break;
+ }
+ break;
+ case 0x17ef: /* Lenovo */
+/* switch (product) { */
+/* case 0x4802: * Lenovo MI1310_SOC */
+ sd->bridge = BRIDGE_VC0323;
+/* break; */
+/* } */
+ break;
+ }
+
+ cam = &gspca_dev->cam;
+ cam->dev_name = (char *) id->driver_info;
+ cam->epaddr = 0x02;
+ if (sd->bridge == BRIDGE_VC0321) {
+ cam->cam_mode = vc0321_mode;
+ cam->nmodes = sizeof vc0321_mode / sizeof vc0321_mode[0];
+ } else {
+ cam->cam_mode = vc0323_mode;
+ cam->nmodes = sizeof vc0323_mode / sizeof vc0323_mode[0];
+ }
+
+ vc0321_reset(gspca_dev);
+ sensor = vc032x_probe_sensor(gspca_dev);
+ switch (sensor) {
+ case -1:
+ PDEBUG(D_PROBE, "Unknown sensor...");
+ return -EINVAL;
+ case SENSOR_HV7131R:
+ PDEBUG(D_PROBE, "Find Sensor HV7131R");
+ sd->sensor = SENSOR_HV7131R;
+ break;
+ case SENSOR_MI1310_SOC:
+ PDEBUG(D_PROBE, "Find Sensor MI1310_SOC");
+ sd->sensor = SENSOR_MI1310_SOC;
+ break;
+ case SENSOR_MI1320:
+ PDEBUG(D_PROBE, "Find Sensor MI1320");
+ sd->sensor = SENSOR_MI1320;
+ break;
+ case SENSOR_OV7660:
+ PDEBUG(D_PROBE, "Find Sensor OV7660");
+ sd->sensor = SENSOR_OV7660;
+ break;
+ case SENSOR_OV7670:
+ PDEBUG(D_PROBE, "Find Sensor OV7670");
+ sd->sensor = SENSOR_OV7670;
+ break;
+ case SENSOR_PO3130NC:
+ PDEBUG(D_PROBE, "Find Sensor PO3130NC");
+ sd->sensor = SENSOR_PO3130NC;
+ break;
+ }
+
+ sd->qindex = 7;
+ sd->autogain = sd_ctrls[SD_AUTOGAIN].qctrl.default_value;
+
+ if (sd->bridge == BRIDGE_VC0321) {
+ reg_r(dev, 0x8a, 0, tmp2, 3);
+ reg_w(dev, 0x87, 0x00, 0x0f0f);
+
+ reg_r(dev, 0x8b, 0, tmp2, 3);
+ reg_w(dev, 0x88, 0x00, 0x0202);
+ }
+ return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+ return 0;
+}
+
+static void setquality(struct gspca_dev *gspca_dev)
+{
+#if 0
+ struct sd *sd = (struct sd *) gspca_dev;
+ __u8 quality = 0;
+
+ quality = sd->qindex & 0xff;
+ reg_w(gspca_dev->dev, 0xa0, quality, 0x0008);
+#endif
+}
+
+static void setautogain(struct gspca_dev *gspca_dev)
+{
+#if 0
+ struct sd *sd = (struct sd *) gspca_dev;
+ __u8 autoval;
+
+ if (sd->autogain)
+ autoval = 0x42;
+ else
+ autoval = 0x02;
+ reg_w(gspca_dev->dev, 0xa0, autoval, 0x0180);
+#endif
+}
+
+static void setlightfreq(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ static const __u8 (*ov7660_freq_tb[3])[4] =
+ {ov7660_NoFliker, ov7660_50HZ, ov7660_60HZ};
+
+ if (sd->sensor != SENSOR_OV7660)
+ return;
+ usb_exchange(gspca_dev, ov7660_freq_tb[sd->lightfreq]);
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+/* __u8 tmp2; */
+ const __u8 *GammaT = NULL;
+ const __u8 *MatrixT = NULL;
+ int mode;
+
+ /* Assume start use the good resolution from gspca_dev->mode */
+ if (sd->bridge == BRIDGE_VC0321) {
+ reg_w(gspca_dev->dev, 0xa0, 0xff, 0xbfec);
+ reg_w(gspca_dev->dev, 0xa0, 0xff, 0xbfed);
+ reg_w(gspca_dev->dev, 0xa0, 0xff, 0xbfee);
+ reg_w(gspca_dev->dev, 0xa0, 0xff, 0xbfef);
+ }
+
+ mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
+ switch (sd->sensor) {
+ case SENSOR_HV7131R:
+ GammaT = hv7131r_gamma;
+ MatrixT = hv7131r_matrix;
+ if (mode) {
+ /* 320x240 */
+ usb_exchange(gspca_dev, hv7131r_initQVGA_data);
+ } else {
+ /* 640x480 */
+ usb_exchange(gspca_dev, hv7131r_initVGA_data);
+ }
+ break;
+ case SENSOR_OV7660:
+ GammaT = ov7660_gamma;
+ MatrixT = ov7660_matrix;
+ if (mode) {
+ /* 320x240 */
+ usb_exchange(gspca_dev, ov7660_initQVGA_data);
+ } else {
+ /* 640x480 */
+ usb_exchange(gspca_dev, ov7660_initVGA_data);
+ }
+ break;
+ case SENSOR_OV7670:
+ /*GammaT = ov7660_gamma; */
+ /*MatrixT = ov7660_matrix; */
+ if (mode) {
+ /* 320x240 */
+ usb_exchange(gspca_dev, ov7670_initQVGA_JPG);
+ } else {
+ /* 640x480 */
+ usb_exchange(gspca_dev, ov7670_initVGA_JPG);
+ }
+ break;
+ case SENSOR_MI1310_SOC:
+ if (mode) {
+ /* 320x240 */
+ usb_exchange(gspca_dev, mi1310_socinitQVGA_JPG);
+ } else {
+ /* 640x480 */
+ usb_exchange(gspca_dev, mi1310_socinitVGA_JPG);
+ }
+ break;
+ case SENSOR_MI1320:
+ GammaT = mi1320_gamma;
+ MatrixT = mi1320_matrix;
+ if (mode) {
+ /* 320x240 */
+ usb_exchange(gspca_dev, mi1320_initQVGA_data);
+ } else {
+ /* 640x480 */
+ usb_exchange(gspca_dev, mi1320_initVGA_data);
+ }
+ break;
+ case SENSOR_PO3130NC:
+ GammaT = po3130_gamma;
+ MatrixT = po3130_matrix;
+ if (mode) {
+ /* 320x240 */
+ usb_exchange(gspca_dev, po3130_initQVGA_data);
+ } else {
+ /* 640x480 */
+ usb_exchange(gspca_dev, po3130_initVGA_data);
+ }
+ usb_exchange(gspca_dev, po3130_rundata);
+ break;
+ default:
+ PDEBUG(D_PROBE, "Damned !! no sensor found Bye");
+ return;
+ }
+ if (GammaT && MatrixT) {
+ put_tab_to_reg(gspca_dev, GammaT, 17, 0xb84a);
+ put_tab_to_reg(gspca_dev, GammaT, 17, 0xb85b);
+ put_tab_to_reg(gspca_dev, GammaT, 17, 0xb86c);
+ put_tab_to_reg(gspca_dev, MatrixT, 9, 0xb82c);
+
+ /* Seem SHARPNESS */
+ /*
+ reg_w(gspca_dev->dev, 0xa0, 0x80, 0xb80a);
+ reg_w(gspca_dev->dev, 0xa0, 0xff, 0xb80b);
+ reg_w(gspca_dev->dev, 0xa0, 0xff, 0xb80e);
+ */
+ /* all 0x40 ??? do nothing
+ reg_w(gspca_dev->dev, 0xa0, 0x40, 0xb822);
+ reg_w(gspca_dev->dev, 0xa0, 0x40, 0xb823);
+ reg_w(gspca_dev->dev, 0xa0, 0x40, 0xb824);
+ */
+ /* Only works for HV7131R ??
+ reg_r (gspca_dev->dev, 0xa1, 0xb881, &tmp2, 1);
+ reg_w(gspca_dev->dev, 0xa0, 0xfe01, 0xb881);
+ reg_w(gspca_dev->dev, 0xa0, 0x79, 0xb801);
+ */
+ /* only hv7131r et ov7660
+ reg_w(gspca_dev->dev, 0xa0, 0x20, 0xb827);
+ reg_w(gspca_dev->dev, 0xa0, 0xff, 0xb826); * ISP_GAIN 80
+ reg_w(gspca_dev->dev, 0xa0, 0x23, 0xb800); * ISP CTRL_BAS
+ */
+ /* set the led on 0x0892 0x0896 */
+ reg_w(gspca_dev->dev, 0x89, 0xffff, 0xfdff);
+ msleep(100);
+ setquality(gspca_dev);
+ setautogain(gspca_dev);
+ setlightfreq(gspca_dev);
+ }
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+ struct usb_device *dev = gspca_dev->dev;
+
+ reg_w(dev, 0x89, 0xffff, 0xffff);
+ reg_w(dev, 0xa0, 0x01, 0xb301);
+ reg_w(dev, 0xa0, 0x09, 0xb003);
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+ struct usb_device *dev = gspca_dev->dev;
+
+ reg_w(dev, 0x89, 0xffff, 0xffff);
+}
+
+/* this function is called at close time */
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+/* struct usb_device *dev = gspca_dev->dev;
+ __u8 buffread;
+
+ reg_w(dev, 0x89, 0xffff, 0xffff);
+ reg_w(dev, 0xa0, 0x01, 0xb301);
+ reg_w(dev, 0xa0, 0x09, 0xb303);
+ reg_w(dev, 0x89, 0xffff, 0xffff);
+*/
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ struct gspca_frame *frame, /* target */
+ __u8 *data, /* isoc packet */
+ int len) /* iso pkt length */
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (data[0] == 0xff && data[1] == 0xd8) {
+ PDEBUG(D_PACK,
+ "vc032x header packet found len %d", len);
+ frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+ data, 0);
+ if (sd->bridge == BRIDGE_VC0321) {
+#define VCHDRSZ 46
+ data += VCHDRSZ;
+ len -= VCHDRSZ;
+#undef VCHDRSZ
+ }
+ gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+ data, len);
+ return;
+ }
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+}
+
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->autogain = val;
+ if (gspca_dev->streaming)
+ setautogain(gspca_dev);
+ return 0;
+}
+
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->autogain;
+ return 0;
+}
+
+static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->lightfreq = val;
+ if (gspca_dev->streaming)
+ setlightfreq(gspca_dev);
+ return 0;
+}
+
+static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->lightfreq;
+ return 0;
+}
+
+static int sd_querymenu(struct gspca_dev *gspca_dev,
+ struct v4l2_querymenu *menu)
+{
+ switch (menu->id) {
+ case V4L2_CID_POWER_LINE_FREQUENCY:
+ switch (menu->index) {
+ case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */
+ strcpy((char *) menu->name, "NoFliker");
+ return 0;
+ case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
+ strcpy((char *) menu->name, "50 Hz");
+ return 0;
+ case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
+ strcpy((char *) menu->name, "60 Hz");
+ return 0;
+ }
+ break;
+ }
+ return -EINVAL;
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .ctrls = sd_ctrls,
+ .nctrls = ARRAY_SIZE(sd_ctrls),
+ .config = sd_config,
+ .open = sd_open,
+ .start = sd_start,
+ .stopN = sd_stopN,
+ .stop0 = sd_stop0,
+ .close = sd_close,
+ .pkt_scan = sd_pkt_scan,
+ .querymenu = sd_querymenu,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static const __devinitdata struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x046d, 0x0892), DVNM("Logitech Orbicam")},
+ {USB_DEVICE(0x046d, 0x0896), DVNM("Logitech Orbicam")},
+ {USB_DEVICE(0x0ac8, 0x0321), DVNM("Vimicro generic vc0321")},
+ {USB_DEVICE(0x0ac8, 0x0323), DVNM("Vimicro Vc0323")},
+ {USB_DEVICE(0x0ac8, 0x0328), DVNM("A4Tech PK-130MG")},
+ {USB_DEVICE(0x0ac8, 0xc001), DVNM("Sony embedded vimicro")},
+ {USB_DEVICE(0x0ac8, 0xc002), DVNM("Sony embedded vimicro")},
+ {USB_DEVICE(0x17ef, 0x4802), DVNM("Lenovo Vc0323+MI1310_SOC")},
+ {}
+};
+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,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+ if (usb_register(&sd_driver) < 0)
+ return -1;
+ PDEBUG(D_PROBE, "v%s registered", version);
+ return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+ usb_deregister(&sd_driver);
+ PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/linux/drivers/media/video/gspca/zc3xx.c b/linux/drivers/media/video/gspca/zc3xx.c
new file mode 100644
index 000000000..b0599532f
--- /dev/null
+++ b/linux/drivers/media/video/gspca/zc3xx.c
@@ -0,0 +1,7615 @@
+/*
+ * Z-Star/Vimicro zc301/zc302p/vc30x library
+ * Copyright (C) 2004 2005 2006 Michel Xhaard
+ * mxhaard@magic.fr
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * 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.
+ */
+
+#define MODULE_NAME "zc3xx"
+
+#include "gspca.h"
+
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 5)
+static const char version[] = "2.1.5";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>, "
+ "Serge A. Suchkov <Serge.A.S@tochka.ru>");
+MODULE_DESCRIPTION("GSPCA ZC03xx/VC3xx USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+static int force_sensor = -1;
+
+#include "jpeg.h"
+
+/* specific webcam descriptor */
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+
+ __u8 brightness;
+ __u8 contrast;
+ __u8 gamma;
+ __u8 autogain;
+ __u8 lightfreq;
+ __u8 sharpness;
+
+ char qindex;
+ char sensor; /* Type of image sensor chip */
+/* !! values used in different tables */
+#define SENSOR_CS2102 0
+#define SENSOR_CS2102K 1
+#define SENSOR_GC0305 2
+#define SENSOR_HDCS2020 3
+#define SENSOR_HDCS2020b 4
+#define SENSOR_HV7131B 5
+#define SENSOR_HV7131C 6
+#define SENSOR_ICM105A 7
+#define SENSOR_MC501CB 8
+#define SENSOR_OV7620 9
+/*#define SENSOR_OV7648 9 - same values */
+#define SENSOR_OV7630C 10
+#define SENSOR_PAS106 11
+#define SENSOR_PB0330 12
+#define SENSOR_PO2030 13
+#define SENSOR_TAS5130CK 14
+#define SENSOR_TAS5130CXX 15
+#define SENSOR_TAS5130C_VF0250 16
+#define SENSOR_MAX 17
+ unsigned short chip_revision;
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+#define SD_BRIGHTNESS 0
+ {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+ .default_value = 128,
+ },
+ .set = sd_setbrightness,
+ .get = sd_getbrightness,
+ },
+#define SD_CONTRAST 1
+ {
+ {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = 0,
+ .maximum = 256,
+ .step = 1,
+ .default_value = 128,
+ },
+ .set = sd_setcontrast,
+ .get = sd_getcontrast,
+ },
+#define SD_GAMMA 2
+ {
+ {
+ .id = V4L2_CID_GAMMA,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Gamma",
+ .minimum = 1,
+ .maximum = 6,
+ .step = 1,
+ .default_value = 4,
+ },
+ .set = sd_setgamma,
+ .get = sd_getgamma,
+ },
+#define SD_AUTOGAIN 3
+ {
+ {
+ .id = V4L2_CID_AUTOGAIN,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Auto Gain",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 1,
+ },
+ .set = sd_setautogain,
+ .get = sd_getautogain,
+ },
+#define SD_FREQ 4
+ {
+ {
+ .id = V4L2_CID_POWER_LINE_FREQUENCY,
+ .type = V4L2_CTRL_TYPE_MENU,
+ .name = "Light frequency filter",
+ .minimum = 0,
+ .maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */
+ .step = 1,
+ .default_value = 1,
+ },
+ .set = sd_setfreq,
+ .get = sd_getfreq,
+ },
+#define SD_SHARPNESS 5
+ {
+ {
+ .id = V4L2_CID_SHARPNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Sharpness",
+ .minimum = 0,
+ .maximum = 3,
+ .step = 1,
+ .default_value = 2,
+ },
+ .set = sd_setsharpness,
+ .get = sd_getsharpness,
+ },
+};
+
+static struct v4l2_pix_format vga_mode[] = {
+ {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 1},
+ {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 0},
+};
+
+static struct v4l2_pix_format sif_mode[] = {
+ {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 176,
+ .sizeimage = 176 * 144 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 1},
+ {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 352,
+ .sizeimage = 352 * 288 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 0},
+};
+
+/* usb exchanges */
+struct usb_action {
+ __u8 req;
+ __u8 val;
+ __u16 idx;
+};
+
+static const struct usb_action cs2102_Initial[] = {
+ {0xa1, 0x01, 0x0008},
+ {0xa1, 0x01, 0x0008},
+ {0xa0, 0x01, 0x0000},
+ {0xa0, 0x10, 0x0002},
+ {0xa0, 0x00, 0x0010},
+ {0xa0, 0x01, 0x0001},
+ {0xa0, 0x20, 0x0080},
+ {0xa0, 0x21, 0x0081},
+ {0xa0, 0x30, 0x0083},
+ {0xa0, 0x31, 0x0084},
+ {0xa0, 0x32, 0x0085},
+ {0xa0, 0x23, 0x0086},
+ {0xa0, 0x24, 0x0087},
+ {0xa0, 0x25, 0x0088},
+ {0xa0, 0xb3, 0x008b},
+ {0xa0, 0x03, 0x0008}, /* 00 */
+ {0xa0, 0x03, 0x0012},
+ {0xa0, 0x01, 0x0012},
+ {0xa0, 0x02, 0x0003},
+ {0xa0, 0x80, 0x0004},
+ {0xa0, 0x01, 0x0005},
+ {0xa0, 0xe0, 0x0006},
+ {0xa0, 0x00, 0x0098},
+ {0xa0, 0x00, 0x009a},
+ {0xa0, 0x00, 0x011a},
+ {0xa0, 0x00, 0x011c},
+ {0xaa, 0x02, 0x0008},
+ {0xaa, 0x03, 0x0000},
+ {0xaa, 0x11, 0x0000},
+ {0xaa, 0x12, 0x0089},
+ {0xaa, 0x13, 0x0000},
+ {0xaa, 0x14, 0x00e9},
+ {0xaa, 0x20, 0x0000},
+ {0xaa, 0x22, 0x0000},
+ {0xaa, 0x0b, 0x0004},
+ {0xaa, 0x30, 0x0030},
+ {0xaa, 0x31, 0x0030},
+ {0xaa, 0x32, 0x0030},
+ {0xa0, 0x37, 0x0101},
+ {0xa0, 0x00, 0x0019},
+ {0xa0, 0x05, 0x0012},
+ {0xa0, 0x0d, 0x0100},
+ {0xa0, 0x06, 0x0189},
+ {0xa0, 0x03, 0x01c5},
+ {0xa0, 0x13, 0x01cb},
+ {0xa0, 0x10, 0x01ae},
+ {0xa0, 0x08, 0x0250},
+ {0xa0, 0x08, 0x0301},
+ {0xa0, 0x68, 0x018d},
+ {0xa0, 0x00, 0x01ad},
+ {0xa1, 0x01, 0x0002},
+ {0xa1, 0x01, 0x0008},
+ {0xa0, 0x03, 0x0008}, /* 00 */
+ {0xa0, 0x08, 0x01c6}, /* sharpness+ */
+ {0xa1, 0x01, 0x01c8},
+ {0xa1, 0x01, 0x01c9},
+ {0xa1, 0x01, 0x01ca},
+ {0xa0, 0x0f, 0x01cb}, /* sharpness- */
+ {0xa0, 0x24, 0x0120}, /* gamma 5 */
+ {0xa0, 0x44, 0x0121},
+ {0xa0, 0x64, 0x0122},
+ {0xa0, 0x84, 0x0123},
+ {0xa0, 0x9d, 0x0124},
+ {0xa0, 0xb2, 0x0125},
+ {0xa0, 0xc4, 0x0126},
+ {0xa0, 0xd3, 0x0127},
+ {0xa0, 0xe0, 0x0128},
+ {0xa0, 0xeb, 0x0129},
+ {0xa0, 0xf4, 0x012a},
+ {0xa0, 0xfb, 0x012b},
+ {0xa0, 0xff, 0x012c},
+ {0xa0, 0xff, 0x012d},
+ {0xa0, 0xff, 0x012e},
+ {0xa0, 0xff, 0x012f},
+ {0xa0, 0x18, 0x0130},
+ {0xa0, 0x20, 0x0131},
+ {0xa0, 0x20, 0x0132},
+ {0xa0, 0x1c, 0x0133},
+ {0xa0, 0x16, 0x0134},
+ {0xa0, 0x13, 0x0135},
+ {0xa0, 0x10, 0x0136},
+ {0xa0, 0x0e, 0x0137},
+ {0xa0, 0x0b, 0x0138},
+ {0xa0, 0x09, 0x0139},
+ {0xa0, 0x07, 0x013a},
+ {0xa0, 0x06, 0x013b},
+ {0xa0, 0x00, 0x013c},
+ {0xa0, 0x00, 0x013d},
+ {0xa0, 0x00, 0x013e},
+ {0xa0, 0x01, 0x013f},
+ {0xa0, 0x58, 0x010a}, /* matrix */
+ {0xa0, 0xf4, 0x010b},
+ {0xa0, 0xf4, 0x010c},
+ {0xa0, 0xf4, 0x010d},
+ {0xa0, 0x58, 0x010e},
+ {0xa0, 0xf4, 0x010f},
+ {0xa0, 0xf4, 0x0110},
+ {0xa0, 0xf4, 0x0111},
+ {0xa0, 0x58, 0x0112},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x00, 0x0180},
+ {0xa0, 0x00, 0x0019},
+ {0xaa, 0x23, 0x0001},
+ {0xaa, 0x24, 0x0055},
+ {0xaa, 0x25, 0x00cc},
+ {0xaa, 0x21, 0x003f},
+ {0xa0, 0x02, 0x0190},
+ {0xa0, 0xab, 0x0191},
+ {0xa0, 0x98, 0x0192},
+ {0xa0, 0x00, 0x0195},
+ {0xa0, 0x30, 0x0196},
+ {0xa0, 0xd4, 0x0197},
+ {0xa0, 0x10, 0x018c},
+ {0xa0, 0x20, 0x018f},
+ {0xa0, 0x10, 0x01a9},
+ {0xa0, 0x24, 0x01aa},
+ {0xa0, 0x39, 0x001d},
+ {0xa0, 0x70, 0x001e},
+ {0xa0, 0xb0, 0x001f},
+ {0xa0, 0xff, 0x0020},
+ {0xa0, 0x40, 0x0180},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x42, 0x0180},
+ {0xa0, 0x40, 0x0116},
+ {0xa0, 0x40, 0x0117},
+ {0xa0, 0x40, 0x0118},
+ {}
+};
+
+static const struct usb_action cs2102_InitialScale[] = {
+ {0xa1, 0x01, 0x0008},
+ {0xa1, 0x01, 0x0008},
+ {0xa0, 0x01, 0x0000},
+ {0xa0, 0x00, 0x0002},
+ {0xa0, 0x00, 0x0010},
+ {0xa0, 0x01, 0x0001},
+ {0xa0, 0x20, 0x0080},
+ {0xa0, 0x21, 0x0081},
+ {0xa0, 0x30, 0x0083},
+ {0xa0, 0x31, 0x0084},
+ {0xa0, 0x32, 0x0085},
+ {0xa0, 0x23, 0x0086},
+ {0xa0, 0x24, 0x0087},
+ {0xa0, 0x25, 0x0088},
+ {0xa0, 0xb3, 0x008b},
+ {0xa0, 0x03, 0x0008}, /* 00 */
+ {0xa0, 0x03, 0x0012},
+ {0xa0, 0x01, 0x0012},
+ {0xa0, 0x02, 0x0003},
+ {0xa0, 0x80, 0x0004},
+ {0xa0, 0x01, 0x0005},
+ {0xa0, 0xe0, 0x0006},
+ {0xa0, 0x00, 0x0098},
+ {0xa0, 0x00, 0x009a},
+ {0xa0, 0x00, 0x011a},
+ {0xa0, 0x00, 0x011c},
+ {0xaa, 0x02, 0x0008},
+ {0xaa, 0x03, 0x0000},
+ {0xaa, 0x11, 0x0001},
+ {0xaa, 0x12, 0x0087},
+ {0xaa, 0x13, 0x0001},
+ {0xaa, 0x14, 0x00e7},
+ {0xaa, 0x20, 0x0000},
+ {0xaa, 0x22, 0x0000},
+ {0xaa, 0x0b, 0x0004},
+ {0xaa, 0x30, 0x0030},
+ {0xaa, 0x31, 0x0030},
+ {0xaa, 0x32, 0x0030},
+ {0xa0, 0x77, 0x0101},
+ {0xa0, 0x00, 0x0019},
+ {0xa0, 0x05, 0x0012},
+ {0xa0, 0x0d, 0x0100},
+ {0xa0, 0x06, 0x0189},
+ {0xa0, 0x03, 0x01c5},
+ {0xa0, 0x13, 0x01cb},
+ {0xa0, 0x15, 0x01ae},
+ {0xa0, 0x08, 0x0250},
+ {0xa0, 0x08, 0x0301},
+ {0xa0, 0x68, 0x018d},
+ {0xa0, 0x00, 0x01ad},
+ {0xa1, 0x01, 0x0002},
+ {0xa1, 0x01, 0x0008},
+ {0xa0, 0x03, 0x0008}, /* 00 */
+ {0xa0, 0x08, 0x01c6}, /* sharpness+ */
+ {0xa1, 0x01, 0x01c8},
+ {0xa1, 0x01, 0x01c9},
+ {0xa1, 0x01, 0x01ca},
+ {0xa0, 0x0f, 0x01cb}, /* sharpness- */
+ {0xa0, 0x24, 0x0120}, /* gamma 5 */
+ {0xa0, 0x44, 0x0121},
+ {0xa0, 0x64, 0x0122},
+ {0xa0, 0x84, 0x0123},
+ {0xa0, 0x9d, 0x0124},
+ {0xa0, 0xb2, 0x0125},
+ {0xa0, 0xc4, 0x0126},
+ {0xa0, 0xd3, 0x0127},
+ {0xa0, 0xe0, 0x0128},
+ {0xa0, 0xeb, 0x0129},
+ {0xa0, 0xf4, 0x012a},
+ {0xa0, 0xfb, 0x012b},
+ {0xa0, 0xff, 0x012c},
+ {0xa0, 0xff, 0x012d},
+ {0xa0, 0xff, 0x012e},
+ {0xa0, 0xff, 0x012f},
+ {0xa0, 0x18, 0x0130},
+ {0xa0, 0x20, 0x0131},
+ {0xa0, 0x20, 0x0132},
+ {0xa0, 0x1c, 0x0133},
+ {0xa0, 0x16, 0x0134},
+ {0xa0, 0x13, 0x0135},
+ {0xa0, 0x10, 0x0136},
+ {0xa0, 0x0e, 0x0137},
+ {0xa0, 0x0b, 0x0138},
+ {0xa0, 0x09, 0x0139},
+ {0xa0, 0x07, 0x013a},
+ {0xa0, 0x06, 0x013b},
+ {0xa0, 0x00, 0x013c},
+ {0xa0, 0x00, 0x013d},
+ {0xa0, 0x00, 0x013e},
+ {0xa0, 0x01, 0x013f},
+ {0xa0, 0x58, 0x010a}, /* matrix */
+ {0xa0, 0xf4, 0x010b},
+ {0xa0, 0xf4, 0x010c},
+ {0xa0, 0xf4, 0x010d},
+ {0xa0, 0x58, 0x010e},
+ {0xa0, 0xf4, 0x010f},
+ {0xa0, 0xf4, 0x0110},
+ {0xa0, 0xf4, 0x0111},
+ {0xa0, 0x58, 0x0112},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x00, 0x0180},
+ {0xa0, 0x00, 0x0019},
+ {0xaa, 0x23, 0x0000},
+ {0xaa, 0x24, 0x00aa},
+ {0xaa, 0x25, 0x00e6},
+ {0xaa, 0x21, 0x003f},
+ {0xa0, 0x01, 0x0190},
+ {0xa0, 0x55, 0x0191},
+ {0xa0, 0xcc, 0x0192},
+ {0xa0, 0x00, 0x0195},
+ {0xa0, 0x18, 0x0196},
+ {0xa0, 0x6a, 0x0197},
+ {0xa0, 0x10, 0x018c},
+ {0xa0, 0x20, 0x018f},
+ {0xa0, 0x10, 0x01a9},
+ {0xa0, 0x24, 0x01aa},
+ {0xa0, 0x3f, 0x001d},
+ {0xa0, 0xa5, 0x001e},
+ {0xa0, 0xf0, 0x001f},
+ {0xa0, 0xff, 0x0020},
+ {0xa0, 0x40, 0x0180},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x42, 0x0180},
+ {0xa0, 0x40, 0x0116},
+ {0xa0, 0x40, 0x0117},
+ {0xa0, 0x40, 0x0118},
+ {}
+};
+static const struct usb_action cs2102_50HZ[] = {
+ {0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
+ {0xaa, 0x0f, 0x008c}, /* 00,0f,8c,aa */
+ {0xaa, 0x03, 0x0005}, /* 00,03,05,aa */
+ {0xaa, 0x04, 0x00ac}, /* 00,04,ac,aa */
+ {0xaa, 0x10, 0x0005}, /* 00,10,05,aa */
+ {0xaa, 0x11, 0x00ac}, /* 00,11,ac,aa */
+ {0xaa, 0x1b, 0x0000}, /* 00,1b,00,aa */
+ {0xaa, 0x1c, 0x0005}, /* 00,1c,05,aa */
+ {0xaa, 0x1d, 0x00ac}, /* 00,1d,ac,aa */
+ {0xa0, 0x00, 0x0190}, /* 01,90,00,cc */
+ {0xa0, 0x3f, 0x0191}, /* 01,91,3f,cc */
+ {0xa0, 0xf0, 0x0192}, /* 01,92,f0,cc */
+ {0xa0, 0x00, 0x0195}, /* 01,95,00,cc */
+ {0xa0, 0x00, 0x0196}, /* 01,96,00,cc */
+ {0xa0, 0x42, 0x0197}, /* 01,97,42,cc */
+ {0xa0, 0x10, 0x018c}, /* 01,8c,10,cc */
+ {0xa0, 0x20, 0x018f}, /* 01,8f,20,cc */
+ {0xa0, 0x10, 0x01a9}, /* 01,a9,10,cc */
+ {0xa0, 0x24, 0x01aa}, /* 01,aa,24,cc */
+ {0xa0, 0x8c, 0x001d}, /* 00,1d,8c,cc */
+ {0xa0, 0xb0, 0x001e}, /* 00,1e,b0,cc */
+ {0xa0, 0xd0, 0x001f}, /* 00,1f,d0,cc */
+ {}
+};
+static const struct usb_action cs2102_50HZScale[] = {
+ {0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
+ {0xaa, 0x0f, 0x0093}, /* 00,0f,93,aa */
+ {0xaa, 0x03, 0x0005}, /* 00,03,05,aa */
+ {0xaa, 0x04, 0x00a1}, /* 00,04,a1,aa */
+ {0xaa, 0x10, 0x0005}, /* 00,10,05,aa */
+ {0xaa, 0x11, 0x00a1}, /* 00,11,a1,aa */
+ {0xaa, 0x1b, 0x0000}, /* 00,1b,00,aa */
+ {0xaa, 0x1c, 0x0005}, /* 00,1c,05,aa */
+ {0xaa, 0x1d, 0x00a1}, /* 00,1d,a1,aa */
+ {0xa0, 0x00, 0x0190}, /* 01,90,00,cc */
+ {0xa0, 0x3f, 0x0191}, /* 01,91,3f,cc */
+ {0xa0, 0xf7, 0x0192}, /* 01,92,f7,cc */
+ {0xa0, 0x00, 0x0195}, /* 01,95,00,cc */
+ {0xa0, 0x00, 0x0196}, /* 01,96,00,cc */
+ {0xa0, 0x83, 0x0197}, /* 01,97,83,cc */
+ {0xa0, 0x10, 0x018c}, /* 01,8c,10,cc */
+ {0xa0, 0x20, 0x018f}, /* 01,8f,20,cc */
+ {0xa0, 0x10, 0x01a9}, /* 01,a9,10,cc */
+ {0xa0, 0x24, 0x01aa}, /* 01,aa,24,cc */
+ {0xa0, 0x93, 0x001d}, /* 00,1d,93,cc */
+ {0xa0, 0xb0, 0x001e}, /* 00,1e,b0,cc */
+ {0xa0, 0xd0, 0x001f}, /* 00,1f,d0,cc */
+ {}
+};
+static const struct usb_action cs2102_60HZ[] = {
+ {0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
+ {0xaa, 0x0f, 0x005d}, /* 00,0f,5d,aa */
+ {0xaa, 0x03, 0x0005}, /* 00,03,05,aa */
+ {0xaa, 0x04, 0x00aa}, /* 00,04,aa,aa */
+ {0xaa, 0x10, 0x0005}, /* 00,10,05,aa */
+ {0xaa, 0x11, 0x00aa}, /* 00,11,aa,aa */
+ {0xaa, 0x1b, 0x0000}, /* 00,1b,00,aa */
+ {0xaa, 0x1c, 0x0005}, /* 00,1c,05,aa */
+ {0xaa, 0x1d, 0x00aa}, /* 00,1d,aa,aa */
+ {0xa0, 0x00, 0x0190}, /* 01,90,00,cc */
+ {0xa0, 0x3f, 0x0191}, /* 01,91,3f,cc */
+ {0xa0, 0xe4, 0x0192}, /* 01,92,e4,cc */
+ {0xa0, 0x00, 0x0195}, /* 01,95,00,cc */
+ {0xa0, 0x00, 0x0196}, /* 01,96,00,cc */
+ {0xa0, 0x3a, 0x0197}, /* 01,97,3a,cc */
+ {0xa0, 0x10, 0x018c}, /* 01,8c,10,cc */
+ {0xa0, 0x20, 0x018f}, /* 01,8f,20,cc */
+ {0xa0, 0x10, 0x01a9}, /* 01,a9,10,cc */
+ {0xa0, 0x24, 0x01aa}, /* 01,aa,24,cc */
+ {0xa0, 0x5d, 0x001d}, /* 00,1d,5d,cc */
+ {0xa0, 0x90, 0x001e}, /* 00,1e,90,cc */
+ {0xa0, 0xd0, 0x00c8}, /* 00,c8,d0,cc */
+ {}
+};
+static const struct usb_action cs2102_60HZScale[] = {
+ {0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
+ {0xaa, 0x0f, 0x00b7}, /* 00,0f,b7,aa */
+ {0xaa, 0x03, 0x0005}, /* 00,03,05,aa */
+ {0xaa, 0x04, 0x00be}, /* 00,04,be,aa */
+ {0xaa, 0x10, 0x0005}, /* 00,10,05,aa */
+ {0xaa, 0x11, 0x00be}, /* 00,11,be,aa */
+ {0xaa, 0x1b, 0x0000}, /* 00,1b,00,aa */
+ {0xaa, 0x1c, 0x0005}, /* 00,1c,05,aa */
+ {0xaa, 0x1d, 0x00be}, /* 00,1d,be,aa */
+ {0xa0, 0x00, 0x0190}, /* 01,90,00,cc */
+ {0xa0, 0x3f, 0x0191}, /* 01,91,3f,cc */
+ {0xa0, 0xfc, 0x0192}, /* 01,92,fc,cc */
+ {0xa0, 0x00, 0x0195}, /* 01,95,00,cc */
+ {0xa0, 0x00, 0x0196}, /* 01,96,00,cc */
+ {0xa0, 0x69, 0x0197}, /* 01,97,69,cc */
+ {0xa0, 0x10, 0x018c}, /* 01,8c,10,cc */
+ {0xa0, 0x20, 0x018f}, /* 01,8f,20,cc */
+ {0xa0, 0x10, 0x01a9}, /* 01,a9,10,cc */
+ {0xa0, 0x24, 0x01aa}, /* 01,aa,24,cc */
+ {0xa0, 0xb7, 0x001d}, /* 00,1d,b7,cc */
+ {0xa0, 0xd0, 0x001e}, /* 00,1e,d0,cc */
+ {0xa0, 0xe8, 0x001f}, /* 00,1f,e8,cc */
+ {}
+};
+static const struct usb_action cs2102_NoFliker[] = {
+ {0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
+ {0xaa, 0x0f, 0x0059}, /* 00,0f,59,aa */
+ {0xaa, 0x03, 0x0005}, /* 00,03,05,aa */
+ {0xaa, 0x04, 0x0080}, /* 00,04,80,aa */
+ {0xaa, 0x10, 0x0005}, /* 00,10,05,aa */
+ {0xaa, 0x11, 0x0080}, /* 00,11,80,aa */
+ {0xaa, 0x1b, 0x0000}, /* 00,1b,00,aa */
+ {0xaa, 0x1c, 0x0005}, /* 00,1c,05,aa */
+ {0xaa, 0x1d, 0x0080}, /* 00,1d,80,aa */
+ {0xa0, 0x00, 0x0190}, /* 01,90,00,cc */
+ {0xa0, 0x3f, 0x0191}, /* 01,91,3f,cc */
+ {0xa0, 0xf0, 0x0192}, /* 01,92,f0,cc */
+ {0xa0, 0x00, 0x0195}, /* 01,95,00,cc */
+ {0xa0, 0x00, 0x0196}, /* 01,96,00,cc */
+ {0xa0, 0x10, 0x0197}, /* 01,97,10,cc */
+ {0xa0, 0x10, 0x018c}, /* 01,8c,10,cc */
+ {0xa0, 0x20, 0x018f}, /* 01,8f,20,cc */
+ {0xa0, 0x00, 0x01a9}, /* 01,a9,00,cc */
+ {0xa0, 0x00, 0x01aa}, /* 01,aa,00,cc */
+ {0xa0, 0x59, 0x001d}, /* 00,1d,59,cc */
+ {0xa0, 0x90, 0x001e}, /* 00,1e,90,cc */
+ {0xa0, 0xc8, 0x001f}, /* 00,1f,c8,cc */
+ {}
+};
+static const struct usb_action cs2102_NoFlikerScale[] = {
+ {0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
+ {0xaa, 0x0f, 0x0059}, /* 00,0f,59,aa */
+ {0xaa, 0x03, 0x0005}, /* 00,03,05,aa */
+ {0xaa, 0x04, 0x0080}, /* 00,04,80,aa */
+ {0xaa, 0x10, 0x0005}, /* 00,10,05,aa */
+ {0xaa, 0x11, 0x0080}, /* 00,11,80,aa */
+ {0xaa, 0x1b, 0x0000}, /* 00,1b,00,aa */
+ {0xaa, 0x1c, 0x0005}, /* 00,1c,05,aa */
+ {0xaa, 0x1d, 0x0080}, /* 00,1d,80,aa */
+ {0xa0, 0x00, 0x0190}, /* 01,90,00,cc */
+ {0xa0, 0x3f, 0x0191}, /* 01,91,3f,cc */
+ {0xa0, 0xf0, 0x0192}, /* 01,92,f0,cc */
+ {0xa0, 0x00, 0x0195}, /* 01,95,00,cc */
+ {0xa0, 0x00, 0x0196}, /* 01,96,00,cc */
+ {0xa0, 0x10, 0x0197}, /* 01,97,10,cc */
+ {0xa0, 0x10, 0x018c}, /* 01,8c,10,cc */
+ {0xa0, 0x20, 0x018f}, /* 01,8f,20,cc */
+ {0xa0, 0x00, 0x01a9}, /* 01,a9,00,cc */
+ {0xa0, 0x00, 0x01aa}, /* 01,aa,00,cc */
+ {0xa0, 0x59, 0x001d}, /* 00,1d,59,cc */
+ {0xa0, 0x90, 0x001e}, /* 00,1e,90,cc */
+ {0xa0, 0xc8, 0x001f}, /* 00,1f,c8,cc */
+ {}
+};
+
+/* CS2102_KOCOM */
+static const struct usb_action cs2102K_Initial[] = {
+ {0xa0, 0x11, 0x0002},
+ {0xa0, 0x03, 0x0008},
+ {0xa0, 0x08, 0x0010},
+ {0xa0, 0x02, 0x0003},
+ {0xa0, 0x80, 0x0004},
+ {0xa0, 0x01, 0x0005},
+ {0xa0, 0xe0, 0x0006},
+ {0xa0, 0x01, 0x0001},
+ {0xa0, 0x03, 0x0012},
+ {0xa0, 0x01, 0x0012},
+ {0xa0, 0x00, 0x0098},
+ {0xa0, 0x00, 0x009a},
+ {0xa0, 0x00, 0x011a},
+ {0xa0, 0x00, 0x011c},
+ {0xa0, 0xe8, 0x009c},
+ {0xa0, 0x88, 0x009e},
+ {0xa0, 0x55, 0x008b},
+ {0xa0, 0x18, 0x0092},
+ {0xa0, 0x00, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x0a, 0x0092},
+ {0xa0, 0x02, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x0b, 0x0092},
+ {0xa0, 0x02, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x0c, 0x0092},
+ {0xa0, 0x7c, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x0d, 0x0092},
+ {0xa0, 0xa3, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x03, 0x0092},
+ {0xa0, 0xfb, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x05, 0x0092},
+ {0xa0, 0x00, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x06, 0x0092},
+ {0xa0, 0x03, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x09, 0x0092},
+ {0xa0, 0x08, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x0e, 0x0092},
+ {0xa0, 0x04, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x0f, 0x0092},
+ {0xa0, 0x18, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x10, 0x0092},
+ {0xa0, 0x18, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x11, 0x0092},
+ {0xa0, 0x18, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x12, 0x0092},
+ {0xa0, 0x18, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x15, 0x0092},
+ {0xa0, 0x00, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x16, 0x0092},
+ {0xa0, 0x0c, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x17, 0x0092},
+ {0xa0, 0x0c, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x18, 0x0092},
+ {0xa0, 0x04, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0xb7, 0x0101},
+ {0xa0, 0x05, 0x0012},
+ {0xa0, 0x78, 0x018d},
+ {0xa0, 0x0d, 0x0100},
+ {0xa0, 0x06, 0x0189},
+ {0xa0, 0x03, 0x01c5},
+ {0xa0, 0x13, 0x01cb},
+ {0xa0, 0x20, 0x0087},
+ {0xa0, 0x21, 0x0088},
+ {0xa0, 0x08, 0x0250},
+ {0xa0, 0x08, 0x0301},
+ {0xa0, 0x00, 0x01ad},
+ {0xa0, 0x01, 0x01b1},
+ {0xa0, 0x02, 0x0180},
+ {0xa0, 0x60, 0x0116},
+ {0xa0, 0x40, 0x0117},
+ {0xa0, 0x4c, 0x0118},
+ {0xa0, 0x03, 0x0008}, /* clock ? */
+ {0xa0, 0x08, 0x01c6}, /* sharpness+ */
+ {0xa0, 0x0f, 0x01cb}, /* sharpness- */
+ {0xa0, 0x13, 0x0120}, /* gamma 4 */
+ {0xa0, 0x38, 0x0121},
+ {0xa0, 0x59, 0x0122},
+ {0xa0, 0x79, 0x0123},
+ {0xa0, 0x92, 0x0124},
+ {0xa0, 0xa7, 0x0125},
+ {0xa0, 0xb9, 0x0126},
+ {0xa0, 0xc8, 0x0127},
+ {0xa0, 0xd4, 0x0128},
+ {0xa0, 0xdf, 0x0129},
+ {0xa0, 0xe7, 0x012a},
+ {0xa0, 0xee, 0x012b},
+ {0xa0, 0xf4, 0x012c},
+ {0xa0, 0xf9, 0x012d},
+ {0xa0, 0xfc, 0x012e},
+ {0xa0, 0xff, 0x012f},
+ {0xa0, 0x26, 0x0130},
+ {0xa0, 0x22, 0x0131},
+ {0xa0, 0x20, 0x0132},
+ {0xa0, 0x1c, 0x0133},
+ {0xa0, 0x16, 0x0134},
+ {0xa0, 0x13, 0x0135},
+ {0xa0, 0x10, 0x0136},
+ {0xa0, 0x0d, 0x0137},
+ {0xa0, 0x0b, 0x0138},
+ {0xa0, 0x09, 0x0139},
+ {0xa0, 0x07, 0x013a},
+ {0xa0, 0x06, 0x013b},
+ {0xa0, 0x05, 0x013c},
+ {0xa0, 0x04, 0x013d},
+ {0xa0, 0x03, 0x013e},
+ {0xa0, 0x02, 0x013f},
+ {0xa0, 0x58, 0x010a}, /* matrix */
+ {0xa0, 0xf4, 0x010b},
+ {0xa0, 0xf4, 0x010c},
+ {0xa0, 0xf4, 0x010d},
+ {0xa0, 0x58, 0x010e},
+ {0xa0, 0xf4, 0x010f},
+ {0xa0, 0xf4, 0x0110},
+ {0xa0, 0xf4, 0x0111},
+ {0xa0, 0x58, 0x0112},
+ {0xa0, 0x00, 0x0180},
+ {0xa0, 0x00, 0x0019},
+ {0xa0, 0x18, 0x0092},
+ {0xa0, 0x00, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x13, 0x0092},
+ {0xa0, 0x22, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x14, 0x0092},
+ {0xa0, 0x01, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x20, 0x0092},
+ {0xa0, 0x01, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x21, 0x0092},
+ {0xa0, 0x22, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x18, 0x0092},
+ {0xa0, 0x04, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x01, 0x00a3},
+ {0xa0, 0x22, 0x00a4},
+ {0xa0, 0x00, 0x0190},
+ {0xa0, 0x07, 0x0191},
+ {0xa0, 0xee, 0x0192},
+ {0xa0, 0x00, 0x0195},
+ {0xa0, 0x00, 0x0196},
+ {0xa0, 0x3a, 0x0197},
+ {0xa0, 0x10, 0x018c},
+ {0xa0, 0x20, 0x018f},
+ {0xa0, 0x0c, 0x01a9},
+ {0xa0, 0x28, 0x01aa},
+ {0xa0, 0x04, 0x001d},
+ {0xa0, 0x0f, 0x001e},
+ {0xa0, 0x19, 0x001f},
+ {0xa0, 0x1f, 0x0020},
+ {0xa0, 0x60, 0x011d},
+ {0xa0, 0x60, 0x011d},
+ {0xa0, 0x42, 0x0180},
+ {0xa0, 0x42, 0x0180},
+ {0xa0, 0x60, 0x0116},
+ {0xa0, 0x40, 0x0117},
+ {0xa0, 0x4c, 0x0118},
+ {0xa0, 0x04, 0x01a7},
+ {0xa0, 0x20, 0x0092},
+ {0xa0, 0x01, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x21, 0x0092},
+ {0xa0, 0x5c, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x18, 0x0092},
+ {0xa0, 0x00, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x13, 0x0092},
+ {0xa0, 0x5c, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x14, 0x0092},
+ {0xa0, 0x01, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x18, 0x0092},
+ {0xa0, 0x04, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x00, 0x01a7},
+ {0xa0, 0x04, 0x01a7},
+ {0xa0, 0x00, 0x01a7},
+ {0xa0, 0x04, 0x01a7},
+ {0xa0, 0x20, 0x0092},
+ {0xa0, 0x01, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x21, 0x0092},
+ {0xa0, 0x96, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x18, 0x0092},
+ {0xa0, 0x00, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x13, 0x0092},
+ {0xa0, 0x96, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x14, 0x0092},
+ {0xa0, 0x01, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x18, 0x0092},
+ {0xa0, 0x04, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x00, 0x01a7},
+ {0xa0, 0x04, 0x01a7},
+ {0xa0, 0x00, 0x01a7},
+ {}
+};
+
+static const struct usb_action cs2102K_InitialScale[] = {
+ {0xa0, 0x11, 0x0002},
+ {0xa0, 0x00, 0x0002},
+ {0xa0, 0x03, 0x0008},
+ {0xa0, 0x08, 0x0010},
+ {0xa0, 0x02, 0x0003},
+ {0xa0, 0x80, 0x0004},
+ {0xa0, 0x01, 0x0005},
+ {0xa0, 0xe0, 0x0006},
+ {0xa0, 0x01, 0x0001},
+ {0xa0, 0x03, 0x0012},
+ {0xa0, 0x01, 0x0012},
+ {0xa0, 0x00, 0x0098},
+ {0xa0, 0x00, 0x009a},
+ {0xa0, 0x00, 0x011a},
+ {0xa0, 0x00, 0x011c},
+ {0xa0, 0xe8, 0x009c},
+ {0xa0, 0x88, 0x009e},
+ {0xa0, 0x55, 0x008b},
+ {0xa0, 0x18, 0x0092},
+ {0xa0, 0x00, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x0a, 0x0092},
+ {0xa0, 0x02, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x0b, 0x0092},
+ {0xa0, 0x02, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x0c, 0x0092},
+ {0xa0, 0x7b, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x0d, 0x0092},
+ {0xa0, 0xa3, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x03, 0x0092},
+ {0xa0, 0xfb, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x05, 0x0092},
+ {0xa0, 0x00, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x06, 0x0092},
+ {0xa0, 0x03, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x09, 0x0092},
+ {0xa0, 0x08, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x0e, 0x0092},
+ {0xa0, 0x04, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x0f, 0x0092},
+ {0xa0, 0x18, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x10, 0x0092},
+ {0xa0, 0x18, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x11, 0x0092},
+ {0xa0, 0x18, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x12, 0x0092},
+ {0xa0, 0x18, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x15, 0x0092},
+ {0xa0, 0x00, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x16, 0x0092},
+ {0xa0, 0x0c, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x17, 0x0092},
+ {0xa0, 0x0c, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x18, 0x0092},
+ {0xa0, 0x04, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0xf7, 0x0101},
+ {0xa0, 0x05, 0x0012},
+ {0xa0, 0x78, 0x018d},
+ {0xa0, 0x0d, 0x0100},
+ {0xa0, 0x06, 0x0189},
+ {0xa0, 0x03, 0x01c5},
+ {0xa0, 0x13, 0x01cb},
+ {0xa0, 0x20, 0x0087},
+ {0xa0, 0x21, 0x0088},
+ {0xa0, 0x08, 0x0250},
+ {0xa0, 0x08, 0x0301},
+ {0xa0, 0x00, 0x01ad},
+ {0xa0, 0x01, 0x01b1},
+ {0xa0, 0x02, 0x0180},
+ {0xa0, 0x60, 0x0116},
+ {0xa0, 0x40, 0x0117},
+ {0xa0, 0x4c, 0x0118},
+ {0xa0, 0x03, 0x0008}, /* clock ? */
+ {0xa0, 0x08, 0x01c6}, /* sharpness+ */
+ {0xa0, 0x0f, 0x01cb}, /* sharpness- */
+ {0xa0, 0x13, 0x0120}, /* gamma 4 */
+ {0xa0, 0x38, 0x0121},
+ {0xa0, 0x59, 0x0122},
+ {0xa0, 0x79, 0x0123},
+ {0xa0, 0x92, 0x0124},
+ {0xa0, 0xa7, 0x0125},
+ {0xa0, 0xb9, 0x0126},
+ {0xa0, 0xc8, 0x0127},
+ {0xa0, 0xd4, 0x0128},
+ {0xa0, 0xdf, 0x0129},
+ {0xa0, 0xe7, 0x012a},
+ {0xa0, 0xee, 0x012b},
+ {0xa0, 0xf4, 0x012c},
+ {0xa0, 0xf9, 0x012d},
+ {0xa0, 0xfc, 0x012e},
+ {0xa0, 0xff, 0x012f},
+ {0xa0, 0x26, 0x0130},
+ {0xa0, 0x22, 0x0131},
+ {0xa0, 0x20, 0x0132},
+ {0xa0, 0x1c, 0x0133},
+ {0xa0, 0x16, 0x0134},
+ {0xa0, 0x13, 0x0135},
+ {0xa0, 0x10, 0x0136},
+ {0xa0, 0x0d, 0x0137},
+ {0xa0, 0x0b, 0x0138},
+ {0xa0, 0x09, 0x0139},
+ {0xa0, 0x07, 0x013a},
+ {0xa0, 0x06, 0x013b},
+ {0xa0, 0x05, 0x013c},
+ {0xa0, 0x04, 0x013d},
+ {0xa0, 0x03, 0x013e},
+ {0xa0, 0x02, 0x013f},
+ {0xa0, 0x58, 0x010a}, /* matrix */
+ {0xa0, 0xf4, 0x010b},
+ {0xa0, 0xf4, 0x010c},
+ {0xa0, 0xf4, 0x010d},
+ {0xa0, 0x58, 0x010e},
+ {0xa0, 0xf4, 0x010f},
+ {0xa0, 0xf4, 0x0110},
+ {0xa0, 0xf4, 0x0111},
+ {0xa0, 0x58, 0x0112},
+ {0xa0, 0x00, 0x0180},
+ {0xa0, 0x00, 0x0019},
+ {0xa0, 0x18, 0x0092},
+ {0xa0, 0x00, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x13, 0x0092},
+ {0xa0, 0x22, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x14, 0x0092},
+ {0xa0, 0x01, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x20, 0x0092},
+ {0xa0, 0x01, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x21, 0x0092},
+ {0xa0, 0x22, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x18, 0x0092},
+ {0xa0, 0x04, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x01, 0x00a3},
+ {0xa0, 0x22, 0x00a4},
+ {0xa0, 0x00, 0x0190},
+ {0xa0, 0x07, 0x0191},
+ {0xa0, 0xee, 0x0192},
+ {0xa0, 0x00, 0x0195},
+ {0xa0, 0x00, 0x0196},
+ {0xa0, 0x3a, 0x0197},
+ {0xa0, 0x10, 0x018c},
+ {0xa0, 0x20, 0x018f},
+ {0xa0, 0x0c, 0x01a9},
+ {0xa0, 0x28, 0x01aa},
+ {0xa0, 0x04, 0x001d},
+ {0xa0, 0x0f, 0x001e},
+ {0xa0, 0x19, 0x001f},
+ {0xa0, 0x1f, 0x0020},
+ {0xa0, 0x60, 0x011d},
+ {0xa0, 0x60, 0x011d},
+ {0xa0, 0x42, 0x0180},
+ {0xa0, 0x42, 0x0180},
+ {0xa0, 0x60, 0x0116},
+ {0xa0, 0x40, 0x0117},
+ {0xa0, 0x4c, 0x0118},
+ {0xa0, 0x01, 0x0000},
+ {0xa0, 0x01, 0x0000},
+ {0xa0, 0x00, 0x0002},
+ {0xa0, 0x03, 0x0008},
+ {0xa0, 0x08, 0x0010},
+ {0xa0, 0x02, 0x0003},
+ {0xa0, 0x80, 0x0004},
+ {0xa0, 0x01, 0x0005},
+ {0xa0, 0xe0, 0x0006},
+ {0xa0, 0x01, 0x0001},
+ {0xa0, 0x03, 0x0012},
+ {0xa0, 0x01, 0x0012},
+ {0xa0, 0x00, 0x0098},
+ {0xa0, 0x00, 0x009a},
+ {0xa0, 0x00, 0x011a},
+ {0xa0, 0x00, 0x011c},
+ {0xa0, 0xe8, 0x009c},
+ {0xa0, 0x88, 0x009e},
+ {0xa0, 0x55, 0x008b},
+ {0xa0, 0x18, 0x0092},
+ {0xa0, 0x00, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x0A, 0x0092},
+ {0xa0, 0x02, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x0B, 0x0092},
+ {0xa0, 0x02, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x0C, 0x0092},
+ {0xa0, 0x7b, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x0D, 0x0092},
+ {0xa0, 0xA3, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x03, 0x0092},
+ {0xa0, 0xfb, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x05, 0x0092},
+ {0xa0, 0x00, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x06, 0x0092},
+ {0xa0, 0x03, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x09, 0x0092},
+ {0xa0, 0x08, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x0E, 0x0092},
+ {0xa0, 0x04, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x0f, 0x0092},
+ {0xa0, 0x18, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x10, 0x0092},
+ {0xa0, 0x18, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x11, 0x0092},
+ {0xa0, 0x18, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x12, 0x0092},
+ {0xa0, 0x18, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x15, 0x0092},
+ {0xa0, 0x00, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x16, 0x0092},
+ {0xa0, 0x0c, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x17, 0x0092},
+ {0xa0, 0x0C, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x18, 0x0092},
+ {0xa0, 0x04, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0xf7, 0x0101},
+ {0xa0, 0x05, 0x0012},
+ {0xa0, 0x78, 0x018d},
+ {0xa0, 0x0d, 0x0100},
+ {0xa0, 0x06, 0x0189},
+ {0xa0, 0x03, 0x01c5},
+ {0xa0, 0x13, 0x01cb},
+ {0xa0, 0x20, 0x0087},
+ {0xa0, 0x21, 0x0088},
+ {0xa0, 0x08, 0x0250},
+ {0xa0, 0x08, 0x0301},
+ {0xa0, 0x00, 0x01ad},
+ {0xa0, 0x01, 0x01b1},
+ {0xa0, 0x02, 0x0180},
+ {0xa0, 0x60, 0x0116},
+ {0xa0, 0x40, 0x0117},
+ {0xa0, 0x4c, 0x0118},
+ {0xa0, 0x03, 0x0008}, /* clock ? */
+ {0xa0, 0x08, 0x01c6}, /* sharpness+ */
+ {0xa0, 0x0f, 0x01cb}, /* sharpness- */
+ {0xa0, 0x13, 0x0120}, /* gamma 4 */
+ {0xa0, 0x38, 0x0121},
+ {0xa0, 0x59, 0x0122},
+ {0xa0, 0x79, 0x0123},
+ {0xa0, 0x92, 0x0124},
+ {0xa0, 0xa7, 0x0125},
+ {0xa0, 0xb9, 0x0126},
+ {0xa0, 0xc8, 0x0127},
+ {0xa0, 0xd4, 0x0128},
+ {0xa0, 0xdf, 0x0129},
+ {0xa0, 0xe7, 0x012a},
+ {0xa0, 0xee, 0x012b},
+ {0xa0, 0xf4, 0x012c},
+ {0xa0, 0xf9, 0x012d},
+ {0xa0, 0xfc, 0x012e},
+ {0xa0, 0xff, 0x012f},
+ {0xa0, 0x26, 0x0130},
+ {0xa0, 0x22, 0x0131},
+ {0xa0, 0x20, 0x0132},
+ {0xa0, 0x1c, 0x0133},
+ {0xa0, 0x16, 0x0134},
+ {0xa0, 0x13, 0x0135},
+ {0xa0, 0x10, 0x0136},
+ {0xa0, 0x0d, 0x0137},
+ {0xa0, 0x0b, 0x0138},
+ {0xa0, 0x09, 0x0139},
+ {0xa0, 0x07, 0x013a},
+ {0xa0, 0x06, 0x013b},
+ {0xa0, 0x05, 0x013c},
+ {0xa0, 0x04, 0x013d},
+ {0xa0, 0x03, 0x013e},
+ {0xa0, 0x02, 0x013f},
+ {0xa0, 0x58, 0x010a}, /* matrix */
+ {0xa0, 0xf4, 0x010b},
+ {0xa0, 0xf4, 0x010c},
+ {0xa0, 0xf4, 0x010d},
+ {0xa0, 0x58, 0x010e},
+ {0xa0, 0xf4, 0x010f},
+ {0xa0, 0xf4, 0x0110},
+ {0xa0, 0xf4, 0x0111},
+ {0xa0, 0x58, 0x0112},
+ {0xa0, 0x00, 0x0180},
+ {0xa0, 0x00, 0x0019},
+ {0xa0, 0x18, 0x0092},
+ {0xa0, 0x00, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x13, 0x0092},
+ {0xa0, 0x22, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x14, 0x0092},
+ {0xa0, 0x01, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x20, 0x0092},
+ {0xa0, 0x01, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x21, 0x0092},
+ {0xa0, 0x22, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x18, 0x0092},
+ {0xa0, 0x04, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x01, 0x00a3},
+ {0xa0, 0x22, 0x00a4},
+ {0xa0, 0x00, 0x0190},
+ {0xa0, 0x07, 0x0191},
+ {0xa0, 0xee, 0x0192},
+ {0xa0, 0x00, 0x0195},
+ {0xa0, 0x00, 0x0196},
+ {0xa0, 0x3a, 0x0197},
+ {0xa0, 0x10, 0x018c},
+ {0xa0, 0x20, 0x018f},
+ {0xa0, 0x0c, 0x01a9},
+ {0xa0, 0x28, 0x01aa},
+ {0xa0, 0x04, 0x001d},
+ {0xa0, 0x0f, 0x001e},
+ {0xa0, 0x19, 0x001f},
+ {0xa0, 0x1f, 0x0020},
+ {0xa0, 0x60, 0x011d},
+ {0xa0, 0x60, 0x011d},
+ {0xa0, 0x42, 0x0180},
+ {0xa0, 0x42, 0x0180},
+ {0xa0, 0x60, 0x0116},
+ {0xa0, 0x40, 0x0117},
+ {0xa0, 0x4c, 0x0118},
+ {0xa0, 0x04, 0x01a7},
+ {0xa0, 0x20, 0x0092},
+ {0xa0, 0x01, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x21, 0x0092},
+ {0xa0, 0x5c, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x18, 0x0092},
+ {0xa0, 0x00, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x13, 0x0092},
+ {0xa0, 0x5c, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x14, 0x0092},
+ {0xa0, 0x01, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x18, 0x0092},
+ {0xa0, 0x04, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x00, 0x01a7},
+ {0xa0, 0x04, 0x01a7},
+ {0xa0, 0x00, 0x01a7},
+ {0xa0, 0x04, 0x01a7},
+ {0xa0, 0x20, 0x0092},
+ {0xa0, 0x01, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x21, 0x0092},
+ {0xa0, 0x96, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x18, 0x0092},
+ {0xa0, 0x00, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x13, 0x0092},
+ {0xa0, 0x96, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x14, 0x0092},
+ {0xa0, 0x01, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x18, 0x0092},
+ {0xa0, 0x04, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x00, 0x01a7},
+ {0xa0, 0x04, 0x01a7},
+ {0xa0, 0x00, 0x01a7},
+ {0xa0, 0x04, 0x01a7},
+ {0xa0, 0x00, 0x01a7},
+ {0xa0, 0x04, 0x01a7},
+ {0xa0, 0x20, 0x0092},
+ {0xa0, 0x01, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x21, 0x0092},
+ {0xa0, 0xd0, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x18, 0x0092},
+ {0xa0, 0x00, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x13, 0x0092},
+ {0xa0, 0xd0, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x14, 0x0092},
+ {0xa0, 0x01, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x18, 0x0092},
+ {0xa0, 0x04, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x00, 0x01a7},
+ {0xa0, 0x02, 0x0008},
+ {0xa0, 0x04, 0x01a7},
+ {0xa0, 0x00, 0x01a7},
+ {0xa0, 0x04, 0x01a7},
+ {0xa0, 0x20, 0x0092},
+ {0xa0, 0x02, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x21, 0x0092},
+ {0xa0, 0x0a, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x18, 0x0092},
+ {0xa0, 0x00, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x13, 0x0092},
+ {0xa0, 0x0a, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x14, 0x0092},
+ {0xa0, 0x02, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x18, 0x0092},
+ {0xa0, 0x04, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x00, 0x01a7},
+ {0xa0, 0x04, 0x01a7},
+ {0xa0, 0x00, 0x01a7},
+ {0xa0, 0x04, 0x01a7},
+ {0xa0, 0x20, 0x0092},
+ {0xa0, 0x02, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x21, 0x0092},
+ {0xa0, 0x44, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x18, 0x0092},
+ {0xa0, 0x00, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x13, 0x0092},
+ {0xa0, 0x44, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x14, 0x0092},
+ {0xa0, 0x02, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x18, 0x0092},
+ {0xa0, 0x04, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x00, 0x01a7},
+ {0xa0, 0x04, 0x01a7},
+ {0xa0, 0x00, 0x01a7},
+ {0xa0, 0x04, 0x01a7},
+ {0xa0, 0x20, 0x0092},
+ {0xa0, 0x02, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x21, 0x0092},
+ {0xa0, 0x7e, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x18, 0x0092},
+ {0xa0, 0x00, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x13, 0x0092},
+ {0xa0, 0x7e, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x14, 0x0092},
+ {0xa0, 0x02, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x18, 0x0092},
+ {0xa0, 0x04, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x00, 0x01a7},
+ {0xa0, 0x04, 0x01a7},
+ {0xa0, 0x00, 0x01a7},
+ {0xa0, 0x04, 0x01a7},
+ {}
+};
+
+static const struct usb_action gc0305_Initial[] = { /* 640x480 */
+ {0xa0, 0x01, 0x0000}, /* 00,00,01,cc */
+ {0xa0, 0x03, 0x0008}, /* 00,08,03,cc */
+ {0xa0, 0x01, 0x0010}, /* 00,10,01,cc */
+ {0xa0, 0x04, 0x0002}, /* 00,02,04,cc */
+ {0xa0, 0x02, 0x0003}, /* 00,03,02,cc */
+ {0xa0, 0x80, 0x0004}, /* 00,04,80,cc */
+ {0xa0, 0x01, 0x0005}, /* 00,05,01,cc */
+ {0xa0, 0xe0, 0x0006}, /* 00,06,e0,cc */
+ {0xa0, 0x01, 0x0001}, /* 00,01,01,cc */
+ {0xa0, 0x03, 0x0012}, /* 00,12,03,cc */
+ {0xa0, 0x01, 0x0012}, /* 00,12,01,cc */
+ {0xa0, 0x00, 0x0098}, /* 00,98,00,cc */
+ {0xa0, 0x00, 0x009a}, /* 00,9a,00,cc */
+ {0xa0, 0x00, 0x011a}, /* 01,1a,00,cc */
+ {0xa0, 0x00, 0x011c}, /* 01,1c,00,cc */
+ {0xa0, 0xe6, 0x009c}, /* 00,9c,e6,cc */
+ {0xa0, 0x86, 0x009e}, /* 00,9e,86,cc */
+ {0xa0, 0x98, 0x008b}, /* 00,8b,98,cc */
+ {0xaa, 0x13, 0x0002}, /* 00,13,02,aa */
+ {0xaa, 0x15, 0x0003}, /* 00,15,03,aa */
+ {0xaa, 0x01, 0x0000}, /* 00,01,00,aa */
+ {0xaa, 0x02, 0x0000}, /* 00,02,00,aa */
+ {0xaa, 0x1a, 0x0000}, /* 00,1a,00,aa */
+ {0xaa, 0x1c, 0x0017}, /* 00,1c,17,aa */
+ {0xaa, 0x1d, 0x0080}, /* 00,1d,80,aa */
+ {0xaa, 0x1f, 0x0008}, /* 00,1f,08,aa */
+ {0xaa, 0x21, 0x0012}, /* 00,21,12,aa */
+ {0xa0, 0x82, 0x0086}, /* 00,86,82,cc */
+ {0xa0, 0x83, 0x0087}, /* 00,87,83,cc */
+ {0xa0, 0x84, 0x0088}, /* 00,88,84,cc */
+ {0xaa, 0x05, 0x0000}, /* 00,05,00,aa */
+ {0xaa, 0x0a, 0x0000}, /* 00,0a,00,aa */
+ {0xaa, 0x0b, 0x00b0}, /* 00,0b,b0,aa */
+ {0xaa, 0x0c, 0x0000}, /* 00,0c,00,aa */
+ {0xaa, 0x0d, 0x00b0}, /* 00,0d,b0,aa */
+ {0xaa, 0x0e, 0x0000}, /* 00,0e,00,aa */
+ {0xaa, 0x0f, 0x00b0}, /* 00,0f,b0,aa */
+ {0xaa, 0x10, 0x0000}, /* 00,10,00,aa */
+ {0xaa, 0x11, 0x00b0}, /* 00,11,b0,aa */
+ {0xaa, 0x16, 0x0001}, /* 00,16,01,aa */
+ {0xaa, 0x17, 0x00e6}, /* 00,17,e6,aa */
+ {0xaa, 0x18, 0x0002}, /* 00,18,02,aa */
+ {0xaa, 0x19, 0x0086}, /* 00,19,86,aa */
+ {0xaa, 0x20, 0x0000}, /* 00,20,00,aa */
+ {0xaa, 0x1b, 0x0020}, /* 00,1b,20,aa */
+ {0xa0, 0xb7, 0x0101}, /* 01,01,b7,cc */
+ {0xa0, 0x05, 0x0012}, /* 00,12,05,cc */
+ {0xa0, 0x0d, 0x0100}, /* 01,00,0d,cc */
+ {0xa0, 0x76, 0x0189}, /* 01,89,76,cc */
+ {0xa0, 0x09, 0x01ad}, /* 01,ad,09,cc */
+ {0xa0, 0x03, 0x01c5}, /* 01,c5,03,cc */
+ {0xa0, 0x13, 0x01cb}, /* 01,cb,13,cc */
+ {0xa0, 0x08, 0x0250}, /* 02,50,08,cc */
+ {0xa0, 0x08, 0x0301}, /* 03,01,08,cc */
+ {0xa0, 0x60, 0x01a8}, /* 01,a8,60,cc */
+ {0xa0, 0x85, 0x018d}, /* 01,8d,85,cc */
+ {0xa0, 0x00, 0x011e}, /* 01,1e,00,cc */
+ {0xa0, 0x52, 0x0116}, /* 01,16,52,cc */
+ {0xa0, 0x40, 0x0117}, /* 01,17,40,cc */
+ {0xa0, 0x52, 0x0118}, /* 01,18,52,cc */
+ {0xa0, 0x03, 0x0113}, /* 01,13,03,cc */
+ {}
+};
+static const struct usb_action gc0305_InitialScale[] = { /* 320x240 */
+ {0xa0, 0x01, 0x0000}, /* 00,00,01,cc */
+ {0xa0, 0x03, 0x0008}, /* 00,08,03,cc */
+ {0xa0, 0x01, 0x0010}, /* 00,10,01,cc */
+ {0xa0, 0x10, 0x0002}, /* 00,02,10,cc */
+ {0xa0, 0x02, 0x0003}, /* 00,03,02,cc */
+ {0xa0, 0x80, 0x0004}, /* 00,04,80,cc */
+ {0xa0, 0x01, 0x0005}, /* 00,05,01,cc */
+ {0xa0, 0xe0, 0x0006}, /* 00,06,e0,cc */
+ {0xa0, 0x01, 0x0001}, /* 00,01,01,cc */
+ {0xa0, 0x03, 0x0012}, /* 00,12,03,cc */
+ {0xa0, 0x01, 0x0012}, /* 00,12,01,cc */
+ {0xa0, 0x00, 0x0098}, /* 00,98,00,cc */
+ {0xa0, 0x00, 0x009a}, /* 00,9a,00,cc */
+ {0xa0, 0x00, 0x011a}, /* 01,1a,00,cc */
+ {0xa0, 0x00, 0x011c}, /* 01,1c,00,cc */
+ {0xa0, 0xe8, 0x009c}, /* 00,9c,e8,cc */
+ {0xa0, 0x88, 0x009e}, /* 00,9e,88,cc */
+ {0xa0, 0x98, 0x008b}, /* 00,8b,98,cc */
+ {0xaa, 0x13, 0x0000}, /* 00,13,00,aa */
+ {0xaa, 0x15, 0x0001}, /* 00,15,01,aa */
+ {0xaa, 0x01, 0x0000}, /* 00,01,00,aa */
+ {0xaa, 0x02, 0x0000}, /* 00,02,00,aa */
+ {0xaa, 0x1a, 0x0000}, /* 00,1a,00,aa */
+ {0xaa, 0x1c, 0x0017}, /* 00,1c,17,aa */
+ {0xaa, 0x1d, 0x0080}, /* 00,1d,80,aa */
+ {0xaa, 0x1f, 0x0008}, /* 00,1f,08,aa */
+ {0xaa, 0x21, 0x0012}, /* 00,21,12,aa */
+ {0xa0, 0x82, 0x0086}, /* 00,86,82,cc */
+ {0xa0, 0x83, 0x0087}, /* 00,87,83,cc */
+ {0xa0, 0x84, 0x0088}, /* 00,88,84,cc */
+ {0xaa, 0x05, 0x0000}, /* 00,05,00,aa */
+ {0xaa, 0x0a, 0x0000}, /* 00,0a,00,aa */
+ {0xaa, 0x0b, 0x00b0}, /* 00,0b,b0,aa */
+ {0xaa, 0x0c, 0x0000}, /* 00,0c,00,aa */
+ {0xaa, 0x0d, 0x00b0}, /* 00,0d,b0,aa */
+ {0xaa, 0x0e, 0x0000}, /* 00,0e,00,aa */
+ {0xaa, 0x0f, 0x00b0}, /* 00,0f,b0,aa */
+ {0xaa, 0x10, 0x0000}, /* 00,10,00,aa */
+ {0xaa, 0x11, 0x00b0}, /* 00,11,b0,aa */
+ {0xaa, 0x16, 0x0001}, /* 00,16,01,aa */
+ {0xaa, 0x17, 0x00e8}, /* 00,17,e8,aa */
+ {0xaa, 0x18, 0x0002}, /* 00,18,02,aa */
+ {0xaa, 0x19, 0x0088}, /* 00,19,88,aa */
+ {0xaa, 0x20, 0x0000}, /* 00,20,00,aa */
+ {0xaa, 0x1b, 0x0020}, /* 00,1b,20,aa */
+ {0xa0, 0xb7, 0x0101}, /* 01,01,b7,cc */
+ {0xa0, 0x05, 0x0012}, /* 00,12,05,cc */
+ {0xa0, 0x0d, 0x0100}, /* 01,00,0d,cc */
+ {0xa0, 0x76, 0x0189}, /* 01,89,76,cc */
+ {0xa0, 0x09, 0x01ad}, /* 01,ad,09,cc */
+ {0xa0, 0x03, 0x01c5}, /* 01,c5,03,cc */
+ {0xa0, 0x13, 0x01cb}, /* 01,cb,13,cc */
+ {0xa0, 0x08, 0x0250}, /* 02,50,08,cc */
+ {0xa0, 0x08, 0x0301}, /* 03,01,08,cc */
+ {0xa0, 0x60, 0x01a8}, /* 01,a8,60,cc */
+ {0xa0, 0x00, 0x011e}, /* 01,1e,00,cc */
+ {0xa0, 0x52, 0x0116}, /* 01,16,52,cc */
+ {0xa0, 0x40, 0x0117}, /* 01,17,40,cc */
+ {0xa0, 0x52, 0x0118}, /* 01,18,52,cc */
+ {0xa0, 0x03, 0x0113}, /* 01,13,03,cc */
+ {}
+};
+static const struct usb_action gc0305_50HZ[] = {
+ {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */
+ {0xaa, 0x83, 0x0002}, /* 00,83,02,aa */
+ {0xaa, 0x84, 0x0038}, /* 00,84,38,aa */ /* win: 00,84,ec */
+ {0xa0, 0x00, 0x0190}, /* 01,90,00,cc */
+ {0xa0, 0x0b, 0x0191}, /* 01,91,0b,cc */
+ {0xa0, 0x18, 0x0192}, /* 01,92,18,cc */ /* win: 01,92,10 */
+ {0xa0, 0x00, 0x0195}, /* 01,95,00,cc */
+ {0xa0, 0x00, 0x0196}, /* 01,96,00,cc */
+ {0xa0, 0x8e, 0x0197}, /* 01,97,8e,cc */ /* win: 01,97,ec */
+ {0xa0, 0x0e, 0x018c}, /* 01,8c,0e,cc */
+ {0xa0, 0x15, 0x018f}, /* 01,8f,15,cc */
+ {0xa0, 0x10, 0x01a9}, /* 01,a9,10,cc */
+ {0xa0, 0x24, 0x01aa}, /* 01,aa,24,cc */
+ {0xa0, 0x62, 0x001d}, /* 00,1d,62,cc */
+ {0xa0, 0x90, 0x001e}, /* 00,1e,90,cc */
+ {0xa0, 0xc8, 0x001f}, /* 00,1f,c8,cc */
+ {0xa0, 0xff, 0x0020}, /* 00,20,ff,cc */
+ {0xa0, 0x60, 0x011d}, /* 01,1d,60,cc */
+ {0xa0, 0x42, 0x0180}, /* 01,80,42,cc */
+/* {0xa0, 0x85, 0x018d}, * 01,8d,85,cc * * if 640x480 */
+ {}
+};
+static const struct usb_action gc0305_60HZ[] = {
+ {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */
+ {0xaa, 0x83, 0x0000}, /* 00,83,00,aa */
+ {0xaa, 0x84, 0x00ec}, /* 00,84,ec,aa */
+ {0xa0, 0x00, 0x0190}, /* 01,90,00,cc */
+ {0xa0, 0x0b, 0x0191}, /* 01,91,0b,cc */
+ {0xa0, 0x10, 0x0192}, /* 01,92,10,cc */
+ {0xa0, 0x00, 0x0195}, /* 01,95,00,cc */
+ {0xa0, 0x00, 0x0196}, /* 01,96,00,cc */
+ {0xa0, 0xec, 0x0197}, /* 01,97,ec,cc */
+ {0xa0, 0x0e, 0x018c}, /* 01,8c,0e,cc */
+ {0xa0, 0x15, 0x018f}, /* 01,8f,15,cc */
+ {0xa0, 0x10, 0x01a9}, /* 01,a9,10,cc */
+ {0xa0, 0x24, 0x01aa}, /* 01,aa,24,cc */
+ {0xa0, 0x62, 0x001d}, /* 00,1d,62,cc */
+ {0xa0, 0x90, 0x001e}, /* 00,1e,90,cc */
+ {0xa0, 0xc8, 0x001f}, /* 00,1f,c8,cc */
+ {0xa0, 0xff, 0x0020}, /* 00,20,ff,cc */
+ {0xa0, 0x60, 0x011d}, /* 01,1d,60,cc */
+ {0xa0, 0x42, 0x0180}, /* 01,80,42,cc */
+ {0xa0, 0x80, 0x018d}, /* 01,8d,80,cc */
+ {}
+};
+
+static const struct usb_action gc0305_NoFliker[] = {
+ {0xa0, 0x0c, 0x0100}, /* 01,00,0c,cc */
+ {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */
+ {0xaa, 0x83, 0x0000}, /* 00,83,00,aa */
+ {0xaa, 0x84, 0x0020}, /* 00,84,20,aa */
+ {0xa0, 0x00, 0x0190}, /* 01,90,00,cc */
+ {0xa0, 0x00, 0x0191}, /* 01,91,00,cc */
+ {0xa0, 0x48, 0x0192}, /* 01,92,48,cc */
+ {0xa0, 0x00, 0x0195}, /* 01,95,00,cc */
+ {0xa0, 0x00, 0x0196}, /* 01,96,00,cc */
+ {0xa0, 0x10, 0x0197}, /* 01,97,10,cc */
+ {0xa0, 0x0e, 0x018c}, /* 01,8c,0e,cc */
+ {0xa0, 0x15, 0x018f}, /* 01,8f,15,cc */
+ {0xa0, 0x62, 0x001d}, /* 00,1d,62,cc */
+ {0xa0, 0x90, 0x001e}, /* 00,1e,90,cc */
+ {0xa0, 0xc8, 0x001f}, /* 00,1f,c8,cc */
+ {0xa0, 0xff, 0x0020}, /* 00,20,ff,cc */
+ {0xa0, 0x60, 0x011d}, /* 01,1d,60,cc */
+ {0xa0, 0x03, 0x0180}, /* 01,80,03,cc */
+ {0xa0, 0x80, 0x018d}, /* 01,8d,80,cc */
+ {}
+};
+
+/* play poker with registers at your own risk !! */
+static const struct usb_action hdcs2020xx_Initial[] = {
+ {0xa0, 0x01, 0x0000},
+ {0xa0, 0x03, 0x0008},
+ {0xa0, 0x0e, 0x0010},
+ {0xa0, 0x10, 0x0002},
+ {0xa0, 0x02, 0x0003},
+ {0xa0, 0x80, 0x0004},
+ {0xa0, 0x01, 0x0005},
+ {0xa0, 0xd0, 0x0006}, /* D0 ?? E0 did not start */
+ {0xa0, 0x01, 0x0001},
+ {0xa0, 0x03, 0x0012},
+ {0xa0, 0x01, 0x0012},
+ {0xa0, 0x08, 0x008d},
+ {0xa0, 0x08, 0x0098},
+ {0xa0, 0x02, 0x009a},
+ {0xa0, 0x08, 0x011a},
+ {0xa0, 0x02, 0x011c},
+ {0xa0, 0x01, 0x009b},
+ {0xa0, 0xd8, 0x009c},
+ {0xa0, 0x02, 0x009d},
+ {0xa0, 0x88, 0x009e},
+ {0xaa, 0x02, 0x0002},
+ {0xaa, 0x07, 0x0006},
+ {0xaa, 0x08, 0x0002},
+ {0xaa, 0x09, 0x0006},
+ {0xaa, 0x0a, 0x0001},
+ {0xaa, 0x0b, 0x0001},
+ {0xaa, 0x0c, 0x0008},
+ {0xaa, 0x0d, 0x0000},
+ {0xaa, 0x10, 0x0000},
+ {0xaa, 0x12, 0x0005},
+ {0xaa, 0x13, 0x0063},
+ {0xaa, 0x15, 0x0070},
+ {0xa0, 0x37, 0x0101},
+ {0xa0, 0x0d, 0x0100},
+ {0xa0, 0x06, 0x0189},
+ {0xa0, 0x00, 0x01ad},
+ {0xa0, 0x03, 0x01c5},
+ {0xa0, 0x13, 0x01cb},
+ {0xa0, 0x08, 0x0250},
+ {0xa0, 0x08, 0x0301},
+ {0xa0, 0x70, 0x018d},
+ {0xa1, 0x01, 0x0002},
+ {0xa1, 0x01, 0x0008},
+ {0xa0, 0x03, 0x0008}, /* clock ? */
+ {0xa0, 0x04, 0x01c6}, /* sharpness+ */
+ {0xa1, 0x01, 0x01c8},
+ {0xa1, 0x01, 0x01c9},
+ {0xa1, 0x01, 0x01ca},
+ {0xa0, 0x07, 0x01cb}, /* sharpness- */
+ {0xa0, 0x11, 0x0120}, /* gamma ~4 */
+ {0xa0, 0x37, 0x0121},
+ {0xa0, 0x58, 0x0122},
+ {0xa0, 0x79, 0x0123},
+ {0xa0, 0x91, 0x0124},
+ {0xa0, 0xa6, 0x0125},
+ {0xa0, 0xb8, 0x0126},
+ {0xa0, 0xc7, 0x0127},
+ {0xa0, 0xd3, 0x0128},
+ {0xa0, 0xde, 0x0129},
+ {0xa0, 0xe6, 0x012a},
+ {0xa0, 0xed, 0x012b},
+ {0xa0, 0xf3, 0x012c},
+ {0xa0, 0xf8, 0x012d},
+ {0xa0, 0xfb, 0x012e},
+ {0xa0, 0xff, 0x012f},
+ {0xa0, 0x26, 0x0130},
+ {0xa0, 0x23, 0x0131},
+ {0xa0, 0x20, 0x0132},
+ {0xa0, 0x1c, 0x0133},
+ {0xa0, 0x16, 0x0134},
+ {0xa0, 0x13, 0x0135},
+ {0xa0, 0x10, 0x0136},
+ {0xa0, 0x0d, 0x0137},
+ {0xa0, 0x0b, 0x0138},
+ {0xa0, 0x09, 0x0139},
+ {0xa0, 0x07, 0x013a},
+ {0xa0, 0x06, 0x013b},
+ {0xa0, 0x05, 0x013c},
+ {0xa0, 0x04, 0x013d},
+ {0xa0, 0x03, 0x013e},
+ {0xa0, 0x02, 0x013f},
+
+ {0xa0, 0x4c, 0x010a}, /* matrix */
+ {0xa0, 0xf5, 0x010b},
+ {0xa0, 0xff, 0x010c},
+ {0xa0, 0xf9, 0x010d},
+ {0xa0, 0x51, 0x010e},
+ {0xa0, 0xf5, 0x010f},
+ {0xa0, 0xfb, 0x0110},
+ {0xa0, 0xed, 0x0111},
+ {0xa0, 0x5f, 0x0112},
+
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x00, 0x0180},
+ {0xa0, 0x00, 0x0019},
+ {0xa0, 0x20, 0x0087},
+ {0xa0, 0x21, 0x0088},
+ {0xaa, 0x20, 0x0004},
+ {0xaa, 0x21, 0x003d},
+ {0xaa, 0x03, 0x0041},
+ {0xaa, 0x04, 0x0010},
+ {0xaa, 0x05, 0x003d},
+ {0xaa, 0x0e, 0x0001},
+ {0xaa, 0x0f, 0x0000},
+ {0xa0, 0x14, 0x01a9},
+ {0xa0, 0x24, 0x01aa},
+ {0xa0, 0x00, 0x0190},
+ {0xa0, 0x04, 0x0191},
+ {0xa0, 0x3d, 0x0192},
+ {0xa0, 0x00, 0x0195},
+ {0xa0, 0x00, 0x0196},
+ {0xa0, 0x9b, 0x0197},
+ {0xa0, 0x10, 0x018c},
+ {0xa0, 0x20, 0x018f},
+ {0xa0, 0x41, 0x001d},
+ {0xa0, 0x6f, 0x001e},
+ {0xa0, 0xad, 0x001f},
+ {0xa0, 0xff, 0x0020},
+ {0xa0, 0x0f, 0x0087},
+ {0xa0, 0x0e, 0x0088},
+ {0xa0, 0x40, 0x0180},
+ {0xa1, 0x01, 0x0195},
+ {0xa1, 0x01, 0x0196},
+ {0xa1, 0x01, 0x0197},
+ {0xa0, 0x3d, 0x0192},
+ {0xa0, 0x04, 0x0191},
+ {0xa0, 0x00, 0x0190},
+ {0xa0, 0x1d, 0x0116},
+ {0xa0, 0x40, 0x0117},
+ {0xa0, 0x85, 0x0118},
+ {0xa1, 0x01, 0x0116},
+ {0xa1, 0x01, 0x0118},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x42, 0x0180},
+ {0xa0, 0x1d, 0x0116},
+ {0xa0, 0x40, 0x0117},
+ {0xa0, 0x85, 0x0118},
+ {0xa1, 0x01, 0x0116},
+ {0xa1, 0x01, 0x0118},
+/* {0xa0, 0x02, 0x0008}, */
+ {0xa0, 0x00, 0x0007},
+ {}
+};
+
+static const struct usb_action hdcs2020xx_InitialScale[] = {
+ {0xa0, 0x01, 0x0000},
+ {0xa0, 0x03, 0x0008},
+ {0xa0, 0x0e, 0x0010},
+ {0xa0, 0x00, 0x0002},
+ {0xa0, 0x02, 0x0003},
+ {0xa0, 0x80, 0x0004},
+ {0xa0, 0x01, 0x0005},
+ {0xa0, 0xe0, 0x0006},
+ {0xa0, 0x01, 0x0001},
+ {0xa0, 0x03, 0x0012},
+ {0xa0, 0x01, 0x0012},
+ {0xa0, 0x08, 0x008d},
+ {0xa0, 0x00, 0x0098},
+ {0xa0, 0x03, 0x009a},
+ {0xa0, 0x00, 0x011a},
+ {0xa0, 0x03, 0x011c},
+ {0xa0, 0x01, 0x009b},
+ {0xa0, 0xe6, 0x009c},
+ {0xa0, 0x02, 0x009d},
+ {0xa0, 0x86, 0x009e},
+ {0xaa, 0x02, 0x0002},
+ {0xaa, 0x07, 0x0006},
+ {0xaa, 0x08, 0x0002},
+ {0xaa, 0x09, 0x0006},
+ {0xaa, 0x0a, 0x0001},
+ {0xaa, 0x0b, 0x0001},
+ {0xaa, 0x0c, 0x0008},
+ {0xaa, 0x0d, 0x0000},
+ {0xaa, 0x10, 0x0000},
+ {0xaa, 0x12, 0x0005},
+ {0xaa, 0x13, 0x0063},
+ {0xaa, 0x15, 0x0070},
+ {0xa0, 0xb7, 0x0101},
+ {0xa0, 0x0d, 0x0100},
+ {0xa0, 0x06, 0x0189},
+ {0xa0, 0x00, 0x01ad},
+ {0xa0, 0x03, 0x01c5},
+ {0xa0, 0x13, 0x01cb},
+ {0xa0, 0x08, 0x0250},
+ {0xa0, 0x08, 0x0301},
+ {0xa0, 0x70, 0x018d},
+ {0xa1, 0x01, 0x0002},
+ {0xa1, 0x01, 0x0008},
+ {0xa0, 0x03, 0x0008}, /* clock ? */
+ {0xa0, 0x04, 0x01c6}, /* sharpness+ */
+ {0xa1, 0x01, 0x01c8},
+ {0xa1, 0x01, 0x01c9},
+ {0xa1, 0x01, 0x01ca},
+ {0xa0, 0x07, 0x01cb}, /* sharpness- */
+ {0xa0, 0x11, 0x0120}, /* gamma ~4*/
+ {0xa0, 0x37, 0x0121},
+ {0xa0, 0x58, 0x0122},
+ {0xa0, 0x79, 0x0123},
+ {0xa0, 0x91, 0x0124},
+ {0xa0, 0xa6, 0x0125},
+ {0xa0, 0xb8, 0x0126},
+ {0xa0, 0xc7, 0x0127},
+ {0xa0, 0xd3, 0x0128},
+ {0xa0, 0xde, 0x0129},
+ {0xa0, 0xe6, 0x012a},
+ {0xa0, 0xed, 0x012b},
+ {0xa0, 0xf3, 0x012c},
+ {0xa0, 0xf8, 0x012d},
+ {0xa0, 0xfb, 0x012e},
+ {0xa0, 0xff, 0x012f},
+ {0xa0, 0x26, 0x0130},
+ {0xa0, 0x23, 0x0131},
+ {0xa0, 0x20, 0x0132},
+ {0xa0, 0x1c, 0x0133},
+ {0xa0, 0x16, 0x0134},
+ {0xa0, 0x13, 0x0135},
+ {0xa0, 0x10, 0x0136},
+ {0xa0, 0x0d, 0x0137},
+ {0xa0, 0x0b, 0x0138},
+ {0xa0, 0x09, 0x0139},
+ {0xa0, 0x07, 0x013a},
+ {0xa0, 0x06, 0x013b},
+ {0xa0, 0x05, 0x013c},
+ {0xa0, 0x04, 0x013d},
+ {0xa0, 0x03, 0x013e},
+ {0xa0, 0x02, 0x013f},
+ {0xa0, 0x60, 0x010a}, /* matrix */
+ {0xa0, 0xff, 0x010b},
+ {0xa0, 0xff, 0x010c},
+ {0xa0, 0xff, 0x010d},
+ {0xa0, 0x60, 0x010e},
+ {0xa0, 0xff, 0x010f},
+ {0xa0, 0xff, 0x0110},
+ {0xa0, 0xff, 0x0111},
+ {0xa0, 0x60, 0x0112},
+
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x00, 0x0180},
+ {0xa0, 0x00, 0x0019},
+ {0xa0, 0x20, 0x0087},
+ {0xa0, 0x21, 0x0088},
+ {0xaa, 0x20, 0x0002},
+ {0xaa, 0x21, 0x001b},
+ {0xaa, 0x03, 0x0044},
+ {0xaa, 0x04, 0x0008},
+ {0xaa, 0x05, 0x001b},
+ {0xaa, 0x0e, 0x0001},
+ {0xaa, 0x0f, 0x0000},
+ {0xa0, 0x14, 0x01a9},
+ {0xa0, 0x24, 0x01aa},
+ {0xa0, 0x00, 0x0190},
+ {0xa0, 0x02, 0x0191},
+ {0xa0, 0x1b, 0x0192},
+ {0xa0, 0x00, 0x0195},
+ {0xa0, 0x00, 0x0196},
+ {0xa0, 0x4d, 0x0197},
+ {0xa0, 0x10, 0x018c},
+ {0xa0, 0x20, 0x018f},
+ {0xa0, 0x44, 0x001d},
+ {0xa0, 0x6f, 0x001e},
+ {0xa0, 0xad, 0x001f},
+ {0xa0, 0xeb, 0x0020},
+ {0xa0, 0x0f, 0x0087},
+ {0xa0, 0x0e, 0x0088},
+ {0xa0, 0x40, 0x0180},
+ {0xa1, 0x01, 0x0195},
+ {0xa1, 0x01, 0x0196},
+ {0xa1, 0x01, 0x0197},
+ {0xa0, 0x1b, 0x0192},
+ {0xa0, 0x02, 0x0191},
+ {0xa0, 0x00, 0x0190},
+ {0xa0, 0x1d, 0x0116},
+ {0xa0, 0x40, 0x0117},
+ {0xa0, 0x99, 0x0118},
+ {0xa1, 0x01, 0x0116},
+ {0xa1, 0x01, 0x0118},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x42, 0x0180},
+ {0xa0, 0x1d, 0x0116},
+ {0xa0, 0x40, 0x0117},
+ {0xa0, 0x99, 0x0118},
+/* {0xa0, 0x02, 0x0008}, */
+ {0xa0, 0x00, 0x0007},
+/* {0xa0, 0x18, 0x00fe}, */
+ {}
+};
+static const struct usb_action hdcs2020xb_Initial[] = {
+ {0xa0, 0x01, 0x0000},
+ {0xa0, 0x11, 0x0002},
+ {0xa0, 0x03, 0x0008}, /* qtable 0x05 */
+ {0xa0, 0x08, 0x0010},
+ {0xa0, 0x02, 0x0003},
+ {0xa0, 0x80, 0x0004},
+ {0xa0, 0x01, 0x0005},
+ {0xa0, 0xe0, 0x0006},
+ {0xa0, 0x01, 0x0001},
+ {0xa0, 0x03, 0x0012},
+ {0xa0, 0x01, 0x0012},
+ {0xa0, 0x00, 0x0098},
+ {0xa0, 0x00, 0x009a},
+ {0xa0, 0x00, 0x011a},
+ {0xa0, 0x00, 0x011c},
+ {0xa0, 0xe8, 0x009c},
+ {0xa0, 0x88, 0x009e},
+ {0xaa, 0x1c, 0x0000},
+ {0xaa, 0x0a, 0x0001},
+ {0xaa, 0x0b, 0x0006},
+ {0xaa, 0x0c, 0x007b},
+ {0xaa, 0x0d, 0x00a7},
+ {0xaa, 0x03, 0x00fb},
+ {0xaa, 0x05, 0x0000},
+ {0xaa, 0x06, 0x0003},
+ {0xaa, 0x09, 0x0008},
+
+ {0xaa, 0x0f, 0x0018}, /* set sensor gain */
+ {0xaa, 0x10, 0x0018},
+ {0xaa, 0x11, 0x0018},
+ {0xaa, 0x12, 0x0018},
+
+ {0xaa, 0x15, 0x004e},
+ {0xaa, 0x1c, 0x0004},
+ {0xa0, 0xb7, 0x0101},
+ {0xa0, 0x05, 0x0012},
+ {0xa0, 0x70, 0x018d},
+ {0xa0, 0x0d, 0x0100},
+ {0xa0, 0x06, 0x0189},
+ {0xa0, 0x03, 0x01c5},
+ {0xa0, 0x13, 0x01cb},
+ {0xa0, 0x08, 0x0250},
+ {0xa0, 0x08, 0x0301},
+ {0xa1, 0x01, 0x0002},
+ {0xa1, 0x01, 0x0008},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x02, 0x0180},
+ {0xa0, 0x40, 0x0116},
+ {0xa0, 0x40, 0x0117},
+ {0xa0, 0x40, 0x0118},
+ {0xa1, 0x01, 0x0008},
+ {0xa0, 0x03, 0x0008}, /* clock ? */
+ {0xa0, 0x08, 0x01c6}, /* sharpness+ */
+ {0xa1, 0x01, 0x01c8},
+ {0xa1, 0x01, 0x01c9},
+ {0xa1, 0x01, 0x01ca},
+ {0xa0, 0x0f, 0x01cb}, /* sharpness- */
+ {0xa0, 0x13, 0x0120}, /* gamma 4 */
+ {0xa0, 0x38, 0x0121},
+ {0xa0, 0x59, 0x0122},
+ {0xa0, 0x79, 0x0123},
+ {0xa0, 0x92, 0x0124},
+ {0xa0, 0xa7, 0x0125},
+ {0xa0, 0xb9, 0x0126},
+ {0xa0, 0xc8, 0x0127},
+ {0xa0, 0xd4, 0x0128},
+ {0xa0, 0xdf, 0x0129},
+ {0xa0, 0xe7, 0x012a},
+ {0xa0, 0xee, 0x012b},
+ {0xa0, 0xf4, 0x012c},
+ {0xa0, 0xf9, 0x012d},
+ {0xa0, 0xfc, 0x012e},
+ {0xa0, 0xff, 0x012f},
+ {0xa0, 0x26, 0x0130},
+ {0xa0, 0x22, 0x0131},
+ {0xa0, 0x20, 0x0132},
+ {0xa0, 0x1c, 0x0133},
+ {0xa0, 0x16, 0x0134},
+ {0xa0, 0x13, 0x0135},
+ {0xa0, 0x10, 0x0136},
+ {0xa0, 0x0d, 0x0137},
+ {0xa0, 0x0b, 0x0138},
+ {0xa0, 0x09, 0x0139},
+ {0xa0, 0x07, 0x013a},
+ {0xa0, 0x06, 0x013b},
+ {0xa0, 0x05, 0x013c},
+ {0xa0, 0x04, 0x013d},
+ {0xa0, 0x03, 0x013e},
+ {0xa0, 0x02, 0x013f},
+
+ {0xa0, 0x66, 0x010a}, /* matrix */
+ {0xa0, 0xed, 0x010b},
+ {0xa0, 0xed, 0x010c},
+ {0xa0, 0xed, 0x010d},
+ {0xa0, 0x66, 0x010e},
+ {0xa0, 0xed, 0x010f},
+ {0xa0, 0xed, 0x0110},
+ {0xa0, 0xed, 0x0111},
+ {0xa0, 0x66, 0x0112},
+
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x00, 0x0180},
+ {0xa0, 0x00, 0x0019},
+ {0xaa, 0x13, 0x0031},
+ {0xaa, 0x14, 0x0001},
+ {0xaa, 0x0e, 0x0004},
+ {0xaa, 0x19, 0x00cd},
+ {0xa0, 0x00, 0x0190},
+ {0xa0, 0x02, 0x0191},
+ {0xa0, 0x62, 0x0192},
+ {0xa0, 0x00, 0x0195},
+ {0xa0, 0x00, 0x0196},
+ {0xa0, 0x3d, 0x0197},
+ {0xa0, 0x10, 0x018c},
+ {0xa0, 0x20, 0x018f},
+
+ {0xa0, 0x0c, 0x01a9}, /* 0x14 */
+ {0xa0, 0x28, 0x01aa},
+ {0xa0, 0x04, 0x001d},
+ {0xa0, 0x18, 0x001e},
+ {0xa0, 0x2c, 0x001f},
+ {0xa0, 0x41, 0x0020},
+ {0xa0, 0x60, 0x011d},
+ {0xa0, 0x42, 0x0180},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x42, 0x0180},
+ {0xa0, 0x40, 0x0116},
+ {0xa0, 0x40, 0x0117},
+ {0xa0, 0x40, 0x0118},
+ {}
+};
+static const struct usb_action hdcs2020xb_InitialScale[] = {
+ {0xa0, 0x01, 0x0000},
+ {0xa0, 0x00, 0x0002},
+ {0xa0, 0x03, 0x0008},
+ {0xa0, 0x08, 0x0010},
+ {0xa0, 0x02, 0x0003},
+ {0xa0, 0x80, 0x0004},
+ {0xa0, 0x01, 0x0005},
+ {0xa0, 0xe0, 0x0006},
+ {0xa0, 0x01, 0x0001},
+ {0xa0, 0x03, 0x0012},
+ {0xa0, 0x01, 0x0012},
+ {0xa0, 0x00, 0x0098},
+ {0xa0, 0x00, 0x009a},
+ {0xa0, 0x00, 0x011a},
+ {0xa0, 0x00, 0x011c},
+ {0xa0, 0xe8, 0x009c},
+ {0xa0, 0x88, 0x009e},
+ {0xaa, 0x1c, 0x0000},
+ {0xaa, 0x0a, 0x0001},
+ {0xaa, 0x0b, 0x0006},
+ {0xaa, 0x0c, 0x007a},
+ {0xaa, 0x0d, 0x00a7},
+ {0xaa, 0x03, 0x00fb},
+ {0xaa, 0x05, 0x0000},
+ {0xaa, 0x06, 0x0003},
+ {0xaa, 0x09, 0x0008},
+ {0xaa, 0x0f, 0x0018}, /* original setting */
+ {0xaa, 0x10, 0x0018},
+ {0xaa, 0x11, 0x0018},
+ {0xaa, 0x12, 0x0018},
+ {0xaa, 0x15, 0x004e},
+ {0xaa, 0x1c, 0x0004},
+ {0xa0, 0xf7, 0x0101},
+ {0xa0, 0x05, 0x0012},
+ {0xa0, 0x70, 0x018d},
+ {0xa0, 0x0d, 0x0100},
+ {0xa0, 0x06, 0x0189},
+ {0xa0, 0x03, 0x01c5},
+ {0xa0, 0x13, 0x01cb},
+ {0xa0, 0x08, 0x0250},
+ {0xa0, 0x08, 0x0301},
+ {0xa1, 0x01, 0x0002},
+ {0xa1, 0x01, 0x0008},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x02, 0x0180},
+ {0xa0, 0x40, 0x0116},
+ {0xa0, 0x40, 0x0117},
+ {0xa0, 0x40, 0x0118},
+ {0xa1, 0x01, 0x0008},
+ {0xa0, 0x03, 0x0008}, /* clock ? */
+ {0xa0, 0x08, 0x01c6}, /* sharpness+ */
+ {0xa1, 0x01, 0x01c8},
+ {0xa1, 0x01, 0x01c9},
+ {0xa1, 0x01, 0x01ca},
+ {0xa0, 0x0f, 0x01cb}, /* sharpness- */
+ {0xa0, 0x13, 0x0120}, /* gamma 4 */
+ {0xa0, 0x38, 0x0121},
+ {0xa0, 0x59, 0x0122},
+ {0xa0, 0x79, 0x0123},
+ {0xa0, 0x92, 0x0124},
+ {0xa0, 0xa7, 0x0125},
+ {0xa0, 0xb9, 0x0126},
+ {0xa0, 0xc8, 0x0127},
+ {0xa0, 0xd4, 0x0128},
+ {0xa0, 0xdf, 0x0129},
+ {0xa0, 0xe7, 0x012a},
+ {0xa0, 0xee, 0x012b},
+ {0xa0, 0xf4, 0x012c},
+ {0xa0, 0xf9, 0x012d},
+ {0xa0, 0xfc, 0x012e},
+ {0xa0, 0xff, 0x012f},
+ {0xa0, 0x26, 0x0130},
+ {0xa0, 0x22, 0x0131},
+ {0xa0, 0x20, 0x0132},
+ {0xa0, 0x1c, 0x0133},
+ {0xa0, 0x16, 0x0134},
+ {0xa0, 0x13, 0x0135},
+ {0xa0, 0x10, 0x0136},
+ {0xa0, 0x0d, 0x0137},
+ {0xa0, 0x0b, 0x0138},
+ {0xa0, 0x09, 0x0139},
+ {0xa0, 0x07, 0x013a},
+ {0xa0, 0x06, 0x013b},
+ {0xa0, 0x05, 0x013c},
+ {0xa0, 0x04, 0x013d},
+ {0xa0, 0x03, 0x013e},
+ {0xa0, 0x02, 0x013f},
+ {0xa0, 0x66, 0x010a}, /* matrix */
+ {0xa0, 0xed, 0x010b},
+ {0xa0, 0xed, 0x010c},
+ {0xa0, 0xed, 0x010d},
+ {0xa0, 0x66, 0x010e},
+ {0xa0, 0xed, 0x010f},
+ {0xa0, 0xed, 0x0110},
+ {0xa0, 0xed, 0x0111},
+ {0xa0, 0x66, 0x0112},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x00, 0x0180},
+ {0xa0, 0x00, 0x0019},
+ /**** set exposure ***/
+ {0xaa, 0x13, 0x0031},
+ {0xaa, 0x14, 0x0001},
+ {0xaa, 0x0e, 0x0004},
+ {0xaa, 0x19, 0x00cd},
+ {0xa0, 0x00, 0x0190},
+ {0xa0, 0x02, 0x0191},
+ {0xa0, 0x62, 0x0192},
+ {0xa0, 0x00, 0x0195},
+ {0xa0, 0x00, 0x0196},
+ {0xa0, 0x3d, 0x0197},
+ {0xa0, 0x10, 0x018c},
+ {0xa0, 0x20, 0x018f},
+ {0xa0, 0x0c, 0x01a9},
+ {0xa0, 0x28, 0x01aa},
+ {0xa0, 0x04, 0x001d},
+ {0xa0, 0x18, 0x001e},
+ {0xa0, 0x2c, 0x001f},
+ {0xa0, 0x41, 0x0020},
+ {0xa0, 0x60, 0x011d},
+ {0xa0, 0x42, 0x0180},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x42, 0x0180},
+ {0xa0, 0x40, 0x0116},
+ {0xa0, 0x40, 0x0117},
+ {0xa0, 0x40, 0x0118},
+ {}
+};
+static const struct usb_action hdcs2020b_50HZ[] = {
+ {0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
+ {0xaa, 0x13, 0x0018}, /* 00,13,18,aa */
+ {0xaa, 0x14, 0x0001}, /* 00,14,01,aa */
+ {0xaa, 0x0e, 0x0005}, /* 00,0e,05,aa */
+ {0xaa, 0x19, 0x001f}, /* 00,19,1f,aa */
+ {0xa0, 0x00, 0x0190}, /* 01,90,00,cc */
+ {0xa0, 0x02, 0x0191}, /* 01,91,02,cc */
+ {0xa0, 0x76, 0x0192}, /* 01,92,76,cc */
+ {0xa0, 0x00, 0x0195}, /* 01,95,00,cc */
+ {0xa0, 0x00, 0x0196}, /* 01,96,00,cc */
+ {0xa0, 0x46, 0x0197}, /* 01,97,46,cc */
+ {0xa0, 0x10, 0x018c}, /* 01,8c,10,cc */
+ {0xa0, 0x20, 0x018f}, /* 01,8f,20,cc */
+ {0xa0, 0x0c, 0x01a9}, /* 01,a9,0c,cc */
+ {0xa0, 0x28, 0x01aa}, /* 01,aa,28,cc */
+ {0xa0, 0x05, 0x001d}, /* 00,1d,05,cc */
+ {0xa0, 0x1a, 0x001e}, /* 00,1e,1a,cc */
+ {0xa0, 0x2f, 0x001f}, /* 00,1f,2f,cc */
+ {}
+};
+static const struct usb_action hdcs2020b_60HZ[] = {
+ {0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
+ {0xaa, 0x13, 0x0031}, /* 00,13,31,aa */
+ {0xaa, 0x14, 0x0001}, /* 00,14,01,aa */
+ {0xaa, 0x0e, 0x0004}, /* 00,0e,04,aa */
+ {0xaa, 0x19, 0x00cd}, /* 00,19,cd,aa */
+ {0xa0, 0x00, 0x0190}, /* 01,90,00,cc */
+ {0xa0, 0x02, 0x0191}, /* 01,91,02,cc */
+ {0xa0, 0x62, 0x0192}, /* 01,92,62,cc */
+ {0xa0, 0x00, 0x0195}, /* 01,95,00,cc */
+ {0xa0, 0x00, 0x0196}, /* 01,96,00,cc */
+ {0xa0, 0x3d, 0x0197}, /* 01,97,3d,cc */
+ {0xa0, 0x10, 0x018c}, /* 01,8c,10,cc */
+ {0xa0, 0x20, 0x018f}, /* 01,8f,20,cc */
+ {0xa0, 0x0c, 0x01a9}, /* 01,a9,0c,cc */
+ {0xa0, 0x28, 0x01aa}, /* 01,aa,28,cc */
+ {0xa0, 0x04, 0x001d}, /* 00,1d,04,cc */
+ {0xa0, 0x18, 0x001e}, /* 00,1e,18,cc */
+ {0xa0, 0x2c, 0x001f}, /* 00,1f,2c,cc */
+ {}
+};
+static const struct usb_action hdcs2020b_NoFliker[] = {
+ {0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
+ {0xaa, 0x13, 0x0010}, /* 00,13,10,aa */
+ {0xaa, 0x14, 0x0001}, /* 00,14,01,aa */
+ {0xaa, 0x0e, 0x0004}, /* 00,0e,04,aa */
+ {0xaa, 0x19, 0x0000}, /* 00,19,00,aa */
+ {0xa0, 0x00, 0x0190}, /* 01,90,00,cc */
+ {0xa0, 0x02, 0x0191}, /* 01,91,02,cc */
+ {0xa0, 0x70, 0x0192}, /* 01,92,70,cc */
+ {0xa0, 0x00, 0x0195}, /* 01,95,00,cc */
+ {0xa0, 0x00, 0x0196}, /* 01,96,00,cc */
+ {0xa0, 0x10, 0x0197}, /* 01,97,10,cc */
+ {0xa0, 0x10, 0x018c}, /* 01,8c,10,cc */
+ {0xa0, 0x20, 0x018f}, /* 01,8f,20,cc */
+ {0xa0, 0x00, 0x01a9}, /* 01,a9,00,cc */
+ {0xa0, 0x00, 0x01aa}, /* 01,aa,00,cc */
+ {0xa0, 0x04, 0x001d}, /* 00,1d,04,cc */
+ {0xa0, 0x17, 0x001e}, /* 00,1e,17,cc */
+ {0xa0, 0x2a, 0x001f}, /* 00,1f,2a,cc */
+ {}
+};
+
+static const struct usb_action hv7131bxx_Initial[] = {
+ {0xa0, 0x01, 0x0000},
+ {0xa0, 0x10, 0x0002},
+ {0xa0, 0x00, 0x0010},
+ {0xa0, 0x01, 0x0001},
+ {0xa0, 0x77, 0x0101},
+ {0xa0, 0x03, 0x0008}, /* 00 */
+ {0xa0, 0x03, 0x0012},
+ {0xa0, 0x01, 0x0012},
+ {0xa0, 0x02, 0x0003},
+ {0xa0, 0x80, 0x0004},
+ {0xa0, 0x01, 0x0005},
+ {0xa0, 0xe0, 0x0006},
+ {0xa0, 0x00, 0x0098},
+ {0xa0, 0x00, 0x009a},
+ {0xa0, 0x00, 0x011a},
+ {0xa0, 0x00, 0x011c},
+ {0xaa, 0x30, 0x002d},
+ {0xaa, 0x01, 0x0005},
+ {0xaa, 0x11, 0x0000},
+ {0xaa, 0x13, 0x0001}, /* {0xaa, 0x13, 0x0000}, */
+ {0xaa, 0x14, 0x0001},
+ {0xaa, 0x15, 0x00e8},
+ {0xaa, 0x16, 0x0002},
+ {0xaa, 0x17, 0x0086},
+ {0xaa, 0x31, 0x0038},
+ {0xaa, 0x32, 0x0038},
+ {0xaa, 0x33, 0x0038},
+ {0xaa, 0x5b, 0x0001},
+ {0xa0, 0x00, 0x0019},
+ {0xa0, 0x05, 0x0012},
+ {0xa0, 0x0d, 0x0100},
+ {0xa0, 0x68, 0x018d},
+ {0xa0, 0x60, 0x01a8},
+ {0xa0, 0x00, 0x01ad},
+ {0xa0, 0xc0, 0x019b},
+ {0xa0, 0xa0, 0x019c},
+ {0xa0, 0x02, 0x0188},
+ {0xa0, 0x06, 0x0189},
+ {0xa0, 0x03, 0x01c5},
+ {0xa0, 0x13, 0x01cb},
+ {0xa0, 0x08, 0x0250},
+ {0xa0, 0x08, 0x0301},
+ {0xaa, 0x02, 0x0080}, /* {0xaa, 0x02, 0x0090}; */
+ {0xa1, 0x01, 0x0002},
+ {0xa0, 0x00, 0x0092},
+ {0xa0, 0x02, 0x0090},
+ {0xa1, 0x01, 0x0091},
+ {0xa1, 0x01, 0x0095},
+ {0xa1, 0x01, 0x0096},
+
+ {0xa1, 0x01, 0x0008},
+ {0xa0, 0x03, 0x0008}, /* clock ? */
+ {0xa0, 0x08, 0x01c6}, /* sharpness+ */
+ {0xa1, 0x01, 0x01c8},
+ {0xa1, 0x01, 0x01c9},
+ {0xa1, 0x01, 0x01ca},
+ {0xa0, 0x0f, 0x01cb}, /* sharpness- */
+
+ {0xa0, 0x50, 0x010a}, /* matrix */
+ {0xa0, 0xf8, 0x010b},
+ {0xa0, 0xf8, 0x010c},
+ {0xa0, 0xf8, 0x010d},
+ {0xa0, 0x50, 0x010e},
+ {0xa0, 0xf8, 0x010f},
+ {0xa0, 0xf8, 0x0110},
+ {0xa0, 0xf8, 0x0111},
+ {0xa0, 0x50, 0x0112},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x10, 0x0180},
+ {0xa0, 0x00, 0x0019},
+ {0xaa, 0x25, 0x0007},
+ {0xaa, 0x26, 0x00a1},
+ {0xaa, 0x27, 0x0020},
+ {0xaa, 0x20, 0x0000},
+ {0xaa, 0x21, 0x00a0},
+ {0xaa, 0x22, 0x0016},
+ {0xaa, 0x23, 0x0040},
+
+ {0xa0, 0x10, 0x0190}, /* 2F */
+ {0xa0, 0x04, 0x0191}, /* 4d */
+ {0xa0, 0x60, 0x0192},
+ {0xa0, 0x01, 0x0195},
+ {0xa0, 0x86, 0x0196},
+ {0xa0, 0xa0, 0x0197},
+ {0xa0, 0x07, 0x018c},
+ {0xa0, 0x0f, 0x018f},
+ {0xa0, 0x18, 0x01a9},
+ {0xa0, 0x24, 0x01aa},
+ {0xa0, 0x00, 0x001d},
+ {0xa0, 0xa0, 0x001e},
+ {0xa0, 0x16, 0x001f},
+ {0xa0, 0x40, 0x0020},
+ {0xa0, 0x60, 0x011d},
+ {0xa1, 0x01, 0x001d},
+ {0xa1, 0x01, 0x001e},
+ {0xa1, 0x01, 0x001f},
+ {0xa1, 0x01, 0x0020},
+ {0xa0, 0x40, 0x0180},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x42, 0x0180},
+ {0xa0, 0x40, 0x0116},
+ {0xa0, 0x40, 0x0117},
+ {0xa0, 0x40, 0x0118},
+/* {0xa0, 0x02, 0x0008}, */
+ {}
+};
+
+static const struct usb_action hv7131bxx_InitialScale[] = {
+ {0xa0, 0x01, 0x0000},
+ {0xa0, 0x00, 0x0002},
+ {0xa0, 0x00, 0x0010},
+ {0xa0, 0x01, 0x0001},
+ {0xa0, 0x37, 0x0101},
+ {0xa0, 0x03, 0x0008}, /* 00 */
+ {0xa0, 0x03, 0x0012},
+ {0xa0, 0x01, 0x0012},
+ {0xa0, 0x02, 0x0003},
+ {0xa0, 0x80, 0x0004},
+ {0xa0, 0x01, 0x0005},
+ {0xa0, 0xe0, 0x0006},
+ {0xa0, 0x00, 0x0098},
+ {0xa0, 0x00, 0x009a},
+ {0xa0, 0x00, 0x011a},
+ {0xa0, 0x00, 0x011c},
+ {0xaa, 0x30, 0x002d},
+ {0xaa, 0x01, 0x0005},
+ {0xaa, 0x11, 0x0001},
+ {0xaa, 0x13, 0x0000}, /* {0xaa, 0x13, 0x0001}; */
+ {0xaa, 0x14, 0x0001},
+ {0xaa, 0x15, 0x00e6},
+ {0xaa, 0x16, 0x0002},
+ {0xaa, 0x17, 0x0086},
+ {0xaa, 0x31, 0x0038},
+ {0xaa, 0x32, 0x0038},
+ {0xaa, 0x33, 0x0038},
+ {0xaa, 0x5b, 0x0001},
+ {0xa0, 0x00, 0x0019},
+ {0xa0, 0x05, 0x0012},
+ {0xa0, 0x0d, 0x0100},
+ {0xa0, 0x70, 0x018d},
+ {0xa0, 0x60, 0x01a8},
+ {0xa0, 0x00, 0x01ad},
+ {0xa0, 0xc0, 0x019b},
+ {0xa0, 0xa0, 0x019c},
+ {0xa0, 0x02, 0x0188},
+ {0xa0, 0x06, 0x0189},
+ {0xa0, 0x03, 0x01c5},
+ {0xa0, 0x13, 0x01cb},
+ {0xa0, 0x08, 0x0250},
+ {0xa0, 0x08, 0x0301},
+ {0xaa, 0x02, 0x0090}, /* {0xaa, 0x02, 0x0080}, */
+ {0xa1, 0x01, 0x0002},
+ {0xa0, 0x00, 0x0092},
+ {0xa0, 0x02, 0x0090},
+ {0xa1, 0x01, 0x0091},
+ {0xa1, 0x01, 0x0095},
+ {0xa1, 0x01, 0x0096},
+ {0xa1, 0x01, 0x0008},
+ {0xa0, 0x03, 0x0008}, /* clock ? */
+ {0xa0, 0x08, 0x01c6}, /* sharpness+ */
+ {0xa1, 0x01, 0x01c8},
+ {0xa1, 0x01, 0x01c9},
+ {0xa1, 0x01, 0x01ca},
+ {0xa0, 0x0f, 0x01cb}, /* sharpness- */
+
+ {0xa0, 0x50, 0x010a}, /* matrix */
+ {0xa0, 0xf8, 0x010b},
+ {0xa0, 0xf8, 0x010c},
+ {0xa0, 0xf8, 0x010d},
+ {0xa0, 0x50, 0x010e},
+ {0xa0, 0xf8, 0x010f},
+ {0xa0, 0xf8, 0x0110},
+ {0xa0, 0xf8, 0x0111},
+ {0xa0, 0x50, 0x0112},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x10, 0x0180},
+ {0xa0, 0x00, 0x0019},
+ {0xaa, 0x25, 0x0007},
+ {0xaa, 0x26, 0x00a1},
+ {0xaa, 0x27, 0x0020},
+ {0xaa, 0x20, 0x0000},
+ {0xaa, 0x21, 0x0040},
+ {0xaa, 0x22, 0x0013},
+ {0xaa, 0x23, 0x004c},
+ {0xa0, 0x10, 0x0190}, /* 2f */
+ {0xa0, 0x04, 0x0191}, /* 4d */
+ {0xa0, 0x60, 0x0192}, /* 60 */
+ {0xa0, 0x00, 0x0195},
+ {0xa0, 0xc3, 0x0196},
+ {0xa0, 0x50, 0x0197},
+ {0xa0, 0x0c, 0x018c},
+ {0xa0, 0x18, 0x018f},
+ {0xa0, 0x18, 0x01a9},
+ {0xa0, 0x24, 0x01aa},
+ {0xa0, 0x00, 0x001d},
+ {0xa0, 0x40, 0x001e},
+ {0xa0, 0x13, 0x001f},
+ {0xa0, 0x4c, 0x0020},
+ {0xa0, 0x60, 0x011d},
+ {0xa1, 0x01, 0x001d},
+ {0xa1, 0x01, 0x001e},
+ {0xa1, 0x01, 0x001f},
+ {0xa1, 0x01, 0x0020},
+ {0xa0, 0x40, 0x0180},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x42, 0x0180},
+ {0xa0, 0x40, 0x0116},
+ {0xa0, 0x40, 0x0117},
+ {0xa0, 0x40, 0x0118},
+/* {0xa0, 0x02, 0x0008}, */
+ {}
+};
+
+static const struct usb_action hv7131cxx_Initial[] = {
+ {0xa0, 0x01, 0x0000},
+ {0xa0, 0x10, 0x0002},
+ {0xa0, 0x01, 0x0010},
+ {0xa0, 0x01, 0x0001},
+ {0xa0, 0x77, 0x0101},
+ {0xa0, 0x03, 0x0008},
+ {0xa0, 0x05, 0x0012},
+ {0xa0, 0x07, 0x0012},
+ {0xa0, 0x02, 0x0003},
+ {0xa0, 0x80, 0x0004},
+ {0xa0, 0x01, 0x0005},
+ {0xa0, 0xe0, 0x0006},
+ {0xa0, 0x00, 0x0098},
+ {0xa0, 0x00, 0x009a},
+ {0xa0, 0x01, 0x009b},
+ {0xa0, 0xe8, 0x009c},
+ {0xa0, 0x02, 0x009d},
+ {0xa0, 0x88, 0x009e},
+ {0xa0, 0x00, 0x011a},
+ {0xa0, 0x00, 0x011c},
+ {0xa0, 0x05, 0x0012},
+ {0xaa, 0x01, 0x000c},
+ {0xaa, 0x11, 0x0000},
+ {0xaa, 0x13, 0x0000},
+ {0xaa, 0x14, 0x0001},
+ {0xaa, 0x15, 0x00e8},
+ {0xaa, 0x16, 0x0002},
+ {0xaa, 0x17, 0x0088},
+
+ {0xa0, 0x00, 0x0019},
+ {0xa0, 0x0d, 0x0100},
+ {0xa0, 0x89, 0x018d},
+ {0xa0, 0x50, 0x01a8},
+ {0xa0, 0x00, 0x01ad},
+ {0xa0, 0xc0, 0x019b},
+ {0xa0, 0xa0, 0x019c},
+ {0xa0, 0x06, 0x0189},
+ {0xa0, 0x03, 0x01c5},
+ {0xa0, 0x13, 0x01cb},
+ {0xa0, 0x08, 0x0250},
+ {0xa0, 0x08, 0x0301},
+ {0xa1, 0x01, 0x0002},
+ {0xa0, 0x00, 0x0092},
+ {0xa0, 0x02, 0x0090},
+ {0xa1, 0x01, 0x0091},
+ {0xa1, 0x01, 0x0095},
+ {0xa1, 0x01, 0x0096},
+
+ {0xa1, 0x01, 0x0008},
+ {0xa0, 0x03, 0x0008}, /* clock ? */
+ {0xa0, 0x08, 0x01c6}, /* sharpness+ */
+ {0xa1, 0x01, 0x01c8},
+ {0xa1, 0x01, 0x01c9},
+ {0xa1, 0x01, 0x01ca},
+ {0xa0, 0x0f, 0x01cb}, /* sharpness- */
+
+ {0xa0, 0x60, 0x010a}, /* matrix */
+ {0xa0, 0xf0, 0x010b},
+ {0xa0, 0xf0, 0x010c},
+ {0xa0, 0xf0, 0x010d},
+ {0xa0, 0x60, 0x010e},
+ {0xa0, 0xf0, 0x010f},
+ {0xa0, 0xf0, 0x0110},
+ {0xa0, 0xf0, 0x0111},
+ {0xa0, 0x60, 0x0112},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x10, 0x0180},
+ {0xa0, 0x00, 0x0019},
+ {0xaa, 0x25, 0x0007},
+ {0xaa, 0x26, 0x0053},
+ {0xaa, 0x27, 0x0000},
+
+ {0xa0, 0x10, 0x0190}, /* 2f */
+ {0xa0, 0x04, 0x0191}, /* 9b */
+ {0xa0, 0x60, 0x0192}, /* 80 */
+ {0xa0, 0x01, 0x0195},
+ {0xa0, 0xd4, 0x0196},
+ {0xa0, 0xc0, 0x0197},
+ {0xa0, 0x10, 0x018c},
+ {0xa0, 0x20, 0x018f},
+ {0xa0, 0x60, 0x01a8},
+ {0xa0, 0x10, 0x01a9},
+ {0xa0, 0x13, 0x01aa},
+ {0xa1, 0x01, 0x001d},
+ {0xa1, 0x01, 0x001e},
+ {0xa1, 0x01, 0x001f},
+ {0xa1, 0x01, 0x0020},
+ {0xa0, 0x40, 0x0180},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x42, 0x0180},
+ {}
+};
+
+static const struct usb_action hv7131cxx_InitialScale[] = {
+ {0xa0, 0x01, 0x0000},
+
+ {0xa0, 0x00, 0x0002}, /* diff */
+ {0xa0, 0x01, 0x0010},
+ {0xa0, 0x01, 0x0001},
+ {0xa0, 0x77, 0x0101},
+ {0xa0, 0x03, 0x0008},
+
+ {0xa0, 0x05, 0x0012},
+ {0xa0, 0x07, 0x0012},
+
+ {0xa0, 0x02, 0x0003},
+ {0xa0, 0x80, 0x0004},
+ {0xa0, 0x01, 0x0005},
+ {0xa0, 0xe0, 0x0006}, /* 1e0 */
+
+ {0xa0, 0x00, 0x0098},
+ {0xa0, 0x00, 0x009a},
+ {0xa0, 0x01, 0x009b},
+ {0xa0, 0xe8, 0x009c},
+ {0xa0, 0x02, 0x009d},
+ {0xa0, 0x88, 0x009e},
+ {0xa0, 0x00, 0x011a},
+ {0xa0, 0x00, 0x011c},
+ {0xa0, 0x05, 0x0012},
+ {0xaa, 0x01, 0x000c},
+ {0xaa, 0x11, 0x0000},
+ {0xaa, 0x13, 0x0000},
+ {0xaa, 0x14, 0x0001},
+ {0xaa, 0x15, 0x00e8},
+ {0xaa, 0x16, 0x0002},
+ {0xaa, 0x17, 0x0088},
+
+ {0xa0, 0x00, 0x0019}, /* 00 */
+
+ {0xa0, 0x0d, 0x0100},
+ {0xa0, 0x89, 0x018d},
+ {0xa0, 0x50, 0x01a8},
+ {0xa0, 0x00, 0x01ad},
+ {0xa0, 0xc0, 0x019b},
+ {0xa0, 0xa0, 0x019c},
+ {0xa0, 0x06, 0x0189},
+ {0xa0, 0x03, 0x01c5},
+ {0xa0, 0x13, 0x01cb},
+ {0xa0, 0x08, 0x0250},
+ {0xa0, 0x08, 0x0301},
+ {0xa1, 0x01, 0x0002},
+ {0xa0, 0x00, 0x0092}, /* read the i2c chips ident */
+ {0xa0, 0x02, 0x0090},
+ {0xa1, 0x01, 0x0091},
+ {0xa1, 0x01, 0x0095},
+ {0xa1, 0x01, 0x0096},
+
+ {0xa1, 0x01, 0x0008},
+ {0xa0, 0x03, 0x0008}, /* clock ? */
+ {0xa0, 0x08, 0x01c6}, /* sharpness+ */
+ {0xa1, 0x01, 0x01c8},
+ {0xa1, 0x01, 0x01c9},
+ {0xa1, 0x01, 0x01ca},
+ {0xa0, 0x0f, 0x01cb}, /* sharpness- */
+
+ {0xa0, 0x60, 0x010a}, /* matrix */
+ {0xa0, 0xf0, 0x010b},
+ {0xa0, 0xf0, 0x010c},
+ {0xa0, 0xf0, 0x010d},
+ {0xa0, 0x60, 0x010e},
+ {0xa0, 0xf0, 0x010f},
+ {0xa0, 0xf0, 0x0110},
+ {0xa0, 0xf0, 0x0111},
+ {0xa0, 0x60, 0x0112},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x10, 0x0180},
+ {0xa0, 0x00, 0x0019},
+ {0xaa, 0x25, 0x0007},
+ {0xaa, 0x26, 0x0053},
+ {0xaa, 0x27, 0x0000},
+
+ {0xa0, 0x10, 0x0190}, /* 2f */
+ {0xa0, 0x04, 0x0191}, /* 9b */
+ {0xa0, 0x60, 0x0192}, /* 80 */
+
+ {0xa0, 0x01, 0x0195},
+ {0xa0, 0xd4, 0x0196},
+ {0xa0, 0xc0, 0x0197},
+
+ {0xa0, 0x10, 0x018c},
+ {0xa0, 0x20, 0x018f},
+ {0xa0, 0x60, 0x01a8},
+ {0xa0, 0x10, 0x01a9},
+ {0xa0, 0x13, 0x01aa},
+ {0xa1, 0x01, 0x001d},
+ {0xa1, 0x01, 0x001e},
+ {0xa1, 0x01, 0x001f},
+ {0xa1, 0x01, 0x0020},
+ {0xa0, 0x40, 0x0180},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x42, 0x0180},
+ {}
+};
+
+static const struct usb_action icm105axx_Initial[] = {
+ {0xa0, 0x01, 0x0000},
+ {0xa0, 0x10, 0x0002},
+ {0xa0, 0x03, 0x0008},
+ {0xa0, 0x0c, 0x0010},
+ {0xa0, 0x02, 0x0003},
+ {0xa0, 0x80, 0x0004},
+ {0xa0, 0x01, 0x0005},
+ {0xa0, 0xe0, 0x0006},
+ {0xa0, 0x01, 0x0001},
+ {0xa0, 0x03, 0x0012},
+ {0xa0, 0x01, 0x0012},
+ {0xa0, 0xa1, 0x008b},
+ {0xa0, 0x00, 0x0097},
+ {0xa0, 0x01, 0x0098},
+ {0xa0, 0x00, 0x0099},
+ {0xa0, 0x01, 0x009a},
+ {0xa0, 0x01, 0x011a},
+ {0xa0, 0x01, 0x011c},
+ {0xa0, 0x01, 0x009b},
+ {0xa0, 0xe8, 0x009c},
+ {0xa0, 0x02, 0x009d},
+ {0xa0, 0x88, 0x009e},
+ {0xa0, 0x37, 0x0101},
+ {0xa0, 0x0d, 0x0100},
+ {0xa0, 0x06, 0x0189},
+ {0xa0, 0x03, 0x01c5},
+ {0xa0, 0x13, 0x01cb},
+ {0xaa, 0x01, 0x0010},
+ {0xaa, 0x03, 0x0000},
+ {0xaa, 0x04, 0x0001},
+ {0xaa, 0x05, 0x0020},
+ {0xaa, 0x06, 0x0001},
+ {0xaa, 0x08, 0x0000},
+ {0xaa, 0x03, 0x0001},
+ {0xaa, 0x04, 0x0011},
+ {0xaa, 0x05, 0x00a0},
+ {0xaa, 0x06, 0x0001},
+ {0xaa, 0x08, 0x0000},
+ {0xaa, 0x03, 0x0002},
+ {0xaa, 0x04, 0x0013},
+ {0xaa, 0x05, 0x0020},
+ {0xaa, 0x06, 0x0001},
+ {0xaa, 0x08, 0x0000},
+ {0xaa, 0x03, 0x0003},
+ {0xaa, 0x04, 0x0015},
+ {0xaa, 0x05, 0x0020},
+ {0xaa, 0x06, 0x0005},
+ {0xaa, 0x08, 0x0000},
+ {0xaa, 0x03, 0x0004},
+ {0xaa, 0x04, 0x0017},
+ {0xaa, 0x05, 0x0020},
+ {0xaa, 0x06, 0x000d},
+ {0xaa, 0x08, 0x0000},
+ {0xaa, 0x03, 0x0005},
+ {0xaa, 0x04, 0x0019},
+ {0xaa, 0x05, 0x0020},
+ {0xaa, 0x06, 0x0005},
+ {0xaa, 0x08, 0x0000},
+ {0xaa, 0x03, 0x0006},
+ {0xaa, 0x04, 0x0017},
+ {0xaa, 0x05, 0x0026},
+ {0xaa, 0x06, 0x0005},
+ {0xaa, 0x08, 0x0000},
+ {0xaa, 0x03, 0x0007},
+ {0xaa, 0x04, 0x0019},
+ {0xaa, 0x05, 0x0022},
+ {0xaa, 0x06, 0x0005},
+ {0xaa, 0x08, 0x0000},
+ {0xaa, 0x03, 0x0008},
+ {0xaa, 0x04, 0x0021},
+ {0xaa, 0x05, 0x00aa},
+ {0xaa, 0x06, 0x0005},
+ {0xaa, 0x08, 0x0000},
+ {0xaa, 0x03, 0x0009},
+ {0xaa, 0x04, 0x0023},
+ {0xaa, 0x05, 0x00aa},
+ {0xaa, 0x06, 0x000d},
+ {0xaa, 0x08, 0x0000},
+ {0xaa, 0x03, 0x000a},
+ {0xaa, 0x04, 0x0025},
+ {0xaa, 0x05, 0x00aa},
+ {0xaa, 0x06, 0x0005},
+ {0xaa, 0x08, 0x0000},
+ {0xaa, 0x03, 0x000b},
+ {0xaa, 0x04, 0x00ec},
+ {0xaa, 0x05, 0x002e},
+ {0xaa, 0x06, 0x0005},
+ {0xaa, 0x08, 0x0000},
+ {0xaa, 0x03, 0x000c},
+ {0xaa, 0x04, 0x00fa},
+ {0xaa, 0x05, 0x002a},
+ {0xaa, 0x06, 0x0005},
+ {0xaa, 0x08, 0x0000},
+ {0xaa, 0x07, 0x000d},
+ {0xaa, 0x01, 0x0005},
+ {0xaa, 0x94, 0x0002},
+ {0xaa, 0x90, 0x0000},
+ {0xaa, 0x91, 0x001f},
+ {0xaa, 0x10, 0x0064},
+ {0xaa, 0x9b, 0x00f0},
+ {0xaa, 0x9c, 0x0002},
+ {0xaa, 0x14, 0x001a},
+ {0xaa, 0x20, 0x0080},
+ {0xaa, 0x22, 0x0080},
+ {0xaa, 0x24, 0x0080},
+ {0xaa, 0x26, 0x0080},
+ {0xaa, 0x00, 0x0084},
+ {0xa0, 0x08, 0x0250},
+ {0xa0, 0x08, 0x0301},
+ {0xaa, 0xa8, 0x00c0},
+ {0xa1, 0x01, 0x0002},
+ {0xa1, 0x01, 0x0008},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x02, 0x0180},
+ {0xa0, 0x40, 0x0116},
+ {0xa0, 0x40, 0x0117},
+ {0xa0, 0x40, 0x0118},
+ {0xa1, 0x01, 0x0008},
+
+ {0xa0, 0x03, 0x0008}, /* clock ? */
+ {0xa0, 0x08, 0x01c6}, /* sharpness+ */
+ {0xa1, 0x01, 0x01c8},
+ {0xa1, 0x01, 0x01c9},
+ {0xa1, 0x01, 0x01ca},
+ {0xa0, 0x0f, 0x01cb}, /* sharpness- */
+ {0xa0, 0x52, 0x010a}, /* matrix */
+ {0xa0, 0xf7, 0x010b},
+ {0xa0, 0xf7, 0x010c},
+ {0xa0, 0xf7, 0x010d},
+ {0xa0, 0x52, 0x010e},
+ {0xa0, 0xf7, 0x010f},
+ {0xa0, 0xf7, 0x0110},
+ {0xa0, 0xf7, 0x0111},
+ {0xa0, 0x52, 0x0112},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x00, 0x0180},
+ {0xa0, 0x00, 0x0019},
+ {0xaa, 0x0d, 0x0003},
+ {0xaa, 0x0c, 0x008c},
+ {0xaa, 0x0e, 0x0095},
+ {0xaa, 0x0f, 0x0002},
+ {0xaa, 0x1c, 0x0094},
+ {0xaa, 0x1d, 0x0002},
+ {0xaa, 0x20, 0x0080},
+ {0xaa, 0x22, 0x0080},
+ {0xaa, 0x24, 0x0080},
+ {0xaa, 0x26, 0x0080},
+ {0xaa, 0x00, 0x0084},
+ {0xa0, 0x02, 0x00a3},
+ {0xa0, 0x94, 0x00a4},
+ {0xa0, 0x00, 0x0190},
+ {0xa0, 0x04, 0x0191},
+ {0xa0, 0x20, 0x0192},
+ {0xa0, 0x00, 0x0195},
+ {0xa0, 0x00, 0x0196},
+ {0xa0, 0x84, 0x0197},
+ {0xa0, 0x10, 0x018c},
+ {0xa0, 0x20, 0x018f},
+ {0xa0, 0x10, 0x01a9},
+ {0xa0, 0x12, 0x01aa},
+ {0xa0, 0xe3, 0x001d},
+ {0xa0, 0xec, 0x001e},
+ {0xa0, 0xf5, 0x001f},
+ {0xa0, 0xff, 0x0020},
+ {0xa0, 0x00, 0x01a7},
+ {0xa0, 0xc0, 0x01a8},
+ {0xa0, 0xc0, 0x011d},
+ {0xa0, 0x42, 0x0180},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x42, 0x0180},
+ {0xa0, 0x40, 0x0116},
+ {0xa0, 0x40, 0x0117},
+ {0xa0, 0x40, 0x0118},
+ {}
+};
+
+static const struct usb_action icm105axx_InitialScale[] = {
+ {0xa0, 0x01, 0x0000},
+ {0xa0, 0x00, 0x0002},
+ {0xa0, 0x03, 0x0008},
+ {0xa0, 0x0c, 0x0010},
+ {0xa0, 0x02, 0x0003},
+ {0xa0, 0x80, 0x0004},
+ {0xa0, 0x01, 0x0005},
+ {0xa0, 0xe0, 0x0006},
+ {0xa0, 0x01, 0x0001},
+ {0xa0, 0x03, 0x0012},
+ {0xa0, 0x01, 0x0012},
+ {0xa0, 0xa1, 0x008b},
+ {0xa0, 0x00, 0x0097},
+ {0xa0, 0x02, 0x0098},
+ {0xa0, 0x00, 0x0099},
+ {0xa0, 0x02, 0x009a},
+ {0xa0, 0x02, 0x011a},
+ {0xa0, 0x02, 0x011c},
+ {0xa0, 0x01, 0x009b},
+ {0xa0, 0xe6, 0x009c},
+ {0xa0, 0x02, 0x009d},
+ {0xa0, 0x86, 0x009e},
+ {0xa0, 0x77, 0x0101},
+ {0xa0, 0x0d, 0x0100},
+ {0xa0, 0x06, 0x0189},
+ {0xa0, 0x03, 0x01c5},
+ {0xa0, 0x13, 0x01cb},
+ {0xaa, 0x01, 0x0010},
+ {0xaa, 0x03, 0x0000},
+ {0xaa, 0x04, 0x0001},
+ {0xaa, 0x05, 0x0020},
+ {0xaa, 0x06, 0x0001},
+ {0xaa, 0x08, 0x0000},
+ {0xaa, 0x03, 0x0001},
+ {0xaa, 0x04, 0x0011},
+ {0xaa, 0x05, 0x00a0},
+ {0xaa, 0x06, 0x0001},
+ {0xaa, 0x08, 0x0000},
+ {0xaa, 0x03, 0x0002},
+ {0xaa, 0x04, 0x0013},
+ {0xaa, 0x05, 0x0020},
+ {0xaa, 0x06, 0x0001},
+ {0xaa, 0x08, 0x0000},
+ {0xaa, 0x03, 0x0003},
+ {0xaa, 0x04, 0x0015},
+ {0xaa, 0x05, 0x0020},
+ {0xaa, 0x06, 0x0005},
+ {0xaa, 0x08, 0x0000},
+ {0xaa, 0x03, 0x0004},
+ {0xaa, 0x04, 0x0017},
+ {0xaa, 0x05, 0x0020},
+ {0xaa, 0x06, 0x000d},
+ {0xaa, 0x08, 0x0000},
+ {0xaa, 0x03, 0x0005},
+ {0xa0, 0x04, 0x0092},
+ {0xa0, 0x19, 0x0093},
+ {0xa0, 0x01, 0x0090},
+ {0xa1, 0x01, 0x0091},
+ {0xaa, 0x05, 0x0020},
+ {0xaa, 0x06, 0x0005},
+ {0xaa, 0x08, 0x0000},
+ {0xaa, 0x03, 0x0006},
+ {0xaa, 0x04, 0x0017},
+ {0xaa, 0x05, 0x0026},
+ {0xaa, 0x06, 0x0005},
+ {0xaa, 0x08, 0x0000},
+ {0xaa, 0x03, 0x0007},
+ {0xaa, 0x04, 0x0019},
+ {0xaa, 0x05, 0x0022},
+ {0xaa, 0x06, 0x0005},
+ {0xaa, 0x08, 0x0000},
+ {0xaa, 0x03, 0x0008},
+ {0xaa, 0x04, 0x0021},
+ {0xaa, 0x05, 0x00aa},
+ {0xaa, 0x06, 0x0005},
+ {0xaa, 0x08, 0x0000},
+ {0xaa, 0x03, 0x0009},
+ {0xaa, 0x04, 0x0023},
+ {0xaa, 0x05, 0x00aa},
+ {0xaa, 0x06, 0x000d},
+ {0xaa, 0x08, 0x0000},
+ {0xaa, 0x03, 0x000a},
+ {0xaa, 0x04, 0x0025},
+ {0xaa, 0x05, 0x00aa},
+ {0xaa, 0x06, 0x0005},
+ {0xaa, 0x08, 0x0000},
+ {0xaa, 0x03, 0x000b},
+ {0xaa, 0x04, 0x00ec},
+ {0xaa, 0x05, 0x002e},
+ {0xaa, 0x06, 0x0005},
+ {0xaa, 0x08, 0x0000},
+ {0xaa, 0x03, 0x000c},
+ {0xaa, 0x04, 0x00fa},
+ {0xaa, 0x05, 0x002a},
+ {0xaa, 0x06, 0x0005},
+ {0xaa, 0x08, 0x0000},
+ {0xaa, 0x07, 0x000d},
+ {0xaa, 0x01, 0x0005},
+ {0xaa, 0x94, 0x0002},
+ {0xaa, 0x90, 0x0000},
+ {0xaa, 0x91, 0x0010},
+ {0xaa, 0x10, 0x0064},
+ {0xaa, 0x9b, 0x00f0},
+ {0xaa, 0x9c, 0x0002},
+ {0xaa, 0x14, 0x001a},
+ {0xaa, 0x20, 0x0080},
+ {0xaa, 0x22, 0x0080},
+ {0xaa, 0x24, 0x0080},
+ {0xaa, 0x26, 0x0080},
+ {0xaa, 0x00, 0x0084},
+ {0xa0, 0x08, 0x0250},
+ {0xa0, 0x08, 0x0301},
+ {0xaa, 0xa8, 0x0080},
+ {0xa0, 0x78, 0x018d},
+ {0xa1, 0x01, 0x0002},
+ {0xa1, 0x01, 0x0008},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x02, 0x0180},
+ {0xa0, 0x40, 0x0116},
+ {0xa0, 0x40, 0x0117},
+ {0xa0, 0x40, 0x0118},
+ {0xa1, 0x01, 0x0008},
+
+ {0xa0, 0x03, 0x0008}, /* clock ? */
+ {0xa0, 0x08, 0x01c6}, /* sharpness+ */
+ {0xa1, 0x01, 0x01c8},
+ {0xa1, 0x01, 0x01c9},
+ {0xa1, 0x01, 0x01ca},
+ {0xa0, 0x0f, 0x01cb}, /* sharpness- */
+
+ {0xa0, 0x52, 0x010a}, /* matrix */
+ {0xa0, 0xf7, 0x010b},
+ {0xa0, 0xf7, 0x010c},
+ {0xa0, 0xf7, 0x010d},
+ {0xa0, 0x52, 0x010e},
+ {0xa0, 0xf7, 0x010f},
+ {0xa0, 0xf7, 0x0110},
+ {0xa0, 0xf7, 0x0111},
+ {0xa0, 0x52, 0x0112},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x00, 0x0180},
+ {0xa0, 0x00, 0x0019},
+ {0xaa, 0x0d, 0x0003},
+ {0xaa, 0x0c, 0x0020},
+ {0xaa, 0x0e, 0x000e},
+ {0xaa, 0x0f, 0x0002},
+ {0xaa, 0x1c, 0x000d},
+ {0xaa, 0x1d, 0x0002},
+ {0xaa, 0x20, 0x0080},
+ {0xaa, 0x22, 0x0080},
+ {0xaa, 0x24, 0x0080},
+ {0xaa, 0x26, 0x0080},
+ {0xaa, 0x00, 0x0084},
+ {0xa0, 0x02, 0x00a3},
+ {0xa0, 0x0d, 0x00a4},
+ {0xa0, 0x00, 0x0190},
+ {0xa0, 0x04, 0x0191},
+ {0xa0, 0x1a, 0x0192},
+ {0xa0, 0x00, 0x0195},
+ {0xa0, 0x00, 0x0196},
+ {0xa0, 0x4b, 0x0197},
+ {0xa0, 0x10, 0x018c},
+ {0xa0, 0x20, 0x018f},
+ {0xa0, 0x10, 0x01a9},
+ {0xa0, 0x12, 0x01aa},
+ {0xa0, 0xc8, 0x001d},
+ {0xa0, 0xd8, 0x001e},
+ {0xa0, 0xea, 0x001f},
+ {0xa0, 0xff, 0x0020},
+ {0xa0, 0x00, 0x01a7},
+ {0xa0, 0x42, 0x0180},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x42, 0x0180},
+ {0xa0, 0x40, 0x0116},
+ {0xa0, 0x40, 0x0117},
+ {0xa0, 0x40, 0x0118},
+ {}
+};
+static const struct usb_action icm105a_50HZ[] = {
+ {0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
+ {0xaa, 0x0d, 0x0003}, /* 00,0d,03,aa */
+ {0xaa, 0x0c, 0x0020}, /* 00,0c,20,aa */
+ {0xaa, 0x0e, 0x000e}, /* 00,0e,0e,aa */
+ {0xaa, 0x0f, 0x0002}, /* 00,0f,02,aa */
+ {0xaa, 0x1c, 0x000d}, /* 00,1c,0d,aa */
+ {0xaa, 0x1d, 0x0002}, /* 00,1d,02,aa */
+ {0xaa, 0x20, 0x0080}, /* 00,20,80,aa */
+ {0xaa, 0x22, 0x0080}, /* 00,22,80,aa */
+ {0xaa, 0x24, 0x0080}, /* 00,24,80,aa */
+ {0xaa, 0x26, 0x0080}, /* 00,26,80,aa */
+ {0xaa, 0x00, 0x0084}, /* 00,00,84,aa */
+ {0xa0, 0x02, 0x00a3}, /* 00,a3,02,cc */
+ {0xa0, 0x0d, 0x00a4}, /* 00,a4,0d,cc */
+ {0xa0, 0x00, 0x0190}, /* 01,90,00,cc */
+ {0xa0, 0x04, 0x0191}, /* 01,91,04,cc */
+ {0xa0, 0x1a, 0x0192}, /* 01,92,1a,cc */
+ {0xa0, 0x00, 0x0195}, /* 01,95,00,cc */
+ {0xa0, 0x00, 0x0196}, /* 01,96,00,cc */
+ {0xa0, 0x4b, 0x0197}, /* 01,97,4b,cc */
+ {0xa0, 0x10, 0x018c}, /* 01,8c,10,cc */
+ {0xa0, 0x20, 0x018f}, /* 01,8f,20,cc */
+ {0xa0, 0x10, 0x01a9}, /* 01,a9,10,cc */
+ {0xa0, 0x12, 0x01aa}, /* 01,aa,12,cc */
+ {0xa0, 0xc8, 0x001d}, /* 00,1d,c8,cc */
+ {0xa0, 0xd8, 0x001e}, /* 00,1e,d8,cc */
+ {0xa0, 0xea, 0x001f}, /* 00,1f,ea,cc */
+ {0xa0, 0xff, 0x0020}, /* 00,20,ff,cc */
+ {}
+};
+static const struct usb_action icm105a_50HZScale[] = {
+ {0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
+ {0xaa, 0x0d, 0x0003}, /* 00,0d,03,aa */
+ {0xaa, 0x0c, 0x008c}, /* 00,0c,8c,aa */
+ {0xaa, 0x0e, 0x0095}, /* 00,0e,95,aa */
+ {0xaa, 0x0f, 0x0002}, /* 00,0f,02,aa */
+ {0xaa, 0x1c, 0x0094}, /* 00,1c,94,aa */
+ {0xaa, 0x1d, 0x0002}, /* 00,1d,02,aa */
+ {0xaa, 0x20, 0x0080}, /* 00,20,80,aa */
+ {0xaa, 0x22, 0x0080}, /* 00,22,80,aa */
+ {0xaa, 0x24, 0x0080}, /* 00,24,80,aa */
+ {0xaa, 0x26, 0x0080}, /* 00,26,80,aa */
+ {0xaa, 0x00, 0x0084}, /* 00,00,84,aa */
+ {0xa0, 0x02, 0x00a3}, /* 00,a3,02,cc */
+ {0xa0, 0x94, 0x00a4}, /* 00,a4,94,cc */
+ {0xa0, 0x00, 0x0190}, /* 01,90,00,cc */
+ {0xa0, 0x04, 0x0191}, /* 01,91,04,cc */
+ {0xa0, 0x20, 0x0192}, /* 01,92,20,cc */
+ {0xa0, 0x00, 0x0195}, /* 01,95,00,cc */
+ {0xa0, 0x00, 0x0196}, /* 01,96,00,cc */
+ {0xa0, 0x84, 0x0197}, /* 01,97,84,cc */
+ {0xa0, 0x10, 0x018c}, /* 01,8c,10,cc */
+ {0xa0, 0x20, 0x018f}, /* 01,8f,20,cc */
+ {0xa0, 0x10, 0x01a9}, /* 01,a9,10,cc */
+ {0xa0, 0x12, 0x01aa}, /* 01,aa,12,cc */
+ {0xa0, 0xe3, 0x001d}, /* 00,1d,e3,cc */
+ {0xa0, 0xec, 0x001e}, /* 00,1e,ec,cc */
+ {0xa0, 0xf5, 0x001f}, /* 00,1f,f5,cc */
+ {0xa0, 0xff, 0x0020}, /* 00,20,ff,cc */
+ {0xa0, 0x00, 0x01a7}, /* 01,a7,00,cc */
+ {0xa0, 0xc0, 0x01a8}, /* 01,a8,c0,cc */
+ {}
+};
+static const struct usb_action icm105a_60HZ[] = {
+ {0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
+ {0xaa, 0x0d, 0x0003}, /* 00,0d,03,aa */
+ {0xaa, 0x0c, 0x0004}, /* 00,0c,04,aa */
+ {0xaa, 0x0e, 0x000d}, /* 00,0e,0d,aa */
+ {0xaa, 0x0f, 0x0002}, /* 00,0f,02,aa */
+ {0xaa, 0x1c, 0x0008}, /* 00,1c,08,aa */
+ {0xaa, 0x1d, 0x0002}, /* 00,1d,02,aa */
+ {0xaa, 0x20, 0x0080}, /* 00,20,80,aa */
+ {0xaa, 0x22, 0x0080}, /* 00,22,80,aa */
+ {0xaa, 0x24, 0x0080}, /* 00,24,80,aa */
+ {0xaa, 0x26, 0x0080}, /* 00,26,80,aa */
+ {0xaa, 0x00, 0x0084}, /* 00,00,84,aa */
+ {0xa0, 0x02, 0x00a3}, /* 00,a3,02,cc */
+ {0xa0, 0x08, 0x00a4}, /* 00,a4,08,cc */
+ {0xa0, 0x00, 0x0190}, /* 01,90,00,cc */
+ {0xa0, 0x04, 0x0191}, /* 01,91,04,cc */
+ {0xa0, 0x10, 0x0192}, /* 01,92,10,cc */
+ {0xa0, 0x00, 0x0195}, /* 01,95,00,cc */
+ {0xa0, 0x00, 0x0196}, /* 01,96,00,cc */
+ {0xa0, 0x41, 0x0197}, /* 01,97,41,cc */
+ {0xa0, 0x10, 0x018c}, /* 01,8c,10,cc */
+ {0xa0, 0x20, 0x018f}, /* 01,8f,20,cc */
+ {0xa0, 0x10, 0x01a9}, /* 01,a9,10,cc */
+ {0xa0, 0x12, 0x01aa}, /* 01,aa,12,cc */
+ {0xa0, 0xc1, 0x001d}, /* 00,1d,c1,cc */
+ {0xa0, 0xd4, 0x001e}, /* 00,1e,d4,cc */
+ {0xa0, 0xe8, 0x001f}, /* 00,1f,e8,cc */
+ {0xa0, 0xff, 0x0020}, /* 00,20,ff,cc */
+ {}
+};
+static const struct usb_action icm105a_60HZScale[] = {
+ {0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
+ {0xaa, 0x0d, 0x0003}, /* 00,0d,03,aa */
+ {0xaa, 0x0c, 0x0008}, /* 00,0c,08,aa */
+ {0xaa, 0x0e, 0x0086}, /* 00,0e,86,aa */
+ {0xaa, 0x0f, 0x0002}, /* 00,0f,02,aa */
+ {0xaa, 0x1c, 0x0085}, /* 00,1c,85,aa */
+ {0xaa, 0x1d, 0x0002}, /* 00,1d,02,aa */
+ {0xaa, 0x20, 0x0080}, /* 00,20,80,aa */
+ {0xaa, 0x22, 0x0080}, /* 00,22,80,aa */
+ {0xaa, 0x24, 0x0080}, /* 00,24,80,aa */
+ {0xaa, 0x26, 0x0080}, /* 00,26,80,aa */
+ {0xaa, 0x00, 0x0084}, /* 00,00,84,aa */
+ {0xa0, 0x02, 0x00a3}, /* 00,a3,02,cc */
+ {0xa0, 0x85, 0x00a4}, /* 00,a4,85,cc */
+ {0xa0, 0x00, 0x0190}, /* 01,90,00,cc */
+ {0xa0, 0x04, 0x0191}, /* 01,91,04,cc */
+ {0xa0, 0x08, 0x0192}, /* 01,92,08,cc */
+ {0xa0, 0x00, 0x0195}, /* 01,95,00,cc */
+ {0xa0, 0x00, 0x0196}, /* 01,96,00,cc */
+ {0xa0, 0x81, 0x0197}, /* 01,97,81,cc */
+ {0xa0, 0x10, 0x018c}, /* 01,8c,10,cc */
+ {0xa0, 0x20, 0x018f}, /* 01,8f,20,cc */
+ {0xa0, 0x10, 0x01a9}, /* 01,a9,10,cc */
+ {0xa0, 0x12, 0x01aa}, /* 01,aa,12,cc */
+ {0xa0, 0xc2, 0x001d}, /* 00,1d,c2,cc */
+ {0xa0, 0xd6, 0x001e}, /* 00,1e,d6,cc */
+ {0xa0, 0xea, 0x001f}, /* 00,1f,ea,cc */
+ {0xa0, 0xff, 0x0020}, /* 00,20,ff,cc */
+ {0xa0, 0x00, 0x01a7}, /* 01,a7,00,cc */
+ {0xa0, 0xc0, 0x01a8}, /* 01,a8,c0,cc */
+ {}
+};
+static const struct usb_action icm105a_NoFliker[] = {
+ {0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
+ {0xaa, 0x0d, 0x0003}, /* 00,0d,03,aa */
+ {0xaa, 0x0c, 0x0004}, /* 00,0c,04,aa */
+ {0xaa, 0x0e, 0x000d}, /* 00,0e,0d,aa */
+ {0xaa, 0x0f, 0x0002}, /* 00,0f,02,aa */
+ {0xaa, 0x1c, 0x0000}, /* 00,1c,00,aa */
+ {0xaa, 0x1d, 0x0002}, /* 00,1d,02,aa */
+ {0xaa, 0x20, 0x0080}, /* 00,20,80,aa */
+ {0xaa, 0x22, 0x0080}, /* 00,22,80,aa */
+ {0xaa, 0x24, 0x0080}, /* 00,24,80,aa */
+ {0xaa, 0x26, 0x0080}, /* 00,26,80,aa */
+ {0xaa, 0x00, 0x0084}, /* 00,00,84,aa */
+ {0xa0, 0x02, 0x00a3}, /* 00,a3,02,cc */
+ {0xa0, 0x00, 0x00a4}, /* 00,a4,00,cc */
+ {0xa0, 0x00, 0x0190}, /* 01,90,00,cc */
+ {0xa0, 0x04, 0x0191}, /* 01,91,04,cc */
+ {0xa0, 0x20, 0x0192}, /* 01,92,20,cc */
+ {0xa0, 0x00, 0x0195}, /* 01,95,00,cc */
+ {0xa0, 0x00, 0x0196}, /* 01,96,00,cc */
+ {0xa0, 0x10, 0x0197}, /* 01,97,10,cc */
+ {0xa0, 0x10, 0x018c}, /* 01,8c,10,cc */
+ {0xa0, 0x20, 0x018f}, /* 01,8f,20,cc */
+ {0xa0, 0x00, 0x01a9}, /* 01,a9,00,cc */
+ {0xa0, 0x00, 0x01aa}, /* 01,aa,00,cc */
+ {0xa0, 0xc1, 0x001d}, /* 00,1d,c1,cc */
+ {0xa0, 0xd4, 0x001e}, /* 00,1e,d4,cc */
+ {0xa0, 0xe8, 0x001f}, /* 00,1f,e8,cc */
+ {0xa0, 0xff, 0x0020}, /* 00,20,ff,cc */
+ {}
+};
+static const struct usb_action icm105a_NoFlikerScale[] = {
+ {0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
+ {0xaa, 0x0d, 0x0003}, /* 00,0d,03,aa */
+ {0xaa, 0x0c, 0x0004}, /* 00,0c,04,aa */
+ {0xaa, 0x0e, 0x0081}, /* 00,0e,81,aa */
+ {0xaa, 0x0f, 0x0002}, /* 00,0f,02,aa */
+ {0xaa, 0x1c, 0x0080}, /* 00,1c,80,aa */
+ {0xaa, 0x1d, 0x0002}, /* 00,1d,02,aa */
+ {0xaa, 0x20, 0x0080}, /* 00,20,80,aa */
+ {0xaa, 0x22, 0x0080}, /* 00,22,80,aa */
+ {0xaa, 0x24, 0x0080}, /* 00,24,80,aa */
+ {0xaa, 0x26, 0x0080}, /* 00,26,80,aa */
+ {0xaa, 0x00, 0x0084}, /* 00,00,84,aa */
+ {0xa0, 0x02, 0x00a3}, /* 00,a3,02,cc */
+ {0xa0, 0x80, 0x00a4}, /* 00,a4,80,cc */
+ {0xa0, 0x00, 0x0190}, /* 01,90,00,cc */
+ {0xa0, 0x04, 0x0191}, /* 01,91,04,cc */
+ {0xa0, 0x20, 0x0192}, /* 01,92,20,cc */
+ {0xa0, 0x00, 0x0195}, /* 01,95,00,cc */
+ {0xa0, 0x00, 0x0196}, /* 01,96,00,cc */
+ {0xa0, 0x10, 0x0197}, /* 01,97,10,cc */
+ {0xa0, 0x10, 0x018c}, /* 01,8c,10,cc */
+ {0xa0, 0x20, 0x018f}, /* 01,8f,20,cc */
+ {0xa0, 0x00, 0x01a9}, /* 01,a9,00,cc */
+ {0xa0, 0x00, 0x01aa}, /* 01,aa,00,cc */
+ {0xa0, 0xc1, 0x001d}, /* 00,1d,c1,cc */
+ {0xa0, 0xd4, 0x001e}, /* 00,1e,d4,cc */
+ {0xa0, 0xe8, 0x001f}, /* 00,1f,e8,cc */
+ {0xa0, 0xff, 0x0020}, /* 00,20,ff,cc */
+ {0xa0, 0x00, 0x01a7}, /* 01,a7,00,cc */
+ {0xa0, 0xc0, 0x01a8}, /* 01,a8,c0,cc */
+ {}
+};
+
+static const struct usb_action MC501CB_InitialScale[] = {
+ {0xa0, 0x01, 0x0000}, /* 00,00,01,cc */
+ {0xa0, 0x00, 0x0002}, /* 00,02,00,cc */
+ {0xa0, 0x01, 0x0010}, /* 00,10,01,cc */
+ {0xa0, 0x01, 0x0001}, /* 00,01,01,cc */
+ {0xa0, 0x03, 0x0008}, /* 00,08,03,cc */
+ {0xa0, 0x01, 0x0012}, /* 00,12,01,cc */
+ {0xa0, 0x05, 0x0012}, /* 00,12,05,cc */
+ {0xa0, 0x02, 0x0003}, /* 00,03,02,cc */
+ {0xa0, 0x80, 0x0004}, /* 00,04,80,cc */
+ {0xa0, 0x01, 0x0005}, /* 00,05,01,cc */
+ {0xa0, 0xd8, 0x0006}, /* 00,06,d8,cc */
+ {0xa0, 0x00, 0x0098}, /* 00,98,00,cc */
+ {0xa0, 0x00, 0x009a}, /* 00,9a,00,cc */
+ {0xa0, 0x00, 0x011a}, /* 01,1a,00,cc */
+ {0xa0, 0x00, 0x011c}, /* 01,1c,00,cc */
+ {0xa0, 0x01, 0x009b}, /* 00,9b,01,cc */
+ {0xa0, 0xde, 0x009c}, /* 00,9c,de,cc */
+ {0xa0, 0x02, 0x009d}, /* 00,9d,02,cc */
+ {0xa0, 0x86, 0x009e}, /* 00,9e,86,cc */
+ {0xa0, 0x33, 0x0086}, /* 00,86,33,cc */
+ {0xa0, 0x34, 0x0087}, /* 00,87,34,cc */
+ {0xa0, 0x35, 0x0088}, /* 00,88,35,cc */
+ {0xa0, 0xb0, 0x008b}, /* 00,8b,b0,cc */
+ {0xa0, 0x05, 0x0012}, /* 00,12,05,cc */
+ {0xaa, 0x01, 0x0001}, /* 00,01,01,aa */
+ {0xaa, 0x01, 0x0003}, /* 00,01,03,aa */
+ {0xaa, 0x01, 0x0001}, /* 00,01,01,aa */
+ {0xaa, 0x03, 0x0000}, /* 00,03,00,aa */
+ {0xaa, 0x10, 0x0000}, /* 00,10,00,aa */
+ {0xaa, 0x11, 0x0080}, /* 00,11,80,aa */
+ {0xaa, 0x12, 0x0000}, /* 00,12,00,aa */
+ {0xaa, 0x13, 0x0000}, /* 00,13,00,aa */
+ {0xaa, 0x14, 0x0000}, /* 00,14,00,aa */
+ {0xaa, 0x15, 0x0000}, /* 00,15,00,aa */
+ {0xaa, 0x16, 0x0000}, /* 00,16,00,aa */
+ {0xaa, 0x17, 0x0001}, /* 00,17,01,aa */
+ {0xaa, 0x18, 0x00de}, /* 00,18,de,aa */
+ {0xaa, 0x19, 0x0002}, /* 00,19,02,aa */
+ {0xaa, 0x1a, 0x0086}, /* 00,1a,86,aa */
+ {0xaa, 0x20, 0x00a8}, /* 00,20,a8,aa */
+ {0xaa, 0x22, 0x0000}, /* 00,22,00,aa */
+ {0xaa, 0x23, 0x0000}, /* 00,23,00,aa */
+ {0xaa, 0x24, 0x0000}, /* 00,24,00,aa */
+ {0xaa, 0x40, 0x0033}, /* 00,40,33,aa */
+ {0xaa, 0x41, 0x0077}, /* 00,41,77,aa */
+ {0xaa, 0x42, 0x0053}, /* 00,42,53,aa */
+ {0xaa, 0x43, 0x00b0}, /* 00,43,b0,aa */
+ {0xaa, 0x4b, 0x0001}, /* 00,4b,01,aa */
+ {0xaa, 0x72, 0x0020}, /* 00,72,20,aa */
+ {0xaa, 0x73, 0x0000}, /* 00,73,00,aa */
+ {0xaa, 0x80, 0x0000}, /* 00,80,00,aa */
+ {0xaa, 0x85, 0x0050}, /* 00,85,50,aa */
+ {0xaa, 0x91, 0x0070}, /* 00,91,70,aa */
+ {0xaa, 0x92, 0x0072}, /* 00,92,72,aa */
+ {0xaa, 0x03, 0x0001}, /* 00,03,01,aa */
+ {0xaa, 0x10, 0x00a0}, /* 00,10,a0,aa */
+ {0xaa, 0x11, 0x0001}, /* 00,11,01,aa */
+ {0xaa, 0x30, 0x0000}, /* 00,30,00,aa */
+ {0xaa, 0x60, 0x0000}, /* 00,60,00,aa */
+ {0xaa, 0xa0, 0x001a}, /* 00,a0,1a,aa */
+ {0xaa, 0xa1, 0x0000}, /* 00,a1,00,aa */
+ {0xaa, 0xa2, 0x003f}, /* 00,a2,3f,aa */
+ {0xaa, 0xa3, 0x0028}, /* 00,a3,28,aa */
+ {0xaa, 0xa4, 0x0010}, /* 00,a4,10,aa */
+ {0xaa, 0xa5, 0x0020}, /* 00,a5,20,aa */
+ {0xaa, 0xb1, 0x0044}, /* 00,b1,44,aa */
+ {0xaa, 0xd0, 0x0001}, /* 00,d0,01,aa */
+ {0xaa, 0xd1, 0x0085}, /* 00,d1,85,aa */
+ {0xaa, 0xd2, 0x0080}, /* 00,d2,80,aa */
+ {0xaa, 0xd3, 0x0080}, /* 00,d3,80,aa */
+ {0xaa, 0xd4, 0x0080}, /* 00,d4,80,aa */
+ {0xaa, 0xd5, 0x0080}, /* 00,d5,80,aa */
+ {0xaa, 0xc0, 0x00c3}, /* 00,c0,c3,aa */
+ {0xaa, 0xc2, 0x0044}, /* 00,c2,44,aa */
+ {0xaa, 0xc4, 0x0040}, /* 00,c4,40,aa */
+ {0xaa, 0xc5, 0x0020}, /* 00,c5,20,aa */
+ {0xaa, 0xc6, 0x0008}, /* 00,c6,08,aa */
+ {0xaa, 0x03, 0x0004}, /* 00,03,04,aa */
+ {0xaa, 0x10, 0x0000}, /* 00,10,00,aa */
+ {0xaa, 0x40, 0x0030}, /* 00,40,30,aa */
+ {0xaa, 0x41, 0x0020}, /* 00,41,20,aa */
+ {0xaa, 0x42, 0x002d}, /* 00,42,2d,aa */
+ {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
+ {0xaa, 0x1c, 0x0050}, /* 00,1C,50,aa */
+ {0xaa, 0x11, 0x0081}, /* 00,11,81,aa */
+ {0xaa, 0x3b, 0x001d}, /* 00,3b,1D,aa */
+ {0xaa, 0x3c, 0x004c}, /* 00,3c,4C,aa */
+ {0xaa, 0x3d, 0x0018}, /* 00,3d,18,aa */
+ {0xaa, 0x3e, 0x006a}, /* 00,3e,6A,aa */
+ {0xaa, 0x01, 0x0000}, /* 00,01,00,aa */
+ {0xaa, 0x52, 0x00ff}, /* 00,52,FF,aa */
+ {0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
+ {0xa0, 0x0d, 0x0100}, /* 01,00,0d,cc */
+ {0xa0, 0x37, 0x0101}, /* 01,01,37,cc */
+ {0xa0, 0x06, 0x0189}, /* 01,89,06,cc */
+ {0xa0, 0x03, 0x01c5}, /* 01,c5,03,cc */
+ {0xa0, 0x13, 0x01cb}, /* 01,cb,13,cc */
+ {0xa0, 0x08, 0x0250}, /* 02,50,08,cc */
+ {0xa0, 0x08, 0x0301}, /* 03,01,08,cc */
+ {0xa0, 0x02, 0x0180}, /* 01,80,02,cc */
+ {0xaa, 0x03, 0x0002}, /* 00,03,02,aa */
+ {0xaa, 0x51, 0x0027}, /* 00,51,27,aa */
+ {0xaa, 0x52, 0x0020}, /* 00,52,20,aa */
+ {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
+ {0xaa, 0x50, 0x0010}, /* 00,50,10,aa */
+ {0xaa, 0x51, 0x0010}, /* 00,51,10,aa */
+ {0xaa, 0x54, 0x0010}, /* 00,54,10,aa */
+ {0xaa, 0x55, 0x0010}, /* 00,55,10,aa */
+ {0xa0, 0xf0, 0x0199}, /* 01,99,F0,cc */
+ {0xa0, 0x80, 0x019a}, /* 01,9A,80,cc */
+
+ {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
+ {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
+ {0xaa, 0x36, 0x001d}, /* 00,36,1D,aa */
+ {0xaa, 0x37, 0x004c}, /* 00,37,4C,aa */
+ {0xaa, 0x3b, 0x001d}, /* 00,3B,1D,aa */
+ {}
+};
+
+static const struct usb_action MC501CB_Initial[] = { /* 320x240 */
+ {0xa0, 0x01, 0x0000}, /* 00,00,01,cc */
+ {0xa0, 0x10, 0x0002}, /* 00,02,10,cc */
+ {0xa0, 0x01, 0x0010}, /* 00,10,01,cc */
+ {0xa0, 0x01, 0x0001}, /* 00,01,01,cc */
+ {0xa0, 0x03, 0x0008}, /* 00,08,03,cc */
+ {0xa0, 0x01, 0x0012}, /* 00,12,01,cc */
+ {0xa0, 0x05, 0x0012}, /* 00,12,05,cc */
+ {0xa0, 0x02, 0x0003}, /* 00,03,02,cc */
+ {0xa0, 0x80, 0x0004}, /* 00,04,80,cc */
+ {0xa0, 0x01, 0x0005}, /* 00,05,01,cc */
+ {0xa0, 0xd0, 0x0006}, /* 00,06,d0,cc */
+ {0xa0, 0x00, 0x0098}, /* 00,98,00,cc */
+ {0xa0, 0x00, 0x009a}, /* 00,9a,00,cc */
+ {0xa0, 0x00, 0x011a}, /* 01,1a,00,cc */
+ {0xa0, 0x00, 0x011c}, /* 01,1c,00,cc */
+ {0xa0, 0x01, 0x009b}, /* 00,9b,01,cc */
+ {0xa0, 0xd8, 0x009c}, /* 00,9c,d8,cc */
+ {0xa0, 0x02, 0x009d}, /* 00,9d,02,cc */
+ {0xa0, 0x88, 0x009e}, /* 00,9e,88,cc */
+ {0xa0, 0x33, 0x0086}, /* 00,86,33,cc */
+ {0xa0, 0x34, 0x0087}, /* 00,87,34,cc */
+ {0xa0, 0x35, 0x0088}, /* 00,88,35,cc */
+ {0xa0, 0xb0, 0x008b}, /* 00,8b,b0,cc */
+ {0xa0, 0x05, 0x0012}, /* 00,12,05,cc */
+ {0xaa, 0x01, 0x0001}, /* 00,01,01,aa */
+ {0xaa, 0x01, 0x0003}, /* 00,01,03,aa */
+ {0xaa, 0x01, 0x0001}, /* 00,01,01,aa */
+ {0xaa, 0x03, 0x0000}, /* 00,03,00,aa */
+ {0xaa, 0x10, 0x0000}, /* 00,10,00,aa */
+ {0xaa, 0x11, 0x0080}, /* 00,11,80,aa */
+ {0xaa, 0x12, 0x0000}, /* 00,12,00,aa */
+ {0xaa, 0x13, 0x0000}, /* 00,13,00,aa */
+ {0xaa, 0x14, 0x0000}, /* 00,14,00,aa */
+ {0xaa, 0x15, 0x0000}, /* 00,15,00,aa */
+ {0xaa, 0x16, 0x0000}, /* 00,16,00,aa */
+ {0xaa, 0x17, 0x0001}, /* 00,17,01,aa */
+ {0xaa, 0x18, 0x00d8}, /* 00,18,d8,aa */
+ {0xaa, 0x19, 0x0002}, /* 00,19,02,aa */
+ {0xaa, 0x1a, 0x0088}, /* 00,1a,88,aa */
+ {0xaa, 0x20, 0x00a8}, /* 00,20,a8,aa */
+ {0xaa, 0x22, 0x0000}, /* 00,22,00,aa */
+ {0xaa, 0x23, 0x0000}, /* 00,23,00,aa */
+ {0xaa, 0x24, 0x0000}, /* 00,24,00,aa */
+ {0xaa, 0x40, 0x0033}, /* 00,40,33,aa */
+ {0xaa, 0x41, 0x0077}, /* 00,41,77,aa */
+ {0xaa, 0x42, 0x0053}, /* 00,42,53,aa */
+ {0xaa, 0x43, 0x00b0}, /* 00,43,b0,aa */
+ {0xaa, 0x4b, 0x0001}, /* 00,4b,01,aa */
+ {0xaa, 0x72, 0x0020}, /* 00,72,20,aa */
+ {0xaa, 0x73, 0x0000}, /* 00,73,00,aa */
+ {0xaa, 0x80, 0x0000}, /* 00,80,00,aa */
+ {0xaa, 0x85, 0x0050}, /* 00,85,50,aa */
+ {0xaa, 0x91, 0x0070}, /* 00,91,70,aa */
+ {0xaa, 0x92, 0x0072}, /* 00,92,72,aa */
+ {0xaa, 0x03, 0x0001}, /* 00,03,01,aa */
+ {0xaa, 0x10, 0x00a0}, /* 00,10,a0,aa */
+ {0xaa, 0x11, 0x0001}, /* 00,11,01,aa */
+ {0xaa, 0x30, 0x0000}, /* 00,30,00,aa */
+ {0xaa, 0x60, 0x0000}, /* 00,60,00,aa */
+ {0xaa, 0xa0, 0x001a}, /* 00,a0,1a,aa */
+ {0xaa, 0xa1, 0x0000}, /* 00,a1,00,aa */
+ {0xaa, 0xa2, 0x003f}, /* 00,a2,3f,aa */
+ {0xaa, 0xa3, 0x0028}, /* 00,a3,28,aa */
+ {0xaa, 0xa4, 0x0010}, /* 00,a4,10,aa */
+ {0xaa, 0xa5, 0x0020}, /* 00,a5,20,aa */
+ {0xaa, 0xb1, 0x0044}, /* 00,b1,44,aa */
+ {0xaa, 0xd0, 0x0001}, /* 00,d0,01,aa */
+ {0xaa, 0xd1, 0x0085}, /* 00,d1,85,aa */
+ {0xaa, 0xd2, 0x0080}, /* 00,d2,80,aa */
+ {0xaa, 0xd3, 0x0080}, /* 00,d3,80,aa */
+ {0xaa, 0xd4, 0x0080}, /* 00,d4,80,aa */
+ {0xaa, 0xd5, 0x0080}, /* 00,d5,80,aa */
+ {0xaa, 0xc0, 0x00c3}, /* 00,c0,c3,aa */
+ {0xaa, 0xc2, 0x0044}, /* 00,c2,44,aa */
+ {0xaa, 0xc4, 0x0040}, /* 00,c4,40,aa */
+ {0xaa, 0xc5, 0x0020}, /* 00,c5,20,aa */
+ {0xaa, 0xc6, 0x0008}, /* 00,c6,08,aa */
+ {0xaa, 0x03, 0x0004}, /* 00,03,04,aa */
+ {0xaa, 0x10, 0x0000}, /* 00,10,00,aa */
+ {0xaa, 0x40, 0x0030}, /* 00,40,30,aa */
+ {0xaa, 0x41, 0x0020}, /* 00,41,20,aa */
+ {0xaa, 0x42, 0x002d}, /* 00,42,2d,aa */
+ {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
+ {0xaa, 0x1c, 0x0050}, /* 00,1c,50,aa */
+ {0xaa, 0x11, 0x0081}, /* 00,11,81,aa */
+ {0xaa, 0x3b, 0x003a}, /* 00,3b,3A,aa */
+ {0xaa, 0x3c, 0x0098}, /* 00,3c,98,aa */
+ {0xaa, 0x3d, 0x0030}, /* 00,3d,30,aa */
+ {0xaa, 0x3e, 0x00d4}, /* 00,3E,D4,aa */
+ {0xaa, 0x01, 0x0000}, /* 00,01,00,aa */
+ {0xaa, 0x52, 0x00ff}, /* 00,52,FF,aa */
+ {0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
+ {0xa0, 0x0d, 0x0100}, /* 01,00,0d,cc */
+ {0xa0, 0x37, 0x0101}, /* 01,01,37,cc */
+ {0xa0, 0x06, 0x0189}, /* 01,89,06,cc */
+ {0xa0, 0x03, 0x01c5}, /* 01,c5,03,cc */
+ {0xa0, 0x13, 0x01cb}, /* 01,cb,13,cc */
+ {0xa0, 0x08, 0x0250}, /* 02,50,08,cc */
+ {0xa0, 0x08, 0x0301}, /* 03,01,08,cc */
+ {0xa0, 0x02, 0x0180}, /* 01,80,02,cc */
+ {0xaa, 0x03, 0x0002}, /* 00,03,02,aa */
+ {0xaa, 0x51, 0x004e}, /* 00,51,4E,aa */
+ {0xaa, 0x52, 0x0041}, /* 00,52,41,aa */
+ {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
+ {0xaa, 0x50, 0x0010}, /* 00,50,10,aa */
+ {0xaa, 0x51, 0x0010}, /* 00,51,10,aa */
+ {0xaa, 0x54, 0x0010}, /* 00,54,10,aa */
+ {0xaa, 0x55, 0x0010}, /* 00,55,10,aa */
+ {0xa0, 0xf0, 0x0199}, /* 01,99,F0,cc */
+ {0xa0, 0x80, 0x019a}, /* 01,9A,80,cc */
+ {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
+ {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
+ {0xaa, 0x36, 0x001d}, /* 00,36,1D,aa */
+ {0xaa, 0x37, 0x004c}, /* 00,37,4C,aa */
+ {0xaa, 0x3b, 0x001d}, /* 00,3B,1D,aa */
+ {}
+};
+
+static const struct usb_action MC501CB_50HZ[] = {
+ {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
+ {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
+ {0xaa, 0x36, 0x001d}, /* 00,36,1D,aa */
+ {0xaa, 0x37, 0x004c}, /* 00,37,4C,aa */
+ {0xaa, 0x3b, 0x001d}, /* 00,3B,1D,aa */
+ {0xaa, 0x3c, 0x004c}, /* 00,3C,4C,aa */
+ {0xaa, 0x3d, 0x001d}, /* 00,3D,1D,aa */
+ {0xaa, 0x3e, 0x004c}, /* 00,3E,4C,aa */
+ {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
+ {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
+ {0xaa, 0x36, 0x003a}, /* 00,36,3A,aa */
+ {0xaa, 0x37, 0x0098}, /* 00,37,98,aa */
+ {0xaa, 0x3b, 0x003a}, /* 00,3B,3A,aa */
+ {}
+};
+
+static const struct usb_action MC501CB_50HZScale[] = {
+ {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
+ {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
+ {0xaa, 0x36, 0x003a}, /* 00,36,3A,aa */
+ {0xaa, 0x37, 0x0098}, /* 00,37,98,aa */
+ {0xaa, 0x3b, 0x003a}, /* 00,3B,3A,aa */
+ {0xaa, 0x3c, 0x0098}, /* 00,3C,98,aa */
+ {0xaa, 0x3d, 0x003a}, /* 00,3D,3A,aa */
+ {0xaa, 0x3e, 0x0098}, /* 00,3E,98,aa */
+ {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
+ {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
+ {0xaa, 0x36, 0x0018}, /* 00,36,18,aa */
+ {0xaa, 0x37, 0x006a}, /* 00,37,6A,aa */
+ {0xaa, 0x3d, 0x0018}, /* 00,3D,18,aa */
+ {}
+};
+
+static const struct usb_action MC501CB_60HZ[] = {
+ {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
+ {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
+ {0xaa, 0x36, 0x0018}, /* 00,36,18,aa */
+ {0xaa, 0x37, 0x006a}, /* 00,37,6A,aa */
+ {0xaa, 0x3d, 0x0018}, /* 00,3D,18,aa */
+ {0xaa, 0x3e, 0x006a}, /* 00,3E,6A,aa */
+ {0xaa, 0x3b, 0x0018}, /* 00,3B,18,aa */
+ {0xaa, 0x3c, 0x006a}, /* 00,3C,6A,aa */
+ {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
+ {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
+ {0xaa, 0x36, 0x0030}, /* 00,36,30,aa */
+ {0xaa, 0x37, 0x00d4}, /* 00,37,D4,aa */
+ {0xaa, 0x3d, 0x0030}, /* 00,3D,30,aa */
+ {}
+};
+
+static const struct usb_action MC501CB_60HZScale[] = {
+ {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
+ {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
+ {0xaa, 0x36, 0x0030}, /* 00,36,30,aa */
+ {0xaa, 0x37, 0x00d4}, /* 00,37,D4,aa */
+ {0xaa, 0x3d, 0x0030}, /* 00,3D,30,aa */
+ {0xaa, 0x3e, 0x00d4}, /* 00,3E,D4,aa */
+ {0xaa, 0x3b, 0x0030}, /* 00,3B,30,aa */
+ {0xaa, 0x3c, 0x00d4}, /* 00,3C,D4,aa */
+ {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
+ {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
+ {0xaa, 0x36, 0x0018}, /* 00,36,18,aa */
+ {0xaa, 0x37, 0x006a}, /* 00,37,6A,aa */
+ {0xaa, 0x3d, 0x0018}, /* 00,3D,18,aa */
+ {}
+};
+
+static const struct usb_action MC501CB_NoFliker[] = {
+ {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
+ {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
+ {0xaa, 0x36, 0x0018}, /* 00,36,18,aa */
+ {0xaa, 0x37, 0x006a}, /* 00,37,6A,aa */
+ {0xaa, 0x3d, 0x0018}, /* 00,3D,18,aa */
+ {0xaa, 0x3e, 0x006a}, /* 00,3E,6A,aa */
+ {0xaa, 0x3b, 0x0018}, /* 00,3B,18,aa */
+ {0xaa, 0x3c, 0x006a}, /* 00,3C,6A,aa */
+ {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
+ {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
+ {0xaa, 0x36, 0x0030}, /* 00,36,30,aa */
+ {0xaa, 0x37, 0x00d4}, /* 00,37,D4,aa */
+ {0xaa, 0x3d, 0x0030}, /* 00,3D,30,aa */
+ {}
+};
+
+static const struct usb_action MC501CB_NoFlikerScale[] = {
+ {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
+ {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
+ {0xaa, 0x36, 0x0030}, /* 00,36,30,aa */
+ {0xaa, 0x37, 0x00d4}, /* 00,37,D4,aa */
+ {0xaa, 0x3d, 0x0030}, /* 00,3D,30,aa */
+ {0xaa, 0x3e, 0x00d4}, /* 00,3E,D4,aa */
+ {0xaa, 0x3b, 0x0030}, /* 00,3B,30,aa */
+ {0xaa, 0x3c, 0x00d4}, /* 00,3C,D4,aa */
+ {}
+};
+
+/* from zs211.inf - HKR,%OV7620%,Initial - 640x480 */
+static const struct usb_action OV7620_mode0[] = {
+ {0xa0, 0x01, 0x0000}, /* 00,00,01,cc */
+ {0xa0, 0x40, 0x0002}, /* 00,02,40,cc */
+#if 1 /*jfm*/
+ {0xa0, 0x00, 0x0008}, /* 00,08,00,cc */
+#else
+ {0xa0, 0x03, 0x0008}, /* 00,08,00,cc */ /* mx change? */
+#endif
+ {0xa0, 0x01, 0x0001}, /* 00,01,01,cc */
+ {0xa0, 0x06, 0x0010}, /* 00,10,06,cc */
+ {0xa0, 0x02, 0x0083}, /* 00,83,02,cc */
+ {0xa0, 0x01, 0x0085}, /* 00,85,01,cc */
+ {0xa0, 0x80, 0x0086}, /* 00,86,80,cc */
+ {0xa0, 0x81, 0x0087}, /* 00,87,81,cc */
+ {0xa0, 0x10, 0x0088}, /* 00,88,10,cc */
+ {0xa0, 0xa1, 0x008b}, /* 00,8b,a1,cc */
+ {0xa0, 0x08, 0x008d}, /* 00,8d,08,cc */
+ {0xa0, 0x02, 0x0003}, /* 00,03,02,cc */
+ {0xa0, 0x80, 0x0004}, /* 00,04,80,cc */
+ {0xa0, 0x01, 0x0005}, /* 00,05,01,cc */
+ {0xa0, 0xd8, 0x0006}, /* 00,06,d8,cc */
+ {0xa0, 0x03, 0x0012}, /* 00,12,03,cc */
+ {0xa0, 0x01, 0x0012}, /* 00,12,01,cc */
+ {0xa0, 0x00, 0x0098}, /* 00,98,00,cc */
+ {0xa0, 0x00, 0x009a}, /* 00,9a,00,cc */
+ {0xa0, 0x00, 0x011a}, /* 01,1a,00,cc */
+ {0xa0, 0x00, 0x011c}, /* 01,1c,00,cc */
+ {0xa0, 0xde, 0x009c}, /* 00,9c,de,cc */
+ {0xa0, 0x86, 0x009e}, /* 00,9e,86,cc */
+ {0xaa, 0x12, 0x0088}, /* 00,12,88,aa */
+ {0xaa, 0x12, 0x0048}, /* 00,12,48,aa */
+ {0xaa, 0x75, 0x008a}, /* 00,75,8a,aa */
+ {0xaa, 0x13, 0x00a3}, /* 00,13,a3,aa */
+ {0xaa, 0x04, 0x0000}, /* 00,04,00,aa */
+ {0xaa, 0x05, 0x0000}, /* 00,05,00,aa */
+ {0xaa, 0x14, 0x0000}, /* 00,14,00,aa */
+ {0xaa, 0x15, 0x0004}, /* 00,15,04,aa */
+ {0xaa, 0x17, 0x0018}, /* 00,17,18,aa */
+ {0xaa, 0x18, 0x00ba}, /* 00,18,ba,aa */
+ {0xaa, 0x19, 0x0002}, /* 00,19,02,aa */
+ {0xaa, 0x1a, 0x00f1}, /* 00,1a,f1,aa */
+ {0xaa, 0x20, 0x0040}, /* 00,20,40,aa */
+ {0xaa, 0x24, 0x0088}, /* 00,24,88,aa */
+ {0xaa, 0x25, 0x0078}, /* 00,25,78,aa */
+ {0xaa, 0x27, 0x00f6}, /* 00,27,f6,aa */
+ {0xaa, 0x28, 0x00a0}, /* 00,28,a0,aa */
+ {0xaa, 0x21, 0x0000}, /* 00,21,00,aa */
+ {0xaa, 0x2a, 0x0083}, /* 00,2a,83,aa */
+ {0xaa, 0x2b, 0x0096}, /* 00,2b,96,aa */
+ {0xaa, 0x2d, 0x0005}, /* 00,2d,05,aa */
+ {0xaa, 0x74, 0x0020}, /* 00,74,20,aa */
+ {0xaa, 0x61, 0x0068}, /* 00,61,68,aa */
+ {0xaa, 0x64, 0x0088}, /* 00,64,88,aa */
+ {0xaa, 0x00, 0x0000}, /* 00,00,00,aa */
+ {0xaa, 0x06, 0x0080}, /* 00,06,80,aa */
+ {0xaa, 0x01, 0x0090}, /* 00,01,90,aa */
+ {0xaa, 0x02, 0x0030}, /* 00,02,30,aa */
+ {0xa0, 0x77, 0x0101}, /* 01,01,77,cc */
+ {0xa0, 0x05, 0x0012}, /* 00,12,05,cc */
+ {0xa0, 0x0d, 0x0100}, /* 01,00,0d,cc */
+ {0xa0, 0x06, 0x0189}, /* 01,89,06,cc */
+ {0xa0, 0x00, 0x01ad}, /* 01,ad,00,cc */
+ {0xa0, 0x03, 0x01c5}, /* 01,c5,03,cc */
+ {0xa0, 0x13, 0x01cb}, /* 01,cb,13,cc */
+ {0xa0, 0x08, 0x0250}, /* 02,50,08,cc */
+ {0xa0, 0x08, 0x0301}, /* 03,01,08,cc */
+ {0xa0, 0x68, 0x0116}, /* 01,16,68,cc */
+ {0xa0, 0x52, 0x0118}, /* 01,18,52,cc */
+ {0xa0, 0x40, 0x011d}, /* 01,1d,40,cc */
+ {0xa0, 0x02, 0x0180}, /* 01,80,02,cc */
+ {0xa0, 0x50, 0x01a8}, /* 01,a8,50,cc */
+ {}
+};
+
+/* from zs211.inf - HKR,%OV7620%,InitialScale - 320x240 */
+static const struct usb_action OV7620_mode1[] = {
+ {0xa0, 0x01, 0x0000}, /* 00,00,01,cc */
+ {0xa0, 0x50, 0x0002}, /* 00,02,50,cc */
+ {0xa0, 0x03, 0x0008}, /* 00,08,00,cc */ /* mx change? */
+ {0xa0, 0x01, 0x0001}, /* 00,01,01,cc */
+ {0xa0, 0x06, 0x0010}, /* 00,10,06,cc */
+ {0xa0, 0x02, 0x0083}, /* 00,83,02,cc */
+ {0xa0, 0x01, 0x0085}, /* 00,85,01,cc */
+ {0xa0, 0x80, 0x0086}, /* 00,86,80,cc */
+ {0xa0, 0x81, 0x0087}, /* 00,87,81,cc */
+ {0xa0, 0x10, 0x0088}, /* 00,88,10,cc */
+ {0xa0, 0xa1, 0x008b}, /* 00,8b,a1,cc */
+ {0xa0, 0x08, 0x008d}, /* 00,8d,08,cc */
+ {0xa0, 0x02, 0x0003}, /* 00,03,02,cc */
+ {0xa0, 0x80, 0x0004}, /* 00,04,80,cc */
+ {0xa0, 0x01, 0x0005}, /* 00,05,01,cc */
+ {0xa0, 0xd0, 0x0006}, /* 00,06,d0,cc */
+ {0xa0, 0x03, 0x0012}, /* 00,12,03,cc */
+ {0xa0, 0x01, 0x0012}, /* 00,12,01,cc */
+ {0xa0, 0x00, 0x0098}, /* 00,98,00,cc */
+ {0xa0, 0x00, 0x009a}, /* 00,9a,00,cc */
+ {0xa0, 0x00, 0x011a}, /* 01,1a,00,cc */
+ {0xa0, 0x00, 0x011c}, /* 01,1c,00,cc */
+ {0xa0, 0xd6, 0x009c}, /* 00,9c,d6,cc */ /* OV7648 00,9c,d8,cc */
+ {0xa0, 0x88, 0x009e}, /* 00,9e,88,cc */
+ {0xaa, 0x12, 0x0088}, /* 00,12,88,aa */
+ {0xaa, 0x12, 0x0048}, /* 00,12,48,aa */
+ {0xaa, 0x75, 0x008a}, /* 00,75,8a,aa */
+ {0xaa, 0x13, 0x00a3}, /* 00,13,a3,aa */
+ {0xaa, 0x04, 0x0000}, /* 00,04,00,aa */
+ {0xaa, 0x05, 0x0000}, /* 00,05,00,aa */
+ {0xaa, 0x14, 0x0000}, /* 00,14,00,aa */
+ {0xaa, 0x15, 0x0004}, /* 00,15,04,aa */
+ {0xaa, 0x24, 0x0088}, /* 00,24,88,aa */
+ {0xaa, 0x25, 0x0078}, /* 00,25,78,aa */
+ {0xaa, 0x17, 0x0018}, /* 00,17,18,aa */
+ {0xaa, 0x18, 0x00ba}, /* 00,18,ba,aa */
+ {0xaa, 0x19, 0x0002}, /* 00,19,02,aa */
+ {0xaa, 0x1a, 0x00f2}, /* 00,1a,f2,aa */
+ {0xaa, 0x20, 0x0040}, /* 00,20,40,aa */
+ {0xaa, 0x27, 0x00f6}, /* 00,27,f6,aa */
+ {0xaa, 0x28, 0x00a0}, /* 00,28,a0,aa */
+ {0xaa, 0x21, 0x0000}, /* 00,21,00,aa */
+ {0xaa, 0x2a, 0x0083}, /* 00,2a,83,aa */
+ {0xaa, 0x2b, 0x0096}, /* 00,2b,96,aa */
+ {0xaa, 0x2d, 0x0005}, /* 00,2d,05,aa */
+ {0xaa, 0x74, 0x0020}, /* 00,74,20,aa */
+ {0xaa, 0x61, 0x0068}, /* 00,61,68,aa */
+ {0xaa, 0x64, 0x0088}, /* 00,64,88,aa */
+ {0xaa, 0x00, 0x0000}, /* 00,00,00,aa */
+ {0xaa, 0x06, 0x0080}, /* 00,06,80,aa */
+ {0xaa, 0x01, 0x0090}, /* 00,01,90,aa */
+ {0xaa, 0x02, 0x0030}, /* 00,02,30,aa */
+ {0xa0, 0x77, 0x0101}, /* 01,01,77,cc */
+ {0xa0, 0x05, 0x0012}, /* 00,12,05,cc */
+ {0xa0, 0x0d, 0x0100}, /* 01,00,0d,cc */
+ {0xa0, 0x06, 0x0189}, /* 01,89,06,cc */
+ {0xa0, 0x00, 0x01ad}, /* 01,ad,00,cc */
+ {0xa0, 0x03, 0x01c5}, /* 01,c5,03,cc */
+ {0xa0, 0x13, 0x01cb}, /* 01,cb,13,cc */
+ {0xa0, 0x08, 0x0250}, /* 02,50,08,cc */
+ {0xa0, 0x08, 0x0301}, /* 03,01,08,cc */
+ {0xa0, 0x68, 0x0116}, /* 01,16,68,cc */
+ {0xa0, 0x52, 0x0118}, /* 01,18,52,cc */
+ {0xa0, 0x50, 0x011d}, /* 01,1d,50,cc */
+ {0xa0, 0x02, 0x0180}, /* 01,80,02,cc */
+ {0xa0, 0x50, 0x01a8}, /* 01,a8,50,cc */
+ {}
+};
+
+/* from zs211.inf - HKR,%OV7620%\AE,50HZ */
+static const struct usb_action OV7620_50HZ[] = {
+ {0xaa, 0x13, 0x00a3}, /* 00,13,a3,aa */
+ {0xdd, 0x00, 0x0100}, /* 00,01,00,dd */
+ {0xaa, 0x2b, 0x0096}, /* 00,2b,96,aa */
+ {0xaa, 0x75, 0x008a}, /* 00,75,8a,aa */
+ {0xaa, 0x2d, 0x0005}, /* 00,2d,05,aa */
+ {0xa0, 0x00, 0x0190}, /* 01,90,00,cc */
+ {0xa0, 0x04, 0x0191}, /* 01,91,04,cc */
+ {0xa0, 0x18, 0x0192}, /* 01,92,18,cc */
+ {0xa0, 0x00, 0x0195}, /* 01,95,00,cc */
+ {0xa0, 0x00, 0x0196}, /* 01,96,00,cc */
+ {0xa0, 0x83, 0x0197}, /* 01,97,83,cc */
+ {0xaa, 0x10, 0x0082}, /* 00,10,82,aa */
+ {0xaa, 0x76, 0x0003}, /* 00,76,03,aa */
+/* {0xa0, 0x40, 0x0002}, * 00,02,40,cc - if mode0 (640x480) */
+ {}
+};
+
+/* from zs211.inf - HKR,%OV7620%\AE,60HZ */
+static const struct usb_action OV7620_60HZ[] = {
+ {0xaa, 0x13, 0x00a3}, /* 00,13,a3,aa */ /* (bug in zs211.inf) */
+ {0xdd, 0x00, 0x0100}, /* 00,01,00,dd */
+ {0xaa, 0x2b, 0x0000}, /* 00,2b,00,aa */
+ {0xaa, 0x75, 0x008a}, /* 00,75,8a,aa */
+ {0xaa, 0x2d, 0x0005}, /* 00,2d,05,aa */
+ {0xa0, 0x00, 0x0190}, /* 01,90,00,cc */
+ {0xa0, 0x04, 0x0191}, /* 01,91,04,cc */
+ {0xa0, 0x18, 0x0192}, /* 01,92,18,cc */
+ {0xa0, 0x00, 0x0195}, /* 01,95,00,cc */
+ {0xa0, 0x00, 0x0196}, /* 01,96,00,cc */
+ {0xa0, 0x83, 0x0197}, /* 01,97,83,cc */
+ {0xaa, 0x10, 0x0020}, /* 00,10,20,aa */
+ {0xaa, 0x76, 0x0003}, /* 00,76,03,aa */
+/* {0xa0, 0x40, 0x0002}, * 00,02,40,cc - if mode0 (640x480) */
+/* ?? in gspca v1, it was
+ {0xa0, 0x00, 0x0039}, * 00,00,00,dd *
+ {0xa1, 0x01, 0x0037}, */
+ {}
+};
+
+/* from zs211.inf - HKR,%OV7620%\AE,NoFliker */
+static const struct usb_action OV7620_NoFliker[] = {
+ {0xaa, 0x13, 0x00a3}, /* 00,13,a3,aa */ /* (bug in zs211.inf) */
+ {0xdd, 0x00, 0x0100}, /* 00,01,00,dd */
+ {0xaa, 0x2b, 0x0000}, /* 00,2b,00,aa */
+ {0xaa, 0x75, 0x008e}, /* 00,75,8e,aa */
+ {0xaa, 0x2d, 0x0001}, /* 00,2d,01,aa */
+ {0xa0, 0x00, 0x0190}, /* 01,90,00,cc */
+ {0xa0, 0x04, 0x0191}, /* 01,91,04,cc */
+ {0xa0, 0x18, 0x0192}, /* 01,92,18,cc */
+ {0xa0, 0x00, 0x0195}, /* 01,95,00,cc */
+ {0xa0, 0x00, 0x0196}, /* 01,96,00,cc */
+ {0xa0, 0x01, 0x0197}, /* 01,97,01,cc */
+/* {0xa0, 0x44, 0x0002}, * 00,02,44,cc - if mode1 (320x240) */
+/* ?? was
+ {0xa0, 0x00, 0x0039}, * 00,00,00,dd *
+ {0xa1, 0x01, 0x0037}, */
+ {}
+};
+
+static const struct usb_action ov7630c_Initial[] = {
+ {0xa0, 0x01, 0x0000},
+ {0xa0, 0x10, 0x0002},
+ {0xa0, 0x01, 0x0000},
+ {0xa0, 0x10, 0x0002},
+ {0xa0, 0x03, 0x0008},
+ {0xa0, 0x01, 0x0001},
+ {0xa0, 0x06, 0x0010},
+ {0xa0, 0xa1, 0x008b},
+ {0xa0, 0x08, 0x008d},
+ {0xa0, 0x02, 0x0003},
+ {0xa0, 0x80, 0x0004},
+ {0xa0, 0x01, 0x0005},
+ {0xa0, 0xe0, 0x0006},
+ {0xa0, 0x01, 0x0012},
+ {0xaa, 0x12, 0x0080},
+ {0xa0, 0x02, 0x0083},
+ {0xa0, 0x01, 0x0085},
+ {0xa0, 0x90, 0x0086},
+ {0xa0, 0x91, 0x0087},
+ {0xa0, 0x10, 0x0088},
+ {0xa0, 0x00, 0x0098},
+ {0xa0, 0x00, 0x009a},
+ {0xa0, 0x00, 0x011a},
+ {0xa0, 0x00, 0x011c},
+ {0xa0, 0xd8, 0x009c},
+ {0xa0, 0x88, 0x009e},
+ {0xaa, 0x12, 0x0069},
+ {0xaa, 0x04, 0x0020},
+ {0xaa, 0x06, 0x0050},
+ {0xaa, 0x13, 0x0083},
+ {0xaa, 0x14, 0x0000},
+ {0xaa, 0x15, 0x0024},
+ {0xaa, 0x17, 0x0018},
+ {0xaa, 0x18, 0x00ba},
+ {0xaa, 0x19, 0x0002},
+ {0xaa, 0x1a, 0x00f6},
+ {0xaa, 0x1b, 0x0002},
+ {0xaa, 0x20, 0x00c2},
+ {0xaa, 0x24, 0x0060},
+ {0xaa, 0x25, 0x0040},
+ {0xaa, 0x26, 0x0030},
+ {0xaa, 0x27, 0x00ea},
+ {0xaa, 0x28, 0x00a0},
+ {0xaa, 0x21, 0x0000},
+ {0xaa, 0x2a, 0x0081},
+ {0xaa, 0x2b, 0x0096},
+ {0xaa, 0x2d, 0x0094},
+ {0xaa, 0x2f, 0x003d},
+ {0xaa, 0x30, 0x0024},
+ {0xaa, 0x60, 0x0000},
+ {0xaa, 0x61, 0x0040},
+ {0xaa, 0x68, 0x007c},
+ {0xaa, 0x6f, 0x0015},
+ {0xaa, 0x75, 0x0088},
+ {0xaa, 0x77, 0x00b5},
+ {0xaa, 0x01, 0x0060},
+ {0xaa, 0x02, 0x0060},
+ {0xa0, 0x05, 0x0012},
+ {0xa0, 0x77, 0x0101},
+ {0xa0, 0x0d, 0x0100},
+ {0xa0, 0x06, 0x0189},
+ {0xa0, 0x04, 0x01a7},
+ {0xa0, 0x00, 0x01ad},
+ {0xa0, 0x03, 0x01c5},
+ {0xa0, 0x13, 0x01cb},
+ {0xa0, 0x08, 0x0250},
+ {0xa0, 0x08, 0x0301},
+ {0xa0, 0x60, 0x0116},
+ {0xa0, 0x46, 0x0118},
+ {0xa0, 0x04, 0x0113},
+/* 0x10, */
+ {0xa1, 0x01, 0x0002},
+ {0xa0, 0x50, 0x010a}, /* matrix */
+ {0xa0, 0xf8, 0x010b},
+ {0xa0, 0xf8, 0x010c},
+ {0xa0, 0xf8, 0x010d},
+ {0xa0, 0x50, 0x010e},
+ {0xa0, 0xf8, 0x010f},
+ {0xa0, 0xf8, 0x0110},
+ {0xa0, 0xf8, 0x0111},
+ {0xa0, 0x50, 0x0112},
+/* 0x03, */
+ {0xa1, 0x01, 0x0008},
+ {0xa0, 0x03, 0x0008}, /* clock ? */
+ {0xa0, 0x08, 0x01c6}, /* sharpness+ */
+ {0xa1, 0x01, 0x01c8},
+ {0xa1, 0x01, 0x01c9},
+ {0xa1, 0x01, 0x01ca},
+ {0xa0, 0x0f, 0x01cb}, /* sharpness- */
+ {0xa0, 0x01, 0x0120}, /* gamma 2 ?*/
+ {0xa0, 0x0c, 0x0121},
+ {0xa0, 0x1f, 0x0122},
+ {0xa0, 0x3a, 0x0123},
+ {0xa0, 0x53, 0x0124},
+ {0xa0, 0x6d, 0x0125},
+ {0xa0, 0x85, 0x0126},
+ {0xa0, 0x9c, 0x0127},
+ {0xa0, 0xb0, 0x0128},
+ {0xa0, 0xc2, 0x0129},
+ {0xa0, 0xd1, 0x012a},
+ {0xa0, 0xde, 0x012b},
+ {0xa0, 0xe9, 0x012c},
+ {0xa0, 0xf2, 0x012d},
+ {0xa0, 0xf9, 0x012e},
+ {0xa0, 0xff, 0x012f},
+ {0xa0, 0x05, 0x0130},
+ {0xa0, 0x0f, 0x0131},
+ {0xa0, 0x16, 0x0132},
+ {0xa0, 0x1a, 0x0133},
+ {0xa0, 0x19, 0x0134},
+ {0xa0, 0x19, 0x0135},
+ {0xa0, 0x17, 0x0136},
+ {0xa0, 0x15, 0x0137},
+ {0xa0, 0x12, 0x0138},
+ {0xa0, 0x10, 0x0139},
+ {0xa0, 0x0e, 0x013a},
+ {0xa0, 0x0b, 0x013b},
+ {0xa0, 0x09, 0x013c},
+ {0xa0, 0x08, 0x013d},
+ {0xa0, 0x06, 0x013e},
+ {0xa0, 0x03, 0x013f},
+ {0xa0, 0x50, 0x010a}, /* matrix */
+ {0xa0, 0xf8, 0x010b},
+ {0xa0, 0xf8, 0x010c},
+ {0xa0, 0xf8, 0x010d},
+ {0xa0, 0x50, 0x010e},
+ {0xa0, 0xf8, 0x010f},
+ {0xa0, 0xf8, 0x0110},
+ {0xa0, 0xf8, 0x0111},
+ {0xa0, 0x50, 0x0112},
+
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x00, 0x0180},
+ {0xaa, 0x10, 0x001b},
+ {0xaa, 0x76, 0x0002},
+ {0xaa, 0x2a, 0x0081},
+ {0xaa, 0x2b, 0x0000},
+ {0xa0, 0x00, 0x0190},
+ {0xa0, 0x01, 0x0191},
+ {0xa0, 0xb8, 0x0192},
+ {0xa0, 0x00, 0x0195},
+ {0xa0, 0x00, 0x0196},
+ {0xa0, 0x37, 0x0197},
+ {0xa0, 0x10, 0x018c},
+ {0xa0, 0x20, 0x018f},
+ {0xa0, 0x10, 0x01a9},
+ {0xa0, 0x26, 0x01aa},
+ {0xa0, 0x50, 0x011d},
+ {0xa0, 0x02, 0x0180},
+ {0xa0, 0x40, 0x0180},
+ {0xaa, 0x13, 0x0083}, /* 40 */
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x42, 0x0180},
+ {}
+};
+
+static const struct usb_action ov7630c_InitialScale[] = {
+ {0xa0, 0x01, 0x0000},
+ {0xa0, 0x00, 0x0002},
+ {0xa0, 0x03, 0x0008},
+ {0xa0, 0x01, 0x0001},
+ {0xa0, 0x06, 0x0010},
+ {0xa0, 0xa1, 0x008b},
+ {0xa0, 0x08, 0x008d},
+ {0xa0, 0x02, 0x0003},
+ {0xa0, 0x80, 0x0004},
+ {0xa0, 0x01, 0x0005},
+ {0xa0, 0xe0, 0x0006},
+ {0xa0, 0x01, 0x0012},
+
+ {0xaa, 0x12, 0x0080},
+ {0xa0, 0x02, 0x0083},
+ {0xa0, 0x01, 0x0085},
+ {0xa0, 0x90, 0x0086},
+ {0xa0, 0x91, 0x0087},
+ {0xa0, 0x10, 0x0088},
+ {0xa0, 0x00, 0x0098},
+ {0xa0, 0x00, 0x009a},
+ {0xa0, 0x00, 0x011a},
+ {0xa0, 0x00, 0x011c},
+ {0xa0, 0xe6, 0x009c},
+ {0xa0, 0x86, 0x009e},
+ {0xaa, 0x12, 0x0069}, /* i2c */
+ {0xaa, 0x04, 0x0020},
+ {0xaa, 0x06, 0x0050},
+ {0xaa, 0x13, 0x00c3},
+ {0xaa, 0x14, 0x0000},
+ {0xaa, 0x15, 0x0024},
+ {0xaa, 0x19, 0x0003},
+ {0xaa, 0x1a, 0x00f6},
+ {0xaa, 0x1b, 0x0002},
+ {0xaa, 0x20, 0x00c2},
+ {0xaa, 0x24, 0x0060},
+ {0xaa, 0x25, 0x0040},
+ {0xaa, 0x26, 0x0030},
+ {0xaa, 0x27, 0x00ea},
+ {0xaa, 0x28, 0x00a0},
+ {0xaa, 0x21, 0x0000},
+ {0xaa, 0x2a, 0x0081},
+ {0xaa, 0x2b, 0x0096},
+ {0xaa, 0x2d, 0x0084},
+ {0xaa, 0x2f, 0x003d},
+ {0xaa, 0x30, 0x0024},
+ {0xaa, 0x60, 0x0000},
+ {0xaa, 0x61, 0x0040},
+ {0xaa, 0x68, 0x007c},
+ {0xaa, 0x6f, 0x0015},
+ {0xaa, 0x75, 0x0088},
+ {0xaa, 0x77, 0x00b5},
+ {0xaa, 0x01, 0x0060},
+ {0xaa, 0x02, 0x0060},
+ {0xaa, 0x17, 0x0018},
+ {0xaa, 0x18, 0x00ba},
+ {0xa0, 0x05, 0x0012},
+ {0xa0, 0x77, 0x0101},
+ {0xa0, 0x0d, 0x0100},
+ {0xa0, 0x06, 0x0189},
+ {0xa0, 0x04, 0x01a7},
+ {0xa0, 0x00, 0x01ad},
+ {0xa0, 0x03, 0x01c5},
+ {0xa0, 0x13, 0x01cb},
+ {0xa0, 0x08, 0x0250},
+ {0xa0, 0x08, 0x0301},
+ {0xa0, 0x60, 0x0116},
+ {0xa0, 0x46, 0x0118},
+ {0xa0, 0x04, 0x0113},
+
+ {0xa1, 0x01, 0x0002},
+ {0xa0, 0x4e, 0x010a}, /* matrix */
+ {0xa0, 0xfe, 0x010b},
+ {0xa0, 0xf4, 0x010c},
+ {0xa0, 0xf7, 0x010d},
+ {0xa0, 0x4d, 0x010e},
+ {0xa0, 0xfc, 0x010f},
+ {0xa0, 0x00, 0x0110},
+ {0xa0, 0xf6, 0x0111},
+ {0xa0, 0x4a, 0x0112},
+
+ {0xa1, 0x01, 0x0008},
+ {0xa0, 0x03, 0x0008}, /* clock ? */
+ {0xa0, 0x08, 0x01c6}, /* sharpness+ */
+ {0xa1, 0x01, 0x01c8},
+ {0xa1, 0x01, 0x01c9},
+ {0xa1, 0x01, 0x01ca},
+ {0xa0, 0x0f, 0x01cb}, /* sharpness- */
+ {0xa0, 0x16, 0x0120}, /* gamma ~4 */
+ {0xa0, 0x3a, 0x0121},
+ {0xa0, 0x5b, 0x0122},
+ {0xa0, 0x7c, 0x0123},
+ {0xa0, 0x94, 0x0124},
+ {0xa0, 0xa9, 0x0125},
+ {0xa0, 0xbb, 0x0126},
+ {0xa0, 0xca, 0x0127},
+ {0xa0, 0xd7, 0x0128},
+ {0xa0, 0xe1, 0x0129},
+ {0xa0, 0xea, 0x012a},
+ {0xa0, 0xf1, 0x012b},
+ {0xa0, 0xf7, 0x012c},
+ {0xa0, 0xfc, 0x012d},
+ {0xa0, 0xff, 0x012e},
+ {0xa0, 0xff, 0x012f},
+ {0xa0, 0x20, 0x0130},
+ {0xa0, 0x22, 0x0131},
+ {0xa0, 0x20, 0x0132},
+ {0xa0, 0x1c, 0x0133},
+ {0xa0, 0x16, 0x0134},
+ {0xa0, 0x13, 0x0135},
+ {0xa0, 0x10, 0x0136},
+ {0xa0, 0x0d, 0x0137},
+ {0xa0, 0x0b, 0x0138},
+ {0xa0, 0x09, 0x0139},
+ {0xa0, 0x07, 0x013a},
+ {0xa0, 0x06, 0x013b},
+ {0xa0, 0x05, 0x013c},
+ {0xa0, 0x04, 0x013d},
+ {0xa0, 0x00, 0x013e},
+ {0xa0, 0x01, 0x013f},
+ {0xa0, 0x4e, 0x010a}, /* matrix */
+ {0xa0, 0xfe, 0x010b},
+ {0xa0, 0xf4, 0x010c},
+ {0xa0, 0xf7, 0x010d},
+ {0xa0, 0x4d, 0x010e},
+ {0xa0, 0xfc, 0x010f},
+ {0xa0, 0x00, 0x0110},
+ {0xa0, 0xf6, 0x0111},
+ {0xa0, 0x4a, 0x0112},
+
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x00, 0x0180},
+ {0xaa, 0x10, 0x000d},
+ {0xaa, 0x76, 0x0002},
+ {0xaa, 0x2a, 0x0081},
+ {0xaa, 0x2b, 0x0000},
+ {0xa0, 0x00, 0x0190},
+ {0xa0, 0x00, 0x0191},
+ {0xa0, 0xd8, 0x0192},
+ {0xa0, 0x00, 0x0195},
+ {0xa0, 0x00, 0x0196},
+ {0xa0, 0x1b, 0x0197},
+ {0xa0, 0x10, 0x018c},
+ {0xa0, 0x20, 0x018f},
+ {0xa0, 0x10, 0x01a9},
+ {0xa0, 0x26, 0x01aa},
+ {0xa0, 0x50, 0x011d},
+ {0xa0, 0x02, 0x0180},
+ {0xa0, 0x40, 0x0180},
+ {0xaa, 0x13, 0x00c3},
+
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x42, 0x0180},
+ {}
+};
+
+static const struct usb_action pas106b_Initial_com[] = {
+/* Sream and Sensor specific */
+ {0xa1, 0x01, 0x0010}, /* CMOSSensorSelect */
+/* System */
+ {0xa0, 0x01, 0x0000}, /* SystemControl */
+ {0xa0, 0x01, 0x0000}, /* SystemControl */
+/* Picture size */
+ {0xa0, 0x00, 0x0002}, /* ClockSelect */
+ {0xa0, 0x03, 0x003a},
+ {0xa0, 0x0c, 0x003b},
+ {0xa0, 0x04, 0x0038},
+ {}
+};
+
+static const struct usb_action pas106b_Initial[] = { /* 176x144 */
+/* JPEG control */
+ {0xa0, 0x03, 0x0008}, /* ClockSetting */
+/* Sream and Sensor specific */
+ {0xa0, 0x0f, 0x0010}, /* CMOSSensorSelect */
+/* Picture size */
+ {0xa0, 0x00, 0x0003}, /* FrameWidthHigh 00 */
+ {0xa0, 0xb0, 0x0004}, /* FrameWidthLow B0 */
+ {0xa0, 0x00, 0x0005}, /* FrameHeightHigh 00 */
+ {0xa0, 0x90, 0x0006}, /* FrameHightLow 90 */
+/* System */
+ {0xa0, 0x01, 0x0001}, /* SystemOperating */
+/* Sream and Sensor specific */
+ {0xa0, 0x03, 0x0012}, /* VideoControlFunction */
+ {0xa0, 0x01, 0x0012}, /* VideoControlFunction */
+/* Sensor Interface */
+ {0xa0, 0x08, 0x008d}, /* Compatibily Mode */
+/* Window inside sensor array */
+ {0xa0, 0x03, 0x009a}, /* WinXStartLow */
+ {0xa0, 0x00, 0x011a}, /* FirstYLow */
+ {0xa0, 0x03, 0x011c}, /* FirstxLow */
+ {0xa0, 0x28, 0x009c}, /* WinHeightLow */
+ {0xa0, 0x68, 0x009e}, /* WinWidthLow */
+/* Init the sensor */
+ {0xaa, 0x02, 0x0004},
+ {0xaa, 0x08, 0x0000},
+ {0xaa, 0x09, 0x0005},
+ {0xaa, 0x0a, 0x0002},
+ {0xaa, 0x0b, 0x0002},
+ {0xaa, 0x0c, 0x0005},
+ {0xaa, 0x0d, 0x0000},
+ {0xaa, 0x0e, 0x0002},
+ {0xaa, 0x14, 0x0081},
+
+/* Other registors */
+ {0xa0, 0x37, 0x0101}, /* SensorCorrection */
+/* Frame retreiving */
+ {0xa0, 0x00, 0x0019}, /* AutoAdjustFPS */
+/* Gains */
+ {0xa0, 0xa0, 0x01a8}, /* DigitalGain */
+/* Unknown */
+ {0xa0, 0x00, 0x01ad},
+/* Sharpness */
+ {0xa0, 0x03, 0x01c5}, /* SharpnessMode */
+ {0xa0, 0x13, 0x01cb}, /* Sharpness05 */
+/* Other registors */
+ {0xa0, 0x0d, 0x0100}, /* OperationMode */
+/* Auto exposure and white balance */
+ {0xa0, 0x06, 0x0189}, /* AWBStatus */
+/*Dead pixels */
+ {0xa0, 0x08, 0x0250}, /* DeadPixelsMode */
+/* EEPROM */
+ {0xa0, 0x08, 0x0301}, /* EEPROMAccess */
+/* JPEG control */
+ {0xa0, 0x03, 0x0008}, /* ClockSetting */
+ {0xa0, 0x08, 0x01c6}, /* sharpness+ */
+ {0xa0, 0x0f, 0x01cb}, /* sharpness- */
+/* Other registers */
+ {0xa0, 0x0d, 0x0100}, /* OperationMode */
+/* Auto exposure and white balance */
+ {0xa0, 0x06, 0x0189}, /* AWBStatus */
+/*Dead pixels */
+ {0xa0, 0x08, 0x0250}, /* DeadPixelsMode */
+/* EEPROM */
+ {0xa0, 0x08, 0x0301}, /* EEPROMAccess */
+/* JPEG control */
+ {0xa0, 0x03, 0x0008}, /* ClockSetting */
+ {0xa0, 0x08, 0x01c6}, /* sharpness+ */
+ {0xa0, 0x0f, 0x01cb}, /* sharpness- */
+
+ {0xa0, 0x58, 0x010a}, /* matrix */
+ {0xa0, 0xf4, 0x010b},
+ {0xa0, 0xf4, 0x010c},
+ {0xa0, 0xf4, 0x010d},
+ {0xa0, 0x58, 0x010e},
+ {0xa0, 0xf4, 0x010f},
+ {0xa0, 0xf4, 0x0110},
+ {0xa0, 0xf4, 0x0111},
+ {0xa0, 0x58, 0x0112},
+/* Auto correction */
+ {0xa0, 0x03, 0x0181}, /* WinXstart */
+ {0xa0, 0x08, 0x0182}, /* WinXWidth */
+ {0xa0, 0x16, 0x0183}, /* WinXCenter */
+ {0xa0, 0x03, 0x0184}, /* WinYStart */
+ {0xa0, 0x05, 0x0185}, /* WinYWidth */
+ {0xa0, 0x14, 0x0186}, /* WinYCenter */
+ {0xa0, 0x00, 0x0180}, /* AutoCorrectEnable */
+
+/* Auto exposure and white balance */
+ {0xa0, 0x00, 0x0190}, /* ExposureLimitHigh */
+ {0xa0, 0x03, 0x0191}, /* ExposureLimitMid */
+ {0xa0, 0xb1, 0x0192}, /* ExposureLimitLow */
+ {0xa0, 0x00, 0x0195}, /* AntiFlickerHigh */
+ {0xa0, 0x00, 0x0196}, /* AntiFlickerLow */
+ {0xa0, 0x87, 0x0197}, /* AntiFlickerLow */
+ {0xa0, 0x0c, 0x018c}, /* AEBFreeze */
+ {0xa0, 0x18, 0x018f}, /* AEBUnfreeze */
+/* sensor on */
+ {0xaa, 0x07, 0x00b1},
+ {0xaa, 0x05, 0x0003},
+ {0xaa, 0x04, 0x0001},
+ {0xaa, 0x03, 0x003b},
+/* Gains */
+ {0xa0, 0x20, 0x01a9}, /* DigitalLimitDiff */
+ {0xa0, 0x26, 0x01aa}, /* DigitalGainStep */
+ {0xa0, 0xa0, 0x011d}, /* GlobalGain */
+ {0xa0, 0x60, 0x011d}, /* GlobalGain */
+/* Auto correction */
+ {0xa0, 0x40, 0x0180}, /* AutoCorrectEnable */
+ {0xa1, 0x01, 0x0180}, /* AutoCorrectEnable */
+ {0xa0, 0x42, 0x0180}, /* AutoCorrectEnable */
+/* Gains */
+ {0xa0, 0x40, 0x0116}, /* RGain */
+ {0xa0, 0x40, 0x0117}, /* GGain */
+ {0xa0, 0x40, 0x0118}, /* BGain */
+ {}
+};
+
+static const struct usb_action pas106b_InitialScale[] = { /* 352x288 */
+/* JPEG control */
+ {0xa0, 0x03, 0x0008}, /* ClockSetting */
+/* Sream and Sensor specific */
+ {0xa0, 0x0f, 0x0010}, /* CMOSSensorSelect */
+/* Picture size */
+ {0xa0, 0x01, 0x0003}, /* FrameWidthHigh */
+ {0xa0, 0x60, 0x0004}, /* FrameWidthLow */
+ {0xa0, 0x01, 0x0005}, /* FrameHeightHigh */
+ {0xa0, 0x20, 0x0006}, /* FrameHightLow */
+/* System */
+ {0xa0, 0x01, 0x0001}, /* SystemOperating */
+/* Sream and Sensor specific */
+ {0xa0, 0x03, 0x0012}, /* VideoControlFunction */
+ {0xa0, 0x01, 0x0012}, /* VideoControlFunction */
+/* Sensor Interface */
+ {0xa0, 0x08, 0x008d}, /* Compatibily Mode */
+/* Window inside sensor array */
+ {0xa0, 0x03, 0x009a}, /* WinXStartLow */
+ {0xa0, 0x00, 0x011a}, /* FirstYLow */
+ {0xa0, 0x03, 0x011c}, /* FirstxLow */
+ {0xa0, 0x28, 0x009c}, /* WinHeightLow */
+ {0xa0, 0x68, 0x009e}, /* WinWidthLow */
+/* Init the sensor */
+ {0xaa, 0x02, 0x0004},
+ {0xaa, 0x08, 0x0000},
+ {0xaa, 0x09, 0x0005},
+ {0xaa, 0x0a, 0x0002},
+ {0xaa, 0x0b, 0x0002},
+ {0xaa, 0x0c, 0x0005},
+ {0xaa, 0x0d, 0x0000},
+ {0xaa, 0x0e, 0x0002},
+ {0xaa, 0x14, 0x0081},
+
+/* Other registors */
+ {0xa0, 0x37, 0x0101}, /* SensorCorrection */
+/* Frame retreiving */
+ {0xa0, 0x00, 0x0019}, /* AutoAdjustFPS */
+/* Gains */
+ {0xa0, 0xa0, 0x01a8}, /* DigitalGain */
+/* Unknown */
+ {0xa0, 0x00, 0x01ad},
+/* Sharpness */
+ {0xa0, 0x03, 0x01c5}, /* SharpnessMode */
+ {0xa0, 0x13, 0x01cb}, /* Sharpness05 */
+/* Other registors */
+ {0xa0, 0x0d, 0x0100}, /* OperationMode */
+/* Auto exposure and white balance */
+ {0xa0, 0x06, 0x0189}, /* AWBStatus */
+ {0xa0, 0x80, 0x018d}, /* ????????? */
+/*Dead pixels */
+ {0xa0, 0x08, 0x0250}, /* DeadPixelsMode */
+/* EEPROM */
+ {0xa0, 0x08, 0x0301}, /* EEPROMAccess */
+/* JPEG control */
+ {0xa0, 0x03, 0x0008}, /* ClockSetting */
+ {0xa0, 0x08, 0x01c6}, /* sharpness+ */
+ {0xa0, 0x0f, 0x01cb}, /* sharpness- */
+/* Other registers */
+ {0xa0, 0x0d, 0x0100}, /* OperationMode */
+/* Auto exposure and white balance */
+ {0xa0, 0x06, 0x0189}, /* AWBStatus */
+/*Dead pixels */
+ {0xa0, 0x08, 0x0250}, /* DeadPixelsMode */
+/* EEPROM */
+ {0xa0, 0x08, 0x0301}, /* EEPROMAccess */
+/* JPEG control */
+ {0xa0, 0x03, 0x0008}, /* ClockSetting */
+ {0xa0, 0x08, 0x01c6}, /* sharpness+ */
+ {0xa0, 0x0f, 0x01cb}, /* sharpness- */
+
+ {0xa0, 0x58, 0x010a}, /* matrix */
+ {0xa0, 0xf4, 0x010b},
+ {0xa0, 0xf4, 0x010c},
+ {0xa0, 0xf4, 0x010d},
+ {0xa0, 0x58, 0x010e},
+ {0xa0, 0xf4, 0x010f},
+ {0xa0, 0xf4, 0x0110},
+ {0xa0, 0xf4, 0x0111},
+ {0xa0, 0x58, 0x0112},
+/* Auto correction */
+ {0xa0, 0x03, 0x0181}, /* WinXstart */
+ {0xa0, 0x08, 0x0182}, /* WinXWidth */
+ {0xa0, 0x16, 0x0183}, /* WinXCenter */
+ {0xa0, 0x03, 0x0184}, /* WinYStart */
+ {0xa0, 0x05, 0x0185}, /* WinYWidth */
+ {0xa0, 0x14, 0x0186}, /* WinYCenter */
+ {0xa0, 0x00, 0x0180}, /* AutoCorrectEnable */
+
+/* Auto exposure and white balance */
+ {0xa0, 0x00, 0x0190}, /* ExposureLimitHigh 0 */
+ {0xa0, 0x03, 0x0191}, /* ExposureLimitMid */
+ {0xa0, 0xb1, 0x0192}, /* ExposureLimitLow 0xb1 */
+
+ {0xa0, 0x00, 0x0195}, /* AntiFlickerHigh 0x00 */
+ {0xa0, 0x00, 0x0196}, /* AntiFlickerLow 0x00 */
+ {0xa0, 0x87, 0x0197}, /* AntiFlickerLow 0x87 */
+
+ {0xa0, 0x10, 0x018c}, /* AEBFreeze 0x10 0x0c */
+ {0xa0, 0x20, 0x018f}, /* AEBUnfreeze 0x30 0x18 */
+/* sensor on */
+ {0xaa, 0x07, 0x00b1},
+ {0xaa, 0x05, 0x0003},
+ {0xaa, 0x04, 0x0001},
+ {0xaa, 0x03, 0x003b},
+/* Gains */
+ {0xa0, 0x20, 0x01a9}, /* DigitalLimitDiff */
+ {0xa0, 0x26, 0x01aa}, /* DigitalGainStep */
+ {0xa0, 0xa0, 0x011d}, /* GlobalGain */
+ {0xa0, 0x60, 0x011d}, /* GlobalGain */
+/* Auto correction */
+ {0xa0, 0x40, 0x0180}, /* AutoCorrectEnable */
+ {0xa1, 0x01, 0x0180}, /* AutoCorrectEnable */
+ {0xa0, 0x42, 0x0180}, /* AutoCorrectEnable */
+/* Gains */
+ {0xa0, 0x40, 0x0116}, /* RGain */
+ {0xa0, 0x40, 0x0117}, /* GGain */
+ {0xa0, 0x40, 0x0118}, /* BGain */
+
+ {0xa0, 0x00, 0x0007}, /* AutoCorrectEnable */
+ {0xa0, 0xff, 0x0018}, /* Frame adjust */
+ {}
+};
+static const struct usb_action pas106b_50HZ[] = {
+ {0xa0, 0x00, 0x0190}, /* 01,90,00,cc */
+ {0xa0, 0x06, 0x0191}, /* 01,91,06,cc */
+ {0xa0, 0x54, 0x0192}, /* 01,92,54,cc */
+ {0xa0, 0x00, 0x0195}, /* 01,95,00,cc */
+ {0xa0, 0x00, 0x0196}, /* 01,96,00,cc */
+ {0xa0, 0x87, 0x0197}, /* 01,97,87,cc */
+ {0xa0, 0x10, 0x018c}, /* 01,8c,10,cc */
+ {0xa0, 0x30, 0x018f}, /* 01,8f,30,cc */
+ {0xaa, 0x03, 0x0021}, /* 00,03,21,aa */
+ {0xaa, 0x04, 0x000c}, /* 00,04,0c,aa */
+ {0xaa, 0x05, 0x0002}, /* 00,05,02,aa */
+ {0xaa, 0x07, 0x001c}, /* 00,07,1c,aa */
+ {0xa0, 0x04, 0x01a9}, /* 01,a9,04,cc */
+ {}
+};
+static const struct usb_action pas106b_60HZ[] = {
+ {0xa0, 0x00, 0x0190}, /* 01,90,00,cc */
+ {0xa0, 0x06, 0x0191}, /* 01,91,06,cc */
+ {0xa0, 0x2e, 0x0192}, /* 01,92,2e,cc */
+ {0xa0, 0x00, 0x0195}, /* 01,95,00,cc */
+ {0xa0, 0x00, 0x0196}, /* 01,96,00,cc */
+ {0xa0, 0x71, 0x0197}, /* 01,97,71,cc */
+ {0xa0, 0x10, 0x018c}, /* 01,8c,10,cc */
+ {0xa0, 0x30, 0x018f}, /* 01,8f,30,cc */
+ {0xaa, 0x03, 0x001c}, /* 00,03,1c,aa */
+ {0xaa, 0x04, 0x0004}, /* 00,04,04,aa */
+ {0xaa, 0x05, 0x0001}, /* 00,05,01,aa */
+ {0xaa, 0x07, 0x00c4}, /* 00,07,c4,aa */
+ {0xa0, 0x04, 0x01a9}, /* 01,a9,04,cc */
+ {}
+};
+static const struct usb_action pas106b_NoFliker[] = {
+ {0xa0, 0x00, 0x0190}, /* 01,90,00,cc */
+ {0xa0, 0x06, 0x0191}, /* 01,91,06,cc */
+ {0xa0, 0x50, 0x0192}, /* 01,92,50,cc */
+ {0xa0, 0x00, 0x0195}, /* 01,95,00,cc */
+ {0xa0, 0x00, 0x0196}, /* 01,96,00,cc */
+ {0xa0, 0x10, 0x0197}, /* 01,97,10,cc */
+ {0xa0, 0x10, 0x018c}, /* 01,8c,10,cc */
+ {0xa0, 0x20, 0x018f}, /* 01,8f,20,cc */
+ {0xaa, 0x03, 0x0013}, /* 00,03,13,aa */
+ {0xaa, 0x04, 0x0000}, /* 00,04,00,aa */
+ {0xaa, 0x05, 0x0001}, /* 00,05,01,aa */
+ {0xaa, 0x07, 0x0030}, /* 00,07,30,aa */
+ {0xa0, 0x00, 0x01a9}, /* 01,a9,00,cc */
+ {}
+};
+
+static const struct usb_action pb03303x_Initial[] = {
+ {0xa0, 0x01, 0x0000},
+ {0xa0, 0x03, 0x0008},
+ {0xa0, 0x0a, 0x0010},
+ {0xa0, 0x10, 0x0002},
+ {0xa0, 0x02, 0x0003},
+ {0xa0, 0x80, 0x0004},
+ {0xa0, 0x01, 0x0005},
+ {0xa0, 0xe0, 0x0006},
+ {0xa0, 0xdc, 0x008b}, /* 8b -> dc */
+ {0xa0, 0x01, 0x0001},
+ {0xa0, 0x03, 0x0012},
+ {0xa0, 0x01, 0x0012},
+ {0xa0, 0x00, 0x0098},
+ {0xa0, 0x00, 0x009a},
+ {0xa0, 0x00, 0x011a},
+ {0xa0, 0x00, 0x011c},
+ {0xa0, 0xdc, 0x008b},
+ {0xaa, 0x01, 0x0001},
+ {0xaa, 0x06, 0x0000},
+ {0xaa, 0x08, 0x0483},
+ {0xaa, 0x01, 0x0004},
+ {0xaa, 0x08, 0x0006},
+ {0xaa, 0x02, 0x0011},
+ {0xaa, 0x03, 0x01e7},
+ {0xaa, 0x04, 0x0287},
+ {0xaa, 0x07, 0x3002},
+ {0xaa, 0x20, 0x1100},
+ {0xaa, 0x35, 0x0050},
+ {0xaa, 0x30, 0x0005},
+ {0xaa, 0x31, 0x0000},
+ {0xaa, 0x58, 0x0078},
+ {0xaa, 0x62, 0x0411},
+ {0xaa, 0x2b, 0x0028},
+ {0xaa, 0x2c, 0x0030},
+ {0xaa, 0x2d, 0x0030},
+ {0xaa, 0x2e, 0x0028},
+ {0xa0, 0x10, 0x0087},
+ {0xa0, 0x37, 0x0101},
+ {0xa0, 0x05, 0x0012},
+ {0xa0, 0x0d, 0x0100},
+ {0xa0, 0x06, 0x0189},
+ {0xa0, 0x00, 0x01ad},
+ {0xa0, 0x03, 0x01c5},
+ {0xa0, 0x13, 0x01cb},
+ {0xa0, 0x08, 0x0250},
+ {0xa0, 0x08, 0x0301},
+ {0xa0, 0x60, 0x01a8},
+ {0xa0, 0x78, 0x018d},
+ {0xa0, 0x61, 0x0116},
+ {0xa0, 0x65, 0x0118},
+
+ {0xa1, 0x01, 0x0002},
+ {0xa0, 0x09, 0x01ad},
+ {0xa0, 0x15, 0x01ae},
+ {0xa0, 0x0d, 0x003a},
+ {0xa0, 0x02, 0x003b},
+ {0xa0, 0x00, 0x0038},
+ {0xa0, 0x50, 0x010a}, /* matrix */
+ {0xa0, 0xf8, 0x010b},
+ {0xa0, 0xf8, 0x010c},
+ {0xa0, 0xf8, 0x010d},
+ {0xa0, 0x50, 0x010e},
+ {0xa0, 0xf8, 0x010f},
+ {0xa0, 0xf8, 0x0110},
+ {0xa0, 0xf8, 0x0111},
+ {0xa0, 0x50, 0x0112},
+
+ {0xa1, 0x01, 0x0008},
+ {0xa0, 0x03, 0x0008}, /* clock ? */
+ {0xa0, 0x08, 0x01c6}, /* sharpness+ */
+ {0xa1, 0x01, 0x01c8},
+ {0xa1, 0x01, 0x01c9},
+ {0xa1, 0x01, 0x01ca},
+ {0xa0, 0x0f, 0x01cb}, /* sharpness- */
+ {0xa0, 0x13, 0x0120}, /* gamma 4 */
+ {0xa0, 0x38, 0x0121},
+ {0xa0, 0x59, 0x0122},
+ {0xa0, 0x79, 0x0123},
+ {0xa0, 0x92, 0x0124},
+ {0xa0, 0xa7, 0x0125},
+ {0xa0, 0xb9, 0x0126},
+ {0xa0, 0xc8, 0x0127},
+ {0xa0, 0xd4, 0x0128},
+ {0xa0, 0xdf, 0x0129},
+ {0xa0, 0xe7, 0x012a},
+ {0xa0, 0xee, 0x012b},
+ {0xa0, 0xf4, 0x012c},
+ {0xa0, 0xf9, 0x012d},
+ {0xa0, 0xfc, 0x012e},
+ {0xa0, 0xff, 0x012f},
+ {0xa0, 0x26, 0x0130},
+ {0xa0, 0x22, 0x0131},
+ {0xa0, 0x20, 0x0132},
+ {0xa0, 0x1c, 0x0133},
+ {0xa0, 0x16, 0x0134},
+ {0xa0, 0x13, 0x0135},
+ {0xa0, 0x10, 0x0136},
+ {0xa0, 0x0d, 0x0137},
+ {0xa0, 0x0b, 0x0138},
+ {0xa0, 0x09, 0x0139},
+ {0xa0, 0x07, 0x013a},
+ {0xa0, 0x06, 0x013b},
+ {0xa0, 0x05, 0x013c},
+ {0xa0, 0x04, 0x013d},
+ {0xa0, 0x03, 0x013e},
+ {0xa0, 0x02, 0x013f},
+ {0xa0, 0x50, 0x010a}, /* matrix */
+ {0xa0, 0xf8, 0x010b},
+ {0xa0, 0xf8, 0x010c},
+ {0xa0, 0xf8, 0x010d},
+ {0xa0, 0x50, 0x010e},
+ {0xa0, 0xf8, 0x010f},
+ {0xa0, 0xf8, 0x0110},
+ {0xa0, 0xf8, 0x0111},
+ {0xa0, 0x50, 0x0112},
+
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x00, 0x0180},
+ {0xa0, 0x00, 0x0180},
+ {0xa0, 0x00, 0x0019},
+ {0xaa, 0x05, 0x0009},
+ {0xaa, 0x09, 0x0134},
+ {0xa0, 0x00, 0x0190},
+ {0xa0, 0x07, 0x0191},
+ {0xa0, 0xec, 0x0192},
+ {0xa0, 0x00, 0x0195},
+ {0xa0, 0x00, 0x0196},
+ {0xa0, 0x9c, 0x0197},
+ {0xa0, 0x0e, 0x018c},
+ {0xa0, 0x1c, 0x018f},
+ {0xa0, 0x14, 0x01a9},
+ {0xa0, 0x24, 0x01aa},
+ {0xa0, 0xd7, 0x001d},
+ {0xa0, 0xf4, 0x001e},
+ {0xa0, 0xf9, 0x001f},
+ {0xa0, 0xff, 0x0020},
+ {0xa0, 0x42, 0x0180},
+ {0xa0, 0x09, 0x01ad},
+ {0xa0, 0x15, 0x01ae},
+ {0xa0, 0x40, 0x0180},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x42, 0x0180},
+ {}
+};
+
+static const struct usb_action pb03303x_InitialScale[] = {
+ {0xa0, 0x01, 0x0000},
+ {0xa0, 0x03, 0x0008},
+ {0xa0, 0x0a, 0x0010},
+ {0xa0, 0x00, 0x0002},
+ {0xa0, 0x02, 0x0003},
+ {0xa0, 0x80, 0x0004},
+ {0xa0, 0x01, 0x0005},
+ {0xa0, 0xe0, 0x0006},
+ {0xa0, 0xdc, 0x008b}, /* 8b -> dc */
+ {0xa0, 0x01, 0x0001},
+ {0xa0, 0x03, 0x0012},
+ {0xa0, 0x01, 0x0012},
+ {0xa0, 0x00, 0x0098},
+ {0xa0, 0x00, 0x009a},
+ {0xa0, 0x00, 0x011a},
+ {0xa0, 0x00, 0x011c},
+ {0xa0, 0xdc, 0x008b},
+ {0xaa, 0x01, 0x0001},
+ {0xaa, 0x06, 0x0000},
+ {0xaa, 0x08, 0x0483},
+ {0xaa, 0x01, 0x0004},
+ {0xaa, 0x08, 0x0006},
+ {0xaa, 0x02, 0x0011},
+ {0xaa, 0x03, 0x01e7},
+ {0xaa, 0x04, 0x0287},
+ {0xaa, 0x07, 0x3002},
+ {0xaa, 0x20, 0x1100},
+ {0xaa, 0x35, 0x0050},
+ {0xaa, 0x30, 0x0005},
+ {0xaa, 0x31, 0x0000},
+ {0xaa, 0x58, 0x0078},
+ {0xaa, 0x62, 0x0411},
+ {0xaa, 0x2b, 0x0028},
+ {0xaa, 0x2c, 0x0030},
+ {0xaa, 0x2d, 0x0030},
+ {0xaa, 0x2e, 0x0028},
+ {0xa0, 0x10, 0x0087},
+ {0xa0, 0x37, 0x0101},
+ {0xa0, 0x05, 0x0012},
+ {0xa0, 0x0d, 0x0100},
+ {0xa0, 0x06, 0x0189},
+ {0xa0, 0x00, 0x01ad},
+ {0xa0, 0x03, 0x01c5},
+ {0xa0, 0x13, 0x01cb},
+ {0xa0, 0x08, 0x0250},
+ {0xa0, 0x08, 0x0301},
+ {0xa0, 0x60, 0x01a8},
+ {0xa0, 0x78, 0x018d},
+ {0xa0, 0x61, 0x0116},
+ {0xa0, 0x65, 0x0118},
+
+ {0xa1, 0x01, 0x0002},
+
+ {0xa0, 0x09, 0x01ad},
+ {0xa0, 0x15, 0x01ae},
+
+ {0xa0, 0x0d, 0x003a},
+ {0xa0, 0x02, 0x003b},
+ {0xa0, 0x00, 0x0038},
+ {0xa0, 0x50, 0x010a}, /* matrix */
+ {0xa0, 0xf8, 0x010b},
+ {0xa0, 0xf8, 0x010c},
+ {0xa0, 0xf8, 0x010d},
+ {0xa0, 0x50, 0x010e},
+ {0xa0, 0xf8, 0x010f},
+ {0xa0, 0xf8, 0x0110},
+ {0xa0, 0xf8, 0x0111},
+ {0xa0, 0x50, 0x0112},
+
+ {0xa1, 0x01, 0x0008},
+ {0xa0, 0x03, 0x0008}, /* clock ? */
+ {0xa0, 0x08, 0x01c6}, /* sharpness+ */
+ {0xa1, 0x01, 0x01c8},
+ {0xa1, 0x01, 0x01c9},
+ {0xa1, 0x01, 0x01ca},
+ {0xa0, 0x0f, 0x01cb}, /* sharpness- */
+
+ {0xa0, 0x13, 0x0120}, /* gamma 4 */
+ {0xa0, 0x38, 0x0121},
+ {0xa0, 0x59, 0x0122},
+ {0xa0, 0x79, 0x0123},
+ {0xa0, 0x92, 0x0124},
+ {0xa0, 0xa7, 0x0125},
+ {0xa0, 0xb9, 0x0126},
+ {0xa0, 0xc8, 0x0127},
+ {0xa0, 0xd4, 0x0128},
+ {0xa0, 0xdf, 0x0129},
+ {0xa0, 0xe7, 0x012a},
+ {0xa0, 0xee, 0x012b},
+ {0xa0, 0xf4, 0x012c},
+ {0xa0, 0xf9, 0x012d},
+ {0xa0, 0xfc, 0x012e},
+ {0xa0, 0xff, 0x012f},
+ {0xa0, 0x26, 0x0130},
+ {0xa0, 0x22, 0x0131},
+ {0xa0, 0x20, 0x0132},
+ {0xa0, 0x1c, 0x0133},
+ {0xa0, 0x16, 0x0134},
+ {0xa0, 0x13, 0x0135},
+ {0xa0, 0x10, 0x0136},
+ {0xa0, 0x0d, 0x0137},
+ {0xa0, 0x0b, 0x0138},
+ {0xa0, 0x09, 0x0139},
+ {0xa0, 0x07, 0x013a},
+ {0xa0, 0x06, 0x013b},
+ {0xa0, 0x05, 0x013c},
+ {0xa0, 0x04, 0x013d},
+ {0xa0, 0x03, 0x013e},
+ {0xa0, 0x02, 0x013f},
+ {0xa0, 0x50, 0x010a}, /* matrix */
+ {0xa0, 0xf8, 0x010b},
+ {0xa0, 0xf8, 0x010c},
+ {0xa0, 0xf8, 0x010d},
+ {0xa0, 0x50, 0x010e},
+ {0xa0, 0xf8, 0x010f},
+ {0xa0, 0xf8, 0x0110},
+ {0xa0, 0xf8, 0x0111},
+ {0xa0, 0x50, 0x0112},
+
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x00, 0x0180},
+ {0xa0, 0x00, 0x0180},
+ {0xa0, 0x00, 0x0019},
+ {0xaa, 0x05, 0x0009},
+ {0xaa, 0x09, 0x0134},
+ {0xa0, 0x00, 0x0190},
+ {0xa0, 0x07, 0x0191},
+ {0xa0, 0xec, 0x0192},
+ {0xa0, 0x00, 0x0195},
+ {0xa0, 0x00, 0x0196},
+ {0xa0, 0x9c, 0x0197},
+ {0xa0, 0x0e, 0x018c},
+ {0xa0, 0x1c, 0x018f},
+ {0xa0, 0x14, 0x01a9},
+ {0xa0, 0x24, 0x01aa},
+ {0xa0, 0xd7, 0x001d},
+ {0xa0, 0xf4, 0x001e},
+ {0xa0, 0xf9, 0x001f},
+ {0xa0, 0xff, 0x0020},
+ {0xa0, 0x42, 0x0180},
+ {0xa0, 0x09, 0x01ad},
+ {0xa0, 0x15, 0x01ae},
+ {0xa0, 0x40, 0x0180},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x42, 0x0180},
+ {}
+};
+static const struct usb_action pb0330xx_Initial[] = {
+ {0xa1, 0x01, 0x0008},
+ {0xa1, 0x01, 0x0008},
+ {0xa0, 0x01, 0x0000},
+ {0xa0, 0x03, 0x0008}, /* 00 */
+ {0xa0, 0x0a, 0x0010},
+ {0xa0, 0x10, 0x0002},
+ {0xa0, 0x02, 0x0003},
+ {0xa0, 0x80, 0x0004},
+ {0xa0, 0x01, 0x0005},
+ {0xa0, 0xe0, 0x0006},
+ {0xa0, 0x01, 0x0001},
+ {0xa0, 0x05, 0x0012},
+ {0xa0, 0x07, 0x0012},
+ {0xa0, 0x00, 0x0098},
+ {0xa0, 0x00, 0x009a},
+ {0xa0, 0x00, 0x011a},
+ {0xa0, 0x00, 0x011c},
+ {0xa0, 0x05, 0x0012},
+ {0xaa, 0x01, 0x0006},
+ {0xaa, 0x02, 0x0011},
+ {0xaa, 0x03, 0x01e7},
+ {0xaa, 0x04, 0x0287},
+ {0xaa, 0x06, 0x0003},
+ {0xaa, 0x07, 0x3002},
+ {0xaa, 0x20, 0x1100},
+ {0xaa, 0x2f, 0xf7b0},
+ {0xaa, 0x30, 0x0005},
+ {0xaa, 0x31, 0x0000},
+ {0xaa, 0x34, 0x0100},
+ {0xaa, 0x35, 0x0060},
+ {0xaa, 0x3d, 0x068f},
+ {0xaa, 0x40, 0x01e0},
+ {0xaa, 0x58, 0x0078},
+ {0xaa, 0x62, 0x0411},
+ {0xa0, 0x10, 0x0087},
+ {0xa0, 0x37, 0x0101},
+ {0xa0, 0x05, 0x0012},
+ {0xa0, 0x0d, 0x0100},
+ {0xa0, 0x06, 0x0189},
+ {0xa0, 0x00, 0x01ad},
+ {0xa0, 0x03, 0x01c5},
+ {0xa0, 0x13, 0x01cb},
+ {0xa0, 0x08, 0x0250},
+ {0xa0, 0x08, 0x0301},
+ {0xa0, 0x60, 0x01a8},
+ {0xa0, 0x6c, 0x018d},
+ {0xa1, 0x01, 0x0002},
+ {0xa0, 0x09, 0x01ad},
+ {0xa0, 0x15, 0x01ae},
+ {0xa0, 0x00, 0x0092},
+ {0xa0, 0x02, 0x0090},
+ {0xa1, 0x01, 0x0091},
+ {0xa1, 0x01, 0x0095},
+ {0xa1, 0x01, 0x0096},
+ {0xa0, 0x50, 0x010a}, /* matrix */
+ {0xa0, 0xf8, 0x010b},
+ {0xa0, 0xf8, 0x010c},
+ {0xa0, 0xf8, 0x010d},
+ {0xa0, 0x50, 0x010e},
+ {0xa0, 0xf8, 0x010f},
+ {0xa0, 0xf8, 0x0110},
+ {0xa0, 0xf8, 0x0111},
+ {0xa0, 0x50, 0x0112},
+ {0xa1, 0x01, 0x0008},
+ {0xa0, 0x03, 0x0008}, /* clock ? */
+ {0xa0, 0x08, 0x01c6}, /* sharpness+ */
+ {0xa1, 0x01, 0x01c8},
+ {0xa1, 0x01, 0x01c9},
+ {0xa1, 0x01, 0x01ca},
+ {0xa0, 0x0f, 0x01cb}, /* sharpness- */
+
+ {0xa0, 0x50, 0x010a}, /* matrix */
+ {0xa0, 0xf8, 0x010b},
+ {0xa0, 0xf8, 0x010c},
+ {0xa0, 0xf8, 0x010d},
+ {0xa0, 0x50, 0x010e},
+ {0xa0, 0xf8, 0x010f},
+ {0xa0, 0xf8, 0x0110},
+ {0xa0, 0xf8, 0x0111},
+ {0xa0, 0x50, 0x0112},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x00, 0x0180},
+ {0xa0, 0x00, 0x0019},
+ {0xaa, 0x05, 0x0066},
+ {0xaa, 0x09, 0x02b2},
+ {0xaa, 0x10, 0x0002},
+
+ {0xa0, 0x60, 0x011d},
+ {0xa0, 0x00, 0x0190},
+ {0xa0, 0x07, 0x0191},
+ {0xa0, 0x8c, 0x0192},
+ {0xa0, 0x00, 0x0195},
+ {0xa0, 0x00, 0x0196},
+ {0xa0, 0x8a, 0x0197},
+ {0xa0, 0x10, 0x018c},
+ {0xa0, 0x20, 0x018f},
+ {0xa0, 0x14, 0x01a9},
+ {0xa0, 0x24, 0x01aa},
+ {0xa0, 0xd7, 0x001d},
+ {0xa0, 0xf0, 0x001e},
+ {0xa0, 0xf8, 0x001f},
+ {0xa0, 0xff, 0x0020},
+ {0xa0, 0x09, 0x01ad},
+ {0xa0, 0x15, 0x01ae},
+ {0xa0, 0x40, 0x0180},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x42, 0x0180},
+ {0xa1, 0x01, 0x0008},
+ {0xa1, 0x01, 0x0007},
+/* {0xa0, 0x30, 0x0007}, */
+/* {0xa0, 0x00, 0x0007}, */
+ {}
+};
+
+static const struct usb_action pb0330xx_InitialScale[] = {
+ {0xa1, 0x01, 0x0008},
+ {0xa1, 0x01, 0x0008},
+ {0xa0, 0x01, 0x0000},
+ {0xa0, 0x03, 0x0008}, /* 00 */
+ {0xa0, 0x0a, 0x0010},
+ {0xa0, 0x00, 0x0002}, /* 10 */
+ {0xa0, 0x02, 0x0003},
+ {0xa0, 0x80, 0x0004},
+ {0xa0, 0x01, 0x0005},
+ {0xa0, 0xe0, 0x0006},
+ {0xa0, 0x01, 0x0001},
+ {0xa0, 0x05, 0x0012},
+ {0xa0, 0x07, 0x0012},
+ {0xa0, 0x00, 0x0098},
+ {0xa0, 0x00, 0x009a},
+ {0xa0, 0x00, 0x011a},
+ {0xa0, 0x00, 0x011c},
+ {0xa0, 0x05, 0x0012},
+ {0xaa, 0x01, 0x0006},
+ {0xaa, 0x02, 0x0011},
+ {0xaa, 0x03, 0x01e7},
+ {0xaa, 0x04, 0x0287},
+ {0xaa, 0x06, 0x0003},
+ {0xaa, 0x07, 0x3002},
+ {0xaa, 0x20, 0x1100},
+ {0xaa, 0x2f, 0xf7b0},
+ {0xaa, 0x30, 0x0005},
+ {0xaa, 0x31, 0x0000},
+ {0xaa, 0x34, 0x0100},
+ {0xaa, 0x35, 0x0060},
+ {0xaa, 0x3d, 0x068f},
+ {0xaa, 0x40, 0x01e0},
+ {0xaa, 0x58, 0x0078},
+ {0xaa, 0x62, 0x0411},
+ {0xa0, 0x10, 0x0087},
+ {0xa0, 0x37, 0x0101},
+ {0xa0, 0x05, 0x0012},
+ {0xa0, 0x0d, 0x0100},
+ {0xa0, 0x06, 0x0189},
+ {0xa0, 0x00, 0x01ad},
+ {0xa0, 0x03, 0x01c5},
+ {0xa0, 0x13, 0x01cb},
+ {0xa0, 0x08, 0x0250},
+ {0xa0, 0x08, 0x0301},
+ {0xa0, 0x60, 0x01a8},
+ {0xa0, 0x6c, 0x018d},
+ {0xa1, 0x01, 0x0002},
+ {0xa0, 0x09, 0x01ad},
+ {0xa0, 0x15, 0x01ae},
+ {0xa0, 0x00, 0x0092},
+ {0xa0, 0x02, 0x0090},
+ {0xa1, 0x01, 0x0091},
+ {0xa1, 0x01, 0x0095},
+ {0xa1, 0x01, 0x0096},
+ {0xa0, 0x50, 0x010a}, /* matrix */
+ {0xa0, 0xf8, 0x010b},
+ {0xa0, 0xf8, 0x010c},
+ {0xa0, 0xf8, 0x010d},
+ {0xa0, 0x50, 0x010e},
+ {0xa0, 0xf8, 0x010f},
+ {0xa0, 0xf8, 0x0110},
+ {0xa0, 0xf8, 0x0111},
+ {0xa0, 0x50, 0x0112},
+ {0xa1, 0x01, 0x0008},
+ {0xa0, 0x03, 0x0008}, /* clock ? */
+ {0xa0, 0x08, 0x01c6}, /* sharpness+ */
+ {0xa1, 0x01, 0x01c8},
+ {0xa1, 0x01, 0x01c9},
+ {0xa1, 0x01, 0x01ca},
+ {0xa0, 0x0f, 0x01cb}, /* sharpness- */
+
+ {0xa0, 0x50, 0x010a}, /* matrix */
+ {0xa0, 0xf8, 0x010b},
+ {0xa0, 0xf8, 0x010c},
+ {0xa0, 0xf8, 0x010d},
+ {0xa0, 0x50, 0x010e},
+ {0xa0, 0xf8, 0x010f},
+ {0xa0, 0xf8, 0x0110},
+ {0xa0, 0xf8, 0x0111},
+ {0xa0, 0x50, 0x0112},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x00, 0x0180},
+ {0xa0, 0x00, 0x0019},
+ {0xaa, 0x05, 0x0066},
+ {0xaa, 0x09, 0x02b2},
+ {0xaa, 0x10, 0x0002},
+ {0xa0, 0x60, 0x011d},
+ {0xa0, 0x00, 0x0190},
+ {0xa0, 0x07, 0x0191},
+ {0xa0, 0x8c, 0x0192},
+ {0xa0, 0x00, 0x0195},
+ {0xa0, 0x00, 0x0196},
+ {0xa0, 0x8a, 0x0197},
+ {0xa0, 0x10, 0x018c},
+ {0xa0, 0x20, 0x018f},
+ {0xa0, 0x14, 0x01a9},
+ {0xa0, 0x24, 0x01aa},
+ {0xa0, 0xd7, 0x001d},
+ {0xa0, 0xf0, 0x001e},
+ {0xa0, 0xf8, 0x001f},
+ {0xa0, 0xff, 0x0020},
+ {0xa0, 0x09, 0x01ad},
+ {0xa0, 0x15, 0x01ae},
+ {0xa0, 0x40, 0x0180},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x42, 0x0180},
+ {0xa1, 0x01, 0x0008},
+ {0xa1, 0x01, 0x0007},
+/* {0xa0, 0x30, 0x0007}, */
+/* {0xa0, 0x00, 0x0007}, */
+ {}
+};
+static const struct usb_action pb0330_50HZ[] = {
+ {0xa0, 0x00, 0x0190}, /* 01,90,00,cc */
+ {0xa0, 0x07, 0x0191}, /* 01,91,07,cc */
+ {0xa0, 0xee, 0x0192}, /* 01,92,ee,cc */
+ {0xa0, 0x00, 0x0195}, /* 01,95,00,cc */
+ {0xa0, 0x00, 0x0196}, /* 01,96,00,cc */
+ {0xa0, 0x46, 0x0197}, /* 01,97,46,cc */
+ {0xa0, 0x10, 0x018c}, /* 01,8c,10,cc */
+ {0xa0, 0x20, 0x018f}, /* 01,8f,20,cc */
+ {0xa0, 0x0c, 0x01a9}, /* 01,a9,0c,cc */
+ {0xa0, 0x26, 0x01aa}, /* 01,aa,26,cc */
+ {0xa0, 0x68, 0x001d}, /* 00,1d,68,cc */
+ {0xa0, 0x90, 0x001e}, /* 00,1e,90,cc */
+ {0xa0, 0xc8, 0x001f}, /* 00,1f,c8,cc */
+ {}
+};
+static const struct usb_action pb0330_50HZScale[] = {
+ {0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
+ {0xa0, 0x00, 0x0190}, /* 01,90,00,cc */
+ {0xa0, 0x07, 0x0191}, /* 01,91,07,cc */
+ {0xa0, 0xa0, 0x0192}, /* 01,92,a0,cc */
+ {0xa0, 0x00, 0x0195}, /* 01,95,00,cc */
+ {0xa0, 0x00, 0x0196}, /* 01,96,00,cc */
+ {0xa0, 0x7a, 0x0197}, /* 01,97,7a,cc */
+ {0xa0, 0x10, 0x018c}, /* 01,8c,10,cc */
+ {0xa0, 0x20, 0x018f}, /* 01,8f,20,cc */
+ {0xa0, 0x0c, 0x01a9}, /* 01,a9,0c,cc */
+ {0xa0, 0x26, 0x01aa}, /* 01,aa,26,cc */
+ {0xa0, 0xe5, 0x001d}, /* 00,1d,e5,cc */
+ {0xa0, 0xf0, 0x001e}, /* 00,1e,f0,cc */
+ {0xa0, 0xf8, 0x001f}, /* 00,1f,f8,cc */
+ {}
+};
+static const struct usb_action pb0330_60HZ[] = {
+ {0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
+ {0xa0, 0x00, 0x0190}, /* 01,90,00,cc */
+ {0xa0, 0x07, 0x0191}, /* 01,91,07,cc */
+ {0xa0, 0xdd, 0x0192}, /* 01,92,dd,cc */
+ {0xa0, 0x00, 0x0195}, /* 01,95,00,cc */
+ {0xa0, 0x00, 0x0196}, /* 01,96,00,cc */
+ {0xa0, 0x3d, 0x0197}, /* 01,97,3d,cc */
+ {0xa0, 0x10, 0x018c}, /* 01,8c,10,cc */
+ {0xa0, 0x20, 0x018f}, /* 01,8f,20,cc */
+ {0xa0, 0x0c, 0x01a9}, /* 01,a9,0c,cc */
+ {0xa0, 0x26, 0x01aa}, /* 01,aa,26,cc */
+ {0xa0, 0x43, 0x001d}, /* 00,1d,43,cc */
+ {0xa0, 0x50, 0x001e}, /* 00,1e,50,cc */
+ {0xa0, 0x90, 0x001f}, /* 00,1f,90,cc */
+ {}
+};
+static const struct usb_action pb0330_60HZScale[] = {
+ {0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
+ {0xa0, 0x00, 0x0190}, /* 01,90,00,cc */
+ {0xa0, 0x07, 0x0191}, /* 01,91,07,cc */
+ {0xa0, 0xa0, 0x0192}, /* 01,92,a0,cc */
+ {0xa0, 0x00, 0x0195}, /* 01,95,00,cc */
+ {0xa0, 0x00, 0x0196}, /* 01,96,00,cc */
+ {0xa0, 0x7a, 0x0197}, /* 01,97,7a,cc */
+ {0xa0, 0x10, 0x018c}, /* 01,8c,10,cc */
+ {0xa0, 0x20, 0x018f}, /* 01,8f,20,cc */
+ {0xa0, 0x0c, 0x01a9}, /* 01,a9,0c,cc */
+ {0xa0, 0x26, 0x01aa}, /* 01,aa,26,cc */
+ {0xa0, 0x41, 0x001d}, /* 00,1d,41,cc */
+ {0xa0, 0x50, 0x001e}, /* 00,1e,50,cc */
+ {0xa0, 0x90, 0x001f}, /* 00,1f,90,cc */
+ {}
+};
+static const struct usb_action pb0330_NoFliker[] = {
+ {0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
+ {0xa0, 0x00, 0x0190}, /* 01,90,00,cc */
+ {0xa0, 0x07, 0x0191}, /* 01,91,07,cc */
+ {0xa0, 0xf0, 0x0192}, /* 01,92,f0,cc */
+ {0xa0, 0x00, 0x0195}, /* 01,95,00,cc */
+ {0xa0, 0x00, 0x0196}, /* 01,96,00,cc */
+ {0xa0, 0x10, 0x0197}, /* 01,97,10,cc */
+ {0xa0, 0x10, 0x018c}, /* 01,8c,10,cc */
+ {0xa0, 0x20, 0x018f}, /* 01,8f,20,cc */
+ {0xa0, 0x00, 0x01a9}, /* 01,a9,00,cc */
+ {0xa0, 0x00, 0x01aa}, /* 01,aa,00,cc */
+ {0xa0, 0x09, 0x001d}, /* 00,1d,09,cc */
+ {0xa0, 0x40, 0x001e}, /* 00,1e,40,cc */
+ {0xa0, 0x90, 0x001f}, /* 00,1f,90,cc */
+ {}
+};
+static const struct usb_action pb0330_NoFlikerScale[] = {
+ {0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
+ {0xa0, 0x00, 0x0190}, /* 01,90,00,cc */
+ {0xa0, 0x07, 0x0191}, /* 01,91,07,cc */
+ {0xa0, 0xf0, 0x0192}, /* 01,92,f0,cc */
+ {0xa0, 0x00, 0x0195}, /* 01,95,00,cc */
+ {0xa0, 0x00, 0x0196}, /* 01,96,00,cc */
+ {0xa0, 0x10, 0x0197}, /* 01,97,10,cc */
+ {0xa0, 0x10, 0x018c}, /* 01,8c,10,cc */
+ {0xa0, 0x20, 0x018f}, /* 01,8f,20,cc */
+ {0xa0, 0x00, 0x01a9}, /* 01,a9,00,cc */
+ {0xa0, 0x00, 0x01aa}, /* 01,aa,00,cc */
+ {0xa0, 0x09, 0x001d}, /* 00,1d,09,cc */
+ {0xa0, 0x40, 0x001e}, /* 00,1e,40,cc */
+ {0xa0, 0x90, 0x001f}, /* 00,1f,90,cc */
+ {}
+};
+
+/* from oem9.inf - HKR,%PO2030%,Initial - 640x480 - (close to CS2102) */
+static const struct usb_action PO2030_mode0[] = {
+ {0xa0, 0x01, 0x0000}, /* 00,00,01,cc */
+ {0xa0, 0x04, 0x0002}, /* 00,02,04,cc */
+ {0xa0, 0x01, 0x0010}, /* 00,10,01,cc */
+ {0xa0, 0x01, 0x0001}, /* 00,01,01,cc */
+ {0xa0, 0x04, 0x0080}, /* 00,80,04,cc */
+ {0xa0, 0x05, 0x0081}, /* 00,81,05,cc */
+ {0xa0, 0x16, 0x0083}, /* 00,83,16,cc */
+ {0xa0, 0x18, 0x0085}, /* 00,85,18,cc */
+ {0xa0, 0x1a, 0x0086}, /* 00,86,1a,cc */
+ {0xa0, 0x1b, 0x0087}, /* 00,87,1b,cc */
+ {0xa0, 0x1c, 0x0088}, /* 00,88,1c,cc */
+ {0xa0, 0xee, 0x008b}, /* 00,8b,ee,cc */
+ {0xa0, 0x03, 0x0008}, /* 00,08,03,cc */
+ {0xa0, 0x03, 0x0012}, /* 00,12,03,cc */
+ {0xa0, 0x01, 0x0012}, /* 00,12,01,cc */
+ {0xa0, 0x02, 0x0003}, /* 00,03,02,cc */
+ {0xa0, 0x80, 0x0004}, /* 00,04,80,cc */
+ {0xa0, 0x01, 0x0005}, /* 00,05,01,cc */
+ {0xa0, 0xe0, 0x0006}, /* 00,06,e0,cc */
+ {0xa0, 0x42, 0x0180}, /* 01,80,42,cc */
+ {0xaa, 0x8d, 0x0008}, /* 00,8d,08,aa */
+ {0xa0, 0x00, 0x0098}, /* 00,98,00,cc */
+ {0xa0, 0x00, 0x009a}, /* 00,9a,00,cc */
+ {0xa0, 0x00, 0x011a}, /* 01,1a,00,cc */
+ {0xa0, 0x00, 0x011c}, /* 01,1c,00,cc */
+ {0xa0, 0xe6, 0x009c}, /* 00,9c,e6,cc */
+ {0xa0, 0x86, 0x009e}, /* 00,9e,86,cc */
+ {0xaa, 0x09, 0x00ce}, /* 00,09,ce,aa */
+ {0xaa, 0x0b, 0x0005}, /* 00,0b,05,aa */
+ {0xaa, 0x0d, 0x0054}, /* 00,0d,54,aa */
+ {0xaa, 0x0f, 0x00eb}, /* 00,0f,eb,aa */
+ {0xaa, 0x87, 0x0000}, /* 00,87,00,aa */
+ {0xaa, 0x88, 0x0004}, /* 00,88,04,aa */
+ {0xaa, 0x89, 0x0000}, /* 00,89,00,aa */
+ {0xaa, 0x8a, 0x0005}, /* 00,8a,05,aa */
+ {0xaa, 0x13, 0x0003}, /* 00,13,03,aa */
+ {0xaa, 0x16, 0x0040}, /* 00,16,40,aa */
+ {0xaa, 0x18, 0x0040}, /* 00,18,40,aa */
+ {0xaa, 0x1d, 0x0002}, /* 00,1d,02,aa */
+ {0xaa, 0x29, 0x00e8}, /* 00,29,e8,aa */
+ {0xaa, 0x45, 0x0045}, /* 00,45,45,aa */
+ {0xaa, 0x50, 0x00ed}, /* 00,50,ed,aa */
+ {0xaa, 0x51, 0x0025}, /* 00,51,25,aa */
+ {0xaa, 0x52, 0x0042}, /* 00,52,42,aa */
+ {0xaa, 0x53, 0x002f}, /* 00,53,2f,aa */
+ {0xaa, 0x79, 0x0025}, /* 00,79,25,aa */
+ {0xaa, 0x7b, 0x0000}, /* 00,7b,00,aa */
+ {0xaa, 0x7e, 0x0025}, /* 00,7e,25,aa */
+ {0xaa, 0x7f, 0x0025}, /* 00,7f,25,aa */
+ {0xaa, 0x21, 0x0000}, /* 00,21,00,aa */
+ {0xaa, 0x33, 0x0036}, /* 00,33,36,aa */
+ {0xaa, 0x36, 0x0060}, /* 00,36,60,aa */
+ {0xaa, 0x37, 0x0008}, /* 00,37,08,aa */
+ {0xaa, 0x3b, 0x0031}, /* 00,3b,31,aa */
+ {0xaa, 0x44, 0x000f}, /* 00,44,0f,aa */
+ {0xaa, 0x58, 0x0002}, /* 00,58,02,aa */
+ {0xaa, 0x66, 0x00c0}, /* 00,66,c0,aa */
+ {0xaa, 0x67, 0x0044}, /* 00,67,44,aa */
+ {0xaa, 0x6b, 0x00a0}, /* 00,6b,a0,aa */
+ {0xaa, 0x6c, 0x0054}, /* 00,6c,54,aa */
+ {0xaa, 0xd6, 0x0007}, /* 00,d6,07,aa */
+ {0xa0, 0xf7, 0x0101}, /* 01,01,f7,cc */
+ {0xa0, 0x05, 0x0012}, /* 00,12,05,cc */
+ {0xa0, 0x0d, 0x0100}, /* 01,00,0d,cc */
+ {0xa0, 0x06, 0x0189}, /* 01,89,06,cc */
+ {0xa0, 0x00, 0x01ad}, /* 01,ad,00,cc */
+ {0xa0, 0x03, 0x01c5}, /* 01,c5,03,cc */
+ {0xa0, 0x13, 0x01cb}, /* 01,cb,13,cc */
+ {0xa0, 0x08, 0x0250}, /* 02,50,08,cc */
+ {0xa0, 0x08, 0x0301}, /* 03,01,08,cc */
+ {0xa0, 0x7a, 0x0116}, /* 01,16,7a,cc */
+ {0xa0, 0x4a, 0x0118}, /* 01,18,4a,cc */
+ {}
+};
+
+/* from oem9.inf - HKR,%PO2030%,InitialScale - 320x240 */
+static const struct usb_action PO2030_mode1[] = {
+ {0xa0, 0x01, 0x0000}, /* 00,00,01,cc */
+ {0xa0, 0x10, 0x0002}, /* 00,02,10,cc */
+ {0xa0, 0x01, 0x0010}, /* 00,10,01,cc */
+ {0xa0, 0x01, 0x0001}, /* 00,01,01,cc */
+ {0xa0, 0x04, 0x0080}, /* 00,80,04,cc */
+ {0xa0, 0x05, 0x0081}, /* 00,81,05,cc */
+ {0xa0, 0x16, 0x0083}, /* 00,83,16,cc */
+ {0xa0, 0x18, 0x0085}, /* 00,85,18,cc */
+ {0xa0, 0x1a, 0x0086}, /* 00,86,1a,cc */
+ {0xa0, 0x1b, 0x0087}, /* 00,87,1b,cc */
+ {0xa0, 0x1c, 0x0088}, /* 00,88,1c,cc */
+ {0xa0, 0xee, 0x008b}, /* 00,8b,ee,cc */
+ {0xa0, 0x03, 0x0008}, /* 00,08,03,cc */
+ {0xa0, 0x03, 0x0012}, /* 00,12,03,cc */
+ {0xa0, 0x01, 0x0012}, /* 00,12,01,cc */
+ {0xa0, 0x02, 0x0003}, /* 00,03,02,cc */
+ {0xa0, 0x80, 0x0004}, /* 00,04,80,cc */
+ {0xa0, 0x01, 0x0005}, /* 00,05,01,cc */
+ {0xa0, 0xe0, 0x0006}, /* 00,06,e0,cc */
+ {0xa0, 0x42, 0x0180}, /* 01,80,42,cc */
+ {0xaa, 0x8d, 0x0008}, /* 00,8d,08,aa */
+ {0xa0, 0x00, 0x0098}, /* 00,98,00,cc */
+ {0xa0, 0x00, 0x009a}, /* 00,9a,00,cc */
+ {0xa0, 0x00, 0x011a}, /* 01,1a,00,cc */
+ {0xa0, 0x00, 0x011c}, /* 01,1c,00,cc */
+ {0xa0, 0xe8, 0x009c}, /* 00,9c,e8,cc */
+ {0xa0, 0x88, 0x009e}, /* 00,9e,88,cc */
+ {0xaa, 0x09, 0x00cc}, /* 00,09,cc,aa */
+ {0xaa, 0x0b, 0x0005}, /* 00,0b,05,aa */
+ {0xaa, 0x0d, 0x0058}, /* 00,0d,58,aa */
+ {0xaa, 0x0f, 0x00ed}, /* 00,0f,ed,aa */
+ {0xaa, 0x87, 0x0000}, /* 00,87,00,aa */
+ {0xaa, 0x88, 0x0004}, /* 00,88,04,aa */
+ {0xaa, 0x89, 0x0000}, /* 00,89,00,aa */
+ {0xaa, 0x8a, 0x0005}, /* 00,8a,05,aa */
+ {0xaa, 0x13, 0x0003}, /* 00,13,03,aa */
+ {0xaa, 0x16, 0x0040}, /* 00,16,40,aa */
+ {0xaa, 0x18, 0x0040}, /* 00,18,40,aa */
+ {0xaa, 0x1d, 0x0002}, /* 00,1d,02,aa */
+ {0xaa, 0x29, 0x00e8}, /* 00,29,e8,aa */
+ {0xaa, 0x45, 0x0045}, /* 00,45,45,aa */
+ {0xaa, 0x50, 0x00ed}, /* 00,50,ed,aa */
+ {0xaa, 0x51, 0x0025}, /* 00,51,25,aa */
+ {0xaa, 0x52, 0x0042}, /* 00,52,42,aa */
+ {0xaa, 0x53, 0x002f}, /* 00,53,2f,aa */
+ {0xaa, 0x79, 0x0025}, /* 00,79,25,aa */
+ {0xaa, 0x7b, 0x0000}, /* 00,7b,00,aa */
+ {0xaa, 0x7e, 0x0025}, /* 00,7e,25,aa */
+ {0xaa, 0x7f, 0x0025}, /* 00,7f,25,aa */
+ {0xaa, 0x21, 0x0000}, /* 00,21,00,aa */
+ {0xaa, 0x33, 0x0036}, /* 00,33,36,aa */
+ {0xaa, 0x36, 0x0060}, /* 00,36,60,aa */
+ {0xaa, 0x37, 0x0008}, /* 00,37,08,aa */
+ {0xaa, 0x3b, 0x0031}, /* 00,3b,31,aa */
+ {0xaa, 0x44, 0x000f}, /* 00,44,0f,aa */
+ {0xaa, 0x58, 0x0002}, /* 00,58,02,aa */
+ {0xaa, 0x66, 0x00c0}, /* 00,66,c0,aa */
+ {0xaa, 0x67, 0x0044}, /* 00,67,44,aa */
+ {0xaa, 0x6b, 0x00a0}, /* 00,6b,a0,aa */
+ {0xaa, 0x6c, 0x0054}, /* 00,6c,54,aa */
+ {0xaa, 0xd6, 0x0007}, /* 00,d6,07,aa */
+ {0xa0, 0xf7, 0x0101}, /* 01,01,f7,cc */
+ {0xa0, 0x05, 0x0012}, /* 00,12,05,cc */
+ {0xa0, 0x0d, 0x0100}, /* 01,00,0d,cc */
+ {0xa0, 0x06, 0x0189}, /* 01,89,06,cc */
+ {0xa0, 0x00, 0x01ad}, /* 01,ad,00,cc */
+ {0xa0, 0x03, 0x01c5}, /* 01,c5,03,cc */
+ {0xa0, 0x13, 0x01cb}, /* 01,cb,13,cc */
+ {0xa0, 0x08, 0x0250}, /* 02,50,08,cc */
+ {0xa0, 0x08, 0x0301}, /* 03,01,08,cc */
+ {0xa0, 0x7a, 0x0116}, /* 01,16,7a,cc */
+ {0xa0, 0x4a, 0x0118}, /* 01,18,4a,cc */
+ {}
+};
+
+static const struct usb_action PO2030_50HZ[] = {
+ {0xaa, 0x8d, 0x0008}, /* 00,8d,08,aa */
+ {0xaa, 0x1a, 0x0001}, /* 00,1a,01,aa */
+ {0xaa, 0x1b, 0x000a}, /* 00,1b,0a,aa */
+ {0xaa, 0x1c, 0x00b0}, /* 00,1c,b0,aa */
+ {0xa0, 0x05, 0x0190}, /* 01,90,05,cc */
+ {0xa0, 0x35, 0x0191}, /* 01,91,35,cc */
+ {0xa0, 0x70, 0x0192}, /* 01,92,70,cc */
+ {0xa0, 0x00, 0x0195}, /* 01,95,00,cc */
+ {0xa0, 0x85, 0x0196}, /* 01,96,85,cc */
+ {0xa0, 0x58, 0x0197}, /* 01,97,58,cc */
+ {0xa0, 0x0c, 0x018c}, /* 01,8c,0c,cc */
+ {0xa0, 0x18, 0x018f}, /* 01,8f,18,cc */
+ {0xa0, 0x60, 0x01a8}, /* 01,a8,60,cc */
+ {0xa0, 0x10, 0x01a9}, /* 01,a9,10,cc */
+ {0xa0, 0x22, 0x01aa}, /* 01,aa,22,cc */
+ {0xa0, 0x88, 0x018d}, /* 01,8d,88,cc */
+ {0xa0, 0x58, 0x011d}, /* 01,1d,58,cc */
+ {0xa0, 0x42, 0x0180}, /* 01,80,42,cc */
+ {}
+};
+
+static const struct usb_action PO2030_60HZ[] = {
+ {0xaa, 0x8d, 0x0008}, /* 00,8d,08,aa */
+ {0xaa, 0x1a, 0x0000}, /* 00,1a,00,aa */
+ {0xaa, 0x1b, 0x00de}, /* 00,1b,de,aa */
+ {0xaa, 0x1c, 0x0040}, /* 00,1c,40,aa */
+ {0xa0, 0x08, 0x0190}, /* 01,90,08,cc */
+ {0xa0, 0xae, 0x0191}, /* 01,91,ae,cc */
+ {0xa0, 0x80, 0x0192}, /* 01,92,80,cc */
+ {0xa0, 0x00, 0x0195}, /* 01,95,00,cc */
+ {0xa0, 0x6f, 0x0196}, /* 01,96,6f,cc */
+ {0xa0, 0x20, 0x0197}, /* 01,97,20,cc */
+ {0xa0, 0x0c, 0x018c}, /* 01,8c,0c,cc */
+ {0xa0, 0x18, 0x018f}, /* 01,8f,18,cc */
+ {0xa0, 0x60, 0x01a8}, /* 01,a8,60,cc */
+ {0xa0, 0x10, 0x01a9}, /* 01,a9,10,cc */
+ {0xa0, 0x22, 0x01aa}, /* 01,aa,22,cc */
+ {0xa0, 0x88, 0x018d}, /* 01,8d,88,cc */ /* win: 01,8d,80 */
+ {0xa0, 0x58, 0x011d}, /* 01,1d,58,cc */
+ {0xa0, 0x42, 0x0180}, /* 01,80,42,cc */
+ {}
+};
+
+static const struct usb_action PO2030_NoFliker[] = {
+ {0xa0, 0x02, 0x0180}, /* 01,80,02,cc */
+ {0xaa, 0x8d, 0x000d}, /* 00,8d,0d,aa */
+ {0xaa, 0x1a, 0x0000}, /* 00,1a,00,aa */
+ {0xaa, 0x1b, 0x0002}, /* 00,1b,02,aa */
+ {0xaa, 0x1c, 0x0078}, /* 00,1c,78,aa */
+ {0xaa, 0x46, 0x0000}, /* 00,46,00,aa */
+ {0xaa, 0x15, 0x0000}, /* 00,15,00,aa */
+ {}
+};
+
+/* TEST */
+static const struct usb_action tas5130CK_Initial[] = {
+ {0xa0, 0x01, 0x0000},
+ {0xa0, 0x01, 0x003b},
+ {0xa0, 0x0e, 0x003a},
+ {0xa0, 0x01, 0x0038},
+ {0xa0, 0x0b, 0x0039},
+ {0xa0, 0x00, 0x0038},
+ {0xa0, 0x0b, 0x0039},
+ {0xa0, 0x01, 0x0000},
+ {0xa0, 0x03, 0x0008},
+ {0xa0, 0x0a, 0x0010},
+ {0xa0, 0x10, 0x0002},
+ {0xa0, 0x02, 0x0003},
+ {0xa0, 0x80, 0x0004},
+ {0xa0, 0x01, 0x0005},
+ {0xa0, 0xe0, 0x0006},
+ {0xa0, 0xdc, 0x008b},
+ {0xa0, 0x01, 0x0001},
+ {0xa0, 0x07, 0x0012},
+ {0xa0, 0x00, 0x0098},
+ {0xa0, 0x00, 0x009a},
+ {0xa0, 0x00, 0x011a},
+ {0xa0, 0x00, 0x011c},
+ {0xa0, 0xdc, 0x008b},
+ {0xa0, 0x05, 0x0012},
+ {0xa0, 0x01, 0x0092},
+ {0xa0, 0x01, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x06, 0x0092},
+ {0xa0, 0x00, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x08, 0x0092},
+ {0xa0, 0x83, 0x0093},
+ {0xa0, 0x04, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x01, 0x0092},
+ {0xa0, 0x04, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x08, 0x0092},
+ {0xa0, 0x06, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x02, 0x0092},
+ {0xa0, 0x11, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x03, 0x0092},
+ {0xa0, 0xE7, 0x0093},
+ {0xa0, 0x01, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x04, 0x0092},
+ {0xa0, 0x87, 0x0093},
+ {0xa0, 0x02, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x07, 0x0092},
+ {0xa0, 0x02, 0x0093},
+ {0xa0, 0x30, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x20, 0x0092},
+ {0xa0, 0x00, 0x0093},
+ {0xa0, 0x51, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x35, 0x0092},
+ {0xa0, 0x7F, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x30, 0x0092},
+ {0xa0, 0x05, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x31, 0x0092},
+ {0xa0, 0x00, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x58, 0x0092},
+ {0xa0, 0x78, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x62, 0x0092},
+ {0xa0, 0x11, 0x0093},
+ {0xa0, 0x04, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x2B, 0x0092},
+ {0xa0, 0x7f, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x2c, 0x0092},
+ {0xa0, 0x7f, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x2D, 0x0092},
+ {0xa0, 0x7f, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x2e, 0x0092},
+ {0xa0, 0x7f, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x10, 0x0087},
+ {0xa0, 0xb7, 0x0101},
+ {0xa0, 0x05, 0x0012},
+ {0xa0, 0x0d, 0x0100},
+ {0xa0, 0x06, 0x0189},
+ {0xa0, 0x09, 0x01ad},
+ {0xa0, 0x03, 0x01c5},
+ {0xa0, 0x13, 0x01cb},
+ {0xa0, 0x08, 0x0250},
+ {0xa0, 0x08, 0x0301},
+ {0xa0, 0x60, 0x01a8},
+ {0xa0, 0x6c, 0x018d},
+ {0xa0, 0x61, 0x0116},
+ {0xa0, 0x65, 0x0118},
+ {0xa0, 0x09, 0x01ad},
+ {0xa0, 0x15, 0x01ae},
+ {0xa0, 0x4c, 0x010a}, /* matrix */
+ {0xa0, 0xf1, 0x010b},
+ {0xa0, 0x03, 0x010c},
+ {0xa0, 0xfe, 0x010d},
+ {0xa0, 0x51, 0x010e},
+ {0xa0, 0xf1, 0x010f},
+ {0xa0, 0xec, 0x0110},
+ {0xa0, 0x03, 0x0111},
+ {0xa0, 0x51, 0x0112},
+ {0xa0, 0x03, 0x0008},
+ {0xa0, 0x08, 0x01c6}, /* sharpness+ */
+ {0xa0, 0x0f, 0x01cb}, /* sharpness- */
+ {0xa0, 0x38, 0x0120}, /* gamma > 5 */
+ {0xa0, 0x51, 0x0121},
+ {0xa0, 0x6e, 0x0122},
+ {0xa0, 0x8c, 0x0123},
+ {0xa0, 0xa2, 0x0124},
+ {0xa0, 0xb6, 0x0125},
+ {0xa0, 0xc8, 0x0126},
+ {0xa0, 0xd6, 0x0127},
+ {0xa0, 0xe2, 0x0128},
+ {0xa0, 0xed, 0x0129},
+ {0xa0, 0xf5, 0x012a},
+ {0xa0, 0xfc, 0x012b},
+ {0xa0, 0xff, 0x012c},
+ {0xa0, 0xff, 0x012d},
+ {0xa0, 0xff, 0x012e},
+ {0xa0, 0xff, 0x012f},
+ {0xa0, 0x12, 0x0130},
+ {0xa0, 0x1b, 0x0131},
+ {0xa0, 0x1d, 0x0132},
+ {0xa0, 0x1a, 0x0133},
+ {0xa0, 0x15, 0x0134},
+ {0xa0, 0x12, 0x0135},
+ {0xa0, 0x0f, 0x0136},
+ {0xa0, 0x0d, 0x0137},
+ {0xa0, 0x0b, 0x0138},
+ {0xa0, 0x09, 0x0139},
+ {0xa0, 0x07, 0x013a},
+ {0xa0, 0x05, 0x013b},
+ {0xa0, 0x00, 0x013c},
+ {0xa0, 0x00, 0x013d},
+ {0xa0, 0x00, 0x013e},
+ {0xa0, 0x01, 0x013f},
+ {0xa0, 0x4c, 0x010a}, /* matrix */
+ {0xa0, 0xf1, 0x010b},
+ {0xa0, 0x03, 0x010c},
+ {0xa0, 0xfe, 0x010d},
+ {0xa0, 0x51, 0x010e},
+ {0xa0, 0xf1, 0x010f},
+ {0xa0, 0xec, 0x0110},
+ {0xa0, 0x03, 0x0111},
+ {0xa0, 0x51, 0x0112},
+ {0xa0, 0x10, 0x0180},
+ {0xa0, 0x00, 0x0180},
+ {0xa0, 0x00, 0x0019},
+ {0xa0, 0x05, 0x0092},
+ {0xa0, 0x09, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x09, 0x0092},
+ {0xa0, 0x34, 0x0093},
+ {0xa0, 0x01, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x00, 0x0190},
+ {0xa0, 0x07, 0x0191},
+ {0xa0, 0xd2, 0x0192},
+ {0xa0, 0x00, 0x0195},
+ {0xa0, 0x00, 0x0196},
+ {0xa0, 0x9a, 0x0197},
+ {0xa0, 0x0e, 0x018c},
+ {0xa0, 0x1c, 0x018f},
+ {0xa0, 0x14, 0x01a9},
+ {0xa0, 0x66, 0x01aa},
+ {0xa0, 0xd7, 0x001d},
+ {0xa0, 0xf4, 0x001e},
+ {0xa0, 0xf9, 0x001f},
+ {0xa0, 0xff, 0x0020},
+ {0xa0, 0x42, 0x0180},
+ {0xa0, 0x09, 0x01ad},
+ {0xa0, 0x15, 0x01ae},
+ {0xa0, 0x40, 0x0180},
+ {0xa0, 0x42, 0x0180},
+ {}
+};
+
+static const struct usb_action tas5130CK_InitialScale[] = {
+ {0xa0, 0x01, 0x0000},
+ {0xa0, 0x01, 0x003b},
+ {0xa0, 0x0e, 0x003a},
+ {0xa0, 0x01, 0x0038},
+ {0xa0, 0x0b, 0x0039},
+ {0xa0, 0x00, 0x0038},
+ {0xa0, 0x0b, 0x0039},
+ {0xa0, 0x01, 0x0000},
+ {0xa0, 0x03, 0x0008},
+ {0xa0, 0x0a, 0x0010},
+ {0xa0, 0x00, 0x0002},
+ {0xa0, 0x02, 0x0003},
+ {0xa0, 0x80, 0x0004},
+ {0xa0, 0x01, 0x0005},
+ {0xa0, 0xe0, 0x0006},
+ {0xa0, 0xdc, 0x008b},
+ {0xa0, 0x01, 0x0001},
+ {0xa0, 0x07, 0x0012},
+ {0xa0, 0x00, 0x0098},
+ {0xa0, 0x00, 0x009a},
+ {0xa0, 0x00, 0x011a},
+ {0xa0, 0x00, 0x011c},
+ {0xa0, 0xdc, 0x008b},
+ {0xa0, 0x05, 0x0012},
+ {0xa0, 0x01, 0x0092},
+ {0xa0, 0x01, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x06, 0x0092},
+ {0xa0, 0x00, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x08, 0x0092},
+ {0xa0, 0x83, 0x0093},
+ {0xa0, 0x04, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x01, 0x0092},
+ {0xa0, 0x04, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x08, 0x0092},
+ {0xa0, 0x06, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x02, 0x0092},
+ {0xa0, 0x11, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x03, 0x0092},
+ {0xa0, 0xe5, 0x0093},
+ {0xa0, 0x01, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x04, 0x0092},
+ {0xa0, 0x85, 0x0093},
+ {0xa0, 0x02, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x07, 0x0092},
+ {0xa0, 0x02, 0x0093},
+ {0xa0, 0x30, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x20, 0x0092},
+ {0xa0, 0x00, 0x0093},
+ {0xa0, 0x51, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x35, 0x0092},
+ {0xa0, 0x7F, 0x0093},
+ {0xa0, 0x50, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x30, 0x0092},
+ {0xa0, 0x05, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x31, 0x0092},
+ {0xa0, 0x00, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x58, 0x0092},
+ {0xa0, 0x78, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x62, 0x0092},
+ {0xa0, 0x11, 0x0093},
+ {0xa0, 0x04, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x2B, 0x0092},
+ {0xa0, 0x7f, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x2C, 0x0092},
+ {0xa0, 0x7F, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x2D, 0x0092},
+ {0xa0, 0x7f, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x2e, 0x0092},
+ {0xa0, 0x7f, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x10, 0x0087},
+ {0xa0, 0xb7, 0x0101},
+ {0xa0, 0x05, 0x0012},
+ {0xa0, 0x0d, 0x0100},
+ {0xa0, 0x06, 0x0189},
+ {0xa0, 0x09, 0x01ad},
+ {0xa0, 0x03, 0x01c5},
+ {0xa0, 0x13, 0x01cb},
+ {0xa0, 0x08, 0x0250},
+ {0xa0, 0x08, 0x0301},
+ {0xa0, 0x60, 0x01a8},
+ {0xa0, 0x6c, 0x018d},
+ {0xa0, 0x61, 0x0116},
+ {0xa0, 0x65, 0x0118},
+ {0xa0, 0x09, 0x01ad},
+ {0xa0, 0x15, 0x01ae},
+ {0xa0, 0x4c, 0x010a}, /* matrix */
+ {0xa0, 0xf1, 0x010b},
+ {0xa0, 0x03, 0x010c},
+ {0xa0, 0xfe, 0x010d},
+ {0xa0, 0x51, 0x010e},
+ {0xa0, 0xf1, 0x010f},
+ {0xa0, 0xec, 0x0110},
+ {0xa0, 0x03, 0x0111},
+ {0xa0, 0x51, 0x0112},
+ {0xa0, 0x03, 0x0008},
+ {0xa0, 0x08, 0x01c6}, /* sharpness+ */
+ {0xa0, 0x0f, 0x01cb}, /* sharpness- */
+ {0xa0, 0x38, 0x0120}, /* gamma > 5 */
+ {0xa0, 0x51, 0x0121},
+ {0xa0, 0x6e, 0x0122},
+ {0xa0, 0x8c, 0x0123},
+ {0xa0, 0xa2, 0x0124},
+ {0xa0, 0xb6, 0x0125},
+ {0xa0, 0xc8, 0x0126},
+ {0xa0, 0xd6, 0x0127},
+ {0xa0, 0xe2, 0x0128},
+ {0xa0, 0xed, 0x0129},
+ {0xa0, 0xf5, 0x012a},
+ {0xa0, 0xfc, 0x012b},
+ {0xa0, 0xff, 0x012c},
+ {0xa0, 0xff, 0x012d},
+ {0xa0, 0xff, 0x012e},
+ {0xa0, 0xff, 0x012f},
+ {0xa0, 0x12, 0x0130},
+ {0xa0, 0x1b, 0x0131},
+ {0xa0, 0x1d, 0x0132},
+ {0xa0, 0x1a, 0x0133},
+ {0xa0, 0x15, 0x0134},
+ {0xa0, 0x12, 0x0135},
+ {0xa0, 0x0f, 0x0136},
+ {0xa0, 0x0d, 0x0137},
+ {0xa0, 0x0b, 0x0138},
+ {0xa0, 0x09, 0x0139},
+ {0xa0, 0x07, 0x013a},
+ {0xa0, 0x05, 0x013b},
+ {0xa0, 0x00, 0x013c},
+ {0xa0, 0x00, 0x013d},
+ {0xa0, 0x00, 0x013e},
+ {0xa0, 0x01, 0x013f},
+ {0xa0, 0x4c, 0x010a}, /* matrix */
+ {0xa0, 0xf1, 0x010b},
+ {0xa0, 0x03, 0x010c},
+ {0xa0, 0xfe, 0x010d},
+ {0xa0, 0x51, 0x010e},
+ {0xa0, 0xf1, 0x010f},
+ {0xa0, 0xec, 0x0110},
+ {0xa0, 0x03, 0x0111},
+ {0xa0, 0x51, 0x0112},
+ {0xa0, 0x10, 0x0180},
+ {0xa0, 0x00, 0x0180},
+ {0xa0, 0x00, 0x0019},
+ {0xa0, 0x05, 0x0092},
+ {0xa0, 0x62, 0x0093},
+ {0xa0, 0x00, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x09, 0x0092},
+ {0xa0, 0xaa, 0x0093},
+ {0xa0, 0x01, 0x0094},
+ {0xa0, 0x01, 0x0090},
+ {0xa0, 0x00, 0x0190},
+ {0xa0, 0x03, 0x0191},
+ {0xa0, 0x9b, 0x0192},
+ {0xa0, 0x00, 0x0195},
+ {0xa0, 0x00, 0x0196},
+ {0xa0, 0x47, 0x0197},
+ {0xa0, 0x0e, 0x018c},
+ {0xa0, 0x1c, 0x018f},
+ {0xa0, 0x14, 0x01a9},
+ {0xa0, 0x66, 0x01aa},
+ {0xa0, 0x62, 0x001d},
+ {0xa0, 0x90, 0x001e},
+ {0xa0, 0xc8, 0x001f},
+ {0xa0, 0xff, 0x0020},
+ {0xa0, 0x60, 0x011d},
+ {0xa0, 0x42, 0x0180},
+ {0xa0, 0x09, 0x01ad},
+ {0xa0, 0x15, 0x01ae},
+ {0xa0, 0x40, 0x0180},
+ {0xa0, 0x42, 0x0180},
+ {0xa0, 0x30, 0x0007},
+ {0xa0, 0x02, 0x0008},
+ {0xa0, 0x00, 0x0007},
+ {0xa0, 0x03, 0x0008},
+ {}
+};
+
+static const struct usb_action tas5130cxx_Initial[] = {
+ {0xa0, 0x01, 0x0000},
+ {0xa0, 0x50, 0x0002},
+ {0xa0, 0x03, 0x0008},
+ {0xa0, 0x02, 0x0010},
+ {0xa0, 0x01, 0x0001},
+ {0xa0, 0x00, 0x0001},
+ {0xa0, 0x01, 0x0012},
+ {0xa0, 0x01, 0x0001},
+ {0xa0, 0x05, 0x0012},
+ {0xa0, 0x07, 0x00a5},
+ {0xa0, 0x02, 0x00a6},
+
+ {0xa0, 0x02, 0x0003},
+ {0xa0, 0x80, 0x0004},
+ {0xa0, 0x01, 0x0005},
+ {0xa0, 0xe0, 0x0006},
+
+ {0xa0, 0x04, 0x0098},
+ {0xa0, 0x0f, 0x009a},
+ {0xa0, 0x04, 0x011a},
+ {0xa0, 0x0f, 0x011c},
+ {0xa0, 0xe8, 0x009c},
+ {0xa0, 0x02, 0x009d},
+ {0xa0, 0x88, 0x009e},
+ {0xa0, 0x06, 0x008d},
+ {0xa0, 0xf7, 0x0101},
+ {0xa0, 0x0d, 0x0100},
+ {0xa0, 0x06, 0x0189},
+ {0xa0, 0x68, 0x018d},
+ {0xa0, 0x60, 0x01a8},
+ {0xa0, 0x00, 0x01ad},
+ {0xa0, 0x03, 0x01c5},
+ {0xa0, 0x13, 0x01cb},
+ {0xa0, 0x08, 0x0250},
+ {0xa0, 0x08, 0x0301},
+ {0xa1, 0x01, 0x0002},
+ {0xa1, 0x01, 0x0008},
+ {0xa0, 0x03, 0x0008}, /* clock ? */
+ {0xa0, 0x08, 0x01c6}, /* sharpness+ */
+ {0xa1, 0x01, 0x01c8},
+ {0xa1, 0x01, 0x01c9},
+ {0xa1, 0x01, 0x01ca},
+ {0xa0, 0x0f, 0x01cb}, /* sharpness- */
+
+ {0xa0, 0x68, 0x010a}, /* matrix */
+ {0xa0, 0xec, 0x010b},
+ {0xa0, 0xec, 0x010c},
+ {0xa0, 0xec, 0x010d},
+ {0xa0, 0x68, 0x010e},
+ {0xa0, 0xec, 0x010f},
+ {0xa0, 0xec, 0x0110},
+ {0xa0, 0xec, 0x0111},
+ {0xa0, 0x68, 0x0112},
+
+ {0xa1, 0x01, 0x018d},
+ {0xa0, 0x90, 0x018d}, /* 90 */
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x00, 0x0180},
+ {0xa0, 0x00, 0x0019},
+
+ {0xaa, 0xa3, 0x0001},
+ {0xaa, 0xa4, 0x0077},
+ {0xa0, 0x01, 0x00a3},
+ {0xa0, 0x77, 0x00a4},
+
+ {0xa0, 0x00, 0x0190}, /* 00 */
+ {0xa0, 0x03, 0x0191}, /* 03 */
+ {0xa0, 0xe8, 0x0192}, /* e8 */
+ {0xa0, 0x00, 0x0195}, /* 0 */
+ {0xa0, 0x00, 0x0196}, /* 0 */
+ {0xa0, 0x7d, 0x0197}, /* 7d */
+
+ {0xa0, 0x0c, 0x018c},
+ {0xa0, 0x18, 0x018f},
+ {0xa0, 0x08, 0x01a9}, /* 08 */
+ {0xa0, 0x24, 0x01aa}, /* 24 */
+ {0xa0, 0xf0, 0x001d},
+ {0xa0, 0xf4, 0x001e},
+ {0xa0, 0xf8, 0x001f},
+ {0xa0, 0xff, 0x0020},
+ {0xa0, 0x03, 0x009f},
+ {0xa0, 0xc0, 0x00a0},
+ {0xa0, 0x50, 0x011d}, /* 50 */
+ {0xa0, 0x40, 0x0180},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x42, 0x0180},
+ {}
+};
+static const struct usb_action tas5130cxx_InitialScale[] = {
+ {0xa0, 0x01, 0x0000},
+ {0xa0, 0x01, 0x0000},
+ {0xa0, 0x40, 0x0002},
+
+ {0xa0, 0x03, 0x0008},
+ {0xa1, 0x01, 0x0008},
+
+ {0xa0, 0x02, 0x0010},
+ {0xa0, 0x01, 0x0001},
+ {0xa0, 0x00, 0x0001},
+ {0xa0, 0x01, 0x0012},
+ {0xa0, 0x01, 0x0001},
+ {0xa0, 0x05, 0x0012},
+ {0xa0, 0x07, 0x00a5},
+ {0xa0, 0x02, 0x00a6},
+ {0xa0, 0x02, 0x0003},
+ {0xa0, 0x80, 0x0004},
+ {0xa0, 0x01, 0x0005},
+ {0xa0, 0xe0, 0x0006},
+ {0xa0, 0x05, 0x0098},
+ {0xa0, 0x0f, 0x009a},
+ {0xa0, 0x05, 0x011a},
+ {0xa0, 0x0f, 0x011c},
+ {0xa0, 0xe6, 0x009c},
+ {0xa0, 0x02, 0x009d},
+ {0xa0, 0x86, 0x009e},
+ {0xa0, 0x06, 0x008d},
+ {0xa0, 0x37, 0x0101},
+ {0xa0, 0x0d, 0x0100},
+ {0xa0, 0x06, 0x0189},
+ {0xa0, 0x68, 0x018d},
+ {0xa0, 0x60, 0x01a8},
+ {0xa0, 0x00, 0x01ad},
+ {0xa0, 0x03, 0x01c5},
+ {0xa0, 0x13, 0x01cb},
+ {0xa0, 0x08, 0x0250},
+ {0xa0, 0x08, 0x0301},
+ {0xa1, 0x01, 0x0002},
+ {0xa1, 0x01, 0x0008},
+
+ {0xa0, 0x03, 0x0008},
+ {0xa1, 0x01, 0x0008}, /* clock ? */
+ {0xa0, 0x08, 0x01c6}, /* sharpness+ */
+ {0xa1, 0x01, 0x01c8},
+ {0xa1, 0x01, 0x01c9},
+ {0xa1, 0x01, 0x01ca},
+ {0xa0, 0x0f, 0x01cb}, /* sharpness- */
+
+ {0xa0, 0x68, 0x010a}, /* matrix */
+ {0xa0, 0xec, 0x010b},
+ {0xa0, 0xec, 0x010c},
+ {0xa0, 0xec, 0x010d},
+ {0xa0, 0x68, 0x010e},
+ {0xa0, 0xec, 0x010f},
+ {0xa0, 0xec, 0x0110},
+ {0xa0, 0xec, 0x0111},
+ {0xa0, 0x68, 0x0112},
+
+ {0xa1, 0x01, 0x018d},
+ {0xa0, 0x90, 0x018d},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x00, 0x0180},
+ {0xa0, 0x00, 0x0019},
+ {0xaa, 0xa3, 0x0001},
+ {0xaa, 0xa4, 0x0063},
+ {0xa0, 0x01, 0x00a3},
+ {0xa0, 0x63, 0x00a4},
+ {0xa0, 0x00, 0x0190},
+ {0xa0, 0x02, 0x0191},
+ {0xa0, 0x38, 0x0192},
+ {0xa0, 0x00, 0x0195},
+ {0xa0, 0x00, 0x0196},
+ {0xa0, 0x47, 0x0197},
+ {0xa0, 0x0c, 0x018c},
+ {0xa0, 0x18, 0x018f},
+ {0xa0, 0x08, 0x01a9},
+ {0xa0, 0x24, 0x01aa},
+ {0xa0, 0xd3, 0x001d},
+ {0xa0, 0xda, 0x001e},
+ {0xa0, 0xea, 0x001f},
+ {0xa0, 0xff, 0x0020},
+ {0xa0, 0x03, 0x009f},
+ {0xa0, 0x4c, 0x00a0},
+ {0xa0, 0x50, 0x011d},
+ {0xa0, 0x40, 0x0180},
+ {0xa1, 0x01, 0x0180},
+ {0xa0, 0x42, 0x0180},
+ {}
+};
+static const struct usb_action tas5130cxx_50HZ[] = {
+ {0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
+ {0xaa, 0xa3, 0x0001}, /* 00,a3,01,aa */
+ {0xaa, 0xa4, 0x0063}, /* 00,a4,63,aa */
+ {0xa0, 0x01, 0x00a3}, /* 00,a3,01,cc */
+ {0xa0, 0x63, 0x00a4}, /* 00,a4,63,cc */
+ {0xa0, 0x00, 0x0190}, /* 01,90,00,cc */
+ {0xa0, 0x02, 0x0191}, /* 01,91,02,cc */
+ {0xa0, 0x38, 0x0192}, /* 01,92,38,cc */
+ {0xa0, 0x00, 0x0195}, /* 01,95,00,cc */
+ {0xa0, 0x00, 0x0196}, /* 01,96,00,cc */
+ {0xa0, 0x47, 0x0197}, /* 01,97,47,cc */
+ {0xa0, 0x10, 0x018c}, /* 01,8c,10,cc */
+ {0xa0, 0x20, 0x018f}, /* 01,8f,20,cc */
+ {0xa0, 0x0c, 0x01a9}, /* 01,a9,0c,cc */
+ {0xa0, 0x26, 0x01aa}, /* 01,aa,26,cc */
+ {0xa0, 0xd3, 0x001d}, /* 00,1d,d3,cc */
+ {0xa0, 0xda, 0x001e}, /* 00,1e,da,cc */
+ {0xa0, 0xea, 0x001f}, /* 00,1f,ea,cc */
+ {0xa0, 0xff, 0x0020}, /* 00,20,ff,cc */
+ {0xa0, 0x03, 0x009f}, /* 00,9f,03,cc */
+ {}
+};
+static const struct usb_action tas5130cxx_50HZScale[] = {
+ {0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
+ {0xaa, 0xa3, 0x0001}, /* 00,a3,01,aa */
+ {0xaa, 0xa4, 0x0077}, /* 00,a4,77,aa */
+ {0xa0, 0x01, 0x00a3}, /* 00,a3,01,cc */
+ {0xa0, 0x77, 0x00a4}, /* 00,a4,77,cc */
+ {0xa0, 0x00, 0x0190}, /* 01,90,00,cc */
+ {0xa0, 0x03, 0x0191}, /* 01,91,03,cc */
+ {0xa0, 0xe8, 0x0192}, /* 01,92,e8,cc */
+ {0xa0, 0x00, 0x0195}, /* 01,95,00,cc */
+ {0xa0, 0x00, 0x0196}, /* 01,96,00,cc */
+ {0xa0, 0x7d, 0x0197}, /* 01,97,7d,cc */
+ {0xa0, 0x14, 0x018c}, /* 01,8c,14,cc */
+ {0xa0, 0x20, 0x018f}, /* 01,8f,20,cc */
+ {0xa0, 0x0c, 0x01a9}, /* 01,a9,0c,cc */
+ {0xa0, 0x26, 0x01aa}, /* 01,aa,26,cc */
+ {0xa0, 0xf0, 0x001d}, /* 00,1d,f0,cc */
+ {0xa0, 0xf4, 0x001e}, /* 00,1e,f4,cc */
+ {0xa0, 0xf8, 0x001f}, /* 00,1f,f8,cc */
+ {0xa0, 0xff, 0x0020}, /* 00,20,ff,cc */
+ {0xa0, 0x03, 0x009f}, /* 00,9f,03,cc */
+ {}
+};
+static const struct usb_action tas5130cxx_60HZ[] = {
+ {0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
+ {0xaa, 0xa3, 0x0001}, /* 00,a3,01,aa */
+ {0xaa, 0xa4, 0x0036}, /* 00,a4,36,aa */
+ {0xa0, 0x01, 0x00a3}, /* 00,a3,01,cc */
+ {0xa0, 0x36, 0x00a4}, /* 00,a4,36,cc */
+ {0xa0, 0x00, 0x0190}, /* 01,90,00,cc */
+ {0xa0, 0x01, 0x0191}, /* 01,91,01,cc */
+ {0xa0, 0xf0, 0x0192}, /* 01,92,f0,cc */
+ {0xa0, 0x00, 0x0195}, /* 01,95,00,cc */
+ {0xa0, 0x00, 0x0196}, /* 01,96,00,cc */
+ {0xa0, 0x3e, 0x0197}, /* 01,97,3e,cc */
+ {0xa0, 0x10, 0x018c}, /* 01,8c,10,cc */
+ {0xa0, 0x20, 0x018f}, /* 01,8f,20,cc */
+ {0xa0, 0x0c, 0x01a9}, /* 01,a9,0c,cc */
+ {0xa0, 0x26, 0x01aa}, /* 01,aa,26,cc */
+ {0xa0, 0xca, 0x001d}, /* 00,1d,ca,cc */
+ {0xa0, 0xd0, 0x001e}, /* 00,1e,d0,cc */
+ {0xa0, 0xe0, 0x001f}, /* 00,1f,e0,cc */
+ {0xa0, 0xff, 0x0020}, /* 00,20,ff,cc */
+ {0xa0, 0x03, 0x009f}, /* 00,9f,03,cc */
+ {}
+};
+static const struct usb_action tas5130cxx_60HZScale[] = {
+ {0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
+ {0xaa, 0xa3, 0x0001}, /* 00,a3,01,aa */
+ {0xaa, 0xa4, 0x0077}, /* 00,a4,77,aa */
+ {0xa0, 0x01, 0x00a3}, /* 00,a3,01,cc */
+ {0xa0, 0x77, 0x00a4}, /* 00,a4,77,cc */
+ {0xa0, 0x00, 0x0190}, /* 01,90,00,cc */
+ {0xa0, 0x03, 0x0191}, /* 01,91,03,cc */
+ {0xa0, 0xe8, 0x0192}, /* 01,92,e8,cc */
+ {0xa0, 0x00, 0x0195}, /* 01,95,00,cc */
+ {0xa0, 0x00, 0x0196}, /* 01,96,00,cc */
+ {0xa0, 0x7d, 0x0197}, /* 01,97,7d,cc */
+ {0xa0, 0x14, 0x018c}, /* 01,8c,14,cc */
+ {0xa0, 0x20, 0x018f}, /* 01,8f,20,cc */
+ {0xa0, 0x0c, 0x01a9}, /* 01,a9,0c,cc */
+ {0xa0, 0x26, 0x01aa}, /* 01,aa,26,cc */
+ {0xa0, 0xc8, 0x001d}, /* 00,1d,c8,cc */
+ {0xa0, 0xd0, 0x001e}, /* 00,1e,d0,cc */
+ {0xa0, 0xe0, 0x001f}, /* 00,1f,e0,cc */
+ {0xa0, 0xff, 0x0020}, /* 00,20,ff,cc */
+ {0xa0, 0x03, 0x009f}, /* 00,9f,03,cc */
+ {}
+};
+static const struct usb_action tas5130cxx_NoFliker[] = {
+ {0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
+ {0xaa, 0xa3, 0x0001}, /* 00,a3,01,aa */
+ {0xaa, 0xa4, 0x0040}, /* 00,a4,40,aa */
+ {0xa0, 0x01, 0x00a3}, /* 00,a3,01,cc */
+ {0xa0, 0x40, 0x00a4}, /* 00,a4,40,cc */
+ {0xa0, 0x00, 0x0190}, /* 01,90,00,cc */
+ {0xa0, 0x01, 0x0191}, /* 01,91,01,cc */
+ {0xa0, 0xf0, 0x0192}, /* 01,92,f0,cc */
+ {0xa0, 0x00, 0x0195}, /* 01,95,00,cc */
+ {0xa0, 0x00, 0x0196}, /* 01,96,00,cc */
+ {0xa0, 0x10, 0x0197}, /* 01,97,10,cc */
+ {0xa0, 0x10, 0x018c}, /* 01,8c,10,cc */
+ {0xa0, 0x20, 0x018f}, /* 01,8f,20,cc */
+ {0xa0, 0x00, 0x01a9}, /* 01,a9,00,cc */
+ {0xa0, 0x00, 0x01aa}, /* 01,aa,00,cc */
+ {0xa0, 0xbc, 0x001d}, /* 00,1d,bc,cc */
+ {0xa0, 0xd0, 0x001e}, /* 00,1e,d0,cc */
+ {0xa0, 0xe0, 0x001f}, /* 00,1f,e0,cc */
+ {0xa0, 0xff, 0x0020}, /* 00,20,ff,cc */
+ {0xa0, 0x02, 0x009f}, /* 00,9f,02,cc */
+ {}
+};
+
+static const struct usb_action tas5130cxx_NoFlikerScale[] = {
+ {0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
+ {0xaa, 0xa3, 0x0001}, /* 00,a3,01,aa */
+ {0xaa, 0xa4, 0x0090}, /* 00,a4,90,aa */
+ {0xa0, 0x01, 0x00a3}, /* 00,a3,01,cc */
+ {0xa0, 0x90, 0x00a4}, /* 00,a4,90,cc */
+ {0xa0, 0x00, 0x0190}, /* 01,90,00,cc */
+ {0xa0, 0x03, 0x0191}, /* 01,91,03,cc */
+ {0xa0, 0xf0, 0x0192}, /* 01,92,f0,cc */
+ {0xa0, 0x00, 0x0195}, /* 01,95,00,cc */
+ {0xa0, 0x00, 0x0196}, /* 01,96,00,cc */
+ {0xa0, 0x10, 0x0197}, /* 01,97,10,cc */
+ {0xa0, 0x10, 0x018c}, /* 01,8c,10,cc */
+ {0xa0, 0x20, 0x018f}, /* 01,8f,20,cc */
+ {0xa0, 0x00, 0x01a9}, /* 01,a9,00,cc */
+ {0xa0, 0x00, 0x01aa}, /* 01,aa,00,cc */
+ {0xa0, 0xbc, 0x001d}, /* 00,1d,bc,cc */
+ {0xa0, 0xd0, 0x001e}, /* 00,1e,d0,cc */
+ {0xa0, 0xe0, 0x001f}, /* 00,1f,e0,cc */
+ {0xa0, 0xff, 0x0020}, /* 00,20,ff,cc */
+ {0xa0, 0x02, 0x009f}, /* 00,9f,02,cc */
+ {}
+};
+
+static const struct usb_action tas5130c_vf0250_Initial[] = {
+ {0xa0, 0x01, 0x0000}, /* 00,00,01,cc, */
+ {0xa0, 0x02, 0x0008}, /* 00,08,02,cc, */
+ {0xa0, 0x01, 0x0010}, /* 00,10,01,cc, */
+ {0xa0, 0x10, 0x0002}, /* 00,02,00,cc, 0<->10 */
+ {0xa0, 0x02, 0x0003}, /* 00,03,02,cc, */
+ {0xa0, 0x80, 0x0004}, /* 00,04,80,cc, */
+ {0xa0, 0x01, 0x0005}, /* 00,05,01,cc, */
+ {0xa0, 0xe0, 0x0006}, /* 00,06,e0,cc, */
+ {0xa0, 0x98, 0x008b}, /* 00,8b,98,cc, */
+ {0xa0, 0x01, 0x0001}, /* 00,01,01,cc, */
+ {0xa0, 0x03, 0x0012}, /* 00,12,03,cc, */
+ {0xa0, 0x01, 0x0012}, /* 00,12,01,cc, */
+ {0xa0, 0x00, 0x0098}, /* 00,98,00,cc, */
+ {0xa0, 0x00, 0x009a}, /* 00,9a,00,cc, */
+ {0xa0, 0x00, 0x011a}, /* 01,1a,00,cc, */
+ {0xa0, 0x00, 0x011c}, /* 01,1c,00,cc, */
+ {0xa0, 0xe8, 0x009c}, /* 00,9c,e6,cc, 6<->8 */
+ {0xa0, 0x88, 0x009e}, /* 00,9e,86,cc, 6<->8 */
+ {0xa0, 0x10, 0x0087}, /* 00,87,10,cc, */
+ {0xa0, 0x98, 0x008b}, /* 00,8b,98,cc, */
+ {0xaa, 0x1b, 0x0024}, /* 00,1b,24,aa, */
+ {0xdd, 0x00, 0x0080}, /* 00,00,80,dd, */
+ {0xaa, 0x1b, 0x0000}, /* 00,1b,00,aa, */
+ {0xaa, 0x13, 0x0002}, /* 00,13,02,aa, */
+ {0xaa, 0x15, 0x0004}, /* 00,15,04,aa */
+ {0xaa, 0x01, 0x0000},
+ {0xaa, 0x01, 0x0000},
+ {0xaa, 0x1a, 0x0000}, /* 00,1a,00,aa, */
+ {0xaa, 0x1c, 0x0017}, /* 00,1c,17,aa, */
+ {0xa0, 0x82, 0x0086}, /* 00,86,82,cc, */
+ {0xa0, 0x83, 0x0087}, /* 00,87,83,cc, */
+ {0xa0, 0x84, 0x0088}, /* 00,88,84,cc, */
+ {0xaa, 0x05, 0x0010}, /* 00,05,10,aa, */
+ {0xaa, 0x0a, 0x0000}, /* 00,0a,00,aa, */
+ {0xaa, 0x0b, 0x00a0}, /* 00,0b,a0,aa, */
+ {0xaa, 0x0c, 0x0000}, /* 00,0c,00,aa, */
+ {0xaa, 0x0d, 0x00a0}, /* 00,0d,a0,aa, */
+ {0xaa, 0x0e, 0x0000}, /* 00,0e,00,aa, */
+ {0xaa, 0x0f, 0x00a0}, /* 00,0f,a0,aa, */
+ {0xaa, 0x10, 0x0000}, /* 00,10,00,aa, */
+ {0xaa, 0x11, 0x00a0}, /* 00,11,a0,aa, */
+ {0xa0, 0x00, 0x0039},
+ {0xa1, 0x01, 0x0037},
+ {0xaa, 0x16, 0x0001}, /* 00,16,01,aa, */
+ {0xaa, 0x17, 0x00e8}, /* 00,17,e6,aa, (e6 -> e8) */
+ {0xaa, 0x18, 0x0002}, /* 00,18,02,aa, */
+ {0xaa, 0x19, 0x0088}, /* 00,19,86,aa, */
+ {0xaa, 0x20, 0x0020}, /* 00,20,20,aa, */
+ {0xa0, 0xb7, 0x0101}, /* 01,01,b7,cc, */
+ {0xa0, 0x05, 0x0012}, /* 00,12,05,cc, */
+ {0xa0, 0x0d, 0x0100}, /* 01,00,0d,cc, */
+ {0xa0, 0x76, 0x0189}, /* 01,89,76,cc, */
+ {0xa0, 0x09, 0x01ad}, /* 01,ad,09,cc, */
+ {0xa0, 0x03, 0x01c5}, /* 01,c5,03,cc, */
+ {0xa0, 0x13, 0x01cb}, /* 01,cb,13,cc, */
+ {0xa0, 0x08, 0x0250}, /* 02,50,08,cc, */
+ {0xa0, 0x08, 0x0301}, /* 03,01,08,cc, */
+ {0xa0, 0x60, 0x01a8}, /* 01,a8,60,cc, */
+ {0xa0, 0x61, 0x0116}, /* 01,16,61,cc, */
+ {0xa0, 0x65, 0x0118}, /* 01,18,65,cc */
+ {}
+};
+
+static const struct usb_action tas5130c_vf0250_InitialScale[] = {
+ {0xa0, 0x01, 0x0000}, /* 00,00,01,cc, */
+ {0xa0, 0x02, 0x0008}, /* 00,08,02,cc, */
+ {0xa0, 0x01, 0x0010}, /* 00,10,01,cc, */
+ {0xa0, 0x00, 0x0002}, /* 00,02,10,cc, */
+ {0xa0, 0x02, 0x0003}, /* 00,03,02,cc, */
+ {0xa0, 0x80, 0x0004}, /* 00,04,80,cc, */
+ {0xa0, 0x01, 0x0005}, /* 00,05,01,cc, */
+ {0xa0, 0xe0, 0x0006}, /* 00,06,e0,cc, */
+ {0xa0, 0x98, 0x008b}, /* 00,8b,98,cc, */
+ {0xa0, 0x01, 0x0001}, /* 00,01,01,cc, */
+ {0xa0, 0x03, 0x0012}, /* 00,12,03,cc, */
+ {0xa0, 0x01, 0x0012}, /* 00,12,01,cc, */
+ {0xa0, 0x00, 0x0098}, /* 00,98,00,cc, */
+ {0xa0, 0x00, 0x009a}, /* 00,9a,00,cc, */
+ {0xa0, 0x00, 0x011a}, /* 01,1a,00,cc, */
+ {0xa0, 0x00, 0x011c}, /* 01,1c,00,cc, */
+ {0xa0, 0xe8, 0x009c}, /* 00,9c,e8,cc, 8<->6 */
+ {0xa0, 0x88, 0x009e}, /* 00,9e,88,cc, 8<->6 */
+ {0xa0, 0x10, 0x0087}, /* 00,87,10,cc, */
+ {0xa0, 0x98, 0x008b}, /* 00,8b,98,cc, */
+ {0xaa, 0x1b, 0x0024}, /* 00,1b,24,aa, */
+ {0xdd, 0x00, 0x0080}, /* 00,00,80,dd, */
+ {0xaa, 0x1b, 0x0000}, /* 00,1b,00,aa, */
+ {0xaa, 0x13, 0x0002}, /* 00,13,02,aa, */
+ {0xaa, 0x15, 0x0004}, /* 00,15,04,aa */
+ {0xaa, 0x01, 0x0000},
+ {0xaa, 0x01, 0x0000},
+ {0xaa, 0x1a, 0x0000}, /* 00,1a,00,aa, */
+ {0xaa, 0x1c, 0x0017}, /* 00,1c,17,aa, */
+ {0xa0, 0x82, 0x0086}, /* 00,86,82,cc, */
+ {0xa0, 0x83, 0x0087}, /* 00,87,83,cc, */
+ {0xa0, 0x84, 0x0088}, /* 00,88,84,cc, */
+ {0xaa, 0x05, 0x0010}, /* 00,05,10,aa, */
+ {0xaa, 0x0a, 0x0000}, /* 00,0a,00,aa, */
+ {0xaa, 0x0b, 0x00a0}, /* 00,0b,a0,aa, */
+ {0xaa, 0x0c, 0x0000}, /* 00,0c,00,aa, */
+ {0xaa, 0x0d, 0x00a0}, /* 00,0d,a0,aa, */
+ {0xaa, 0x0e, 0x0000}, /* 00,0e,00,aa, */
+ {0xaa, 0x0f, 0x00a0}, /* 00,0f,a0,aa, */
+ {0xaa, 0x10, 0x0000}, /* 00,10,00,aa, */
+ {0xaa, 0x11, 0x00a0}, /* 00,11,a0,aa, */
+ {0xa0, 0x00, 0x0039},
+ {0xa1, 0x01, 0x0037},
+ {0xaa, 0x16, 0x0001}, /* 00,16,01,aa, */
+ {0xaa, 0x17, 0x00e8}, /* 00,17,e6,aa (e6 -> e8) */
+ {0xaa, 0x18, 0x0002}, /* 00,18,02,aa, */
+ {0xaa, 0x19, 0x0088}, /* 00,19,88,aa, */
+ {0xaa, 0x20, 0x0020}, /* 00,20,20,aa, */
+ {0xa0, 0xb7, 0x0101}, /* 01,01,b7,cc, */
+ {0xa0, 0x05, 0x0012}, /* 00,12,05,cc, */
+ {0xa0, 0x0d, 0x0100}, /* 01,00,0d,cc, */
+ {0xa0, 0x76, 0x0189}, /* 01,89,76,cc, */
+ {0xa0, 0x09, 0x01ad}, /* 01,ad,09,cc, */
+ {0xa0, 0x03, 0x01c5}, /* 01,c5,03,cc, */
+ {0xa0, 0x13, 0x01cb}, /* 01,cb,13,cc, */
+ {0xa0, 0x08, 0x0250}, /* 02,50,08,cc, */
+ {0xa0, 0x08, 0x0301}, /* 03,01,08,cc, */
+ {0xa0, 0x60, 0x01a8}, /* 01,a8,60,cc, */
+ {0xa0, 0x61, 0x0116}, /* 01,16,61,cc, */
+ {0xa0, 0x65, 0x0118}, /* 01,18,65,cc */
+ {}
+};
+/* "50HZ" light frequency banding filter */
+static const struct usb_action tas5130c_vf0250_50HZ[] = {
+ {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */
+ {0xaa, 0x83, 0x0001}, /* 00,83,01,aa */
+ {0xaa, 0x84, 0x00aa}, /* 00,84,aa,aa */
+ {0xa0, 0x00, 0x0190}, /* 01,90,00,cc, */
+ {0xa0, 0x06, 0x0191}, /* 01,91,0d,cc, */
+ {0xa0, 0xa8, 0x0192}, /* 01,92,50,cc, */
+ {0xa0, 0x00, 0x0195}, /* 01,95,00,cc, */
+ {0xa0, 0x00, 0x0196}, /* 01,96,00,cc, */
+ {0xa0, 0x8e, 0x0197}, /* 01,97,47,cc, */
+ {0xa0, 0x0e, 0x018c}, /* 01,8c,0e,cc, */
+ {0xa0, 0x15, 0x018f}, /* 01,8f,15,cc, */
+ {0xa0, 0x10, 0x01a9}, /* 01,a9,10,cc, */
+ {0xa0, 0x24, 0x01aa}, /* 01,aa,24,cc, */
+ {0xa0, 0x62, 0x001d}, /* 00,1d,62,cc, */
+ {0xa0, 0x90, 0x001e}, /* 00,1e,90,cc, */
+ {0xa0, 0xc8, 0x001f}, /* 00,1f,c8,cc, */
+ {0xa0, 0xff, 0x0020}, /* 00,20,ff,cc, */
+ {0xa0, 0x58, 0x011d}, /* 01,1d,58,cc, */
+ {0xa0, 0x42, 0x0180}, /* 01,80,42,cc, */
+ {0xa0, 0x78, 0x018d}, /* 01,8d,78,cc */
+ {}
+};
+
+/* "50HZScale" light frequency banding filter */
+static const struct usb_action tas5130c_vf0250_50HZScale[] = {
+ {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */
+ {0xaa, 0x83, 0x0003}, /* 00,83,03,aa */
+ {0xaa, 0x84, 0x0054}, /* 00,84,54,aa */
+ {0xa0, 0x00, 0x0190}, /* 01,90,00,cc, */
+ {0xa0, 0x0d, 0x0191}, /* 01,91,0d,cc, */
+ {0xa0, 0x50, 0x0192}, /* 01,92,50,cc, */
+ {0xa0, 0x00, 0x0195}, /* 01,95,00,cc, */
+ {0xa0, 0x00, 0x0196}, /* 01,96,00,cc, */
+ {0xa0, 0x8e, 0x0197}, /* 01,97,8e,cc, */
+ {0xa0, 0x0e, 0x018c}, /* 01,8c,0e,cc, */
+ {0xa0, 0x15, 0x018f}, /* 01,8f,15,cc, */
+ {0xa0, 0x10, 0x01a9}, /* 01,a9,10,cc, */
+ {0xa0, 0x24, 0x01aa}, /* 01,aa,24,cc, */
+ {0xa0, 0x62, 0x001d}, /* 00,1d,62,cc, */
+ {0xa0, 0x90, 0x001e}, /* 00,1e,90,cc, */
+ {0xa0, 0xc8, 0x001f}, /* 00,1f,c8,cc, */
+ {0xa0, 0xff, 0x0020}, /* 00,20,ff,cc, */
+ {0xa0, 0x58, 0x011d}, /* 01,1d,58,cc, */
+ {0xa0, 0x42, 0x0180}, /* 01,80,42,cc, */
+ {0xa0, 0x78, 0x018d}, /* 01,8d,78,cc */
+ {}
+};
+
+/* "60HZ" light frequency banding filter */
+static const struct usb_action tas5130c_vf0250_60HZ[] = {
+ {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */
+ {0xaa, 0x83, 0x0001}, /* 00,83,01,aa */
+ {0xaa, 0x84, 0x0062}, /* 00,84,62,aa */
+ {0xa0, 0x00, 0x0190}, /* 01,90,00,cc, */
+ {0xa0, 0x05, 0x0191}, /* 01,91,05,cc, */
+ {0xa0, 0x88, 0x0192}, /* 01,92,88,cc, */
+ {0xa0, 0x00, 0x0195}, /* 01,95,00,cc, */
+ {0xa0, 0x00, 0x0196}, /* 01,96,00,cc, */
+ {0xa0, 0x3b, 0x0197}, /* 01,97,3b,cc, */
+ {0xa0, 0x0e, 0x018c}, /* 01,8c,0e,cc, */
+ {0xa0, 0x15, 0x018f}, /* 01,8f,15,cc, */
+ {0xa0, 0x10, 0x01a9}, /* 01,a9,10,cc, */
+ {0xa0, 0x24, 0x01aa}, /* 01,aa,24,cc, */
+ {0xa0, 0x62, 0x001d}, /* 00,1d,62,cc, */
+ {0xa0, 0x90, 0x001e}, /* 00,1e,90,cc, */
+ {0xa0, 0xc8, 0x001f}, /* 00,1f,c8,cc, */
+ {0xa0, 0xff, 0x0020}, /* 00,20,ff,cc, */
+ {0xa0, 0x58, 0x011d}, /* 01,1d,58,cc, */
+ {0xa0, 0x42, 0x0180}, /* 01,80,42,cc, */
+ {0xa0, 0x78, 0x018d}, /* 01,8d,78,cc */
+ {}
+};
+
+/* "60HZScale" light frequency banding ilter */
+static const struct usb_action tas5130c_vf0250_60HZScale[] = {
+ {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */
+ {0xaa, 0x83, 0x0002}, /* 00,83,02,aa */
+ {0xaa, 0x84, 0x00c4}, /* 00,84,c4,aa */
+ {0xa0, 0x00, 0x0190}, /* 01,90,00,cc, */
+ {0xa0, 0x0b, 0x0191}, /* 01,1,0b,cc, */
+ {0xa0, 0x10, 0x0192}, /* 01,2,10,cc, */
+ {0xa0, 0x00, 0x0195}, /* 01,5,00,cc, */
+ {0xa0, 0x00, 0x0196}, /* 01,6,00,cc, */
+ {0xa0, 0x76, 0x0197}, /* 01,7,76,cc, */
+ {0xa0, 0x0e, 0x018c}, /* 01,c,0e,cc, */
+ {0xa0, 0x15, 0x018f}, /* 01,f,15,cc, */
+ {0xa0, 0x10, 0x01a9}, /* 01,9,10,cc, */
+ {0xa0, 0x24, 0x01aa}, /* 01,a,24,cc, */
+ {0xa0, 0x62, 0x001d}, /* 00,d,62,cc, */
+ {0xa0, 0x90, 0x001e}, /* 00,e,90,cc, */
+ {0xa0, 0xc8, 0x001f}, /* 00,f,c8,cc, */
+ {0xa0, 0xff, 0x0020}, /* 00,0,ff,cc, */
+ {0xa0, 0x58, 0x011d}, /* 01,d,58,cc, */
+ {0xa0, 0x42, 0x0180}, /* 01,80,42,cc, */
+ {0xa0, 0x78, 0x018d}, /* 01,d,78,cc */
+ {}
+};
+
+/* "NoFliker" light frequency banding flter */
+static const struct usb_action tas5130c_vf0250_NoFliker[] = {
+ {0xa0, 0x0c, 0x0100}, /* 01,00,0c,cc, */
+ {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */
+ {0xaa, 0x83, 0x0000}, /* 00,83,00,aa */
+ {0xaa, 0x84, 0x0020}, /* 00,84,20,aa */
+ {0xa0, 0x00, 0x0190}, /* 01,0,00,cc, */
+ {0xa0, 0x05, 0x0191}, /* 01,91,05,cc, */
+ {0xa0, 0x88, 0x0192}, /* 01,92,88,cc, */
+ {0xa0, 0x00, 0x0195}, /* 01,95,00,cc, */
+ {0xa0, 0x00, 0x0196}, /* 01,96,00,cc, */
+ {0xa0, 0x10, 0x0197}, /* 01,97,10,cc, */
+ {0xa0, 0x0e, 0x018c}, /* 01,8c,0e,cc, */
+ {0xa0, 0x15, 0x018f}, /* 01,8f,15,cc, */
+ {0xa0, 0x62, 0x001d}, /* 00,1d,62,cc, */
+ {0xa0, 0x90, 0x001e}, /* 00,1e,90,cc, */
+ {0xa0, 0xc8, 0x001f}, /* 00,1f,c8,cc, */
+ {0xa0, 0xff, 0x0020}, /* 00,20,ff,cc, */
+ {0xa0, 0x58, 0x011d}, /* 01,1d,58,cc, */
+ {0xa0, 0x03, 0x0180}, /* 01,80,03,cc */
+ {}
+};
+
+/* "NoFlikerScale" light frequency banding filter */
+static const struct usb_action tas5130c_vf0250_NoFlikerScale[] = {
+ {0xa0, 0x0c, 0x0100}, /* 01,00,0c,cc, */
+ {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */
+ {0xaa, 0x83, 0x0000}, /* 00,83,00,aa */
+ {0xaa, 0x84, 0x0020}, /* 00,84,20,aa */
+ {0xa0, 0x00, 0x0190}, /* 01,90,00,cc, */
+ {0xa0, 0x0b, 0x0191}, /* 01,91,0b,cc, */
+ {0xa0, 0x10, 0x0192}, /* 01,92,10,cc, */
+ {0xa0, 0x00, 0x0195}, /* 01,95,00,cc, */
+ {0xa0, 0x00, 0x0196}, /* 01,96,00,cc, */
+ {0xa0, 0x10, 0x0197}, /* 01,97,10,cc, */
+ {0xa0, 0x0e, 0x018c}, /* 01,8c,0e,cc, */
+ {0xa0, 0x15, 0x018f}, /* 01,8f,15,cc, */
+ {0xa0, 0x62, 0x001d}, /* 00,1d,62,cc, */
+ {0xa0, 0x90, 0x001e}, /* 00,1e,90,cc, */
+ {0xa0, 0xc8, 0x001f}, /* 00,1f,c8,cc, */
+ {0xa0, 0xff, 0x0020}, /* 00,20,ff,cc, */
+ {0xa0, 0x58, 0x011d}, /* 01,1d,58,cc, */
+ {0xa0, 0x03, 0x0180}, /* 01,80,03,cc */
+ {}
+};
+
+static void reg_r_i(struct usb_device *dev,
+ __u16 index, __u8 *buffer)
+{
+ usb_control_msg(dev,
+ usb_rcvctrlpipe(dev, 0),
+ 0xa1,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0x01, /* value */
+ index, buffer, 1,
+ 500);
+}
+
+static void reg_r(struct usb_device *dev,
+ __u16 index, __u8 *buffer)
+{
+ reg_r_i(dev, index, buffer);
+ PDEBUG(D_USBI, "reg r [%04x] -> %02x", index, *buffer);
+}
+
+static void reg_w_i(struct usb_device *dev,
+ __u8 value,
+ __u16 index)
+{
+ usb_control_msg(dev,
+ usb_sndctrlpipe(dev, 0),
+ 0xa0,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value, index, NULL, 0,
+ 500);
+}
+
+static void reg_w(struct usb_device *dev,
+ __u8 value,
+ __u16 index)
+{
+ PDEBUG(D_USBO, "reg w %02x -> [%04x]", value, index);
+ reg_w_i(dev, value, index);
+}
+
+static __u16 i2c_read(struct usb_device *dev, __u8 reg)
+{
+ __u8 retbyte;
+ __u8 retval[2];
+
+ reg_w_i(dev, reg, 0x92);
+ reg_w_i(dev, 0x02, 0x90); /* <- read command */
+ msleep(25);
+ reg_r_i(dev, 0x0091, &retbyte); /* read status */
+ reg_r_i(dev, 0x0095, &retval[0]); /* read Lowbyte */
+ reg_r_i(dev, 0x0096, &retval[1]); /* read Hightbyte */
+ PDEBUG(D_USBO, "i2c r [%02x] -> (%02x) %02x%02x",
+ reg, retbyte, retval[1], retval[0]);
+ return (retval[1] << 8) | retval[0];
+}
+
+static __u8 i2c_write(struct usb_device *dev,
+ __u8 reg,
+ __u8 valL,
+ __u8 valH)
+{
+ __u8 retbyte;
+
+ reg_w_i(dev, reg, 0x92);
+ reg_w_i(dev, valL, 0x93);
+ reg_w_i(dev, valH, 0x94);
+ reg_w_i(dev, 0x01, 0x90); /* <- write command */
+ msleep(5);
+ reg_r_i(dev, 0x0091, &retbyte); /* read status */
+ PDEBUG(D_USBO, "i2c w [%02x] %02x%02x (%02x)",
+ reg, valH, valL, retbyte);
+ return retbyte;
+}
+
+static void usb_exchange(struct usb_device *dev,
+ const struct usb_action *action)
+{
+ __u8 buffread;
+
+ while (action->req) {
+ switch (action->req) {
+ case 0xa0: /* write register */
+ reg_w(dev, action->val, action->idx);
+ break;
+ case 0xa1: /* read status */
+ reg_r(dev, action->idx, &buffread);
+ break;
+ case 0xaa:
+ i2c_write(dev,
+ action->val, /* reg */
+ action->idx & 0xff, /* valL */
+ action->idx >> 8); /* valH */
+ break;
+ default:
+/* case 0xdd: * delay */
+ msleep(action->val / 64 + 10);
+ break;
+ }
+ action++;
+/* msleep(1); */
+ }
+}
+
+static void setmatrix(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int i;
+ const __u8 *matrix;
+ static const __u8 gc0305_matrix[9] =
+ {0x50, 0xf8, 0xf8, 0xf8, 0x50, 0xf8, 0xf8, 0xf8, 0x50};
+ static const __u8 ov7620_matrix[9] =
+ {0x58, 0xf4, 0xf4, 0xf4, 0x58, 0xf4, 0xf4, 0xf4, 0x58};
+ static const __u8 po2030_matrix[9] =
+ {0x60, 0xf0, 0xf0, 0xf0, 0x60, 0xf0, 0xf0, 0xf0, 0x60};
+
+ switch (sd->sensor) {
+ case SENSOR_GC0305:
+ matrix = gc0305_matrix;
+ break;
+ case SENSOR_MC501CB:
+ return; /* no matrix? */
+ case SENSOR_OV7620:
+/* case SENSOR_OV7648: */
+ matrix = ov7620_matrix;
+ break;
+ case SENSOR_PO2030:
+ matrix = po2030_matrix;
+ break;
+ case SENSOR_TAS5130C_VF0250: /* no matrix? */
+ return;
+ default: /* matrix already loaded */
+ return;
+ }
+ for (i = 0; i < ARRAY_SIZE(ov7620_matrix); i++)
+ reg_w(gspca_dev->dev, matrix[i], 0x010a + i);
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ __u8 brightness;
+
+ switch (sd->sensor) {
+ case SENSOR_GC0305:
+ case SENSOR_OV7620:
+ case SENSOR_PO2030:
+ return;
+ }
+/*fixme: is it really write to 011d and 018d for all other sensors? */
+ brightness = sd->brightness;
+ reg_w(gspca_dev->dev, brightness, 0x011d);
+ if (brightness < 0x70)
+ brightness += 0x10;
+ else
+ brightness = 0x80;
+ reg_w(gspca_dev->dev, brightness, 0x018d);
+}
+
+static void setsharpness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+ int sharpness;
+ __u8 retbyte;
+ static const __u8 sharpness_tb[][2] = {
+ {0x02, 0x03},
+ {0x04, 0x07},
+ {0x08, 0x0f},
+ {0x10, 0x1e}
+ };
+
+ sharpness = sd->sharpness;
+ reg_w(dev, sharpness_tb[sharpness][0], 0x01c6);
+ reg_r(dev, 0x01c8, &retbyte);
+ reg_r(dev, 0x01c9, &retbyte);
+ reg_r(dev, 0x01ca, &retbyte);
+ reg_w(dev, sharpness_tb[sharpness][1], 0x01cb);
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+ const __u8 *Tgamma, *Tgradient;
+ int g, i, k;
+ static const __u8 kgamma_tb[16] = /* delta for contrast */
+ {0x15, 0x0d, 0x0a, 0x09, 0x08, 0x08, 0x08, 0x08,
+ 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
+ static const __u8 kgrad_tb[16] =
+ {0x1b, 0x06, 0x03, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x04};
+ static const __u8 Tgamma_1[16] =
+ {0x00, 0x00, 0x03, 0x0d, 0x1b, 0x2e, 0x45, 0x5f,
+ 0x79, 0x93, 0xab, 0xc1, 0xd4, 0xe5, 0xf3, 0xff};
+ static const __u8 Tgradient_1[16] =
+ {0x00, 0x01, 0x05, 0x0b, 0x10, 0x15, 0x18, 0x1a,
+ 0x1a, 0x18, 0x16, 0x14, 0x12, 0x0f, 0x0d, 0x06};
+ static const __u8 Tgamma_2[16] =
+ {0x01, 0x0c, 0x1f, 0x3a, 0x53, 0x6d, 0x85, 0x9c,
+ 0xb0, 0xc2, 0xd1, 0xde, 0xe9, 0xf2, 0xf9, 0xff};
+ static const __u8 Tgradient_2[16] =
+ {0x05, 0x0f, 0x16, 0x1a, 0x19, 0x19, 0x17, 0x15,
+ 0x12, 0x10, 0x0e, 0x0b, 0x09, 0x08, 0x06, 0x03};
+ static const __u8 Tgamma_3[16] =
+ {0x04, 0x16, 0x30, 0x4e, 0x68, 0x81, 0x98, 0xac,
+ 0xbe, 0xcd, 0xda, 0xe4, 0xed, 0xf5, 0xfb, 0xff};
+ static const __u8 Tgradient_3[16] =
+ {0x0c, 0x16, 0x1b, 0x1c, 0x19, 0x18, 0x15, 0x12,
+ 0x10, 0x0d, 0x0b, 0x09, 0x08, 0x06, 0x05, 0x03};
+ static const __u8 Tgamma_4[16] =
+ {0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
+ 0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff};
+ static const __u8 Tgradient_4[16] =
+ {0x26, 0x22, 0x20, 0x1c, 0x16, 0x13, 0x10, 0x0d,
+ 0x0b, 0x09, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02};
+ static const __u8 Tgamma_5[16] =
+ {0x20, 0x4b, 0x6e, 0x8d, 0xa3, 0xb5, 0xc5, 0xd2,
+ 0xdc, 0xe5, 0xec, 0xf2, 0xf6, 0xfa, 0xfd, 0xff};
+ static const __u8 Tgradient_5[16] =
+ {0x37, 0x26, 0x20, 0x1a, 0x14, 0x10, 0x0e, 0x0b,
+ 0x09, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x02};
+ static const __u8 Tgamma_6[16] = /* ?? was gamma 5 */
+ {0x24, 0x44, 0x64, 0x84, 0x9d, 0xb2, 0xc4, 0xd3,
+ 0xe0, 0xeb, 0xf4, 0xff, 0xff, 0xff, 0xff, 0xff};
+ static const __u8 Tgradient_6[16] =
+ {0x18, 0x20, 0x20, 0x1c, 0x16, 0x13, 0x10, 0x0e,
+ 0x0b, 0x09, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01};
+ static const __u8 *gamma_tb[] = {
+ NULL, Tgamma_1, Tgamma_2,
+ Tgamma_3, Tgamma_4, Tgamma_5, Tgamma_6
+ };
+ static const __u8 *gradient_tb[] = {
+ NULL, Tgradient_1, Tgradient_2,
+ Tgradient_3, Tgradient_4, Tgradient_5, Tgradient_6
+ };
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ __u8 v[16];
+#endif
+
+ Tgamma = gamma_tb[sd->gamma];
+ Tgradient = gradient_tb[sd->gamma];
+
+ k = (sd->contrast - 128) /* -128 / 128 */
+ * Tgamma[0];
+ PDEBUG(D_CONF, "gamma:%d contrast:%d gamma coeff: %d/128",
+ sd->gamma, sd->contrast, k);
+ for (i = 0; i < 16; i++) {
+ g = Tgamma[i] + kgamma_tb[i] * k / 128;
+ if (g > 0xff)
+ g = 0xff;
+ else if (g <= 0)
+ g = 1;
+ reg_w(dev, g, 0x0120 + i); /* gamma */
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ if (gspca_debug & D_CONF)
+ v[i] = g;
+#endif
+ }
+ PDEBUG(D_CONF, "tb: %02x %02x %02x %02x %02x %02x %02x %02x",
+ v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]);
+ PDEBUG(D_CONF, " %02x %02x %02x %02x %02x %02x %02x %02x",
+ v[8], v[9], v[10], v[11], v[12], v[13], v[14], v[15]);
+ for (i = 0; i < 16; i++) {
+ g = Tgradient[i] - kgrad_tb[i] * k / 128;
+ if (g > 0xff)
+ g = 0xff;
+ else if (g <= 0) {
+ if (i != 15)
+ g = 0;
+ else
+ g = 1;
+ }
+ reg_w(dev, g, 0x0130 + i); /* gradient */
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ if (gspca_debug & D_CONF)
+ v[i] = g;
+#endif
+ }
+ PDEBUG(D_CONF, " %02x %02x %02x %02x %02x %02x %02x %02x",
+ v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]);
+ PDEBUG(D_CONF, " %02x %02x %02x %02x %02x %02x %02x %02x",
+ v[8], v[9], v[10], v[11], v[12], v[13], v[14], v[15]);
+}
+
+static void setquality(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+ __u8 quality;
+ __u8 frxt;
+
+ switch (sd->sensor) {
+ case SENSOR_GC0305:
+ case SENSOR_OV7620:
+ case SENSOR_PO2030:
+ return;
+ }
+/*fixme: is it really 0008 0007 0018 for all other sensors? */
+ quality = sd->qindex;
+ reg_w(dev, quality, 0x0008);
+ frxt = 0x30;
+ reg_w(dev, frxt, 0x0007);
+ switch (quality) {
+ case 0:
+ case 1:
+ case 2:
+ frxt = 0xff;
+ break;
+ case 3:
+ frxt = 0xf0;
+ break;
+ case 4:
+ frxt = 0xe0;
+ break;
+ case 5:
+ frxt = 0x20;
+ break;
+ }
+ reg_w(dev, frxt, 0x0018);
+}
+
+/* Matches the sensor's internal frame rate to the lighting frequency.
+ * Valid frequencies are:
+ * 50Hz, for European and Asian lighting (default)
+ * 60Hz, for American lighting
+ * 0 = No Fliker (for outdoore usage)
+ * Returns: 0 for success
+ */
+static int setlightfreq(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int i, mode;
+ const struct usb_action *zc3_freq;
+ static const struct usb_action *freq_tb[SENSOR_MAX][6] = {
+/* SENSOR_CS2102 0 */
+ {cs2102_NoFliker, cs2102_NoFlikerScale,
+ cs2102_50HZ, cs2102_50HZScale,
+ cs2102_60HZ, cs2102_60HZScale},
+/* SENSOR_CS2102K 1 */
+ {cs2102_NoFliker, cs2102_NoFlikerScale,
+ cs2102_50HZ, cs2102_50HZScale,
+ cs2102_60HZ, cs2102_60HZScale},
+/* SENSOR_GC0305 2 */
+ {gc0305_NoFliker, gc0305_NoFliker,
+ gc0305_50HZ, gc0305_50HZ,
+ gc0305_60HZ, gc0305_60HZ},
+/* SENSOR_HDCS2020 3 */
+ {NULL, NULL,
+ NULL, NULL,
+ NULL, NULL},
+/* SENSOR_HDCS2020b 4 */
+ {hdcs2020b_NoFliker, hdcs2020b_NoFliker,
+ hdcs2020b_50HZ, hdcs2020b_50HZ,
+ hdcs2020b_60HZ, hdcs2020b_60HZ},
+/* SENSOR_HV7131B 5 */
+ {NULL, NULL,
+ NULL, NULL,
+ NULL, NULL},
+/* SENSOR_HV7131C 6 */
+ {NULL, NULL,
+ NULL, NULL,
+ NULL, NULL},
+/* SENSOR_ICM105A 7 */
+ {icm105a_NoFliker, icm105a_NoFlikerScale,
+ icm105a_50HZ, icm105a_50HZScale,
+ icm105a_60HZ, icm105a_60HZScale},
+/* SENSOR_MC501CB 8 */
+ {MC501CB_NoFliker, MC501CB_NoFlikerScale,
+ MC501CB_50HZ, MC501CB_50HZScale,
+ MC501CB_60HZ, MC501CB_60HZScale},
+/* SENSOR_OV7620 9 */
+ {OV7620_NoFliker, OV7620_NoFliker,
+ OV7620_50HZ, OV7620_50HZ,
+ OV7620_60HZ, OV7620_60HZ},
+/* SENSOR_OV7630C 10 */
+ {NULL, NULL,
+ NULL, NULL,
+ NULL, NULL},
+/* SENSOR_PAS106 11 */
+ {pas106b_NoFliker, pas106b_NoFliker,
+ pas106b_50HZ, pas106b_50HZ,
+ pas106b_60HZ, pas106b_60HZ},
+/* SENSOR_PB0330 12 */
+ {pb0330_NoFliker, pb0330_NoFlikerScale,
+ pb0330_50HZ, pb0330_50HZScale,
+ pb0330_60HZ, pb0330_60HZScale},
+/* SENSOR_PO2030 13 */
+ {PO2030_NoFliker, PO2030_NoFliker,
+ PO2030_50HZ, PO2030_50HZ,
+ PO2030_60HZ, PO2030_60HZ},
+/* SENSOR_TAS5130CK 14 */
+ {tas5130cxx_NoFliker, tas5130cxx_NoFlikerScale,
+ tas5130cxx_50HZ, tas5130cxx_50HZScale,
+ tas5130cxx_60HZ, tas5130cxx_60HZScale},
+/* SENSOR_TAS5130CXX 15 */
+ {tas5130cxx_NoFliker, tas5130cxx_NoFlikerScale,
+ tas5130cxx_50HZ, tas5130cxx_50HZScale,
+ tas5130cxx_60HZ, tas5130cxx_60HZScale},
+/* SENSOR_TAS5130C_VF0250 16 */
+ {tas5130c_vf0250_NoFliker, tas5130c_vf0250_NoFlikerScale,
+ tas5130c_vf0250_50HZ, tas5130c_vf0250_50HZScale,
+ tas5130c_vf0250_60HZ, tas5130c_vf0250_60HZScale},
+ };
+
+ i = sd->lightfreq * 2;
+ mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
+ if (!mode)
+ i++; /* 640x480 */
+ zc3_freq = freq_tb[(int) sd->sensor][i];
+ if (zc3_freq != NULL) {
+ usb_exchange(gspca_dev->dev, zc3_freq);
+ switch (sd->sensor) {
+ case SENSOR_GC0305:
+ if (mode /* if 320x240 */
+ && sd->lightfreq == 1) /* and 50Hz */
+ reg_w(gspca_dev->dev, 0x85, 0x018d);
+ /* win: 0x80, 0x018d */
+ break;
+ case SENSOR_OV7620:
+ if (!mode) { /* if 640x480 */
+ if (sd->lightfreq != 0) /* and 50 or 60 Hz */
+ reg_w(gspca_dev->dev, 0x40, 0x0002);
+ else
+ reg_w(gspca_dev->dev, 0x44, 0x0002);
+ }
+ break;
+ }
+ }
+ return 0;
+}
+
+static void setautogain(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ __u8 autoval;
+
+ if (sd->autogain)
+ autoval = 0x42;
+ else
+ autoval = 0x02;
+ reg_w(gspca_dev->dev, autoval, 0x0180);
+}
+
+static void send_unknown(struct usb_device *dev, int sensor)
+{
+ reg_w(dev, 0x01, 0x0000); /* led off */
+ switch (sensor) {
+ case SENSOR_PAS106:
+ reg_w(dev, 0x03, 0x003a);
+ reg_w(dev, 0x0c, 0x003b);
+ reg_w(dev, 0x08, 0x0038);
+ break;
+ case SENSOR_GC0305:
+ case SENSOR_OV7620:
+ case SENSOR_PB0330:
+ case SENSOR_PO2030:
+ reg_w(dev, 0x0d, 0x003a);
+ reg_w(dev, 0x02, 0x003b);
+ reg_w(dev, 0x00, 0x0038);
+ break;
+ }
+}
+
+/* start probe 2 wires */
+static void start_2wr_probe(struct usb_device *dev, int sensor)
+{
+ reg_w(dev, 0x01, 0x0000);
+ reg_w(dev, sensor, 0x0010);
+ reg_w(dev, 0x01, 0x0001);
+ reg_w(dev, 0x03, 0x0012);
+ reg_w(dev, 0x01, 0x0012);
+/* msleep(2); */
+}
+
+static int sif_probe(struct usb_device *dev)
+{
+ __u16 checkword;
+
+ start_2wr_probe(dev, 0x0f); /* PAS106 */
+ reg_w(dev, 0x08, 0x008d);
+ msleep(150);
+ checkword = ((i2c_read(dev, 0x00) & 0x0f) << 4)
+ | ((i2c_read(dev, 0x01) & 0xf0) >> 4);
+ PDEBUG(D_PROBE, "probe sif 0x%04x", checkword);
+ if (checkword == 0x0007) {
+ send_unknown(dev, SENSOR_PAS106);
+ return 0x0f; /* PAS106 */
+ }
+ return -1;
+}
+
+static int vga_2wr_probe(struct usb_device *dev)
+{
+ __u8 retbyte;
+ __u16 checkword;
+
+ start_2wr_probe(dev, 0x00); /* HV7131B */
+ i2c_write(dev, 0x01, 0xaa, 0x00);
+ retbyte = i2c_read(dev, 0x01);
+ if (retbyte != 0)
+ return 0x00; /* HV7131B */
+
+ start_2wr_probe(dev, 0x04); /* CS2102 */
+ i2c_write(dev, 0x01, 0xaa, 0x00);
+ retbyte = i2c_read(dev, 0x01);
+ if (retbyte != 0)
+ return 0x04; /* CS2102 */
+
+ start_2wr_probe(dev, 0x06); /* OmniVision */
+ reg_w(dev, 0x08, 0x8d);
+ i2c_write(dev, 0x11, 0xaa, 0x00);
+ retbyte = i2c_read(dev, 0x11);
+ if (retbyte != 0) {
+ /* (should have returned 0xaa) --> Omnivision? */
+ /* reg_r 0x10 -> 0x06 --> */
+ goto ov_check;
+ }
+
+ start_2wr_probe(dev, 0x08); /* HDCS2020 */
+ i2c_write(dev, 0x15, 0xaa, 0x00);
+ retbyte = i2c_read(dev, 0x15);
+ if (retbyte != 0)
+ return 0x08; /* HDCS2020 */
+
+ start_2wr_probe(dev, 0x0a); /* PB0330 */
+ i2c_write(dev, 0x07, 0xaa, 0xaa);
+ retbyte = i2c_read(dev, 0x07);
+ if (retbyte != 0)
+ return 0x0a; /* PB0330 */
+ retbyte = i2c_read(dev, 0x03);
+ if (retbyte != 0)
+ return 0x0a; /* PB0330 ?? */
+ retbyte = i2c_read(dev, 0x04);
+ if (retbyte != 0)
+ return 0x0a; /* PB0330 ?? */
+
+ start_2wr_probe(dev, 0x0c); /* ICM105A */
+ i2c_write(dev, 0x01, 0x11, 0x00);
+ retbyte = i2c_read(dev, 0x01);
+ if (retbyte != 0)
+ return 0x0c; /* ICM105A */
+
+ start_2wr_probe(dev, 0x0e); /* PAS202BCB */
+ reg_w(dev, 0x08, 0x8d);
+ i2c_write(dev, 0x03, 0xaa, 0x00);
+ msleep(500);
+ retbyte = i2c_read(dev, 0x03);
+ if (retbyte != 0)
+ return 0x0e; /* PAS202BCB */
+
+ start_2wr_probe(dev, 0x02); /* ?? */
+ i2c_write(dev, 0x01, 0xaa, 0x00);
+ retbyte = i2c_read(dev, 0x01);
+ if (retbyte != 0)
+ return 0x02; /* ?? */
+ov_check:
+ reg_r(dev, 0x0010, &retbyte); /* ?? */
+ reg_r(dev, 0x0010, &retbyte);
+
+ reg_w(dev, 0x01, 0x0000);
+ reg_w(dev, 0x01, 0x0001);
+ reg_w(dev, 0x06, 0x0010); /* OmniVision */
+ reg_w(dev, 0xa1, 0x008b);
+ reg_w(dev, 0x08, 0x008d);
+ msleep(500);
+ reg_w(dev, 0x01, 0x0012);
+ i2c_write(dev, 0x12, 0x80, 0x00); /* sensor reset */
+ retbyte = i2c_read(dev, 0x0a);
+ checkword = retbyte << 8;
+ retbyte = i2c_read(dev, 0x0b);
+ checkword |= retbyte;
+ PDEBUG(D_PROBE, "probe 2wr ov vga 0x%04x", checkword);
+ switch (checkword) {
+ case 0x7631: /* OV7630C */
+ reg_w(dev, 0x06, 0x0010);
+ break;
+ case 0x7620: /* OV7620 */
+ case 0x7648: /* OV7648 */
+ break;
+ default:
+ return -1; /* not OmniVision */
+ }
+ return checkword;
+}
+
+struct sensor_by_chipset_revision {
+ __u16 revision;
+ __u8 internal_sensor_id;
+};
+static const struct sensor_by_chipset_revision chipset_revision_sensor[] = {
+ {0xc001, 0x13}, /* MI0360 */
+ {0xe001, 0x13},
+ {0x8001, 0x13},
+ {0x8000, 0x14}, /* CS2102K */
+ {0x8400, 0x15}, /* TAS5130K */
+ {0, 0}
+};
+
+static int vga_3wr_probe(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+ int i;
+ __u8 retbyte;
+ __u16 checkword;
+
+/*fixme: lack of 8b=b3 (11,12)-> 10, 8b=e0 (14,15,16)-> 12 found in gspcav1*/
+ reg_w(dev, 0x02, 0x0010);
+ reg_r(dev, 0x10, &retbyte);
+ reg_w(dev, 0x01, 0x0000);
+ reg_w(dev, 0x00, 0x0010);
+ reg_w(dev, 0x01, 0x0001);
+ reg_w(dev, 0x91, 0x008b);
+ reg_w(dev, 0x03, 0x0012);
+ reg_w(dev, 0x01, 0x0012);
+ reg_w(dev, 0x05, 0x0012);
+ retbyte = i2c_read(dev, 0x14);
+ if (retbyte != 0)
+ return 0x11; /* HV7131R */
+ retbyte = i2c_read(dev, 0x15);
+ if (retbyte != 0)
+ return 0x11; /* HV7131R */
+ retbyte = i2c_read(dev, 0x16);
+ if (retbyte != 0)
+ return 0x11; /* HV7131R */
+
+ reg_w(dev, 0x02, 0x0010);
+ reg_r(dev, 0x000b, &retbyte);
+ checkword = retbyte << 8;
+ reg_r(dev, 0x000a, &retbyte);
+ checkword |= retbyte;
+ PDEBUG(D_PROBE, "probe 3wr vga 1 0x%04x", checkword);
+ reg_r(dev, 0x0010, &retbyte);
+ /* this is tested only once anyway */
+ i = 0;
+ while (chipset_revision_sensor[i].revision) {
+ if (chipset_revision_sensor[i].revision == checkword) {
+ sd->chip_revision = checkword;
+ send_unknown(dev, SENSOR_PB0330);
+ return chipset_revision_sensor[i].internal_sensor_id;
+ }
+ i++;
+ }
+
+ reg_w(dev, 0x01, 0x0000);
+ reg_w(dev, 0x01, 0x0001);
+ reg_w(dev, 0xdd, 0x008b);
+ reg_w(dev, 0x0a, 0x0010);
+ reg_w(dev, 0x03, 0x0012);
+ reg_w(dev, 0x01, 0x0012);
+ retbyte = i2c_read(dev, 0x00);
+ if (retbyte != 0) {
+ PDEBUG(D_PROBE, "probe 3wr vga type 0a ?");
+ return 0x0a; /* ?? */
+ }
+
+ reg_w(dev, 0x01, 0x0000);
+ reg_w(dev, 0x01, 0x0001);
+ reg_w(dev, 0x98, 0x008b);
+ reg_w(dev, 0x01, 0x0010);
+ reg_w(dev, 0x03, 0x0012);
+ msleep(2);
+ reg_w(dev, 0x01, 0x0012);
+ retbyte = i2c_read(dev, 0x00);
+ if (retbyte != 0) {
+ PDEBUG(D_PROBE, "probe 3wr vga type %02x", retbyte);
+ send_unknown(dev, SENSOR_GC0305);
+ return retbyte; /* 0x29 = gc0305 - should continue? */
+ }
+
+ reg_w(dev, 0x01, 0x0000); /* check OmniVision */
+ reg_w(dev, 0x01, 0x0001);
+ reg_w(dev, 0xa1, 0x008b);
+ reg_w(dev, 0x08, 0x008d);
+ reg_w(dev, 0x06, 0x0010);
+ reg_w(dev, 0x01, 0x0012);
+ reg_w(dev, 0x05, 0x0012);
+ if (i2c_read(dev, 0x1c) == 0x7f /* OV7610 - manufacturer ID */
+ && i2c_read(dev, 0x1d) == 0xa2) {
+ send_unknown(dev, SENSOR_OV7620);
+ return 0x06; /* OmniVision confirm ? */
+ }
+
+ reg_w(dev, 0x01, 0x00);
+ reg_w(dev, 0x00, 0x02);
+ reg_w(dev, 0x01, 0x10);
+ reg_w(dev, 0x01, 0x01);
+ reg_w(dev, 0xee, 0x8b);
+ reg_w(dev, 0x03, 0x12);
+/* msleep(150); */
+ reg_w(dev, 0x01, 0x12);
+ reg_w(dev, 0x05, 0x12);
+ retbyte = i2c_read(dev, 0x00); /* ID 0 */
+ checkword = retbyte << 8;
+ retbyte = i2c_read(dev, 0x01); /* ID 1 */
+ checkword |= retbyte;
+ PDEBUG(D_PROBE, "probe 3wr vga 2 0x%04x", checkword);
+ if (checkword == 0x2030) {
+ retbyte = i2c_read(dev, 0x02); /* revision number */
+ PDEBUG(D_PROBE, "sensor PO2030 rev 0x%02x", retbyte);
+ send_unknown(dev, SENSOR_PO2030);
+ return checkword;
+ }
+
+ reg_w(dev, 0x01, 0x00);
+ reg_w(dev, 0x0a, 0x10);
+ reg_w(dev, 0xd3, 0x8b);
+ reg_w(dev, 0x01, 0x01);
+ reg_w(dev, 0x03, 0x12);
+ reg_w(dev, 0x01, 0x12);
+ reg_w(dev, 0x05, 0x01);
+ reg_w(dev, 0xd3, 0x8b);
+ retbyte = i2c_read(dev, 0x01);
+ if (retbyte != 0) {
+ PDEBUG(D_PROBE, "probe 3wr vga type 0a ?");
+ return 0x0a; /* ?? */
+ }
+ return -1;
+}
+
+static int zcxx_probeSensor(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+ int sensor, sensor2;
+
+ switch (sd->sensor) {
+ case SENSOR_MC501CB:
+ case SENSOR_TAS5130C_VF0250:
+ return -1; /* don't probe */
+ }
+ sensor = vga_2wr_probe(dev);
+ if (sensor >= 0) {
+ if (sensor < 0x7600)
+ return sensor;
+ /* next probe is needed for OmniVision ? */
+ }
+ sensor2 = vga_3wr_probe(gspca_dev);
+ if (sensor2 >= 0) {
+ if (sensor >= 0)
+ return sensor;
+ return sensor2;
+ }
+ return sif_probe(dev);
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+ const struct usb_device_id *id)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct cam *cam;
+ int sensor;
+ __u8 bsensor;
+ int vga = 1; /* 1: vga, 0: sif */
+ static const __u8 gamma[SENSOR_MAX] = {
+ 5, /* SENSOR_CS2102 0 */
+ 5, /* SENSOR_CS2102K 1 */
+ 4, /* SENSOR_GC0305 2 */
+ 4, /* SENSOR_HDCS2020 3 */
+ 4, /* SENSOR_HDCS2020b 4 */
+ 4, /* SENSOR_HV7131B 5 */
+ 4, /* SENSOR_HV7131C 6 */
+ 4, /* SENSOR_ICM105A 7 */
+ 4, /* SENSOR_MC501CB 8 */
+ 3, /* SENSOR_OV7620 9 */
+ 4, /* SENSOR_OV7630C 10 */
+ 4, /* SENSOR_PAS106 11 */
+ 4, /* SENSOR_PB0330 12 */
+ 4, /* SENSOR_PO2030 13 */
+ 4, /* SENSOR_TAS5130CK 14 */
+ 4, /* SENSOR_TAS5130CXX 15 */
+ 3, /* SENSOR_TAS5130C_VF0250 16 */
+ };
+
+ /* define some sensors from the vendor/product */
+ sd->sharpness = 2;
+ switch (id->idVendor) {
+ case 0x041e: /* Creative */
+ switch (id->idProduct) {
+ case 0x4051: /* zc301 chips */
+ case 0x4053:
+ sd->sensor = SENSOR_TAS5130C_VF0250;
+ break;
+ }
+ break;
+ case 0x046d: /* Logitech Labtec */
+ switch (id->idProduct) {
+ case 0x08dd:
+ sd->sensor = SENSOR_MC501CB;
+ break;
+ }
+ break;
+ case 0x0ac8: /* Vimicro z-star */
+ switch (id->idProduct) {
+ case 0x305b:
+ sd->sensor = SENSOR_TAS5130C_VF0250;
+ break;
+ }
+ break;
+ }
+ sensor = zcxx_probeSensor(gspca_dev);
+ if (sensor >= 0)
+ PDEBUG(D_PROBE, "probe sensor -> %02x", sensor);
+ if ((unsigned) force_sensor < SENSOR_MAX) {
+ sd->sensor = force_sensor;
+ PDEBUG(D_PROBE, "sensor forced to %d", force_sensor);
+ } else {
+ switch (sensor) {
+ case -1:
+ switch (sd->sensor) {
+ case SENSOR_MC501CB:
+ PDEBUG(D_PROBE, "Sensor MC501CB");
+ break;
+ case SENSOR_TAS5130C_VF0250:
+ PDEBUG(D_PROBE, "Sensor Tas5130 (VF0250)");
+ break;
+ default:
+ PDEBUG(D_PROBE,
+ "Sensor UNKNOW_0 force Tas5130");
+ sd->sensor = SENSOR_TAS5130CXX;
+ }
+ break;
+ case 0:
+ PDEBUG(D_PROBE, "Find Sensor HV7131B");
+ sd->sensor = SENSOR_HV7131B;
+ break;
+ case 0x04:
+ PDEBUG(D_PROBE, "Find Sensor CS2102");
+ sd->sensor = SENSOR_CS2102;
+ break;
+ case 0x08:
+ PDEBUG(D_PROBE, "Find Sensor HDCS2020(b)");
+ sd->sensor = SENSOR_HDCS2020b;
+ break;
+ case 0x0a:
+ PDEBUG(D_PROBE,
+ "Find Sensor PB0330. Chip revision %x",
+ sd->chip_revision);
+ sd->sensor = SENSOR_PB0330;
+ break;
+ case 0x0c:
+ PDEBUG(D_PROBE, "Find Sensor ICM105A");
+ sd->sensor = SENSOR_ICM105A;
+ break;
+ case 0x0e:
+ PDEBUG(D_PROBE, "Find Sensor HDCS2020");
+ sd->sensor = SENSOR_HDCS2020;
+ sd->sharpness = 1;
+ break;
+ case 0x0f:
+ PDEBUG(D_PROBE, "Find Sensor PAS106");
+ sd->sensor = SENSOR_PAS106;
+ vga = 0; /* SIF */
+ break;
+ case 0x10:
+ case 0x12:
+ PDEBUG(D_PROBE, "Find Sensor TAS5130");
+ sd->sensor = SENSOR_TAS5130CXX;
+ break;
+ case 0x11:
+ PDEBUG(D_PROBE, "Find Sensor HV7131R(c)");
+ sd->sensor = SENSOR_HV7131C;
+ break;
+ case 0x13:
+ PDEBUG(D_PROBE,
+ "Find Sensor MI0360. Chip revision %x",
+ sd->chip_revision);
+ sd->sensor = SENSOR_PB0330;
+ break;
+ case 0x14:
+ PDEBUG(D_PROBE,
+ "Find Sensor CS2102K?. Chip revision %x",
+ sd->chip_revision);
+ sd->sensor = SENSOR_CS2102K;
+ break;
+ case 0x15:
+ PDEBUG(D_PROBE,
+ "Find Sensor TAS5130CK?. Chip revision %x",
+ sd->chip_revision);
+ sd->sensor = SENSOR_TAS5130CK;
+ break;
+ case 0x29:
+ PDEBUG(D_PROBE, "Find Sensor GC0305");
+ sd->sensor = SENSOR_GC0305;
+ break;
+ case 0x2030:
+ PDEBUG(D_PROBE, "Find Sensor PO2030");
+ sd->sensor = SENSOR_PO2030;
+ sd->sharpness = 0; /* from win traces */
+ break;
+ case 0x7620:
+ PDEBUG(D_PROBE, "Find Sensor OV7620");
+ sd->sensor = SENSOR_OV7620;
+ break;
+ case 0x7648:
+ PDEBUG(D_PROBE, "Find Sensor OV7648");
+ sd->sensor = SENSOR_OV7620; /* same sensor (?) */
+ break;
+ default:
+ PDEBUG(D_ERR|D_PROBE, "Unknown sensor %02x", sensor);
+ return -EINVAL;
+ }
+ }
+ if (sensor < 0x20) {
+ if (sensor == -1 || sensor == 0x10 || sensor == 0x12)
+ reg_w(gspca_dev->dev, 0x02, 0x0010);
+ else
+ reg_w(gspca_dev->dev, sensor & 0x0f, 0x0010);
+ reg_r(gspca_dev->dev, 0x0010, &bsensor);
+ }
+
+ cam = &gspca_dev->cam;
+ cam->dev_name = (char *) id->driver_info;
+ cam->epaddr = 0x01;
+/*fixme:test*/
+ gspca_dev->nbalt--;
+ if (vga) {
+ cam->cam_mode = vga_mode;
+ cam->nmodes = ARRAY_SIZE(vga_mode);
+ } else {
+ cam->cam_mode = sif_mode;
+ cam->nmodes = ARRAY_SIZE(sif_mode);
+ }
+ sd->qindex = 1;
+ sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
+ sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
+ sd->gamma = gamma[(int) sd->sensor];
+ sd->autogain = sd_ctrls[SD_AUTOGAIN].qctrl.default_value;
+ sd->lightfreq = sd_ctrls[SD_FREQ].qctrl.default_value;
+ sd->sharpness = sd_ctrls[SD_SHARPNESS].qctrl.default_value;
+
+ /* switch the led off */
+ reg_w(gspca_dev->dev, 0x01, 0x0000);
+ return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+ reg_w(gspca_dev->dev, 0x01, 0x0000);
+ return 0;
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *dev = gspca_dev->dev;
+ const struct usb_action *zc3_init;
+ int mode;
+ __u8 retbyte;
+ static const struct usb_action *init_tb[SENSOR_MAX][2] = {
+ {cs2102_InitialScale, cs2102_Initial}, /* 0 */
+ {cs2102K_InitialScale, cs2102K_Initial}, /* 1 */
+ {gc0305_Initial, gc0305_InitialScale}, /* 2 */
+ {hdcs2020xx_InitialScale, hdcs2020xx_Initial}, /* 3 */
+ {hdcs2020xb_InitialScale, hdcs2020xb_Initial}, /* 4 */
+ {hv7131bxx_InitialScale, hv7131bxx_Initial}, /* 5 */
+ {hv7131cxx_InitialScale, hv7131cxx_Initial}, /* 6 */
+ {icm105axx_InitialScale, icm105axx_Initial}, /* 7 */
+ {MC501CB_InitialScale, MC501CB_Initial}, /* 9 */
+ {OV7620_mode0, OV7620_mode1}, /* 9 */
+ {ov7630c_InitialScale, ov7630c_Initial}, /* 10 */
+ {pas106b_InitialScale, pas106b_Initial}, /* 11 */
+ {pb0330xx_InitialScale, pb0330xx_Initial}, /* 12 */
+/* or {pb03303x_InitialScale, pb03303x_Initial}, */
+ {PO2030_mode0, PO2030_mode1}, /* 13 */
+ {tas5130CK_InitialScale, tas5130CK_Initial}, /* 14 */
+ {tas5130cxx_InitialScale, tas5130cxx_Initial}, /* 15 */
+ {tas5130c_vf0250_InitialScale, tas5130c_vf0250_Initial},
+ /* 16 */
+ };
+
+ mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
+ zc3_init = init_tb[(int) sd->sensor][mode];
+ switch (sd->sensor) {
+ case SENSOR_HV7131B:
+ case SENSOR_HV7131C:
+ zcxx_probeSensor(gspca_dev);
+ break;
+ case SENSOR_PAS106:
+ usb_exchange(dev, pas106b_Initial_com);
+ break;
+ case SENSOR_PB0330:
+ if (mode) {
+ if (sd->chip_revision == 0xc001
+ || sd->chip_revision == 0xe001
+ || sd->chip_revision == 0x8001)
+ zc3_init = pb03303x_Initial;
+ } else {
+ if (sd->chip_revision == 0xc001
+ || sd->chip_revision == 0xe001
+ || sd->chip_revision == 0x8001)
+ zc3_init = pb03303x_InitialScale;
+ }
+ break;
+ }
+ usb_exchange(dev, zc3_init);
+
+ switch (sd->sensor) {
+ case SENSOR_GC0305:
+ case SENSOR_OV7620:
+ case SENSOR_PO2030:
+ msleep(100); /* ?? */
+ reg_r(dev, 0x0002, &retbyte); /* --> 0x40 */
+ reg_w(dev, 0x09, 0x01ad); /* (from win traces) */
+ reg_w(dev, 0x15, 0x01ae);
+ reg_w(dev, 0x0d, 0x003a);
+ reg_w(dev, 0x02, 0x003b);
+ reg_w(dev, 0x00, 0x0038);
+ break;
+ }
+
+ setmatrix(gspca_dev);
+ setbrightness(gspca_dev);
+ switch (sd->sensor) {
+ case SENSOR_OV7620:
+ reg_r(dev, 0x0008, &retbyte);
+ reg_w(dev, 0x00, 0x0008);
+ break;
+ case SENSOR_GC0305:
+ reg_r(dev, 0x0008, &retbyte);
+ /* fall thru */
+ case SENSOR_PO2030:
+ reg_w(dev, 0x03, 0x0008);
+ break;
+ }
+ setsharpness(gspca_dev);
+
+ /* set the gamma tables when not set */
+ switch (sd->sensor) {
+ case SENSOR_CS2102: /* gamma set in xxx_Initial */
+ case SENSOR_CS2102K:
+ case SENSOR_HDCS2020:
+ case SENSOR_HDCS2020b:
+ case SENSOR_PB0330: /* pb with chip_revision - see above */
+ case SENSOR_OV7630C:
+ case SENSOR_TAS5130CK:
+ break;
+ default:
+ setcontrast(gspca_dev);
+ break;
+ }
+ setmatrix(gspca_dev); /* one more time? */
+ switch (sd->sensor) {
+ case SENSOR_OV7620:
+ reg_r(dev, 0x0180, &retbyte); /* from win */
+ reg_w(dev, 0x00, 0x0180);
+ break;
+ default:
+ setquality(gspca_dev);
+ break;
+ }
+ setlightfreq(gspca_dev);
+
+ switch (sd->sensor) {
+ case SENSOR_GC0305:
+ case SENSOR_OV7620:
+ reg_w(dev, 0x09, 0x01ad); /* (from win traces) */
+ reg_w(dev, 0x15, 0x01ae);
+ sd->autogain = 0;
+ break;
+ case SENSOR_PO2030:
+ reg_w(dev, 0x40, 0x0117); /* (from win traces) */
+ reg_r(dev, 0x0180, &retbyte);
+ break;
+ }
+
+ setautogain(gspca_dev);
+ switch (sd->sensor) {
+ case SENSOR_GC0305:
+/* setlightfreq(gspca_dev); ?? (end: 80 -> [18d]) */
+ reg_w(dev, 0x09, 0x01ad); /* (from win traces) */
+ reg_w(dev, 0x15, 0x01ae);
+ reg_w(dev, 0x40, 0x0180);
+ reg_w(dev, 0x40, 0x0117);
+ reg_r(dev, 0x0180, &retbyte);
+ sd->autogain = 1;
+ setautogain(gspca_dev);
+ break;
+ case SENSOR_OV7620:
+ i2c_read(dev, 0x13); /*fixme: returns 0xa3 */
+ i2c_write(dev, 0x13, 0xa3, 0x00); /*fixme: same to send? */
+ reg_w(dev, 0x40, 0x0117); /* (from win traces) */
+ reg_r(dev, 0x0180, &retbyte);
+ setautogain(gspca_dev);
+ msleep(500);
+ break;
+ case SENSOR_PO2030:
+ msleep(500);
+ reg_r(dev, 0x0008, &retbyte);
+ reg_r(dev, 0x0007, &retbyte);
+ reg_w(dev, 0x00, 0x0007); /* (from win traces) */
+ reg_w(dev, 0x02, 0x0008);
+ break;
+ }
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ send_unknown(gspca_dev->dev, sd->sensor);
+}
+
+/* this function is called at close time */
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+#if 0 /* test */
+ struct usb_device *dev = gspca_dev->dev;
+ __u8 buffread;
+
+ reg_r(dev, 0x0180, &buffread);
+ reg_w(dev, 0x00, 0x0180);
+ reg_w(dev, 0x01, 0x0000);
+#endif
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ struct gspca_frame *frame,
+ __u8 *data,
+ int len)
+{
+
+ if (data[0] == 0xff && data[1] == 0xd8) { /* start of frame */
+ frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+ data, 0);
+ /* put the JPEG header in the new frame */
+ jpeg_put_header(gspca_dev, frame,
+ ((struct sd *) gspca_dev)->qindex,
+ 0x21);
+ /* remove the webcam's header:
+ * ff d8 ff fe 00 0e 00 00 ss ss 00 01 ww ww hh hh pp pp
+ * - 'ss ss' is the frame sequence number (BE)
+ * - 'ww ww' and 'hh hh' are the window dimensions (BE)
+ * - 'pp pp' is the packet sequence number (BE)
+ */
+ data += 18;
+ len -= 18;
+ }
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->brightness = val;
+ if (gspca_dev->streaming)
+ setbrightness(gspca_dev);
+ return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->brightness;
+ return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->contrast = val;
+ if (gspca_dev->streaming)
+ setcontrast(gspca_dev);
+ return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->contrast;
+ return 0;
+}
+
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->autogain = val;
+ if (gspca_dev->streaming)
+ setautogain(gspca_dev);
+ return 0;
+}
+
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->autogain;
+ return 0;
+}
+
+static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->gamma = val;
+ if (gspca_dev->streaming)
+ setcontrast(gspca_dev);
+ return 0;
+}
+
+static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->gamma;
+ return 0;
+}
+
+static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->lightfreq = val;
+ if (gspca_dev->streaming)
+ setlightfreq(gspca_dev);
+ return 0;
+}
+
+static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->lightfreq;
+ return 0;
+}
+
+static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->sharpness = val;
+ if (gspca_dev->streaming)
+ setsharpness(gspca_dev);
+ return 0;
+}
+
+static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->sharpness;
+ return 0;
+}
+
+static int sd_querymenu(struct gspca_dev *gspca_dev,
+ struct v4l2_querymenu *menu)
+{
+ switch (menu->id) {
+ case V4L2_CID_POWER_LINE_FREQUENCY:
+ switch (menu->index) {
+ case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */
+ strcpy((char *) menu->name, "NoFliker");
+ return 0;
+ case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
+ strcpy((char *) menu->name, "50 Hz");
+ return 0;
+ case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
+ strcpy((char *) menu->name, "60 Hz");
+ return 0;
+ }
+ break;
+ }
+ return -EINVAL;
+}
+
+static const struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .ctrls = sd_ctrls,
+ .nctrls = sizeof sd_ctrls / sizeof sd_ctrls[0],
+ .config = sd_config,
+ .open = sd_open,
+ .start = sd_start,
+ .stopN = sd_stopN,
+ .stop0 = sd_stop0,
+ .close = sd_close,
+ .pkt_scan = sd_pkt_scan,
+ .querymenu = sd_querymenu,
+};
+
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static const __devinitdata struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x041e, 0x041e), DVNM("Creative WebCam Live!")},
+#ifndef CONFIG_USB_ZC0301
+ {USB_DEVICE(0x041e, 0x4017), DVNM("Creative Webcam Mobile PD1090")},
+ {USB_DEVICE(0x041e, 0x401c), DVNM("Creative NX")},
+ {USB_DEVICE(0x041e, 0x401e), DVNM("Creative Nx Pro")},
+ {USB_DEVICE(0x041e, 0x401f), DVNM("Creative Webcam Notebook PD1171")},
+#endif
+ {USB_DEVICE(0x041e, 0x4029), DVNM("Creative WebCam Vista Pro")},
+#ifndef CONFIG_USB_ZC0301
+ {USB_DEVICE(0x041e, 0x4034), DVNM("Creative Instant P0620")},
+ {USB_DEVICE(0x041e, 0x4035), DVNM("Creative Instant P0620D")},
+ {USB_DEVICE(0x041e, 0x4036), DVNM("Creative Live !")},
+ {USB_DEVICE(0x041e, 0x403a), DVNM("Creative Nx Pro 2")},
+#endif
+ {USB_DEVICE(0x041e, 0x4051), DVNM("Creative Notebook Pro (VF0250)")},
+ {USB_DEVICE(0x041e, 0x4053), DVNM("Creative Live!Cam Video IM")},
+#ifndef CONFIG_USB_ZC0301
+ {USB_DEVICE(0x0458, 0x7007), DVNM("Genius VideoCam V2")},
+ {USB_DEVICE(0x0458, 0x700c), DVNM("Genius VideoCam V3")},
+ {USB_DEVICE(0x0458, 0x700f), DVNM("Genius VideoCam Web V2")},
+#endif
+ {USB_DEVICE(0x0461, 0x0a00), DVNM("MicroInnovation WebCam320")},
+ {USB_DEVICE(0x046d, 0x08a0), DVNM("Logitech QC IM")},
+ {USB_DEVICE(0x046d, 0x08a1), DVNM("Logitech QC IM 0x08A1 +sound")},
+ {USB_DEVICE(0x046d, 0x08a2), DVNM("Labtec Webcam Pro")},
+ {USB_DEVICE(0x046d, 0x08a3), DVNM("Logitech QC Chat")},
+ {USB_DEVICE(0x046d, 0x08a6), DVNM("Logitech QCim")},
+ {USB_DEVICE(0x046d, 0x08a7), DVNM("Logitech QuickCam Image")},
+ {USB_DEVICE(0x046d, 0x08a9), DVNM("Logitech Notebook Deluxe")},
+ {USB_DEVICE(0x046d, 0x08aa), DVNM("Labtec Webcam Notebook")},
+ {USB_DEVICE(0x046d, 0x08ac), DVNM("Logitech QuickCam Cool")},
+ {USB_DEVICE(0x046d, 0x08ad), DVNM("Logitech QCCommunicate STX")},
+#ifndef CONFIG_USB_ZC0301
+ {USB_DEVICE(0x046d, 0x08ae), DVNM("Logitech QuickCam for Notebooks")},
+#endif
+ {USB_DEVICE(0x046d, 0x08af), DVNM("Logitech QuickCam Cool")},
+ {USB_DEVICE(0x046d, 0x08b9), DVNM("Logitech QC IM ???")},
+ {USB_DEVICE(0x046d, 0x08d7), DVNM("Logitech QCam STX")},
+ {USB_DEVICE(0x046d, 0x08d9), DVNM("Logitech QuickCam IM/Connect")},
+ {USB_DEVICE(0x046d, 0x08d8), DVNM("Logitech Notebook Deluxe")},
+ {USB_DEVICE(0x046d, 0x08da), DVNM("Logitech QuickCam Messenger")},
+ {USB_DEVICE(0x046d, 0x08dd), DVNM("Logitech QuickCam for Notebooks")},
+ {USB_DEVICE(0x0471, 0x0325), DVNM("Philips SPC 200 NC")},
+ {USB_DEVICE(0x0471, 0x0326), DVNM("Philips SPC 300 NC")},
+ {USB_DEVICE(0x0471, 0x032d), DVNM("Philips spc210nc")},
+ {USB_DEVICE(0x0471, 0x032e), DVNM("Philips spc315nc")},
+ {USB_DEVICE(0x055f, 0xc005), DVNM("Mustek Wcam300A")},
+#ifndef CONFIG_USB_ZC0301
+ {USB_DEVICE(0x055f, 0xd003), DVNM("Mustek WCam300A")},
+ {USB_DEVICE(0x055f, 0xd004), DVNM("Mustek WCam300 AN")},
+#endif
+ {USB_DEVICE(0x0698, 0x2003), DVNM("CTX M730V built in")},
+ {USB_DEVICE(0x0ac8, 0x0302), DVNM("Z-star Vimicro zc0302")},
+#ifndef CONFIG_USB_ZC0301
+ {USB_DEVICE(0x0ac8, 0x301b), DVNM("Z-Star zc301b")},
+ {USB_DEVICE(0x0ac8, 0x303b), DVNM("Vimicro 0x303b")},
+#endif
+ {USB_DEVICE(0x0ac8, 0x305b), DVNM("Z-star Vimicro zc0305b")},
+#ifndef CONFIG_USB_ZC0301
+ {USB_DEVICE(0x0ac8, 0x307b), DVNM("Z-Star 307b")},
+ {USB_DEVICE(0x10fd, 0x0128), DVNM("Typhoon Webshot II 300k 0x0128")},
+ {USB_DEVICE(0x10fd, 0x8050), DVNM("Typhoon Webshot II USB 300k")},
+#endif
+ {} /* end of entry */
+};
+#undef DVNAME
+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);
+}
+
+/* USB driver */
+static struct usb_driver sd_driver = {
+ .name = MODULE_NAME,
+ .id_table = device_table,
+ .probe = sd_probe,
+ .disconnect = gspca_disconnect,
+};
+
+static int __init sd_mod_init(void)
+{
+ if (usb_register(&sd_driver) < 0)
+ return -1;
+ PDEBUG(D_PROBE, "v%s registered", version);
+ return 0;
+}
+
+static void __exit sd_mod_exit(void)
+{
+ usb_deregister(&sd_driver);
+ PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
+
+module_param(force_sensor, int, 0644);
+MODULE_PARM_DESC(force_sensor,
+ "Force sensor. Only for experts!!!");
diff --git a/linux/drivers/media/video/ir-kbd-i2c.c b/linux/drivers/media/video/ir-kbd-i2c.c
index 9a8795523..85806fe10 100644
--- a/linux/drivers/media/video/ir-kbd-i2c.c
+++ b/linux/drivers/media/video/ir-kbd-i2c.c
@@ -328,10 +328,8 @@ static int ir_detach(struct i2c_client *client);
static int ir_probe(struct i2c_adapter *adap);
static struct i2c_driver driver = {
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0))&&(LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15))
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15)
.owner = THIS_MODULE,
-#endif
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15)
.name = "ir-kbd-i2c",
.flags = I2C_DF_NOTIFY,
#else
diff --git a/linux/drivers/media/video/ivtv/ivtv-cards.c b/linux/drivers/media/video/ivtv/ivtv-cards.c
index 03455fb30..c52371f9e 100644
--- a/linux/drivers/media/video/ivtv/ivtv-cards.c
+++ b/linux/drivers/media/video/ivtv/ivtv-cards.c
@@ -40,7 +40,7 @@
#define MSP_MONO MSP_INPUT(MSP_IN_MONO, MSP_IN_TUNER1, \
MSP_DSP_IN_SCART, MSP_DSP_IN_SCART)
-#define V4L2_STD_NOT_MN (V4L2_STD_PAL|V4L2_STD_SECAM)
+#define V4L2_STD_PAL_SECAM (V4L2_STD_PAL|V4L2_STD_SECAM)
/* usual i2c tuner addresses to probe */
static struct ivtv_card_tuner_i2c ivtv_i2c_std = {
@@ -300,7 +300,7 @@ static const struct ivtv_card ivtv_card_mpg600 = {
.gpio_audio_detect = { .mask = 0x0900, .stereo = 0x0100 },
.tuners = {
/* The PAL tuner is confirmed */
- { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FQ1216ME },
+ { .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FQ1216ME },
{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 },
},
.pci_list = ivtv_pci_mpg600,
@@ -341,7 +341,7 @@ static const struct ivtv_card ivtv_card_mpg160 = {
.lang1 = 0x0004, .lang2 = 0x0000, .both = 0x0008 },
.gpio_audio_detect = { .mask = 0x0900, .stereo = 0x0100 },
.tuners = {
- { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FQ1216ME },
+ { .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FQ1216ME },
{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 },
},
.pci_list = ivtv_pci_mpg160,
@@ -377,7 +377,7 @@ static const struct ivtv_card ivtv_card_pg600 = {
{ IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL },
},
.tuners = {
- { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FQ1216ME },
+ { .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FQ1216ME },
{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 },
},
.pci_list = ivtv_pci_pg600,
@@ -418,7 +418,7 @@ static const struct ivtv_card ivtv_card_avc2410 = {
on the country/region setting of the user to decide which tuner
is available. */
.tuners = {
- { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
+ { .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
{ .std = V4L2_STD_ALL - V4L2_STD_NTSC_M_JP,
.tuner = TUNER_PHILIPS_FM1236_MK3 },
{ .std = V4L2_STD_NTSC_M_JP, .tuner = TUNER_PHILIPS_FQ1286 },
@@ -492,7 +492,7 @@ static const struct ivtv_card ivtv_card_tg5000tv = {
.gpio_video_input = { .mask = 0x0030, .tuner = 0x0000,
.composite = 0x0010, .svideo = 0x0020 },
.tuners = {
- { .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_PHILIPS_FQ1286 },
+ { .std = V4L2_STD_MN, .tuner = TUNER_PHILIPS_FQ1286 },
},
.pci_list = ivtv_pci_tg5000tv,
.i2c = &ivtv_i2c_std,
@@ -523,7 +523,7 @@ static const struct ivtv_card ivtv_card_va2000 = {
{ IVTV_CARD_INPUT_AUD_TUNER, MSP_TUNER },
},
.tuners = {
- { .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_PHILIPS_FQ1286 },
+ { .std = V4L2_STD_MN, .tuner = TUNER_PHILIPS_FQ1286 },
},
.pci_list = ivtv_pci_va2000,
.i2c = &ivtv_i2c_std,
@@ -567,7 +567,7 @@ static const struct ivtv_card ivtv_card_cx23416gyc = {
.gpio_audio_freq = { .mask = 0xc000, .f32000 = 0x0000,
.f44100 = 0x4000, .f48000 = 0x8000 },
.tuners = {
- { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
+ { .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 },
},
.pci_list = ivtv_pci_cx23416gyc,
@@ -599,7 +599,7 @@ static const struct ivtv_card ivtv_card_cx23416gyc_nogr = {
.gpio_audio_freq = { .mask = 0xc000, .f32000 = 0x0000,
.f44100 = 0x4000, .f48000 = 0x8000 },
.tuners = {
- { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
+ { .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 },
},
.i2c = &ivtv_i2c_std,
@@ -629,7 +629,7 @@ static const struct ivtv_card ivtv_card_cx23416gyc_nogrycs = {
.gpio_audio_freq = { .mask = 0xc000, .f32000 = 0x0000,
.f44100 = 0x4000, .f48000 = 0x8000 },
.tuners = {
- { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
+ { .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 },
},
.i2c = &ivtv_i2c_std,
@@ -669,7 +669,7 @@ static const struct ivtv_card ivtv_card_gv_mvprx = {
.gpio_audio_input = { .mask = 0xffff, .tuner = 0x0200, .linein = 0x0300 },
.tuners = {
/* This card has the Panasonic VP27 tuner */
- { .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_PANASONIC_VP27 },
+ { .std = V4L2_STD_MN, .tuner = TUNER_PANASONIC_VP27 },
},
.pci_list = ivtv_pci_gv_mvprx,
.i2c = &ivtv_i2c_std,
@@ -706,7 +706,7 @@ static const struct ivtv_card ivtv_card_gv_mvprx2e = {
.gpio_audio_input = { .mask = 0xffff, .tuner = 0x0200, .linein = 0x0300 },
.tuners = {
/* This card has the Panasonic VP27 tuner */
- { .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_PANASONIC_VP27 },
+ { .std = V4L2_STD_MN, .tuner = TUNER_PANASONIC_VP27 },
},
.pci_list = ivtv_pci_gv_mvprx2e,
.i2c = &ivtv_i2c_std,
@@ -741,7 +741,7 @@ static const struct ivtv_card ivtv_card_gotview_pci_dvd = {
.gpio_init = { .direction = 0xf000, .initial_value = 0xA000 },
.tuners = {
/* This card has a Philips FQ1216ME MK3 tuner */
- { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
+ { .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
},
.pci_list = ivtv_pci_gotview_pci_dvd,
.i2c = &ivtv_i2c_std,
@@ -780,7 +780,7 @@ static const struct ivtv_card ivtv_card_gotview_pci_dvd2 = {
.gpio_audio_input = { .mask = 0x0800, .tuner = 0, .linein = 0, .radio = 0x0800 },
.tuners = {
/* This card has a Philips FQ1216ME MK5 tuner */
- { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
+ { .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
},
.pci_list = ivtv_pci_gotview_pci_dvd2,
.i2c = &ivtv_i2c_std,
@@ -858,7 +858,7 @@ static const struct ivtv_card ivtv_card_dctmvtvp1 = {
.gpio_video_input = { .mask = 0x0030, .tuner = 0x0000,
.composite = 0x0010, .svideo = 0x0020},
.tuners = {
- { .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_PHILIPS_FQ1286 },
+ { .std = V4L2_STD_MN, .tuner = TUNER_PHILIPS_FQ1286 },
},
.pci_list = ivtv_pci_dctmvtvp1,
.i2c = &ivtv_i2c_std,
@@ -1021,7 +1021,7 @@ static const struct ivtv_card ivtv_card_aver_pvr150 = {
.gpio_audio_input = { .mask = 0x0800, .tuner = 0, .linein = 0, .radio = 0x0800 },
.tuners = {
/* This card has a Partsnic PTI-5NF05 tuner */
- { .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_TCL_2002N },
+ { .std = V4L2_STD_MN, .tuner = TUNER_TCL_2002N },
},
.pci_list = ivtv_pci_aver_pvr150,
.i2c = &ivtv_i2c_radio,
@@ -1089,7 +1089,7 @@ static const struct ivtv_card ivtv_card_asus_falcon2 = {
},
.radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO_SERIAL, M52790_IN_TUNER },
.tuners = {
- { .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_PHILIPS_FM1236_MK3 },
+ { .std = V4L2_STD_MN, .tuner = TUNER_PHILIPS_FM1236_MK3 },
},
.pci_list = ivtv_pci_asus_falcon2,
.i2c = &ivtv_i2c_std,
diff --git a/linux/drivers/media/video/ivtv/ivtv-controls.c b/linux/drivers/media/video/ivtv/ivtv-controls.c
index c7e449f63..48e103be7 100644
--- a/linux/drivers/media/video/ivtv/ivtv-controls.c
+++ b/linux/drivers/media/video/ivtv/ivtv-controls.c
@@ -47,12 +47,12 @@ static const u32 *ctrl_classes[] = {
NULL
};
-static int ivtv_queryctrl(struct ivtv *itv, struct v4l2_queryctrl *qctrl)
+
+int ivtv_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qctrl)
{
+ struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
const char *name;
- IVTV_DEBUG_IOCTL("VIDIOC_QUERYCTRL(%08x)\n", qctrl->id);
-
qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
if (qctrl->id == 0)
return -EINVAL;
@@ -87,21 +87,35 @@ static int ivtv_queryctrl(struct ivtv *itv, struct v4l2_queryctrl *qctrl)
return 0;
}
-static int ivtv_querymenu(struct ivtv *itv, struct v4l2_querymenu *qmenu)
+int ivtv_querymenu(struct file *file, void *fh, struct v4l2_querymenu *qmenu)
{
+ struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
struct v4l2_queryctrl qctrl;
qctrl.id = qmenu->id;
- ivtv_queryctrl(itv, &qctrl);
- return v4l2_ctrl_query_menu(qmenu, &qctrl, cx2341x_ctrl_get_menu(qmenu->id));
+ ivtv_queryctrl(file, fh, &qctrl);
+ return v4l2_ctrl_query_menu(qmenu, &qctrl,
+ cx2341x_ctrl_get_menu(&itv->params, qmenu->id));
}
-static int ivtv_s_ctrl(struct ivtv *itv, struct v4l2_control *vctrl)
+static int ivtv_try_ctrl(struct file *file, void *fh,
+ struct v4l2_ext_control *vctrl)
{
- s32 v = vctrl->value;
-
- IVTV_DEBUG_IOCTL("VIDIOC_S_CTRL(%08x, %x)\n", vctrl->id, v);
+ struct v4l2_queryctrl qctrl;
+ const char **menu_items = NULL;
+ int err;
+
+ qctrl.id = vctrl->id;
+ err = ivtv_queryctrl(file, fh, &qctrl);
+ if (err)
+ return err;
+ if (qctrl.type == V4L2_CTRL_TYPE_MENU)
+ menu_items = v4l2_ctrl_get_menu(qctrl.id);
+ return v4l2_ctrl_check(vctrl, &qctrl, menu_items);
+}
+static int ivtv_s_ctrl(struct ivtv *itv, struct v4l2_control *vctrl)
+{
switch (vctrl->id) {
/* Standard V4L2 controls */
case V4L2_CID_BRIGHTNESS:
@@ -119,7 +133,7 @@ static int ivtv_s_ctrl(struct ivtv *itv, struct v4l2_control *vctrl)
return ivtv_i2c_hw(itv, itv->card->hw_audio_ctrl, VIDIOC_S_CTRL, vctrl);
default:
- IVTV_DEBUG_IOCTL("invalid control %x\n", vctrl->id);
+ IVTV_DEBUG_IOCTL("invalid control 0x%x\n", vctrl->id);
return -EINVAL;
}
return 0;
@@ -127,8 +141,6 @@ static int ivtv_s_ctrl(struct ivtv *itv, struct v4l2_control *vctrl)
static int ivtv_g_ctrl(struct ivtv *itv, struct v4l2_control *vctrl)
{
- IVTV_DEBUG_IOCTL("VIDIOC_G_CTRL(%08x)\n", vctrl->id);
-
switch (vctrl->id) {
/* Standard V4L2 controls */
case V4L2_CID_BRIGHTNESS:
@@ -145,7 +157,7 @@ static int ivtv_g_ctrl(struct ivtv *itv, struct v4l2_control *vctrl)
case V4L2_CID_AUDIO_LOUDNESS:
return ivtv_i2c_hw(itv, itv->card->hw_audio_ctrl, VIDIOC_G_CTRL, vctrl);
default:
- IVTV_DEBUG_IOCTL("invalid control %x\n", vctrl->id);
+ IVTV_DEBUG_IOCTL("invalid control 0x%x\n", vctrl->id);
return -EINVAL;
}
return 0;
@@ -191,119 +203,106 @@ static int ivtv_setup_vbi_fmt(struct ivtv *itv, enum v4l2_mpeg_stream_vbi_fmt fm
return 0;
}
-int ivtv_control_ioctls(struct ivtv *itv, unsigned int cmd, void *arg)
+int ivtv_g_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
{
+ struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
struct v4l2_control ctrl;
- switch (cmd) {
- case VIDIOC_QUERYMENU:
- IVTV_DEBUG_IOCTL("VIDIOC_QUERYMENU\n");
- return ivtv_querymenu(itv, arg);
-
- case VIDIOC_QUERYCTRL:
- return ivtv_queryctrl(itv, arg);
-
- case VIDIOC_S_CTRL:
- return ivtv_s_ctrl(itv, arg);
-
- case VIDIOC_G_CTRL:
- return ivtv_g_ctrl(itv, arg);
-
- case VIDIOC_S_EXT_CTRLS:
- {
- struct v4l2_ext_controls *c = arg;
-
- if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
- int i;
- int err = 0;
-
- for (i = 0; i < c->count; i++) {
- ctrl.id = c->controls[i].id;
- ctrl.value = c->controls[i].value;
- err = ivtv_s_ctrl(itv, &ctrl);
- c->controls[i].value = ctrl.value;
- if (err) {
- c->error_idx = i;
- break;
- }
+ if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
+ int i;
+ int err = 0;
+
+ for (i = 0; i < c->count; i++) {
+ ctrl.id = c->controls[i].id;
+ ctrl.value = c->controls[i].value;
+ err = ivtv_g_ctrl(itv, &ctrl);
+ c->controls[i].value = ctrl.value;
+ if (err) {
+ c->error_idx = i;
+ break;
}
- return err;
}
- IVTV_DEBUG_IOCTL("VIDIOC_S_EXT_CTRLS\n");
- if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
- static u32 freqs[3] = { 44100, 48000, 32000 };
- struct cx2341x_mpeg_params p = itv->params;
- int err = cx2341x_ext_ctrls(&p, atomic_read(&itv->capturing), arg, cmd);
- unsigned idx;
-
- if (err)
- return err;
-
- if (p.video_encoding != itv->params.video_encoding) {
- int is_mpeg1 = p.video_encoding ==
- V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
- struct v4l2_format fmt;
-
- /* fix videodecoder resolution */
- fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- fmt.fmt.pix.width = itv->params.width / (is_mpeg1 ? 2 : 1);
- fmt.fmt.pix.height = itv->params.height;
- itv->video_dec_func(itv, VIDIOC_S_FMT, &fmt);
- }
- err = cx2341x_update(itv, ivtv_api_func, &itv->params, &p);
- if (!err && itv->params.stream_vbi_fmt != p.stream_vbi_fmt) {
- err = ivtv_setup_vbi_fmt(itv, p.stream_vbi_fmt);
+ return err;
+ }
+ if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG)
+ return cx2341x_ext_ctrls(&itv->params, 0, c, VIDIOC_G_EXT_CTRLS);
+ return -EINVAL;
+}
+
+int ivtv_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
+{
+ struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+ struct v4l2_control ctrl;
+
+ if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
+ int i;
+ int err = 0;
+
+ for (i = 0; i < c->count; i++) {
+ ctrl.id = c->controls[i].id;
+ ctrl.value = c->controls[i].value;
+ err = ivtv_s_ctrl(itv, &ctrl);
+ c->controls[i].value = ctrl.value;
+ if (err) {
+ c->error_idx = i;
+ break;
}
- itv->params = p;
- itv->dualwatch_stereo_mode = p.audio_properties & 0x0300;
- idx = p.audio_properties & 0x03;
- /* The audio clock of the digitizer must match the codec sample
- rate otherwise you get some very strange effects. */
- if (idx < sizeof(freqs))
- ivtv_call_i2c_clients(itv, VIDIOC_INT_AUDIO_CLOCK_FREQ, &freqs[idx]);
- return err;
}
- return -EINVAL;
+ return err;
}
+ if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
+ static u32 freqs[3] = { 44100, 48000, 32000 };
+ struct cx2341x_mpeg_params p = itv->params;
+ int err = cx2341x_ext_ctrls(&p, atomic_read(&itv->capturing), c, VIDIOC_S_EXT_CTRLS);
+ unsigned idx;
- case VIDIOC_G_EXT_CTRLS:
- {
- struct v4l2_ext_controls *c = arg;
-
- if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
- int i;
- int err = 0;
-
- for (i = 0; i < c->count; i++) {
- ctrl.id = c->controls[i].id;
- ctrl.value = c->controls[i].value;
- err = ivtv_g_ctrl(itv, &ctrl);
- c->controls[i].value = ctrl.value;
- if (err) {
- c->error_idx = i;
- break;
- }
- }
+ if (err)
return err;
+
+ if (p.video_encoding != itv->params.video_encoding) {
+ int is_mpeg1 = p.video_encoding ==
+ V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
+ struct v4l2_format fmt;
+
+ /* fix videodecoder resolution */
+ fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ fmt.fmt.pix.width = itv->params.width / (is_mpeg1 ? 2 : 1);
+ fmt.fmt.pix.height = itv->params.height;
+ itv->video_dec_func(itv, VIDIOC_S_FMT, &fmt);
}
- IVTV_DEBUG_IOCTL("VIDIOC_G_EXT_CTRLS\n");
- if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG)
- return cx2341x_ext_ctrls(&itv->params, 0, arg, cmd);
- return -EINVAL;
+ err = cx2341x_update(itv, ivtv_api_func, &itv->params, &p);
+ if (!err && itv->params.stream_vbi_fmt != p.stream_vbi_fmt)
+ err = ivtv_setup_vbi_fmt(itv, p.stream_vbi_fmt);
+ itv->params = p;
+ itv->dualwatch_stereo_mode = p.audio_properties & 0x0300;
+ idx = p.audio_properties & 0x03;
+ /* The audio clock of the digitizer must match the codec sample
+ rate otherwise you get some very strange effects. */
+ if (idx < sizeof(freqs))
+ ivtv_call_i2c_clients(itv, VIDIOC_INT_AUDIO_CLOCK_FREQ, &freqs[idx]);
+ return err;
}
+ return -EINVAL;
+}
- case VIDIOC_TRY_EXT_CTRLS:
- {
- struct v4l2_ext_controls *c = arg;
+int ivtv_try_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
+{
+ struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
- IVTV_DEBUG_IOCTL("VIDIOC_TRY_EXT_CTRLS\n");
- if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG)
- return cx2341x_ext_ctrls(&itv->params, atomic_read(&itv->capturing), arg, cmd);
- return -EINVAL;
- }
+ if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
+ int i;
+ int err = 0;
- default:
- return -EINVAL;
+ for (i = 0; i < c->count; i++) {
+ err = ivtv_try_ctrl(file, fh, &c->controls[i]);
+ if (err) {
+ c->error_idx = i;
+ break;
+ }
+ }
+ return err;
}
- return 0;
+ if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG)
+ return cx2341x_ext_ctrls(&itv->params, atomic_read(&itv->capturing), c, VIDIOC_TRY_EXT_CTRLS);
+ return -EINVAL;
}
diff --git a/linux/drivers/media/video/ivtv/ivtv-controls.h b/linux/drivers/media/video/ivtv/ivtv-controls.h
index bb8a6a5ed..1c7721e23 100644
--- a/linux/drivers/media/video/ivtv/ivtv-controls.h
+++ b/linux/drivers/media/video/ivtv/ivtv-controls.h
@@ -21,6 +21,10 @@
#ifndef IVTV_CONTROLS_H
#define IVTV_CONTROLS_H
-int ivtv_control_ioctls(struct ivtv *itv, unsigned int cmd, void *arg);
+int ivtv_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *a);
+int ivtv_g_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *a);
+int ivtv_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *a);
+int ivtv_try_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *a);
+int ivtv_querymenu(struct file *file, void *fh, struct v4l2_querymenu *a);
#endif
diff --git a/linux/drivers/media/video/ivtv/ivtv-driver.c b/linux/drivers/media/video/ivtv/ivtv-driver.c
index 094f5524f..c0b98a83b 100644
--- a/linux/drivers/media/video/ivtv/ivtv-driver.c
+++ b/linux/drivers/media/video/ivtv/ivtv-driver.c
@@ -1132,6 +1132,12 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
/* if no tuner was found, then pick the first tuner in the card list */
if (itv->options.tuner == -1 && itv->card->tuners[0].std) {
itv->std = itv->card->tuners[0].std;
+ if (itv->std & V4L2_STD_PAL)
+ itv->std = V4L2_STD_PAL_BG | V4L2_STD_PAL_H;
+ else if (itv->std & V4L2_STD_NTSC)
+ itv->std = V4L2_STD_NTSC_M;
+ else if (itv->std & V4L2_STD_SECAM)
+ itv->std = V4L2_STD_SECAM_L;
itv->options.tuner = itv->card->tuners[0].tuner;
}
if (itv->options.radio == -1)
@@ -1266,9 +1272,13 @@ err:
int ivtv_init_on_first_open(struct ivtv *itv)
{
struct v4l2_frequency vf;
+ /* Needed to call ioctls later */
+ struct ivtv_open_id fh;
int fw_retry_count = 3;
int video_input;
+ fh.itv = itv;
+
if (test_bit(IVTV_F_I_FAILED, &itv->i_flags))
return -ENXIO;
@@ -1316,18 +1326,18 @@ int ivtv_init_on_first_open(struct ivtv *itv)
video_input = itv->active_input;
itv->active_input++; /* Force update of input */
- ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_INPUT, &video_input);
+ ivtv_s_input(NULL, &fh, video_input);
/* Let the VIDIOC_S_STD ioctl do all the work, keeps the code
in one place. */
itv->std++; /* Force full standard initialization */
itv->std_out = itv->std;
- ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_FREQUENCY, &vf);
+ ivtv_s_frequency(NULL, &fh, &vf);
if (itv->card->v4l2_capabilities & V4L2_CAP_VIDEO_OUTPUT) {
ivtv_init_mpeg_decoder(itv);
}
- ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_STD, &itv->tuner_std);
+ ivtv_s_std(NULL, &fh, &itv->tuner_std);
/* On a cx23416 this seems to be able to enable DMA to the chip? */
if (!itv->has_cx23415)
diff --git a/linux/drivers/media/video/ivtv/ivtv-driver.h b/linux/drivers/media/video/ivtv/ivtv-driver.h
index ba8763f62..5134d8a09 100644
--- a/linux/drivers/media/video/ivtv/ivtv-driver.h
+++ b/linux/drivers/media/video/ivtv/ivtv-driver.h
@@ -262,6 +262,12 @@ struct ivtv_mailbox_data {
/* Scatter-Gather array element, used in DMA transfers */
struct ivtv_sg_element {
+ __le32 src;
+ __le32 dst;
+ __le32 size;
+};
+
+struct ivtv_sg_host_element {
u32 src;
u32 dst;
u32 size;
@@ -356,8 +362,8 @@ struct ivtv_stream {
u16 dma_xfer_cnt;
/* Base Dev SG Array for cx23415/6 */
- struct ivtv_sg_element *sg_pending;
- struct ivtv_sg_element *sg_processing;
+ struct ivtv_sg_host_element *sg_pending;
+ struct ivtv_sg_host_element *sg_processing;
struct ivtv_sg_element *sg_dma;
dma_addr_t sg_handle;
int sg_pending_size;
diff --git a/linux/drivers/media/video/ivtv/ivtv-fileops.c b/linux/drivers/media/video/ivtv/ivtv-fileops.c
index f2fa434b6..7ec5c99f9 100644
--- a/linux/drivers/media/video/ivtv/ivtv-fileops.c
+++ b/linux/drivers/media/video/ivtv/ivtv-fileops.c
@@ -582,12 +582,25 @@ ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t c
ivtv_queue_init(&q);
set_bit(IVTV_F_S_APPL_IO, &s->s_flags);
+ /* Start decoder (returns 0 if already started) */
+ mutex_lock(&itv->serialize_lock);
+ rc = ivtv_start_decoding(id, itv->speed);
+ mutex_unlock(&itv->serialize_lock);
+ if (rc) {
+ IVTV_DEBUG_WARN("Failed start decode stream %s\n", s->name);
+
+ /* failure, clean up */
+ clear_bit(IVTV_F_S_STREAMING, &s->s_flags);
+ clear_bit(IVTV_F_S_APPL_IO, &s->s_flags);
+ return rc;
+ }
+
retry:
/* If possible, just DMA the entire frame - Check the data transfer size
since we may get here before the stream has been fully set-up */
if (mode == OUT_YUV && s->q_full.length == 0 && itv->dma_data_req_size) {
while (count >= itv->dma_data_req_size) {
- if (!ivtv_yuv_udma_stream_frame (itv, (void *)user_buf)) {
+ if (!ivtv_yuv_udma_stream_frame (itv, (void __user *)user_buf)) {
bytes_written += itv->dma_data_req_size;
user_buf += itv->dma_data_req_size;
count -= itv->dma_data_req_size;
@@ -664,18 +677,6 @@ retry:
ivtv_enqueue(s, buf, &s->q_full);
}
- /* Start decoder (returns 0 if already started) */
- mutex_lock(&itv->serialize_lock);
- rc = ivtv_start_decoding(id, itv->speed);
- mutex_unlock(&itv->serialize_lock);
- if (rc) {
- IVTV_DEBUG_WARN("Failed start decode stream %s\n", s->name);
-
- /* failure, clean up */
- clear_bit(IVTV_F_S_STREAMING, &s->s_flags);
- clear_bit(IVTV_F_S_APPL_IO, &s->s_flags);
- return rc;
- }
if (test_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags)) {
if (s->q_full.length >= itv->dma_data_req_size) {
int got_sig;
diff --git a/linux/drivers/media/video/ivtv/ivtv-i2c.c b/linux/drivers/media/video/ivtv/ivtv-i2c.c
index db9243b08..3446ab458 100644
--- a/linux/drivers/media/video/ivtv/ivtv-i2c.c
+++ b/linux/drivers/media/video/ivtv/ivtv-i2c.c
@@ -75,10 +75,6 @@
#define IVTV_REG_I2C_GETSCL_OFFSET 0x7008
#define IVTV_REG_I2C_GETSDA_OFFSET 0x700c
-#ifndef I2C_ADAP_CLASS_TV_ANALOG
-#define I2C_ADAP_CLASS_TV_ANALOG I2C_CLASS_TV_ANALOG
-#endif /* I2C_ADAP_CLASS_TV_ANALOG */
-
#define IVTV_CS53L32A_I2C_ADDR 0x11
#define IVTV_M52790_I2C_ADDR 0x48
#define IVTV_CX25840_I2C_ADDR 0x44
@@ -136,7 +132,7 @@ static const u8 hw_addrs[] = {
};
/* This array should match the IVTV_HW_ defines */
-static const char * const hw_drivernames[] = {
+static const char * const hw_devicenames[] = {
"cx25840",
"saa7115",
"saa7127",
@@ -145,7 +141,7 @@ static const char * const hw_drivernames[] = {
"wm8775",
"cs53l32a",
"tveeprom",
- "saa7115",
+ "saa7114",
"upd64031a",
"upd64083",
"saa717x",
@@ -168,8 +164,12 @@ int ivtv_i2c_register(struct ivtv *itv, unsigned idx)
return -1;
id = hw_driverids[idx];
memset(&info, 0, sizeof(info));
- strlcpy(info.driver_name, hw_drivernames[idx],
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
+ strlcpy(info.driver_name, hw_devicenames[idx],
sizeof(info.driver_name));
+#else
+ strlcpy(info.type, hw_devicenames[idx], sizeof(info.type));
+#endif
info.addr = hw_addrs[idx];
for (i = 0; itv->i2c_clients[i] && i < I2C_CLIENTS_MAX; i++) {}
@@ -560,9 +560,7 @@ static struct i2c_adapter ivtv_i2c_adap_hw_template = {
.client_unregister = detach_inform,
.owner = THIS_MODULE,
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
-#ifdef I2C_ADAP_CLASS_TV_ANALOG
- .class = I2C_ADAP_CLASS_TV_ANALOG,
-#endif
+ .class = I2C_CLASS_TV_ANALOG,
#endif
};
@@ -618,9 +616,7 @@ static struct i2c_adapter ivtv_i2c_adap_template = {
.client_unregister = detach_inform,
.owner = THIS_MODULE,
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
-#ifdef I2C_ADAP_CLASS_TV_ANALOG
- .class = I2C_ADAP_CLASS_TV_ANALOG,
-#endif
+ .class = I2C_CLASS_TV_ANALOG,
#endif
};
@@ -686,7 +682,7 @@ static const char *ivtv_i2c_id_name(u32 id)
for (i = 0; i < ARRAY_SIZE(hw_driverids); i++)
if (hw_driverids[i] == id)
- return hw_drivernames[i];
+ return hw_devicenames[i];
return "unknown device";
}
@@ -697,7 +693,7 @@ static const char *ivtv_i2c_hw_name(u32 hw)
for (i = 0; i < ARRAY_SIZE(hw_driverids); i++)
if (1 << i == hw)
- return hw_drivernames[i];
+ return hw_devicenames[i];
return "unknown device";
}
@@ -799,7 +795,7 @@ int init_ivtv_i2c(struct ivtv *itv)
* same size and GPIO must be the last entry.
*/
if (ARRAY_SIZE(hw_driverids) != ARRAY_SIZE(hw_addrs) ||
- ARRAY_SIZE(hw_drivernames) != ARRAY_SIZE(hw_addrs) ||
+ ARRAY_SIZE(hw_devicenames) != ARRAY_SIZE(hw_addrs) ||
IVTV_HW_GPIO != (1 << (ARRAY_SIZE(hw_addrs) - 1)) ||
hw_driverids[ARRAY_SIZE(hw_addrs) - 1]) {
IVTV_ERR("Mismatched I2C hardware arrays\n");
diff --git a/linux/drivers/media/video/ivtv/ivtv-ioctl.c b/linux/drivers/media/video/ivtv/ivtv-ioctl.c
index 7101a0ea5..52e00a7f3 100644
--- a/linux/drivers/media/video/ivtv/ivtv-ioctl.c
+++ b/linux/drivers/media/video/ivtv/ivtv-ioctl.c
@@ -128,37 +128,6 @@ u16 ivtv_get_service_set(struct v4l2_sliced_vbi_format *fmt)
return set;
}
-static const struct {
- v4l2_std_id std;
- char *name;
-} enum_stds[] = {
- { V4L2_STD_PAL_BG | V4L2_STD_PAL_H, "PAL-BGH" },
- { V4L2_STD_PAL_DK, "PAL-DK" },
- { V4L2_STD_PAL_I, "PAL-I" },
- { V4L2_STD_PAL_M, "PAL-M" },
- { V4L2_STD_PAL_N, "PAL-N" },
- { V4L2_STD_PAL_Nc, "PAL-Nc" },
- { V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H, "SECAM-BGH" },
- { V4L2_STD_SECAM_DK, "SECAM-DK" },
- { V4L2_STD_SECAM_L, "SECAM-L" },
- { V4L2_STD_SECAM_LC, "SECAM-L'" },
- { V4L2_STD_NTSC_M, "NTSC-M" },
- { V4L2_STD_NTSC_M_JP, "NTSC-J" },
- { V4L2_STD_NTSC_M_KR, "NTSC-K" },
-};
-
-static const struct v4l2_standard ivtv_std_60hz =
-{
- .frameperiod = {.numerator = 1001, .denominator = 30000},
- .framelines = 525,
-};
-
-static const struct v4l2_standard ivtv_std_50hz =
-{
- .frameperiod = {.numerator = 1, .denominator = 25},
- .framelines = 625,
-};
-
void ivtv_set_osd_alpha(struct ivtv *itv)
{
ivtv_vapi(itv, CX2341X_OSD_SET_GLOBAL_ALPHA, 3,
@@ -345,1085 +314,1219 @@ static int ivtv_video_command(struct ivtv *itv, struct ivtv_open_id *id,
return 0;
}
-static int ivtv_itvc(struct ivtv *itv, unsigned int cmd, void *arg)
+static int ivtv_g_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt)
{
- struct v4l2_register *regs = arg;
- unsigned long flags;
- volatile u8 __iomem *reg_start;
+ struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+ struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- if (regs->reg >= IVTV_REG_OFFSET && regs->reg < IVTV_REG_OFFSET + IVTV_REG_SIZE)
- reg_start = itv->reg_mem - IVTV_REG_OFFSET;
- else if (itv->has_cx23415 && regs->reg >= IVTV_DECODER_OFFSET &&
- regs->reg < IVTV_DECODER_OFFSET + IVTV_DECODER_SIZE)
- reg_start = itv->dec_mem - IVTV_DECODER_OFFSET;
- else if (regs->reg >= 0 && regs->reg < IVTV_ENCODER_SIZE)
- reg_start = itv->enc_mem;
- else
+ vbifmt->reserved[0] = 0;
+ vbifmt->reserved[1] = 0;
+ if (!(itv->v4l2_cap & V4L2_CAP_SLICED_VBI_OUTPUT))
return -EINVAL;
-
- spin_lock_irqsave(&ivtv_cards_lock, flags);
- if (cmd == VIDIOC_DBG_G_REGISTER) {
- regs->val = readl(regs->reg + reg_start);
+ vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
+ if (itv->is_60hz) {
+ vbifmt->service_lines[0][21] = V4L2_SLICED_CAPTION_525;
+ vbifmt->service_lines[1][21] = V4L2_SLICED_CAPTION_525;
} else {
- writel(regs->val, regs->reg + reg_start);
+ vbifmt->service_lines[0][23] = V4L2_SLICED_WSS_625;
+ vbifmt->service_lines[0][16] = V4L2_SLICED_VPS;
}
- spin_unlock_irqrestore(&ivtv_cards_lock, flags);
+ vbifmt->service_set = ivtv_get_service_set(vbifmt);
return 0;
}
-static int ivtv_get_fmt(struct ivtv *itv, int streamtype, struct v4l2_format *fmt)
+static int ivtv_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
{
- switch (fmt->type) {
- case V4L2_BUF_TYPE_VIDEO_OUTPUT:
- if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
- return -EINVAL;
- fmt->fmt.pix.width = itv->main_rect.width;
- fmt->fmt.pix.height = itv->main_rect.height;
- fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
- fmt->fmt.pix.field = V4L2_FIELD_INTERLACED;
- if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
- switch (itv->yuv_info.lace_mode & IVTV_YUV_MODE_MASK) {
- case IVTV_YUV_MODE_INTERLACED:
- fmt->fmt.pix.field = (itv->yuv_info.lace_mode & IVTV_YUV_SYNC_MASK) ?
- V4L2_FIELD_INTERLACED_BT : V4L2_FIELD_INTERLACED_TB;
- break;
- case IVTV_YUV_MODE_PROGRESSIVE:
- fmt->fmt.pix.field = V4L2_FIELD_NONE;
- break;
- default:
- fmt->fmt.pix.field = V4L2_FIELD_ANY;
- break;
- }
- fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12;
- fmt->fmt.pix.bytesperline = 720;
- fmt->fmt.pix.width = itv->yuv_info.v4l2_src_w;
- fmt->fmt.pix.height = itv->yuv_info.v4l2_src_h;
- /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */
- fmt->fmt.pix.sizeimage =
- 1080 * ((fmt->fmt.pix.height + 31) & ~31);
- } else if (streamtype == IVTV_ENC_STREAM_TYPE_YUV) {
- fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12;
- /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */
- fmt->fmt.pix.sizeimage =
- fmt->fmt.pix.height * fmt->fmt.pix.width +
- fmt->fmt.pix.height * (fmt->fmt.pix.width / 2);
- } else {
- fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
- fmt->fmt.pix.sizeimage = 128 * 1024;
- }
- break;
-
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- fmt->fmt.pix.width = itv->params.width;
- fmt->fmt.pix.height = itv->params.height;
- fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
- fmt->fmt.pix.field = V4L2_FIELD_INTERLACED;
- if (streamtype == IVTV_ENC_STREAM_TYPE_YUV ||
- streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
- fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12;
- /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */
- fmt->fmt.pix.sizeimage =
- fmt->fmt.pix.height * fmt->fmt.pix.width +
- fmt->fmt.pix.height * (fmt->fmt.pix.width / 2);
- } else {
- fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
- fmt->fmt.pix.sizeimage = 128 * 1024;
- }
- break;
+ struct ivtv_open_id *id = fh;
+ struct ivtv *itv = id->itv;
+ struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
+
+ pixfmt->width = itv->params.width;
+ pixfmt->height = itv->params.height;
+ pixfmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
+ pixfmt->field = V4L2_FIELD_INTERLACED;
+ pixfmt->priv = 0;
+ if (id->type == IVTV_ENC_STREAM_TYPE_YUV) {
+ pixfmt->pixelformat = V4L2_PIX_FMT_HM12;
+ /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */
+ pixfmt->sizeimage =
+ pixfmt->height * pixfmt->width +
+ pixfmt->height * (pixfmt->width / 2);
+ pixfmt->bytesperline = 720;
+ } else {
+ pixfmt->pixelformat = V4L2_PIX_FMT_MPEG;
+ pixfmt->sizeimage = 128 * 1024;
+ pixfmt->bytesperline = 0;
+ }
+ return 0;
+}
- case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
- if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
- return -EINVAL;
- fmt->fmt.win.chromakey = itv->osd_chroma_key;
- fmt->fmt.win.global_alpha = itv->osd_global_alpha;
- break;
+static int ivtv_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+ struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+ struct v4l2_vbi_format *vbifmt = &fmt->fmt.vbi;
+
+ vbifmt->sampling_rate = 27000000;
+ vbifmt->offset = 248;
+ vbifmt->samples_per_line = itv->vbi.raw_decoder_line_size - 4;
+ vbifmt->sample_format = V4L2_PIX_FMT_GREY;
+ vbifmt->start[0] = itv->vbi.start[0];
+ vbifmt->start[1] = itv->vbi.start[1];
+ vbifmt->count[0] = vbifmt->count[1] = itv->vbi.count;
+ vbifmt->flags = 0;
+ vbifmt->reserved[0] = 0;
+ vbifmt->reserved[1] = 0;
+ return 0;
+}
- case V4L2_BUF_TYPE_VBI_CAPTURE:
- fmt->fmt.vbi.sampling_rate = 27000000;
- fmt->fmt.vbi.offset = 248;
- fmt->fmt.vbi.samples_per_line = itv->vbi.raw_decoder_line_size - 4;
- fmt->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
- fmt->fmt.vbi.start[0] = itv->vbi.start[0];
- fmt->fmt.vbi.start[1] = itv->vbi.start[1];
- fmt->fmt.vbi.count[0] = fmt->fmt.vbi.count[1] = itv->vbi.count;
- break;
+static int ivtv_g_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+ struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
+ struct ivtv_open_id *id = fh;
+ struct ivtv *itv = id->itv;
- case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
- {
- struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
+ vbifmt->reserved[0] = 0;
+ vbifmt->reserved[1] = 0;
+ vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
- if (!(itv->v4l2_cap & V4L2_CAP_SLICED_VBI_OUTPUT))
- return -EINVAL;
- vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
- memset(vbifmt->reserved, 0, sizeof(vbifmt->reserved));
- memset(vbifmt->service_lines, 0, sizeof(vbifmt->service_lines));
- if (itv->is_60hz) {
- vbifmt->service_lines[0][21] = V4L2_SLICED_CAPTION_525;
- vbifmt->service_lines[1][21] = V4L2_SLICED_CAPTION_525;
- } else {
- vbifmt->service_lines[0][23] = V4L2_SLICED_WSS_625;
- vbifmt->service_lines[0][16] = V4L2_SLICED_VPS;
- }
- vbifmt->service_set = ivtv_get_service_set(vbifmt);
- break;
+ if (id->type == IVTV_DEC_STREAM_TYPE_VBI) {
+ vbifmt->service_set = itv->is_50hz ? V4L2_SLICED_VBI_625 :
+ V4L2_SLICED_VBI_525;
+ ivtv_expand_service_set(vbifmt, itv->is_50hz);
+ return 0;
}
- case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
- {
- struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
+ itv->video_dec_func(itv, VIDIOC_G_FMT, fmt);
+ vbifmt->service_set = ivtv_get_service_set(vbifmt);
+ return 0;
+}
- vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
- memset(vbifmt->reserved, 0, sizeof(vbifmt->reserved));
- memset(vbifmt->service_lines, 0, sizeof(vbifmt->service_lines));
+static int ivtv_g_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+ struct ivtv_open_id *id = fh;
+ struct ivtv *itv = id->itv;
+ struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
- if (streamtype == IVTV_DEC_STREAM_TYPE_VBI) {
- vbifmt->service_set = itv->is_50hz ? V4L2_SLICED_VBI_625 :
- V4L2_SLICED_VBI_525;
- ivtv_expand_service_set(vbifmt, itv->is_50hz);
+ if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+ return -EINVAL;
+ pixfmt->width = itv->main_rect.width;
+ pixfmt->height = itv->main_rect.height;
+ pixfmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
+ pixfmt->field = V4L2_FIELD_INTERLACED;
+ pixfmt->priv = 0;
+ if (id->type == IVTV_DEC_STREAM_TYPE_YUV) {
+ switch (itv->yuv_info.lace_mode & IVTV_YUV_MODE_MASK) {
+ case IVTV_YUV_MODE_INTERLACED:
+ pixfmt->field = (itv->yuv_info.lace_mode & IVTV_YUV_SYNC_MASK) ?
+ V4L2_FIELD_INTERLACED_BT : V4L2_FIELD_INTERLACED_TB;
+ break;
+ case IVTV_YUV_MODE_PROGRESSIVE:
+ pixfmt->field = V4L2_FIELD_NONE;
+ break;
+ default:
+ pixfmt->field = V4L2_FIELD_ANY;
break;
}
-
- itv->video_dec_func(itv, VIDIOC_G_FMT, fmt);
- vbifmt->service_set = ivtv_get_service_set(vbifmt);
- break;
+ pixfmt->pixelformat = V4L2_PIX_FMT_HM12;
+ pixfmt->bytesperline = 720;
+ pixfmt->width = itv->yuv_info.v4l2_src_w;
+ pixfmt->height = itv->yuv_info.v4l2_src_h;
+ /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */
+ pixfmt->sizeimage =
+ 1080 * ((pixfmt->height + 31) & ~31);
+ } else {
+ pixfmt->pixelformat = V4L2_PIX_FMT_MPEG;
+ pixfmt->sizeimage = 128 * 1024;
+ pixfmt->bytesperline = 0;
}
- case V4L2_BUF_TYPE_VBI_OUTPUT:
- case V4L2_BUF_TYPE_VIDEO_OVERLAY:
- default:
+ return 0;
+}
+
+static int ivtv_g_fmt_vid_out_overlay(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+ struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+ struct v4l2_window *winfmt = &fmt->fmt.win;
+
+ if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
return -EINVAL;
- }
+ winfmt->chromakey = itv->osd_chroma_key;
+ winfmt->global_alpha = itv->osd_global_alpha;
+ winfmt->field = V4L2_FIELD_INTERLACED;
+ winfmt->clips = NULL;
+ winfmt->clipcount = 0;
+ winfmt->bitmap = NULL;
+ winfmt->w.top = winfmt->w.left = 0;
+ winfmt->w.width = itv->osd_rect.width;
+ winfmt->w.height = itv->osd_rect.height;
return 0;
}
-static int ivtv_try_or_set_fmt(struct ivtv *itv, int streamtype,
- struct v4l2_format *fmt, int set_fmt)
+static int ivtv_try_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+ return ivtv_g_fmt_sliced_vbi_out(file, fh, fmt);
+}
+
+static int ivtv_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+ struct ivtv_open_id *id = fh;
+ struct ivtv *itv = id->itv;
+ int w = fmt->fmt.pix.width;
+ int h = fmt->fmt.pix.height;
+
+ w = min(w, 720);
+ w = max(w, 1);
+ h = min(h, itv->is_50hz ? 576 : 480);
+ h = max(h, 2);
+ ivtv_g_fmt_vid_cap(file, fh, fmt);
+ fmt->fmt.pix.width = w;
+ fmt->fmt.pix.height = h;
+ return 0;
+}
+
+static int ivtv_try_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+ return ivtv_g_fmt_vbi_cap(file, fh, fmt);
+}
+
+static int ivtv_try_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt)
{
- struct yuv_playback_info *yi = &itv->yuv_info;
struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
- u16 set;
+ struct ivtv_open_id *id = fh;
+ struct ivtv *itv = id->itv;
- if (fmt->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
- struct v4l2_rect r;
- int field;
+ if (id->type == IVTV_DEC_STREAM_TYPE_VBI)
+ return ivtv_g_fmt_sliced_vbi_cap(file, fh, fmt);
- if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
- return -EINVAL;
- field = fmt->fmt.pix.field;
- r.top = 0;
- r.left = 0;
- r.width = fmt->fmt.pix.width;
- r.height = fmt->fmt.pix.height;
- ivtv_get_fmt(itv, streamtype, fmt);
- fmt->fmt.pix.width = r.width;
- fmt->fmt.pix.height = r.height;
- if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
- fmt->fmt.pix.field = field;
- if (fmt->fmt.pix.width < 2)
- fmt->fmt.pix.width = 2;
- if (fmt->fmt.pix.width > 720)
- fmt->fmt.pix.width = 720;
- if (fmt->fmt.pix.height < 2)
- fmt->fmt.pix.height = 2;
- if (fmt->fmt.pix.height > 576)
- fmt->fmt.pix.height = 576;
- }
- if (set_fmt && streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
- /* Return now if we already have some frame data */
- if (yi->stream_size)
- return -EBUSY;
+ /* set sliced VBI capture format */
+ vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
+ vbifmt->reserved[0] = 0;
+ vbifmt->reserved[1] = 0;
- yi->v4l2_src_w = r.width;
- yi->v4l2_src_h = r.height;
+ if (vbifmt->service_set)
+ ivtv_expand_service_set(vbifmt, itv->is_50hz);
+ check_service_set(vbifmt, itv->is_50hz);
+ vbifmt->service_set = ivtv_get_service_set(vbifmt);
+ return 0;
+}
- switch (field) {
- case V4L2_FIELD_NONE:
- yi->lace_mode = IVTV_YUV_MODE_PROGRESSIVE;
- break;
- case V4L2_FIELD_ANY:
- yi->lace_mode = IVTV_YUV_MODE_AUTO;
- break;
- case V4L2_FIELD_INTERLACED_BT:
- yi->lace_mode =
- IVTV_YUV_MODE_INTERLACED|IVTV_YUV_SYNC_ODD;
- break;
- case V4L2_FIELD_INTERLACED_TB:
- default:
- yi->lace_mode = IVTV_YUV_MODE_INTERLACED;
- break;
- }
- yi->lace_sync_field = (yi->lace_mode & IVTV_YUV_SYNC_MASK) == IVTV_YUV_SYNC_EVEN ? 0 : 1;
+static int ivtv_try_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+ struct ivtv_open_id *id = fh;
+ s32 w, h;
+ int field;
+ int ret;
- if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags))
- itv->dma_data_req_size =
- 1080 * ((yi->v4l2_src_h + 31) & ~31);
+ w = fmt->fmt.pix.width;
+ h = fmt->fmt.pix.height;
+ field = fmt->fmt.pix.field;
+ ret = ivtv_g_fmt_vid_out(file, fh, fmt);
+ fmt->fmt.pix.width = w;
+ fmt->fmt.pix.height = h;
+ if (!ret && id->type == IVTV_DEC_STREAM_TYPE_YUV) {
+ fmt->fmt.pix.field = field;
+ if (fmt->fmt.pix.width < 2)
+ fmt->fmt.pix.width = 2;
+ if (fmt->fmt.pix.width > 720)
+ fmt->fmt.pix.width = 720;
+ if (fmt->fmt.pix.height < 2)
+ fmt->fmt.pix.height = 2;
+ if (fmt->fmt.pix.height > 576)
+ fmt->fmt.pix.height = 576;
+ }
+ return ret;
+}
- /* Force update of yuv registers */
- yi->yuv_forced_update = 1;
- return 0;
- }
- return 0;
- }
+static int ivtv_try_fmt_vid_out_overlay(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+ struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+ u32 chromakey = fmt->fmt.win.chromakey;
+ u8 global_alpha = fmt->fmt.win.global_alpha;
- if (fmt->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY) {
- if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
- return -EINVAL;
- if (set_fmt) {
- itv->osd_chroma_key = fmt->fmt.win.chromakey;
- itv->osd_global_alpha = fmt->fmt.win.global_alpha;
- ivtv_set_osd_alpha(itv);
- }
- return 0;
- }
+ if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+ return -EINVAL;
+ ivtv_g_fmt_vid_out_overlay(file, fh, fmt);
+ fmt->fmt.win.chromakey = chromakey;
+ fmt->fmt.win.global_alpha = global_alpha;
+ return 0;
+}
- /* set window size */
- if (fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- struct cx2341x_mpeg_params *p = &itv->params;
- int w = fmt->fmt.pix.width;
- int h = fmt->fmt.pix.height;
-
- if (w > 720) w = 720;
- else if (w < 1) w = 1;
- if (h > (itv->is_50hz ? 576 : 480)) h = (itv->is_50hz ? 576 : 480);
- else if (h < 2) h = 2;
- ivtv_get_fmt(itv, streamtype, fmt);
- fmt->fmt.pix.width = w;
- fmt->fmt.pix.height = h;
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18)
- if (p->width != 720 || p->height != (itv->is_50hz ? 576 : 480))
- p->video_temporal_filter = 0;
- else
- p->video_temporal_filter = 8;
-#endif
+static int ivtv_s_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+ return ivtv_g_fmt_sliced_vbi_out(file, fh, fmt);
+}
- if (!set_fmt || (p->width == w && p->height == h))
- return 0;
- if (atomic_read(&itv->capturing) > 0)
- return -EBUSY;
+static int ivtv_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+ struct ivtv_open_id *id = fh;
+ struct ivtv *itv = id->itv;
+ struct cx2341x_mpeg_params *p = &itv->params;
+ int w = fmt->fmt.pix.width;
+ int h = fmt->fmt.pix.height;
+ int ret = ivtv_try_fmt_vid_cap(file, fh, fmt);
- p->width = w;
- p->height = h;
- if (w != 720 || h != (itv->is_50hz ? 576 : 480))
- p->video_temporal_filter = 0;
- else
- p->video_temporal_filter = 8;
- if (p->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1)
- fmt->fmt.pix.width /= 2;
- itv->video_dec_func(itv, VIDIOC_S_FMT, fmt);
- return ivtv_get_fmt(itv, streamtype, fmt);
- }
+ if (ret)
+ return ret;
- /* set raw VBI format */
- if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
- if (set_fmt && atomic_read(&itv->capturing) > 0) {
- return -EBUSY;
- }
- if (set_fmt) {
- itv->vbi.sliced_in->service_set = 0;
- itv->video_dec_func(itv, VIDIOC_S_FMT, &itv->vbi.in);
- }
- return ivtv_get_fmt(itv, streamtype, fmt);
- }
+ if (p->width == w && p->height == h)
+ return 0;
- /* set sliced VBI output
- In principle the user could request that only certain
- VBI types are output and that the others are ignored.
- I.e., suppress CC in the even fields or only output
- WSS and no VPS. Currently though there is no choice. */
- if (fmt->type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT)
- return ivtv_get_fmt(itv, streamtype, fmt);
+ if (atomic_read(&itv->capturing) > 0)
+ return -EBUSY;
- /* any else but sliced VBI capture is an error */
- if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
- return -EINVAL;
+ p->width = w;
+ p->height = h;
+ if (p->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1)
+ fmt->fmt.pix.width /= 2;
+ itv->video_dec_func(itv, VIDIOC_S_FMT, fmt);
+ return ivtv_g_fmt_vid_cap(file, fh, fmt);
+}
- if (streamtype == IVTV_DEC_STREAM_TYPE_VBI)
- return ivtv_get_fmt(itv, streamtype, fmt);
+static int ivtv_s_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+ struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
- /* set sliced VBI capture format */
- vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
- memset(vbifmt->reserved, 0, sizeof(vbifmt->reserved));
+ itv->vbi.sliced_in->service_set = 0;
+ itv->video_dec_func(itv, VIDIOC_S_FMT, &itv->vbi.in);
+ return ivtv_g_fmt_vbi_cap(file, fh, fmt);
+}
- if (vbifmt->service_set)
- ivtv_expand_service_set(vbifmt, itv->is_50hz);
- set = check_service_set(vbifmt, itv->is_50hz);
- vbifmt->service_set = ivtv_get_service_set(vbifmt);
+static int ivtv_s_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+ struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
+ struct ivtv_open_id *id = fh;
+ struct ivtv *itv = id->itv;
+ int ret = ivtv_try_fmt_sliced_vbi_cap(file, fh, fmt);
- if (!set_fmt)
- return 0;
- if (set == 0)
+ if (ret || id->type == IVTV_DEC_STREAM_TYPE_VBI)
+ return ret;
+
+ if (check_service_set(vbifmt, itv->is_50hz) == 0)
return -EINVAL;
- if (atomic_read(&itv->capturing) > 0) {
+ if (atomic_read(&itv->capturing) > 0)
return -EBUSY;
- }
itv->video_dec_func(itv, VIDIOC_S_FMT, fmt);
memcpy(itv->vbi.sliced_in, vbifmt, sizeof(*itv->vbi.sliced_in));
return 0;
}
-static int ivtv_debug_ioctls(struct file *filp, unsigned int cmd, void *arg)
+static int ivtv_s_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *fmt)
{
- struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data;
+ struct ivtv_open_id *id = fh;
struct ivtv *itv = id->itv;
- struct v4l2_register *reg = arg;
+ struct yuv_playback_info *yi = &itv->yuv_info;
+ int ret = ivtv_try_fmt_vid_out(file, fh, fmt);
- switch (cmd) {
- /* ioctls to allow direct access to the encoder registers for testing */
- case VIDIOC_DBG_G_REGISTER:
- if (v4l2_chip_match_host(reg->match_type, reg->match_chip))
- return ivtv_itvc(itv, cmd, arg);
- if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
- return ivtv_i2c_id(itv, reg->match_chip, cmd, arg);
- return ivtv_call_i2c_client(itv, reg->match_chip, cmd, arg);
-
- case VIDIOC_DBG_S_REGISTER:
- if (v4l2_chip_match_host(reg->match_type, reg->match_chip))
- return ivtv_itvc(itv, cmd, arg);
- if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
- return ivtv_i2c_id(itv, reg->match_chip, cmd, arg);
- return ivtv_call_i2c_client(itv, reg->match_chip, cmd, arg);
-
- case VIDIOC_G_CHIP_IDENT: {
- struct v4l2_chip_ident *chip = arg;
-
- chip->ident = V4L2_IDENT_NONE;
- chip->revision = 0;
- if (reg->match_type == V4L2_CHIP_MATCH_HOST) {
- if (v4l2_chip_match_host(reg->match_type, reg->match_chip))
- chip->ident = itv->has_cx23415 ? V4L2_IDENT_CX23415 : V4L2_IDENT_CX23416;
- return 0;
- }
- if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
- return ivtv_i2c_id(itv, reg->match_chip, cmd, arg);
- if (reg->match_type == V4L2_CHIP_MATCH_I2C_ADDR)
- return ivtv_call_i2c_client(itv, reg->match_chip, cmd, arg);
- return -EINVAL;
- }
+ if (ret)
+ return ret;
- case VIDIOC_INT_S_AUDIO_ROUTING: {
- struct v4l2_routing *route = arg;
+ if (id->type != IVTV_DEC_STREAM_TYPE_YUV)
+ return 0;
- ivtv_i2c_hw(itv, itv->card->hw_audio, VIDIOC_INT_S_AUDIO_ROUTING, route);
- break;
- }
+ /* Return now if we already have some frame data */
+ if (yi->stream_size)
+ return -EBUSY;
- case VIDIOC_INT_RESET: {
- u32 val = *(u32 *)arg;
+ yi->v4l2_src_w = fmt->fmt.pix.width;
+ yi->v4l2_src_h = fmt->fmt.pix.height;
- if ((val == 0 && itv->options.newi2c) || (val & 0x01)) {
- ivtv_reset_ir_gpio(itv);
- }
- if (val & 0x02) {
- itv->video_dec_func(itv, cmd, NULL);
- }
+ switch (fmt->fmt.pix.field) {
+ case V4L2_FIELD_NONE:
+ yi->lace_mode = IVTV_YUV_MODE_PROGRESSIVE;
break;
- }
-
+ case V4L2_FIELD_ANY:
+ yi->lace_mode = IVTV_YUV_MODE_AUTO;
+ break;
+ case V4L2_FIELD_INTERLACED_BT:
+ yi->lace_mode =
+ IVTV_YUV_MODE_INTERLACED|IVTV_YUV_SYNC_ODD;
+ break;
+ case V4L2_FIELD_INTERLACED_TB:
default:
- return -EINVAL;
+ yi->lace_mode = IVTV_YUV_MODE_INTERLACED;
+ break;
}
+ yi->lace_sync_field = (yi->lace_mode & IVTV_YUV_SYNC_MASK) == IVTV_YUV_SYNC_EVEN ? 0 : 1;
+
+ if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags))
+ itv->dma_data_req_size =
+ 1080 * ((yi->v4l2_src_h + 31) & ~31);
+
+ /* Force update of yuv registers */
+ yi->yuv_forced_update = 1;
return 0;
}
-int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void *arg)
+static int ivtv_s_fmt_vid_out_overlay(struct file *file, void *fh, struct v4l2_format *fmt)
{
- struct ivtv_open_id *id = NULL;
- struct yuv_playback_info *yi = &itv->yuv_info;
- u32 data[CX2341X_MBOX_MAX_DATA];
- int streamtype = 0;
+ struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+ int ret = ivtv_try_fmt_vid_out_overlay(file, fh, fmt);
- if (filp) {
- id = (struct ivtv_open_id *)filp->private_data;
- streamtype = id->type;
+ if (ret == 0) {
+ itv->osd_chroma_key = fmt->fmt.win.chromakey;
+ itv->osd_global_alpha = fmt->fmt.win.global_alpha;
+ ivtv_set_osd_alpha(itv);
}
+ return ret;
+}
- switch (cmd) {
- case VIDIOC_G_PRIORITY:
- {
- enum v4l2_priority *p = arg;
+static int ivtv_g_chip_ident(struct file *file, void *fh, struct v4l2_chip_ident *chip)
+{
+ struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
- *p = v4l2_prio_max(&itv->prio);
- break;
+ chip->ident = V4L2_IDENT_NONE;
+ chip->revision = 0;
+ if (chip->match_type == V4L2_CHIP_MATCH_HOST) {
+ if (v4l2_chip_match_host(chip->match_type, chip->match_chip))
+ chip->ident = itv->has_cx23415 ? V4L2_IDENT_CX23415 : V4L2_IDENT_CX23416;
+ return 0;
}
+ if (chip->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
+ return ivtv_i2c_id(itv, chip->match_chip, VIDIOC_G_CHIP_IDENT, chip);
+ if (chip->match_type == V4L2_CHIP_MATCH_I2C_ADDR)
+ return ivtv_call_i2c_client(itv, chip->match_chip, VIDIOC_G_CHIP_IDENT, chip);
+ return -EINVAL;
+}
- case VIDIOC_S_PRIORITY:
- {
- enum v4l2_priority *prio = arg;
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int ivtv_itvc(struct ivtv *itv, unsigned int cmd, void *arg)
+{
+ struct v4l2_register *regs = arg;
+ unsigned long flags;
+ volatile u8 __iomem *reg_start;
- return v4l2_prio_change(&itv->prio, &id->prio, *prio);
- }
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ if (regs->reg >= IVTV_REG_OFFSET && regs->reg < IVTV_REG_OFFSET + IVTV_REG_SIZE)
+ reg_start = itv->reg_mem - IVTV_REG_OFFSET;
+ else if (itv->has_cx23415 && regs->reg >= IVTV_DECODER_OFFSET &&
+ regs->reg < IVTV_DECODER_OFFSET + IVTV_DECODER_SIZE)
+ reg_start = itv->dec_mem - IVTV_DECODER_OFFSET;
+ else if (regs->reg >= 0 && regs->reg < IVTV_ENCODER_SIZE)
+ reg_start = itv->enc_mem;
+ else
+ return -EINVAL;
- case VIDIOC_QUERYCAP:{
- struct v4l2_capability *vcap = arg;
+ spin_lock_irqsave(&ivtv_cards_lock, flags);
+ if (cmd == VIDIOC_DBG_G_REGISTER)
+ regs->val = readl(regs->reg + reg_start);
+ else
+ writel(regs->val, regs->reg + reg_start);
+ spin_unlock_irqrestore(&ivtv_cards_lock, flags);
+ return 0;
+}
- memset(vcap, 0, sizeof(*vcap));
- strlcpy(vcap->driver, IVTV_DRIVER_NAME, sizeof(vcap->driver));
- strlcpy(vcap->card, itv->card_name, sizeof(vcap->card));
- strlcpy(vcap->bus_info, pci_name(itv->dev), sizeof(vcap->bus_info));
- vcap->version = IVTV_DRIVER_VERSION; /* version */
- vcap->capabilities = itv->v4l2_cap; /* capabilities */
+static int ivtv_g_register(struct file *file, void *fh, struct v4l2_register *reg)
+{
+ struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
- /* reserved.. must set to 0! */
- vcap->reserved[0] = vcap->reserved[1] =
- vcap->reserved[2] = vcap->reserved[3] = 0;
- break;
- }
+ if (v4l2_chip_match_host(reg->match_type, reg->match_chip))
+ return ivtv_itvc(itv, VIDIOC_DBG_G_REGISTER, reg);
+ if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
+ return ivtv_i2c_id(itv, reg->match_chip, VIDIOC_DBG_G_REGISTER, reg);
+ return ivtv_call_i2c_client(itv, reg->match_chip, VIDIOC_DBG_G_REGISTER, reg);
+}
- case VIDIOC_ENUMAUDIO:{
- struct v4l2_audio *vin = arg;
+static int ivtv_s_register(struct file *file, void *fh, struct v4l2_register *reg)
+{
+ struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
- return ivtv_get_audio_input(itv, vin->index, vin);
- }
+ if (v4l2_chip_match_host(reg->match_type, reg->match_chip))
+ return ivtv_itvc(itv, VIDIOC_DBG_S_REGISTER, reg);
+ if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
+ return ivtv_i2c_id(itv, reg->match_chip, VIDIOC_DBG_S_REGISTER, reg);
+ return ivtv_call_i2c_client(itv, reg->match_chip, VIDIOC_DBG_S_REGISTER, reg);
+}
+#endif
- case VIDIOC_G_AUDIO:{
- struct v4l2_audio *vin = arg;
+static int ivtv_g_priority(struct file *file, void *fh, enum v4l2_priority *p)
+{
+ struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
- vin->index = itv->audio_input;
- return ivtv_get_audio_input(itv, vin->index, vin);
- }
+ *p = v4l2_prio_max(&itv->prio);
- case VIDIOC_S_AUDIO:{
- struct v4l2_audio *vout = arg;
+ return 0;
+}
- if (vout->index >= itv->nof_audio_inputs)
- return -EINVAL;
- itv->audio_input = vout->index;
- ivtv_audio_set_io(itv);
- break;
- }
+static int ivtv_s_priority(struct file *file, void *fh, enum v4l2_priority prio)
+{
+ struct ivtv_open_id *id = fh;
+ struct ivtv *itv = id->itv;
- case VIDIOC_ENUMAUDOUT:{
- struct v4l2_audioout *vin = arg;
+ return v4l2_prio_change(&itv->prio, &id->prio, prio);
+}
- /* set it to defaults from our table */
- return ivtv_get_audio_output(itv, vin->index, vin);
- }
+static int ivtv_querycap(struct file *file, void *fh, struct v4l2_capability *vcap)
+{
+ struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
- case VIDIOC_G_AUDOUT:{
- struct v4l2_audioout *vin = arg;
+ strlcpy(vcap->driver, IVTV_DRIVER_NAME, sizeof(vcap->driver));
+ strlcpy(vcap->card, itv->card_name, sizeof(vcap->card));
+ strlcpy(vcap->bus_info, pci_name(itv->dev), sizeof(vcap->bus_info));
+ vcap->version = IVTV_DRIVER_VERSION; /* version */
+ vcap->capabilities = itv->v4l2_cap; /* capabilities */
+ return 0;
+}
- vin->index = 0;
- return ivtv_get_audio_output(itv, vin->index, vin);
- }
+static int ivtv_enumaudio(struct file *file, void *fh, struct v4l2_audio *vin)
+{
+ struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
- case VIDIOC_S_AUDOUT:{
- struct v4l2_audioout *vout = arg;
+ return ivtv_get_audio_input(itv, vin->index, vin);
+}
- return ivtv_get_audio_output(itv, vout->index, vout);
- }
+static int ivtv_g_audio(struct file *file, void *fh, struct v4l2_audio *vin)
+{
+ struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
- case VIDIOC_ENUMINPUT:{
- struct v4l2_input *vin = arg;
+ vin->index = itv->audio_input;
+ return ivtv_get_audio_input(itv, vin->index, vin);
+}
- /* set it to defaults from our table */
- return ivtv_get_input(itv, vin->index, vin);
- }
+static int ivtv_s_audio(struct file *file, void *fh, struct v4l2_audio *vout)
+{
+ struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
- case VIDIOC_ENUMOUTPUT:{
- struct v4l2_output *vout = arg;
+ if (vout->index >= itv->nof_audio_inputs)
+ return -EINVAL;
- return ivtv_get_output(itv, vout->index, vout);
- }
+ itv->audio_input = vout->index;
+ ivtv_audio_set_io(itv);
- case VIDIOC_TRY_FMT:
- case VIDIOC_S_FMT: {
- struct v4l2_format *fmt = arg;
+ return 0;
+}
- return ivtv_try_or_set_fmt(itv, id->type, fmt, cmd == VIDIOC_S_FMT);
- }
+static int ivtv_enumaudout(struct file *file, void *fh, struct v4l2_audioout *vin)
+{
+ struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
- case VIDIOC_G_FMT: {
- struct v4l2_format *fmt = arg;
- int type = fmt->type;
+ /* set it to defaults from our table */
+ return ivtv_get_audio_output(itv, vin->index, vin);
+}
- memset(fmt, 0, sizeof(*fmt));
- fmt->type = type;
- return ivtv_get_fmt(itv, id->type, fmt);
- }
+static int ivtv_g_audout(struct file *file, void *fh, struct v4l2_audioout *vin)
+{
+ struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
- case VIDIOC_CROPCAP: {
- struct v4l2_cropcap *cropcap = arg;
+ vin->index = 0;
+ return ivtv_get_audio_output(itv, vin->index, vin);
+}
- if (cropcap->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
- return -EINVAL;
- cropcap->bounds.top = cropcap->bounds.left = 0;
- cropcap->bounds.width = 720;
- if (cropcap->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- cropcap->bounds.height = itv->is_50hz ? 576 : 480;
- cropcap->pixelaspect.numerator = itv->is_50hz ? 59 : 10;
- cropcap->pixelaspect.denominator = itv->is_50hz ? 54 : 11;
- } else if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
- if (yi->track_osd) {
- cropcap->bounds.width = yi->osd_full_w;
- cropcap->bounds.height = yi->osd_full_h;
- } else {
- cropcap->bounds.width = 720;
- cropcap->bounds.height =
- itv->is_out_50hz ? 576 : 480;
- }
- cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10;
- cropcap->pixelaspect.denominator = itv->is_out_50hz ? 54 : 11;
+static int ivtv_s_audout(struct file *file, void *fh, struct v4l2_audioout *vout)
+{
+ struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+
+ return ivtv_get_audio_output(itv, vout->index, vout);
+}
+
+static int ivtv_enum_input(struct file *file, void *fh, struct v4l2_input *vin)
+{
+ struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+
+ /* set it to defaults from our table */
+ return ivtv_get_input(itv, vin->index, vin);
+}
+
+static int ivtv_enum_output(struct file *file, void *fh, struct v4l2_output *vout)
+{
+ struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+
+ return ivtv_get_output(itv, vout->index, vout);
+}
+
+static int ivtv_cropcap(struct file *file, void *fh, struct v4l2_cropcap *cropcap)
+{
+ struct ivtv_open_id *id = fh;
+ struct ivtv *itv = id->itv;
+ struct yuv_playback_info *yi = &itv->yuv_info;
+ int streamtype;
+
+ streamtype = id->type;
+
+ if (cropcap->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ return -EINVAL;
+ cropcap->bounds.top = cropcap->bounds.left = 0;
+ cropcap->bounds.width = 720;
+ if (cropcap->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ cropcap->bounds.height = itv->is_50hz ? 576 : 480;
+ cropcap->pixelaspect.numerator = itv->is_50hz ? 59 : 10;
+ cropcap->pixelaspect.denominator = itv->is_50hz ? 54 : 11;
+ } else if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
+ if (yi->track_osd) {
+ cropcap->bounds.width = yi->osd_full_w;
+ cropcap->bounds.height = yi->osd_full_h;
} else {
- cropcap->bounds.height = itv->is_out_50hz ? 576 : 480;
- cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10;
- cropcap->pixelaspect.denominator = itv->is_out_50hz ? 54 : 11;
+ cropcap->bounds.width = 720;
+ cropcap->bounds.height =
+ itv->is_out_50hz ? 576 : 480;
}
- cropcap->defrect = cropcap->bounds;
- return 0;
+ cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10;
+ cropcap->pixelaspect.denominator = itv->is_out_50hz ? 54 : 11;
+ } else {
+ cropcap->bounds.height = itv->is_out_50hz ? 576 : 480;
+ cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10;
+ cropcap->pixelaspect.denominator = itv->is_out_50hz ? 54 : 11;
}
+ cropcap->defrect = cropcap->bounds;
+ return 0;
+}
+
+static int ivtv_s_crop(struct file *file, void *fh, struct v4l2_crop *crop)
+{
+ struct ivtv_open_id *id = fh;
+ struct ivtv *itv = id->itv;
+ struct yuv_playback_info *yi = &itv->yuv_info;
+ int streamtype;
- case VIDIOC_S_CROP: {
- struct v4l2_crop *crop = arg;
+ streamtype = id->type;
- if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
- (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
- if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
- yi->main_rect = crop->c;
+ if (ivtv_debug & IVTV_DBGFLG_IOCTL) {
+ printk(KERN_INFO "ivtv%d ioctl: ", itv->num);
+ /* Should be replaced */
+ /* v4l_printk_ioctl(VIDIOC_S_CROP); */
+ }
+
+ if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
+ (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
+ if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
+ yi->main_rect = crop->c;
+ return 0;
+ } else {
+ if (!ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4,
+ crop->c.width, crop->c.height, crop->c.left, crop->c.top)) {
+ itv->main_rect = crop->c;
return 0;
- } else {
- if (!ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4,
- crop->c.width, crop->c.height, crop->c.left, crop->c.top)) {
- itv->main_rect = crop->c;
- return 0;
- }
}
- return -EINVAL;
}
return -EINVAL;
}
+ return -EINVAL;
+}
- case VIDIOC_G_CROP: {
- struct v4l2_crop *crop = arg;
+static int ivtv_g_crop(struct file *file, void *fh, struct v4l2_crop *crop)
+{
+ struct ivtv_open_id *id = fh;
+ struct ivtv *itv = id->itv;
+ struct yuv_playback_info *yi = &itv->yuv_info;
+ int streamtype;
- if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
- (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
- if (streamtype == IVTV_DEC_STREAM_TYPE_YUV)
- crop->c = yi->main_rect;
- else
- crop->c = itv->main_rect;
- return 0;
+ streamtype = id->type;
+
+ if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
+ (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
+ if (streamtype == IVTV_DEC_STREAM_TYPE_YUV)
+ crop->c = yi->main_rect;
+ else
+ crop->c = itv->main_rect;
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static int ivtv_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt)
+{
+ static struct v4l2_fmtdesc formats[] = {
+ { 0, 0, 0,
+ "HM12 (YUV 4:2:0)", V4L2_PIX_FMT_HM12,
+ { 0, 0, 0, 0 }
+ },
+ { 1, 0, V4L2_FMT_FLAG_COMPRESSED,
+ "MPEG", V4L2_PIX_FMT_MPEG,
+ { 0, 0, 0, 0 }
}
+ };
+ enum v4l2_buf_type type = fmt->type;
+
+ if (fmt->index > 1)
return -EINVAL;
- }
- case VIDIOC_ENUM_FMT: {
- static struct v4l2_fmtdesc formats[] = {
- { 0, 0, 0,
- "HM12 (YUV 4:2:0)", V4L2_PIX_FMT_HM12,
- { 0, 0, 0, 0 }
- },
- { 1, 0, V4L2_FMT_FLAG_COMPRESSED,
- "MPEG", V4L2_PIX_FMT_MPEG,
- { 0, 0, 0, 0 }
- }
- };
- struct v4l2_fmtdesc *fmt = arg;
- enum v4l2_buf_type type = fmt->type;
+ *fmt = formats[fmt->index];
+ fmt->type = type;
+ return 0;
+}
- switch (type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- break;
- case V4L2_BUF_TYPE_VIDEO_OUTPUT:
- if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
- return -EINVAL;
- break;
- default:
- return -EINVAL;
+static int ivtv_enum_fmt_vid_out(struct file *file, void *fh, struct v4l2_fmtdesc *fmt)
+{
+ struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+
+ static struct v4l2_fmtdesc formats[] = {
+ { 0, 0, 0,
+ "HM12 (YUV 4:2:0)", V4L2_PIX_FMT_HM12,
+ { 0, 0, 0, 0 }
+ },
+ { 1, 0, V4L2_FMT_FLAG_COMPRESSED,
+ "MPEG", V4L2_PIX_FMT_MPEG,
+ { 0, 0, 0, 0 }
}
- if (fmt->index > 1)
- return -EINVAL;
- *fmt = formats[fmt->index];
- fmt->type = type;
+ };
+ enum v4l2_buf_type type = fmt->type;
+
+ if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+ return -EINVAL;
+
+ if (fmt->index > 1)
+ return -EINVAL;
+
+ *fmt = formats[fmt->index];
+ fmt->type = type;
+
+ return 0;
+}
+
+static int ivtv_g_input(struct file *file, void *fh, unsigned int *i)
+{
+ struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+
+ *i = itv->active_input;
+
+ return 0;
+}
+
+int ivtv_s_input(struct file *file, void *fh, unsigned int inp)
+{
+ struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+
+ if (inp < 0 || inp >= itv->nof_inputs)
+ return -EINVAL;
+
+ if (inp == itv->active_input) {
+ IVTV_DEBUG_INFO("Input unchanged\n");
return 0;
}
- case VIDIOC_G_INPUT:{
- *(int *)arg = itv->active_input;
- break;
+ if (atomic_read(&itv->capturing) > 0) {
+ return -EBUSY;
}
- case VIDIOC_S_INPUT:{
- int inp = *(int *)arg;
+ IVTV_DEBUG_INFO("Changing input from %d to %d\n",
+ itv->active_input, inp);
- if (inp < 0 || inp >= itv->nof_inputs)
- return -EINVAL;
+ itv->active_input = inp;
+ /* Set the audio input to whatever is appropriate for the
+ input type. */
+ itv->audio_input = itv->card->video_inputs[inp].audio_index;
- if (inp == itv->active_input) {
- IVTV_DEBUG_INFO("Input unchanged\n");
- break;
- }
- if (atomic_read(&itv->capturing) > 0) {
- return -EBUSY;
- }
- IVTV_DEBUG_INFO("Changing input from %d to %d\n",
- itv->active_input, inp);
+ /* prevent others from messing with the streams until
+ we're finished changing inputs. */
+ ivtv_mute(itv);
+ ivtv_video_set_io(itv);
+ ivtv_audio_set_io(itv);
+ ivtv_unmute(itv);
- itv->active_input = inp;
- /* Set the audio input to whatever is appropriate for the
- input type. */
- itv->audio_input = itv->card->video_inputs[inp].audio_index;
+ return 0;
+}
- /* prevent others from messing with the streams until
- we're finished changing inputs. */
- ivtv_mute(itv);
- ivtv_video_set_io(itv);
- ivtv_audio_set_io(itv);
- ivtv_unmute(itv);
- break;
- }
+static int ivtv_g_output(struct file *file, void *fh, unsigned int *i)
+{
+ struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
- case VIDIOC_G_OUTPUT:{
- if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
- return -EINVAL;
- *(int *)arg = itv->active_output;
- break;
- }
+ if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+ return -EINVAL;
- case VIDIOC_S_OUTPUT:{
- int outp = *(int *)arg;
- struct v4l2_routing route;
+ *i = itv->active_output;
- if (outp >= itv->card->nof_outputs)
- return -EINVAL;
+ return 0;
+}
- if (outp == itv->active_output) {
- IVTV_DEBUG_INFO("Output unchanged\n");
- break;
- }
- IVTV_DEBUG_INFO("Changing output from %d to %d\n",
- itv->active_output, outp);
+static int ivtv_s_output(struct file *file, void *fh, unsigned int outp)
+{
+ struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+ struct v4l2_routing route;
- itv->active_output = outp;
- route.input = SAA7127_INPUT_TYPE_NORMAL;
- route.output = itv->card->video_outputs[outp].video_output;
- ivtv_saa7127(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route);
- break;
+ if (outp >= itv->card->nof_outputs)
+ return -EINVAL;
+
+ if (outp == itv->active_output) {
+ IVTV_DEBUG_INFO("Output unchanged\n");
+ return 0;
}
+ IVTV_DEBUG_INFO("Changing output from %d to %d\n",
+ itv->active_output, outp);
- case VIDIOC_G_FREQUENCY:{
- struct v4l2_frequency *vf = arg;
+ itv->active_output = outp;
+ route.input = SAA7127_INPUT_TYPE_NORMAL;
+ route.output = itv->card->video_outputs[outp].video_output;
+ ivtv_saa7127(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route);
- if (vf->tuner != 0)
- return -EINVAL;
- ivtv_call_i2c_clients(itv, cmd, arg);
- break;
- }
+ return 0;
+}
- case VIDIOC_S_FREQUENCY:{
- struct v4l2_frequency vf = *(struct v4l2_frequency *)arg;
+static int ivtv_g_frequency(struct file *file, void *fh, struct v4l2_frequency *vf)
+{
+ struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
- if (vf.tuner != 0)
- return -EINVAL;
+ if (vf->tuner != 0)
+ return -EINVAL;
- ivtv_mute(itv);
- IVTV_DEBUG_INFO("v4l2 ioctl: set frequency %d\n", vf.frequency);
- ivtv_call_i2c_clients(itv, cmd, &vf);
- ivtv_unmute(itv);
- break;
- }
+ ivtv_call_i2c_clients(itv, VIDIOC_G_FREQUENCY, vf);
+ return 0;
+}
- case VIDIOC_ENUMSTD:{
- struct v4l2_standard *vs = arg;
- int idx = vs->index;
+int ivtv_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf)
+{
+ struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
- if (idx < 0 || idx >= ARRAY_SIZE(enum_stds))
- return -EINVAL;
+ if (vf->tuner != 0)
+ return -EINVAL;
- *vs = (enum_stds[idx].std & V4L2_STD_525_60) ?
- ivtv_std_60hz : ivtv_std_50hz;
- vs->index = idx;
- vs->id = enum_stds[idx].std;
- strlcpy(vs->name, enum_stds[idx].name, sizeof(vs->name));
- break;
- }
+ ivtv_mute(itv);
+ IVTV_DEBUG_INFO("v4l2 ioctl: set frequency %d\n", vf->frequency);
+ ivtv_call_i2c_clients(itv, VIDIOC_S_FREQUENCY, vf);
+ ivtv_unmute(itv);
+ return 0;
+}
- case VIDIOC_G_STD:{
- *(v4l2_std_id *) arg = itv->std;
- break;
- }
+static int ivtv_g_std(struct file *file, void *fh, v4l2_std_id *std)
+{
+ struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
- case VIDIOC_S_STD: {
- v4l2_std_id std = *(v4l2_std_id *) arg;
+ *std = itv->std;
+ return 0;
+}
- if ((std & V4L2_STD_ALL) == 0)
- return -EINVAL;
+int ivtv_s_std(struct file *file, void *fh, v4l2_std_id *std)
+{
+ struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+ struct yuv_playback_info *yi = &itv->yuv_info;
- if (std == itv->std)
- break;
+ if ((*std & V4L2_STD_ALL) == 0)
+ return -EINVAL;
- if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ||
- atomic_read(&itv->capturing) > 0 ||
- atomic_read(&itv->decoding) > 0) {
- /* Switching standard would turn off the radio or mess
- with already running streams, prevent that by
- returning EBUSY. */
- return -EBUSY;
- }
+ if (*std == itv->std)
+ return 0;
- itv->std = std;
- itv->is_60hz = (std & V4L2_STD_525_60) ? 1 : 0;
- itv->params.is_50hz = itv->is_50hz = !itv->is_60hz;
- itv->params.width = 720;
- itv->params.height = itv->is_50hz ? 576 : 480;
- itv->vbi.count = itv->is_50hz ? 18 : 12;
- itv->vbi.start[0] = itv->is_50hz ? 6 : 10;
- itv->vbi.start[1] = itv->is_50hz ? 318 : 273;
- if (itv->hw_flags & IVTV_HW_CX25840) {
- itv->vbi.sliced_decoder_line_size = itv->is_60hz ? 272 : 284;
- }
- IVTV_DEBUG_INFO("Switching standard to %llx.\n", (unsigned long long)itv->std);
-
- /* Tuner */
- ivtv_call_i2c_clients(itv, VIDIOC_S_STD, &itv->std);
-
- if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
- /* set display standard */
- itv->std_out = std;
- itv->is_out_60hz = itv->is_60hz;
- itv->is_out_50hz = itv->is_50hz;
- ivtv_call_i2c_clients(itv, VIDIOC_INT_S_STD_OUTPUT, &itv->std_out);
- ivtv_vapi(itv, CX2341X_DEC_SET_STANDARD, 1, itv->is_out_50hz);
- itv->main_rect.left = itv->main_rect.top = 0;
- itv->main_rect.width = 720;
- itv->main_rect.height = itv->params.height;
- ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4,
- 720, itv->main_rect.height, 0, 0);
- yi->main_rect = itv->main_rect;
- if (!itv->osd_info) {
- yi->osd_full_w = 720;
- yi->osd_full_h = itv->is_out_50hz ? 576 : 480;
- }
+ if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ||
+ atomic_read(&itv->capturing) > 0 ||
+ atomic_read(&itv->decoding) > 0) {
+ /* Switching standard would turn off the radio or mess
+ with already running streams, prevent that by
+ returning EBUSY. */
+ return -EBUSY;
+ }
+
+ itv->std = *std;
+ itv->is_60hz = (*std & V4L2_STD_525_60) ? 1 : 0;
+ itv->params.is_50hz = itv->is_50hz = !itv->is_60hz;
+ itv->params.width = 720;
+ itv->params.height = itv->is_50hz ? 576 : 480;
+ itv->vbi.count = itv->is_50hz ? 18 : 12;
+ itv->vbi.start[0] = itv->is_50hz ? 6 : 10;
+ itv->vbi.start[1] = itv->is_50hz ? 318 : 273;
+
+ if (itv->hw_flags & IVTV_HW_CX25840)
+ itv->vbi.sliced_decoder_line_size = itv->is_60hz ? 272 : 284;
+
+ IVTV_DEBUG_INFO("Switching standard to %llx.\n", (unsigned long long)itv->std);
+
+ /* Tuner */
+ ivtv_call_i2c_clients(itv, VIDIOC_S_STD, &itv->std);
+
+ if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
+ /* set display standard */
+ itv->std_out = *std;
+ itv->is_out_60hz = itv->is_60hz;
+ itv->is_out_50hz = itv->is_50hz;
+ ivtv_call_i2c_clients(itv, VIDIOC_INT_S_STD_OUTPUT, &itv->std_out);
+ ivtv_vapi(itv, CX2341X_DEC_SET_STANDARD, 1, itv->is_out_50hz);
+ itv->main_rect.left = itv->main_rect.top = 0;
+ itv->main_rect.width = 720;
+ itv->main_rect.height = itv->params.height;
+ ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4,
+ 720, itv->main_rect.height, 0, 0);
+ yi->main_rect = itv->main_rect;
+ if (!itv->osd_info) {
+ yi->osd_full_w = 720;
+ yi->osd_full_h = itv->is_out_50hz ? 576 : 480;
}
- break;
}
+ return 0;
+}
- case VIDIOC_S_TUNER: { /* Setting tuner can only set audio mode */
- struct v4l2_tuner *vt = arg;
+static int ivtv_s_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
+{
+ struct ivtv_open_id *id = fh;
+ struct ivtv *itv = id->itv;
- if (vt->index != 0)
- return -EINVAL;
+ if (vt->index != 0)
+ return -EINVAL;
- ivtv_call_i2c_clients(itv, VIDIOC_S_TUNER, vt);
- break;
- }
+ ivtv_call_i2c_clients(itv, VIDIOC_S_TUNER, vt);
- case VIDIOC_G_TUNER: {
- struct v4l2_tuner *vt = arg;
+ return 0;
+}
- if (vt->index != 0)
- return -EINVAL;
+static int ivtv_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
+{
+ struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
- memset(vt, 0, sizeof(*vt));
- ivtv_call_i2c_clients(itv, VIDIOC_G_TUNER, vt);
+ if (vt->index != 0)
+ return -EINVAL;
- if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) {
- strlcpy(vt->name, "ivtv Radio Tuner", sizeof(vt->name));
- vt->type = V4L2_TUNER_RADIO;
- } else {
- strlcpy(vt->name, "ivtv TV Tuner", sizeof(vt->name));
- vt->type = V4L2_TUNER_ANALOG_TV;
- }
- break;
+ ivtv_call_i2c_clients(itv, VIDIOC_G_TUNER, vt);
+
+ if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) {
+ strlcpy(vt->name, "ivtv Radio Tuner", sizeof(vt->name));
+ vt->type = V4L2_TUNER_RADIO;
+ } else {
+ strlcpy(vt->name, "ivtv TV Tuner", sizeof(vt->name));
+ vt->type = V4L2_TUNER_ANALOG_TV;
}
- case VIDIOC_G_SLICED_VBI_CAP: {
- struct v4l2_sliced_vbi_cap *cap = arg;
- int set = itv->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525;
- int f, l;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
- enum v4l2_buf_type type = cap->type;
-#else
- enum v4l2_buf_type type = VIDIOC_G_SLICED_VBI_CAP;
-#endif
+ return 0;
+}
- memset(cap, 0, sizeof(*cap));
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
- cap->type = type;
-#endif
- if (type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
- for (f = 0; f < 2; f++) {
- for (l = 0; l < 24; l++) {
- if (valid_service_line(f, l, itv->is_50hz)) {
- cap->service_lines[f][l] = set;
- }
- }
+static int ivtv_g_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_sliced_vbi_cap *cap)
+{
+ struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+ int set = itv->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525;
+ int f, l;
+
+ if (cap->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
+ for (f = 0; f < 2; f++) {
+ for (l = 0; l < 24; l++) {
+ if (valid_service_line(f, l, itv->is_50hz))
+ cap->service_lines[f][l] = set;
}
- return 0;
}
- if (type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) {
- if (!(itv->v4l2_cap & V4L2_CAP_SLICED_VBI_OUTPUT))
- return -EINVAL;
- if (itv->is_60hz) {
- cap->service_lines[0][21] = V4L2_SLICED_CAPTION_525;
- cap->service_lines[1][21] = V4L2_SLICED_CAPTION_525;
- } else {
- cap->service_lines[0][23] = V4L2_SLICED_WSS_625;
- cap->service_lines[0][16] = V4L2_SLICED_VPS;
- }
- return 0;
+ return 0;
+ }
+ if (cap->type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) {
+ if (!(itv->v4l2_cap & V4L2_CAP_SLICED_VBI_OUTPUT))
+ return -EINVAL;
+ if (itv->is_60hz) {
+ cap->service_lines[0][21] = V4L2_SLICED_CAPTION_525;
+ cap->service_lines[1][21] = V4L2_SLICED_CAPTION_525;
+ } else {
+ cap->service_lines[0][23] = V4L2_SLICED_WSS_625;
+ cap->service_lines[0][16] = V4L2_SLICED_VPS;
}
- return -EINVAL;
+ return 0;
}
+ return -EINVAL;
+}
- case VIDIOC_G_ENC_INDEX: {
- struct v4l2_enc_idx *idx = arg;
- struct v4l2_enc_idx_entry *e = idx->entry;
- int entries;
- int i;
-
- entries = (itv->pgm_info_write_idx + IVTV_MAX_PGM_INDEX - itv->pgm_info_read_idx) %
- IVTV_MAX_PGM_INDEX;
- if (entries > V4L2_ENC_IDX_ENTRIES)
- entries = V4L2_ENC_IDX_ENTRIES;
- idx->entries = 0;
- for (i = 0; i < entries; i++) {
- *e = itv->pgm_info[(itv->pgm_info_read_idx + i) % IVTV_MAX_PGM_INDEX];
- if ((e->flags & V4L2_ENC_IDX_FRAME_MASK) <= V4L2_ENC_IDX_FRAME_B) {
- idx->entries++;
- e++;
- }
+static int ivtv_g_enc_index(struct file *file, void *fh, struct v4l2_enc_idx *idx)
+{
+ struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+ struct v4l2_enc_idx_entry *e = idx->entry;
+ int entries;
+ int i;
+
+ entries = (itv->pgm_info_write_idx + IVTV_MAX_PGM_INDEX - itv->pgm_info_read_idx) %
+ IVTV_MAX_PGM_INDEX;
+ if (entries > V4L2_ENC_IDX_ENTRIES)
+ entries = V4L2_ENC_IDX_ENTRIES;
+ idx->entries = 0;
+ for (i = 0; i < entries; i++) {
+ *e = itv->pgm_info[(itv->pgm_info_read_idx + i) % IVTV_MAX_PGM_INDEX];
+ if ((e->flags & V4L2_ENC_IDX_FRAME_MASK) <= V4L2_ENC_IDX_FRAME_B) {
+ idx->entries++;
+ e++;
}
- itv->pgm_info_read_idx = (itv->pgm_info_read_idx + idx->entries) % IVTV_MAX_PGM_INDEX;
- break;
}
+ itv->pgm_info_read_idx = (itv->pgm_info_read_idx + idx->entries) % IVTV_MAX_PGM_INDEX;
+ return 0;
+}
- case VIDIOC_ENCODER_CMD:
- case VIDIOC_TRY_ENCODER_CMD: {
- struct v4l2_encoder_cmd *enc = arg;
- int try = cmd == VIDIOC_TRY_ENCODER_CMD;
-
- memset(&enc->raw, 0, sizeof(enc->raw));
- switch (enc->cmd) {
- case V4L2_ENC_CMD_START:
- IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_START\n");
- enc->flags = 0;
- if (try)
- return 0;
- return ivtv_start_capture(id);
+static int ivtv_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *enc)
+{
+ struct ivtv_open_id *id = fh;
+ struct ivtv *itv = id->itv;
- case V4L2_ENC_CMD_STOP:
- IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n");
- enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END;
- if (try)
- return 0;
- ivtv_stop_capture(id, enc->flags & V4L2_ENC_CMD_STOP_AT_GOP_END);
+
+ switch (enc->cmd) {
+ case V4L2_ENC_CMD_START:
+ IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_START\n");
+ enc->flags = 0;
+ return ivtv_start_capture(id);
+
+ case V4L2_ENC_CMD_STOP:
+ IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n");
+ enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END;
+ ivtv_stop_capture(id, enc->flags & V4L2_ENC_CMD_STOP_AT_GOP_END);
+ return 0;
+
+ case V4L2_ENC_CMD_PAUSE:
+ IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n");
+ enc->flags = 0;
+
+ if (!atomic_read(&itv->capturing))
+ return -EPERM;
+ if (test_and_set_bit(IVTV_F_I_ENC_PAUSED, &itv->i_flags))
return 0;
- case V4L2_ENC_CMD_PAUSE:
- IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n");
- enc->flags = 0;
- if (try)
- return 0;
- if (!atomic_read(&itv->capturing))
- return -EPERM;
- if (test_and_set_bit(IVTV_F_I_ENC_PAUSED, &itv->i_flags))
- return 0;
- ivtv_mute(itv);
- ivtv_vapi(itv, CX2341X_ENC_PAUSE_ENCODER, 1, 0);
- break;
+ ivtv_mute(itv);
+ ivtv_vapi(itv, CX2341X_ENC_PAUSE_ENCODER, 1, 0);
+ break;
- case V4L2_ENC_CMD_RESUME:
- IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n");
- enc->flags = 0;
- if (try)
- return 0;
- if (!atomic_read(&itv->capturing))
- return -EPERM;
- if (!test_and_clear_bit(IVTV_F_I_ENC_PAUSED, &itv->i_flags))
- return 0;
- ivtv_vapi(itv, CX2341X_ENC_PAUSE_ENCODER, 1, 1);
- ivtv_unmute(itv);
- break;
- default:
- IVTV_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd);
- return -EINVAL;
- }
+ case V4L2_ENC_CMD_RESUME:
+ IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n");
+ enc->flags = 0;
+
+ if (!atomic_read(&itv->capturing))
+ return -EPERM;
+
+ if (!test_and_clear_bit(IVTV_F_I_ENC_PAUSED, &itv->i_flags))
+ return 0;
+
+ ivtv_vapi(itv, CX2341X_ENC_PAUSE_ENCODER, 1, 1);
+ ivtv_unmute(itv);
break;
+ default:
+ IVTV_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd);
+ return -EINVAL;
}
- case VIDIOC_G_FBUF: {
- struct v4l2_framebuffer *fb = arg;
- int pixfmt;
- static u32 pixel_format[16] = {
- V4L2_PIX_FMT_PAL8, /* Uses a 256-entry RGB colormap */
- V4L2_PIX_FMT_RGB565,
- V4L2_PIX_FMT_RGB555,
- V4L2_PIX_FMT_RGB444,
- V4L2_PIX_FMT_RGB32,
- 0,
- 0,
- 0,
- V4L2_PIX_FMT_PAL8, /* Uses a 256-entry YUV colormap */
- V4L2_PIX_FMT_YUV565,
- V4L2_PIX_FMT_YUV555,
- V4L2_PIX_FMT_YUV444,
- V4L2_PIX_FMT_YUV32,
- 0,
- 0,
- 0,
- };
+ return 0;
+}
- memset(fb, 0, sizeof(*fb));
- if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
- return -EINVAL;
- fb->capability = V4L2_FBUF_CAP_EXTERNOVERLAY | V4L2_FBUF_CAP_CHROMAKEY |
- V4L2_FBUF_CAP_GLOBAL_ALPHA;
- ivtv_vapi_result(itv, data, CX2341X_OSD_GET_STATE, 0);
- data[0] |= (read_reg(0x2a00) >> 7) & 0x40;
- pixfmt = (data[0] >> 3) & 0xf;
- fb->fmt.pixelformat = pixel_format[pixfmt];
- fb->fmt.width = itv->osd_rect.width;
- fb->fmt.height = itv->osd_rect.height;
- fb->base = (void *)itv->osd_video_pbase;
- if (itv->osd_chroma_key_state)
- fb->flags |= V4L2_FBUF_FLAG_CHROMAKEY;
- if (itv->osd_global_alpha_state)
- fb->flags |= V4L2_FBUF_FLAG_GLOBAL_ALPHA;
- pixfmt &= 7;
- /* no local alpha for RGB565 or unknown formats */
- if (pixfmt == 1 || pixfmt > 4)
- break;
+static int ivtv_try_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *enc)
+{
+ struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+
+ switch (enc->cmd) {
+ case V4L2_ENC_CMD_START:
+ IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_START\n");
+ enc->flags = 0;
+ return 0;
+
+ case V4L2_ENC_CMD_STOP:
+ IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n");
+ enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END;
+ return 0;
+
+ case V4L2_ENC_CMD_PAUSE:
+ IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n");
+ enc->flags = 0;
+ return 0;
+
+ case V4L2_ENC_CMD_RESUME:
+ IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n");
+ enc->flags = 0;
+ return 0;
+ default:
+ IVTV_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd);
+ return -EINVAL;
+ }
+}
+
+static int ivtv_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb)
+{
+ struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+ u32 data[CX2341X_MBOX_MAX_DATA];
+ struct yuv_playback_info *yi = &itv->yuv_info;
+
+ int pixfmt;
+ static u32 pixel_format[16] = {
+ V4L2_PIX_FMT_PAL8, /* Uses a 256-entry RGB colormap */
+ V4L2_PIX_FMT_RGB565,
+ V4L2_PIX_FMT_RGB555,
+ V4L2_PIX_FMT_RGB444,
+ V4L2_PIX_FMT_RGB32,
+ 0,
+ 0,
+ 0,
+ V4L2_PIX_FMT_PAL8, /* Uses a 256-entry YUV colormap */
+ V4L2_PIX_FMT_YUV565,
+ V4L2_PIX_FMT_YUV555,
+ V4L2_PIX_FMT_YUV444,
+ V4L2_PIX_FMT_YUV32,
+ 0,
+ 0,
+ 0,
+ };
+
+ if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
+ return -EINVAL;
+ if (!itv->osd_video_pbase)
+ return -EINVAL;
+
+ fb->capability = V4L2_FBUF_CAP_EXTERNOVERLAY | V4L2_FBUF_CAP_CHROMAKEY |
+ V4L2_FBUF_CAP_GLOBAL_ALPHA;
+
+ ivtv_vapi_result(itv, data, CX2341X_OSD_GET_STATE, 0);
+ data[0] |= (read_reg(0x2a00) >> 7) & 0x40;
+ pixfmt = (data[0] >> 3) & 0xf;
+
+ fb->fmt.pixelformat = pixel_format[pixfmt];
+ fb->fmt.width = itv->osd_rect.width;
+ fb->fmt.height = itv->osd_rect.height;
+ fb->fmt.field = V4L2_FIELD_INTERLACED;
+ fb->fmt.bytesperline = fb->fmt.width;
+ fb->fmt.colorspace = V4L2_COLORSPACE_SMPTE170M;
+ fb->fmt.field = V4L2_FIELD_INTERLACED;
+ fb->fmt.priv = 0;
+ if (fb->fmt.pixelformat != V4L2_PIX_FMT_PAL8)
+ fb->fmt.bytesperline *= 2;
+ if (fb->fmt.pixelformat == V4L2_PIX_FMT_RGB32 ||
+ fb->fmt.pixelformat == V4L2_PIX_FMT_YUV32)
+ fb->fmt.bytesperline *= 2;
+ fb->fmt.sizeimage = fb->fmt.bytesperline * fb->fmt.height;
+ fb->base = (void *)itv->osd_video_pbase;
+ fb->flags = 0;
+
+ if (itv->osd_chroma_key_state)
+ fb->flags |= V4L2_FBUF_FLAG_CHROMAKEY;
+
+ if (itv->osd_global_alpha_state)
+ fb->flags |= V4L2_FBUF_FLAG_GLOBAL_ALPHA;
+
+ pixfmt &= 7;
+
+ /* no local alpha for RGB565 or unknown formats */
+ if (pixfmt == 1 || pixfmt > 4)
+ return 0;
+
+ /* 16-bit formats have inverted local alpha */
+ if (pixfmt == 2 || pixfmt == 3)
+ fb->capability |= V4L2_FBUF_CAP_LOCAL_INV_ALPHA;
+ else
+ fb->capability |= V4L2_FBUF_CAP_LOCAL_ALPHA;
+
+ if (itv->osd_local_alpha_state) {
/* 16-bit formats have inverted local alpha */
if (pixfmt == 2 || pixfmt == 3)
- fb->capability |= V4L2_FBUF_CAP_LOCAL_INV_ALPHA;
+ fb->flags |= V4L2_FBUF_FLAG_LOCAL_INV_ALPHA;
else
- fb->capability |= V4L2_FBUF_CAP_LOCAL_ALPHA;
- if (itv->osd_local_alpha_state) {
- /* 16-bit formats have inverted local alpha */
- if (pixfmt == 2 || pixfmt == 3)
- fb->flags |= V4L2_FBUF_FLAG_LOCAL_INV_ALPHA;
- else
- fb->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA;
- }
- if (yi->track_osd)
- fb->flags |= V4L2_FBUF_FLAG_OVERLAY;
- break;
+ fb->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA;
}
+ if (yi->track_osd)
+ fb->flags |= V4L2_FBUF_FLAG_OVERLAY;
- case VIDIOC_S_FBUF: {
- struct v4l2_framebuffer *fb = arg;
+ return 0;
+}
- if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
- return -EINVAL;
- itv->osd_global_alpha_state = (fb->flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) != 0;
- itv->osd_local_alpha_state =
- (fb->flags & (V4L2_FBUF_FLAG_LOCAL_ALPHA|V4L2_FBUF_FLAG_LOCAL_INV_ALPHA)) != 0;
- itv->osd_chroma_key_state = (fb->flags & V4L2_FBUF_FLAG_CHROMAKEY) != 0;
- ivtv_set_osd_alpha(itv);
- yi->track_osd = (fb->flags & V4L2_FBUF_FLAG_OVERLAY) != 0;
- break;
- }
+static int ivtv_s_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb)
+{
+ struct ivtv_open_id *id = fh;
+ struct ivtv *itv = id->itv;
+ struct yuv_playback_info *yi = &itv->yuv_info;
- case VIDIOC_OVERLAY: {
- int *on = arg;
+ if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
+ return -EINVAL;
+ if (!itv->osd_video_pbase)
+ return -EINVAL;
- if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
- return -EINVAL;
- ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, *on != 0);
- break;
- }
+ itv->osd_global_alpha_state = (fb->flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) != 0;
+ itv->osd_local_alpha_state =
+ (fb->flags & (V4L2_FBUF_FLAG_LOCAL_ALPHA|V4L2_FBUF_FLAG_LOCAL_INV_ALPHA)) != 0;
+ itv->osd_chroma_key_state = (fb->flags & V4L2_FBUF_FLAG_CHROMAKEY) != 0;
+ ivtv_set_osd_alpha(itv);
+ yi->track_osd = (fb->flags & V4L2_FBUF_FLAG_OVERLAY) != 0;
+ return ivtv_g_fbuf(file, fh, fb);
+}
- case VIDIOC_LOG_STATUS:
- {
- int has_output = itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT;
- struct v4l2_input vidin;
- struct v4l2_audio audin;
- int i;
+static int ivtv_overlay(struct file *file, void *fh, unsigned int on)
+{
+ struct ivtv_open_id *id = fh;
+ struct ivtv *itv = id->itv;
- IVTV_INFO("================= START STATUS CARD #%d =================\n", itv->num);
- IVTV_INFO("Version: %s Card: %s\n", IVTV_VERSION, itv->card_name);
- if (itv->hw_flags & IVTV_HW_TVEEPROM) {
- struct tveeprom tv;
+ if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
+ return -EINVAL;
- ivtv_read_eeprom(itv, &tv);
- }
- ivtv_call_i2c_clients(itv, VIDIOC_LOG_STATUS, NULL);
- ivtv_get_input(itv, itv->active_input, &vidin);
- ivtv_get_audio_input(itv, itv->audio_input, &audin);
- IVTV_INFO("Video Input: %s\n", vidin.name);
- IVTV_INFO("Audio Input: %s%s\n", audin.name,
- (itv->dualwatch_stereo_mode & ~0x300) == 0x200 ? " (Bilingual)" : "");
- if (has_output) {
- struct v4l2_output vidout;
- struct v4l2_audioout audout;
- int mode = itv->output_mode;
- static const char * const output_modes[5] = {
- "None",
- "MPEG Streaming",
- "YUV Streaming",
- "YUV Frames",
- "Passthrough",
- };
- static const char * const audio_modes[5] = {
- "Stereo",
- "Left",
- "Right",
- "Mono",
- "Swapped"
- };
- static const char * const alpha_mode[4] = {
- "None",
- "Global",
- "Local",
- "Global and Local"
- };
- static const char * const pixel_format[16] = {
- "ARGB Indexed",
- "RGB 5:6:5",
- "ARGB 1:5:5:5",
- "ARGB 1:4:4:4",
- "ARGB 8:8:8:8",
- "5",
- "6",
- "7",
- "AYUV Indexed",
- "YUV 5:6:5",
- "AYUV 1:5:5:5",
- "AYUV 1:4:4:4",
- "AYUV 8:8:8:8",
- "13",
- "14",
- "15",
- };
-
- ivtv_get_output(itv, itv->active_output, &vidout);
- ivtv_get_audio_output(itv, 0, &audout);
- IVTV_INFO("Video Output: %s\n", vidout.name);
- IVTV_INFO("Audio Output: %s (Stereo/Bilingual: %s/%s)\n", audout.name,
- audio_modes[itv->audio_stereo_mode],
- audio_modes[itv->audio_bilingual_mode]);
- if (mode < 0 || mode > OUT_PASSTHROUGH)
- mode = OUT_NONE;
- IVTV_INFO("Output Mode: %s\n", output_modes[mode]);
- ivtv_vapi_result(itv, data, CX2341X_OSD_GET_STATE, 0);
- data[0] |= (read_reg(0x2a00) >> 7) & 0x40;
- IVTV_INFO("Overlay: %s, Alpha: %s, Pixel Format: %s\n",
- data[0] & 1 ? "On" : "Off",
- alpha_mode[(data[0] >> 1) & 0x3],
- pixel_format[(data[0] >> 3) & 0xf]);
- }
- IVTV_INFO("Tuner: %s\n",
- test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ? "Radio" : "TV");
- cx2341x_log_status(&itv->params, itv->name);
- IVTV_INFO("Status flags: 0x%08lx\n", itv->i_flags);
- for (i = 0; i < IVTV_MAX_STREAMS; i++) {
- struct ivtv_stream *s = &itv->streams[i];
-
- if (s->v4l2dev == NULL || s->buffers == 0)
- continue;
- IVTV_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n", s->name, s->s_flags,
- (s->buffers - s->q_free.buffers) * 100 / s->buffers,
- (s->buffers * s->buf_size) / 1024, s->buffers);
- }
- IVTV_INFO("Read MPG/VBI: %lld/%lld bytes\n", (long long)itv->mpg_data_received, (long long)itv->vbi_data_inserted);
- IVTV_INFO("================== END STATUS CARD #%d ==================\n", itv->num);
- break;
+ ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, on != 0);
+
+ return 0;
+}
+
+static int ivtv_log_status(struct file *file, void *fh)
+{
+ struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+ u32 data[CX2341X_MBOX_MAX_DATA];
+
+ int has_output = itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT;
+ struct v4l2_input vidin;
+ struct v4l2_audio audin;
+ int i;
+
+ IVTV_INFO("================= START STATUS CARD #%d =================\n", itv->num);
+ IVTV_INFO("Version: %s Card: %s\n", IVTV_VERSION, itv->card_name);
+ if (itv->hw_flags & IVTV_HW_TVEEPROM) {
+ struct tveeprom tv;
+
+ ivtv_read_eeprom(itv, &tv);
+ }
+ ivtv_call_i2c_clients(itv, VIDIOC_LOG_STATUS, NULL);
+ ivtv_get_input(itv, itv->active_input, &vidin);
+ ivtv_get_audio_input(itv, itv->audio_input, &audin);
+ IVTV_INFO("Video Input: %s\n", vidin.name);
+ IVTV_INFO("Audio Input: %s%s\n", audin.name,
+ (itv->dualwatch_stereo_mode & ~0x300) == 0x200 ? " (Bilingual)" : "");
+ if (has_output) {
+ struct v4l2_output vidout;
+ struct v4l2_audioout audout;
+ int mode = itv->output_mode;
+ static const char * const output_modes[5] = {
+ "None",
+ "MPEG Streaming",
+ "YUV Streaming",
+ "YUV Frames",
+ "Passthrough",
+ };
+ static const char * const audio_modes[5] = {
+ "Stereo",
+ "Left",
+ "Right",
+ "Mono",
+ "Swapped"
+ };
+ static const char * const alpha_mode[4] = {
+ "None",
+ "Global",
+ "Local",
+ "Global and Local"
+ };
+ static const char * const pixel_format[16] = {
+ "ARGB Indexed",
+ "RGB 5:6:5",
+ "ARGB 1:5:5:5",
+ "ARGB 1:4:4:4",
+ "ARGB 8:8:8:8",
+ "5",
+ "6",
+ "7",
+ "AYUV Indexed",
+ "YUV 5:6:5",
+ "AYUV 1:5:5:5",
+ "AYUV 1:4:4:4",
+ "AYUV 8:8:8:8",
+ "13",
+ "14",
+ "15",
+ };
+
+ ivtv_get_output(itv, itv->active_output, &vidout);
+ ivtv_get_audio_output(itv, 0, &audout);
+ IVTV_INFO("Video Output: %s\n", vidout.name);
+ IVTV_INFO("Audio Output: %s (Stereo/Bilingual: %s/%s)\n", audout.name,
+ audio_modes[itv->audio_stereo_mode],
+ audio_modes[itv->audio_bilingual_mode]);
+ if (mode < 0 || mode > OUT_PASSTHROUGH)
+ mode = OUT_NONE;
+ IVTV_INFO("Output Mode: %s\n", output_modes[mode]);
+ ivtv_vapi_result(itv, data, CX2341X_OSD_GET_STATE, 0);
+ data[0] |= (read_reg(0x2a00) >> 7) & 0x40;
+ IVTV_INFO("Overlay: %s, Alpha: %s, Pixel Format: %s\n",
+ data[0] & 1 ? "On" : "Off",
+ alpha_mode[(data[0] >> 1) & 0x3],
+ pixel_format[(data[0] >> 3) & 0xf]);
}
+ IVTV_INFO("Tuner: %s\n",
+ test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ? "Radio" : "TV");
+ cx2341x_log_status(&itv->params, itv->name);
+ IVTV_INFO("Status flags: 0x%08lx\n", itv->i_flags);
+ for (i = 0; i < IVTV_MAX_STREAMS; i++) {
+ struct ivtv_stream *s = &itv->streams[i];
- default:
- return -EINVAL;
+ if (s->v4l2dev == NULL || s->buffers == 0)
+ continue;
+ IVTV_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n", s->name, s->s_flags,
+ (s->buffers - s->q_free.buffers) * 100 / s->buffers,
+ (s->buffers * s->buf_size) / 1024, s->buffers);
}
+
+ IVTV_INFO("Read MPG/VBI: %lld/%lld bytes\n", (long long)itv->mpg_data_received, (long long)itv->vbi_data_inserted);
+ IVTV_INFO("================== END STATUS CARD #%d ==================\n", itv->num);
+
return 0;
}
@@ -1445,7 +1548,7 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg)
return -EINVAL;
if (itv->output_mode == OUT_UDMA_YUV && args->y_source == NULL)
return 0;
- if (ivtv_claim_stream(id, id->type)) {
+ if (ivtv_start_decoding(id, id->type)) {
return -EBUSY;
}
if (ivtv_set_output_mode(itv, OUT_UDMA_YUV) != OUT_UDMA_YUV) {
@@ -1619,121 +1722,30 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg)
return 0;
}
-static int ivtv_v4l2_do_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, void *arg)
+static int ivtv_default(struct file *file, void *fh, int cmd, void *arg)
{
- struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data;
- struct ivtv *itv = id->itv;
- int ret;
+ struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
- /* check priority */
switch (cmd) {
- case VIDIOC_S_CTRL:
- case VIDIOC_S_STD:
- case VIDIOC_S_INPUT:
- case VIDIOC_S_OUTPUT:
- case VIDIOC_S_TUNER:
- case VIDIOC_S_FREQUENCY:
- case VIDIOC_S_FMT:
- case VIDIOC_S_CROP:
- case VIDIOC_S_AUDIO:
- case VIDIOC_S_AUDOUT:
- case VIDIOC_S_EXT_CTRLS:
- case VIDIOC_S_FBUF:
- case VIDIOC_OVERLAY:
- ret = v4l2_prio_check(&itv->prio, &id->prio);
- if (ret)
- return ret;
- }
-
- switch (cmd) {
- case VIDIOC_DBG_G_REGISTER:
- case VIDIOC_DBG_S_REGISTER:
- case VIDIOC_G_CHIP_IDENT:
- case VIDIOC_INT_S_AUDIO_ROUTING:
- case VIDIOC_INT_RESET:
- if (ivtv_debug & IVTV_DBGFLG_IOCTL) {
- printk(KERN_INFO "ivtv%d ioctl: ", itv->num);
- v4l_printk_ioctl(cmd);
- printk("\n");
- }
- return ivtv_debug_ioctls(filp, cmd, arg);
+ case VIDIOC_INT_S_AUDIO_ROUTING: {
+ struct v4l2_routing *route = arg;
- case VIDIOC_G_PRIORITY:
- case VIDIOC_S_PRIORITY:
- case VIDIOC_QUERYCAP:
- case VIDIOC_ENUMINPUT:
- case VIDIOC_G_INPUT:
- case VIDIOC_S_INPUT:
- case VIDIOC_ENUMOUTPUT:
- case VIDIOC_G_OUTPUT:
- case VIDIOC_S_OUTPUT:
- case VIDIOC_G_FMT:
- case VIDIOC_S_FMT:
- case VIDIOC_TRY_FMT:
- case VIDIOC_ENUM_FMT:
- case VIDIOC_CROPCAP:
- case VIDIOC_G_CROP:
- case VIDIOC_S_CROP:
- case VIDIOC_G_FREQUENCY:
- case VIDIOC_S_FREQUENCY:
- case VIDIOC_ENUMSTD:
- case VIDIOC_G_STD:
- case VIDIOC_S_STD:
- case VIDIOC_S_TUNER:
- case VIDIOC_G_TUNER:
- case VIDIOC_ENUMAUDIO:
- case VIDIOC_S_AUDIO:
- case VIDIOC_G_AUDIO:
- case VIDIOC_ENUMAUDOUT:
- case VIDIOC_S_AUDOUT:
- case VIDIOC_G_AUDOUT:
- case VIDIOC_G_SLICED_VBI_CAP:
- case VIDIOC_LOG_STATUS:
- case VIDIOC_G_ENC_INDEX:
- case VIDIOC_ENCODER_CMD:
- case VIDIOC_TRY_ENCODER_CMD:
- case VIDIOC_G_FBUF:
- case VIDIOC_S_FBUF:
- case VIDIOC_OVERLAY:
- if (ivtv_debug & IVTV_DBGFLG_IOCTL) {
- printk(KERN_INFO "ivtv%d ioctl: ", itv->num);
- v4l_printk_ioctl(cmd);
- printk("\n");
- }
- return ivtv_v4l2_ioctls(itv, filp, cmd, arg);
+ ivtv_i2c_hw(itv, itv->card->hw_audio, VIDIOC_INT_S_AUDIO_ROUTING, route);
+ break;
+ }
- case VIDIOC_QUERYMENU:
- case VIDIOC_QUERYCTRL:
- case VIDIOC_S_CTRL:
- case VIDIOC_G_CTRL:
- case VIDIOC_S_EXT_CTRLS:
- case VIDIOC_G_EXT_CTRLS:
- case VIDIOC_TRY_EXT_CTRLS:
- if (ivtv_debug & IVTV_DBGFLG_IOCTL) {
- printk(KERN_INFO "ivtv%d ioctl: ", itv->num);
- v4l_printk_ioctl(cmd);
- printk("\n");
- }
- return ivtv_control_ioctls(itv, cmd, arg);
+ case VIDIOC_INT_RESET: {
+ u32 val = *(u32 *)arg;
- case IVTV_IOC_DMA_FRAME:
- case VIDEO_GET_PTS:
- case VIDEO_GET_FRAME_COUNT:
- case VIDEO_GET_EVENT:
- case VIDEO_PLAY:
- case VIDEO_STOP:
- case VIDEO_FREEZE:
- case VIDEO_CONTINUE:
- case VIDEO_COMMAND:
- case VIDEO_TRY_COMMAND:
- return ivtv_decoder_ioctls(filp, cmd, arg);
+ if ((val == 0 && itv->options.newi2c) || (val & 0x01))
+ ivtv_reset_ir_gpio(itv);
+ if (val & 0x02)
+ itv->video_dec_func(itv, cmd, NULL);
+ break;
+ }
- case 0x00005401: /* Handle isatty() calls */
- return -EINVAL;
default:
- return v4l_compat_translate_ioctl(inode, filp, cmd, arg,
- ivtv_v4l2_do_ioctl);
+ return -EINVAL;
}
return 0;
}
@@ -1741,7 +1753,11 @@ static int ivtv_v4l2_do_ioctl(struct inode *inode, struct file *filp,
static int ivtv_serialized_ioctl(struct ivtv *itv, struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- /* Filter dvb ioctls that cannot be handled by video_usercopy */
+ struct video_device *vfd = video_devdata(filp);
+ struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data;
+ int ret;
+
+ /* Filter dvb ioctls that cannot be handled by the v4l ioctl framework */
switch (cmd) {
case VIDEO_SELECT_SOURCE:
IVTV_DEBUG_IOCTL("VIDEO_SELECT_SOURCE\n");
@@ -1770,10 +1786,47 @@ static int ivtv_serialized_ioctl(struct ivtv *itv, struct inode *inode, struct f
ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode);
return 0;
+ case IVTV_IOC_DMA_FRAME:
+ case VIDEO_GET_PTS:
+ case VIDEO_GET_FRAME_COUNT:
+ case VIDEO_GET_EVENT:
+ case VIDEO_PLAY:
+ case VIDEO_STOP:
+ case VIDEO_FREEZE:
+ case VIDEO_CONTINUE:
+ case VIDEO_COMMAND:
+ case VIDEO_TRY_COMMAND:
+ return ivtv_decoder_ioctls(filp, cmd, (void *)arg);
+
default:
break;
}
- return video_usercopy(inode, filp, cmd, arg, ivtv_v4l2_do_ioctl);
+
+ /* check priority */
+ switch (cmd) {
+ case VIDIOC_S_CTRL:
+ case VIDIOC_S_STD:
+ case VIDIOC_S_INPUT:
+ case VIDIOC_S_OUTPUT:
+ case VIDIOC_S_TUNER:
+ case VIDIOC_S_FREQUENCY:
+ case VIDIOC_S_FMT:
+ case VIDIOC_S_CROP:
+ case VIDIOC_S_AUDIO:
+ case VIDIOC_S_AUDOUT:
+ case VIDIOC_S_EXT_CTRLS:
+ case VIDIOC_S_FBUF:
+ case VIDIOC_OVERLAY:
+ ret = v4l2_prio_check(&itv->prio, &id->prio);
+ if (ret)
+ return ret;
+ }
+
+ if (ivtv_debug & IVTV_DBGFLG_IOCTL)
+ vfd->debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG;
+ ret = video_ioctl2(inode, filp, cmd, arg);
+ vfd->debug = 0;
+ return ret;
}
int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
@@ -1788,3 +1841,70 @@ int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
mutex_unlock(&itv->serialize_lock);
return res;
}
+
+void ivtv_set_funcs(struct video_device *vdev)
+{
+ vdev->vidioc_querycap = ivtv_querycap;
+ vdev->vidioc_g_priority = ivtv_g_priority;
+ vdev->vidioc_s_priority = ivtv_s_priority;
+ vdev->vidioc_s_audio = ivtv_s_audio;
+ vdev->vidioc_g_audio = ivtv_g_audio;
+ vdev->vidioc_enumaudio = ivtv_enumaudio;
+ vdev->vidioc_s_audout = ivtv_s_audout;
+ vdev->vidioc_g_audout = ivtv_g_audout;
+ vdev->vidioc_enum_input = ivtv_enum_input;
+ vdev->vidioc_enum_output = ivtv_enum_output;
+ vdev->vidioc_enumaudout = ivtv_enumaudout;
+ vdev->vidioc_cropcap = ivtv_cropcap;
+ vdev->vidioc_s_crop = ivtv_s_crop;
+ vdev->vidioc_g_crop = ivtv_g_crop;
+ vdev->vidioc_g_input = ivtv_g_input;
+ vdev->vidioc_s_input = ivtv_s_input;
+ vdev->vidioc_g_output = ivtv_g_output;
+ vdev->vidioc_s_output = ivtv_s_output;
+ vdev->vidioc_g_frequency = ivtv_g_frequency;
+ vdev->vidioc_s_frequency = ivtv_s_frequency;
+ vdev->vidioc_s_tuner = ivtv_s_tuner;
+ vdev->vidioc_g_tuner = ivtv_g_tuner;
+ vdev->vidioc_g_enc_index = ivtv_g_enc_index;
+ vdev->vidioc_g_fbuf = ivtv_g_fbuf;
+ vdev->vidioc_s_fbuf = ivtv_s_fbuf;
+ vdev->vidioc_g_std = ivtv_g_std;
+ vdev->vidioc_s_std = ivtv_s_std;
+ vdev->vidioc_overlay = ivtv_overlay;
+ vdev->vidioc_log_status = ivtv_log_status;
+ vdev->vidioc_enum_fmt_vid_cap = ivtv_enum_fmt_vid_cap;
+ vdev->vidioc_encoder_cmd = ivtv_encoder_cmd;
+ vdev->vidioc_try_encoder_cmd = ivtv_try_encoder_cmd;
+ vdev->vidioc_enum_fmt_vid_out = ivtv_enum_fmt_vid_out;
+ vdev->vidioc_g_fmt_vid_cap = ivtv_g_fmt_vid_cap;
+ vdev->vidioc_g_fmt_vbi_cap = ivtv_g_fmt_vbi_cap;
+ vdev->vidioc_g_fmt_sliced_vbi_cap = ivtv_g_fmt_sliced_vbi_cap;
+ vdev->vidioc_g_fmt_vid_out = ivtv_g_fmt_vid_out;
+ vdev->vidioc_g_fmt_vid_out_overlay = ivtv_g_fmt_vid_out_overlay;
+ vdev->vidioc_g_fmt_sliced_vbi_out = ivtv_g_fmt_sliced_vbi_out;
+ vdev->vidioc_s_fmt_vid_cap = ivtv_s_fmt_vid_cap;
+ vdev->vidioc_s_fmt_vbi_cap = ivtv_s_fmt_vbi_cap;
+ vdev->vidioc_s_fmt_sliced_vbi_cap = ivtv_s_fmt_sliced_vbi_cap;
+ vdev->vidioc_s_fmt_vid_out = ivtv_s_fmt_vid_out;
+ vdev->vidioc_s_fmt_vid_out_overlay = ivtv_s_fmt_vid_out_overlay;
+ vdev->vidioc_s_fmt_sliced_vbi_out = ivtv_s_fmt_sliced_vbi_out;
+ vdev->vidioc_try_fmt_vid_cap = ivtv_try_fmt_vid_cap;
+ vdev->vidioc_try_fmt_vbi_cap = ivtv_try_fmt_vbi_cap;
+ vdev->vidioc_try_fmt_sliced_vbi_cap = ivtv_try_fmt_sliced_vbi_cap;
+ vdev->vidioc_try_fmt_vid_out = ivtv_try_fmt_vid_out;
+ vdev->vidioc_try_fmt_vid_out_overlay = ivtv_try_fmt_vid_out_overlay;
+ vdev->vidioc_try_fmt_sliced_vbi_out = ivtv_try_fmt_sliced_vbi_out;
+ vdev->vidioc_g_sliced_vbi_cap = ivtv_g_sliced_vbi_cap;
+ vdev->vidioc_g_chip_ident = ivtv_g_chip_ident;
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ vdev->vidioc_g_register = ivtv_g_register;
+ vdev->vidioc_s_register = ivtv_s_register;
+#endif
+ vdev->vidioc_default = ivtv_default;
+ vdev->vidioc_queryctrl = ivtv_queryctrl;
+ vdev->vidioc_querymenu = ivtv_querymenu;
+ vdev->vidioc_g_ext_ctrls = ivtv_g_ext_ctrls;
+ vdev->vidioc_s_ext_ctrls = ivtv_s_ext_ctrls;
+ vdev->vidioc_try_ext_ctrls = ivtv_try_ext_ctrls;
+}
diff --git a/linux/drivers/media/video/ivtv/ivtv-ioctl.h b/linux/drivers/media/video/ivtv/ivtv-ioctl.h
index 4e67f0ed1..70188588b 100644
--- a/linux/drivers/media/video/ivtv/ivtv-ioctl.h
+++ b/linux/drivers/media/video/ivtv/ivtv-ioctl.h
@@ -24,10 +24,13 @@
u16 ivtv_service2vbi(int type);
void ivtv_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal);
u16 ivtv_get_service_set(struct v4l2_sliced_vbi_format *fmt);
-int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
- unsigned long arg);
-int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void *arg);
void ivtv_set_osd_alpha(struct ivtv *itv);
int ivtv_set_speed(struct ivtv *itv, int speed);
+void ivtv_set_funcs(struct video_device *vdev);
+int ivtv_s_std(struct file *file, void *fh, v4l2_std_id *std);
+int ivtv_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf);
+int ivtv_s_input(struct file *file, void *fh, unsigned int inp);
+int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg);
#endif
diff --git a/linux/drivers/media/video/ivtv/ivtv-irq.c b/linux/drivers/media/video/ivtv/ivtv-irq.c
index 41066e87f..d5ac766c1 100644
--- a/linux/drivers/media/video/ivtv/ivtv-irq.c
+++ b/linux/drivers/media/video/ivtv/ivtv-irq.c
@@ -237,14 +237,14 @@ static void dma_post(struct ivtv_stream *s)
struct ivtv_buffer *buf = NULL;
struct list_head *p;
u32 offset;
- u32 *u32buf;
+ __le32 *u32buf;
int x = 0;
IVTV_DEBUG_HI_DMA("%s %s completed (%x)\n", ivtv_use_pio(s) ? "PIO" : "DMA",
s->name, s->dma_offset);
list_for_each(p, &s->q_dma.list) {
buf = list_entry(p, struct ivtv_buffer, list);
- u32buf = (u32 *)buf->buf;
+ u32buf = (__le32 *)buf->buf;
/* Sync Buffer */
ivtv_buf_sync_for_cpu(s, buf);
@@ -450,7 +450,7 @@ static void ivtv_dma_enc_start(struct ivtv_stream *s)
}
s->dma_xfer_cnt++;
- memcpy(s->sg_processing, s->sg_pending, sizeof(struct ivtv_sg_element) * s->sg_pending_size);
+ memcpy(s->sg_processing, s->sg_pending, sizeof(struct ivtv_sg_host_element) * s->sg_pending_size);
s->sg_processing_size = s->sg_pending_size;
s->sg_pending_size = 0;
s->sg_processed = 0;
@@ -479,7 +479,7 @@ static void ivtv_dma_dec_start(struct ivtv_stream *s)
if (s->q_predma.bytesused)
ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused);
s->dma_xfer_cnt++;
- memcpy(s->sg_processing, s->sg_pending, sizeof(struct ivtv_sg_element) * s->sg_pending_size);
+ memcpy(s->sg_processing, s->sg_pending, sizeof(struct ivtv_sg_host_element) * s->sg_pending_size);
s->sg_processing_size = s->sg_pending_size;
s->sg_pending_size = 0;
s->sg_processed = 0;
diff --git a/linux/drivers/media/video/ivtv/ivtv-queue.c b/linux/drivers/media/video/ivtv/ivtv-queue.c
index fc8b1eaa3..71bd13e22 100644
--- a/linux/drivers/media/video/ivtv/ivtv-queue.c
+++ b/linux/drivers/media/video/ivtv/ivtv-queue.c
@@ -193,7 +193,7 @@ void ivtv_flush_queues(struct ivtv_stream *s)
int ivtv_stream_alloc(struct ivtv_stream *s)
{
struct ivtv *itv = s->itv;
- int SGsize = sizeof(struct ivtv_sg_element) * s->buffers;
+ int SGsize = sizeof(struct ivtv_sg_host_element) * s->buffers;
int i;
if (s->buffers == 0)
diff --git a/linux/drivers/media/video/ivtv/ivtv-streams.c b/linux/drivers/media/video/ivtv/ivtv-streams.c
index 01f546083..f8883b487 100644
--- a/linux/drivers/media/video/ivtv/ivtv-streams.c
+++ b/linux/drivers/media/video/ivtv/ivtv-streams.c
@@ -49,9 +49,7 @@ static const struct file_operations ivtv_v4l2_enc_fops = {
.write = ivtv_v4l2_write,
.open = ivtv_v4l2_open,
.ioctl = ivtv_v4l2_ioctl,
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11)
.compat_ioctl = v4l_compat_ioctl32,
-#endif
.release = ivtv_v4l2_close,
.poll = ivtv_v4l2_enc_poll,
};
@@ -62,9 +60,7 @@ static const struct file_operations ivtv_v4l2_dec_fops = {
.write = ivtv_v4l2_write,
.open = ivtv_v4l2_open,
.ioctl = ivtv_v4l2_ioctl,
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11)
.compat_ioctl = v4l_compat_ioctl32,
-#endif
.release = ivtv_v4l2_close,
.poll = ivtv_v4l2_dec_poll,
};
@@ -224,7 +220,8 @@ static int ivtv_prep_dev(struct ivtv *itv, int type)
s->v4l2dev->dev = &itv->dev->dev;
s->v4l2dev->fops = ivtv_stream_info[type].fops;
s->v4l2dev->release = video_device_release;
-
+ s->v4l2dev->tvnorms = V4L2_STD_ALL;
+ ivtv_set_funcs(s->v4l2dev);
return 0;
}
diff --git a/linux/drivers/media/video/ivtv/ivtv-yuv.c b/linux/drivers/media/video/ivtv/ivtv-yuv.c
index a9417f6e4..3092ff1d0 100644
--- a/linux/drivers/media/video/ivtv/ivtv-yuv.c
+++ b/linux/drivers/media/video/ivtv/ivtv-yuv.c
@@ -1116,7 +1116,7 @@ void ivtv_yuv_setup_stream_frame(struct ivtv *itv)
}
/* Attempt to dma a frame from a user buffer */
-int ivtv_yuv_udma_stream_frame(struct ivtv *itv, void *src)
+int ivtv_yuv_udma_stream_frame(struct ivtv *itv, void __user *src)
{
struct yuv_playback_info *yi = &itv->yuv_info;
struct ivtv_dma_frame dma_args;
diff --git a/linux/drivers/media/video/ivtv/ivtv-yuv.h b/linux/drivers/media/video/ivtv/ivtv-yuv.h
index 2fe5f1250..ca5173fbf 100644
--- a/linux/drivers/media/video/ivtv/ivtv-yuv.h
+++ b/linux/drivers/media/video/ivtv/ivtv-yuv.h
@@ -35,7 +35,7 @@ extern const u32 yuv_offset[IVTV_YUV_BUFFERS];
int ivtv_yuv_filter_check(struct ivtv *itv);
void ivtv_yuv_setup_stream_frame(struct ivtv *itv);
-int ivtv_yuv_udma_stream_frame(struct ivtv *itv, void *src);
+int ivtv_yuv_udma_stream_frame(struct ivtv *itv, void __user *src);
void ivtv_yuv_frame_complete(struct ivtv *itv);
int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args);
void ivtv_yuv_close(struct ivtv *itv);
diff --git a/linux/drivers/media/video/ivtv/ivtvfb.c b/linux/drivers/media/video/ivtv/ivtvfb.c
index e8dbee443..14f93341f 100644
--- a/linux/drivers/media/video/ivtv/ivtvfb.c
+++ b/linux/drivers/media/video/ivtv/ivtvfb.c
@@ -789,6 +789,9 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv)
else
var->pixclock = pixclock;
+ itv->osd_rect.width = var->xres;
+ itv->osd_rect.height = var->yres;
+
IVTVFB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n",
var->xres, var->yres,
var->xres_virtual, var->yres_virtual,
diff --git a/linux/drivers/media/video/m52790.c b/linux/drivers/media/video/m52790.c
index 6cca77680..87e948caf 100644
--- a/linux/drivers/media/video/m52790.c
+++ b/linux/drivers/media/video/m52790.c
@@ -31,10 +31,6 @@
#include <media/v4l2-common.h>
#include <media/v4l2-chip-ident.h>
#include <media/v4l2-i2c-drv.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
-#include "i2c-compat.h"
-#include <linux/slab.h>
-#endif
#include "compat.h"
MODULE_DESCRIPTION("i2c device driver for m52790 A/V switch");
@@ -44,10 +40,6 @@ MODULE_LICENSE("GPL");
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
static unsigned short normal_i2c[] = { 0x90 >> 1, I2C_CLIENT_END };
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 13)
-static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
-#endif
-
I2C_CLIENT_INSMOD;
#endif
@@ -149,8 +141,10 @@ static int m52790_probe(struct i2c_client *client,
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -EIO;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
snprintf(client->name, sizeof(client->name) - 1, "m52790");
+#endif
v4l_info(client, "chip found @ 0x%x (%s)\n",
client->addr << 1, client->adapter->name);
@@ -173,14 +167,21 @@ static int m52790_remove(struct i2c_client *client)
/* ----------------------------------------------------------------------- */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+static const struct i2c_device_id m52790_id[] = {
+ { "m52790", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, m52790_id);
+
+#endif
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.name = "m52790",
.driverid = I2C_DRIVERID_M52790,
.command = m52790_command,
.probe = m52790_probe,
.remove = m52790_remove,
-};
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
-EXPORT_NO_SYMBOLS;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ .id_table = m52790_id,
#endif
+};
diff --git a/linux/drivers/media/video/msp3400-driver.c b/linux/drivers/media/video/msp3400-driver.c
index 4ae9a5acf..cd92f1f68 100644
--- a/linux/drivers/media/video/msp3400-driver.c
+++ b/linux/drivers/media/video/msp3400-driver.c
@@ -57,17 +57,12 @@
#include <media/v4l2-i2c-drv-legacy.h>
#include <media/tvaudio.h>
#include <media/msp3400.h>
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
#include <linux/kthread.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
#include <linux/suspend.h>
#else
#include <linux/freezer.h>
#endif
-#endif
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
-#include "i2c-compat.h"
-#endif
#include "compat.h"
#include "msp3400-driver.h"
@@ -90,7 +85,6 @@ int msp_dolby;
int msp_stereo_thresh = 0x190; /* a2 threshold for stereo/bilingual
(msp34xxg only) 0x00a0-0x03c0 */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
/* read-only */
module_param(opmode, int, 0444);
@@ -101,15 +95,6 @@ module_param_named(stereo_threshold, msp_stereo_thresh, int, 0644);
module_param_named(standard, msp_standard, int, 0644);
module_param_named(amsound, msp_amsound, bool, 0644);
module_param_named(dolby, msp_dolby, bool, 0644);
-#else
-MODULE_PARM(opmode, "i");
-MODULE_PARM(msp_once, "i");
-MODULE_PARM(msp_debug, "i");
-MODULE_PARM(msp_stereo_thresh, "i");
-MODULE_PARM(msp_standard, "i");
-MODULE_PARM(msp_amsound, "i");
-MODULE_PARM(msp_dolby, "i");
-#endif
MODULE_PARM_DESC(opmode, "Forces a MSP3400 opmode. 0=Manual, 1=Autodetect, 2=Autodetect and autoselect");
MODULE_PARM_DESC(once, "No continuous stereo monitoring");
@@ -130,9 +115,7 @@ MODULE_PARM_DESC(dolby, "Activates Dolby processsing");
/* Addresses to scan */
static unsigned short normal_i2c[] = { 0x80 >> 1, 0x88 >> 1, I2C_CLIENT_END };
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 13)
-static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
-#endif
+
I2C_CLIENT_INSMOD;
/* ----------------------------------------------------------------------- */
@@ -356,24 +339,6 @@ void msp_set_audio(struct i2c_client *client)
/* ------------------------------------------------------------------------ */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
-static void msp_setup_thread(struct msp_state *state)
-{
- daemonize();
- exit_files(current);
- reparent_to_init();
-
- spin_lock_irq(SIGMASK_LOCK(current));
- sigfillset(&current->blocked);
- spin_unlock_irq(SIGMASK_LOCK(current));
- strcpy(current->comm, "msp3400");
-
- state->kthread = current;
- if (state->notify != NULL)
- up(state->notify);
-}
-#endif
-
static void msp_wake_thread(struct i2c_client *client)
{
struct msp_state *state = i2c_get_clientdata(client);
@@ -390,11 +355,7 @@ int msp_sleep(struct msp_state *state, int timeout)
DECLARE_WAITQUEUE(wait, current);
add_wait_queue(&state->wq, &wait);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
- if (!(state->rmmod || signal_pending(current))) {
-#else
if (!kthread_should_stop()) {
-#endif
if (timeout < 0) {
set_current_state(TASK_INTERRUPTIBLE);
schedule();
@@ -859,7 +820,12 @@ static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id)
int msp_product, msp_prod_hi, msp_prod_lo;
int msp_rom;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
snprintf(client->name, sizeof(client->name) - 1, "msp3400");
+#else
+ if (!id)
+ strlcpy(client->name, "msp3400", sizeof(client->name));
+#endif
if (msp_reset(client) == -1) {
v4l_dbg(1, msp_debug, client, "msp3400 not found\n");
@@ -912,9 +878,11 @@ static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id)
msp_revision = (state->rev1 & 0x0f) + '@';
msp_hard = ((state->rev1 >> 8) & 0xff) + '@';
msp_rom = state->rev2 & 0x1f;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
snprintf(client->name, sizeof(client->name), "MSP%d4%02d%c-%c%d",
msp_family, msp_product,
msp_revision, msp_hard, msp_rom);
+#endif
/* Rev B=2, C=3, D=4, G=7 */
state->ident = msp_family * 10000 + 4000 + msp_product * 10 +
msp_revision - '@';
@@ -979,7 +947,9 @@ static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id)
}
/* hello world :-) */
- v4l_info(client, "%s found @ 0x%x (%s)\n", client->name,
+ v4l_info(client, "MSP%d4%02d%c-%c%d found @ 0x%x (%s)\n",
+ msp_family, msp_product,
+ msp_revision, msp_hard, msp_rom,
client->addr << 1, client->adapter->name);
v4l_info(client, "%s ", client->name);
if (state->has_nicam && state->has_radio)
@@ -1009,20 +979,10 @@ static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id)
/* startup control thread if needed */
if (thread_func) {
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
state->kthread = kthread_run(thread_func, client, "msp34xx");
if (IS_ERR(state->kthread))
v4l_warn(client, "kernel_thread() failed\n");
-#else
- DECLARE_MUTEX_LOCKED(sem);
-
- state->kthread = NULL;
- state->notify = &sem;
- kernel_thread(thread_func, client, 0);
- down(&sem);
- state->notify = NULL;
-#endif
msp_wake_thread(client);
}
return 0;
@@ -1034,20 +994,8 @@ static int msp_remove(struct i2c_client *client)
/* shutdown control thread */
if (state->kthread) {
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
- DECLARE_MUTEX_LOCKED(sem);
-#endif
state->restart = 1;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
- /* shutdown control thread */
- state->notify = &sem;
- state->rmmod = 1;
- wake_up_interruptible(&state->wq);
- down(&sem);
- state->notify = NULL;
-#else
kthread_stop(state->kthread);
-#endif
}
msp_reset(client);
@@ -1057,6 +1005,14 @@ static int msp_remove(struct i2c_client *client)
/* ----------------------------------------------------------------------- */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+static const struct i2c_device_id msp_id[] = {
+ { "msp3400", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, msp_id);
+
+#endif
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.name = "msp3400",
.driverid = I2C_DRIVERID_MSP3400,
@@ -1065,11 +1021,10 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.remove = msp_remove,
.suspend = msp_suspend,
.resume = msp_resume,
-};
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
-EXPORT_NO_SYMBOLS;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ .id_table = msp_id,
#endif
+};
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
diff --git a/linux/drivers/media/video/msp3400-driver.h b/linux/drivers/media/video/msp3400-driver.h
index 20337567b..ab69a290e 100644
--- a/linux/drivers/media/video/msp3400-driver.h
+++ b/linux/drivers/media/video/msp3400-driver.h
@@ -92,10 +92,6 @@ struct msp_state {
/* thread */
struct task_struct *kthread;
wait_queue_head_t wq;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
- struct semaphore *notify;
- int rmmod:1;
-#endif
unsigned int restart:1;
unsigned int watch_stereo:1;
};
diff --git a/linux/drivers/media/video/msp3400-kthreads.c b/linux/drivers/media/video/msp3400-kthreads.c
index 0280feaac..ba19edac0 100644
--- a/linux/drivers/media/video/msp3400-kthreads.c
+++ b/linux/drivers/media/video/msp3400-kthreads.c
@@ -31,13 +31,8 @@
#include <linux/videodev2.h>
#include <media/v4l2-common.h>
#include <media/msp3400.h>
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
#include <linux/kthread.h>
#include <linux/suspend.h>
-#endif
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
-#include "i2c-compat.h"
-#endif
#include "compat.h"
#include "msp3400-driver.h"
@@ -488,10 +483,6 @@ int msp3400c_thread(void *data)
struct msp3400c_carrier_detect *cd;
int count, max1, max2, val1, val2, val, i;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
- msp_setup_thread(state);
-#endif
-
v4l_dbg(1, msp_debug, client, "msp3400 daemon started\n");
set_freezable();
for (;;) {
@@ -502,11 +493,7 @@ int msp3400c_thread(void *data)
restart:
v4l_dbg(2, msp_debug, client, "thread: restart scan\n");
state->restart = 0;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
- if (state->rmmod || signal_pending(current))
-#else
if (kthread_should_stop())
-#endif
break;
if (state->radio || MSP_MODE_EXTERN == state->mode) {
@@ -669,12 +656,6 @@ no_second:
}
}
v4l_dbg(1, msp_debug, client, "thread: exit\n");
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
- state->kthread = NULL;
-
- if (state->notify != NULL)
- up(state->notify);
-#endif
return 0;
}
@@ -685,9 +666,6 @@ int msp3410d_thread(void *data)
struct msp_state *state = i2c_get_clientdata(client);
int val, i, std, count;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
- msp_setup_thread(state);
-#endif
v4l_dbg(1, msp_debug, client, "msp3410 daemon started\n");
set_freezable();
for (;;) {
@@ -698,11 +676,7 @@ int msp3410d_thread(void *data)
restart:
v4l_dbg(2, msp_debug, client, "thread: restart scan\n");
state->restart = 0;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
- if (state->rmmod || signal_pending(current))
-#else
if (kthread_should_stop())
-#endif
break;
if (state->mode == MSP_MODE_EXTERN) {
@@ -842,12 +816,6 @@ restart:
}
}
v4l_dbg(1, msp_debug, client, "thread: exit\n");
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
- state->kthread = NULL;
-
- if (state->notify != NULL)
- up(state->notify);
-#endif
return 0;
}
@@ -993,9 +961,6 @@ int msp34xxg_thread(void *data)
struct msp_state *state = i2c_get_clientdata(client);
int val, i;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
- msp_setup_thread(state);
-#endif
v4l_dbg(1, msp_debug, client, "msp34xxg daemon started\n");
set_freezable();
for (;;) {
@@ -1006,11 +971,7 @@ int msp34xxg_thread(void *data)
restart:
v4l_dbg(1, msp_debug, client, "thread: restart scan\n");
state->restart = 0;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
- if (state->rmmod || signal_pending(current))
-#else
if (kthread_should_stop())
-#endif
break;
if (state->mode == MSP_MODE_EXTERN) {
@@ -1087,12 +1048,6 @@ unmute:
}
}
v4l_dbg(1, msp_debug, client, "thread: exit\n");
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
- state->kthread = NULL;
-
- if (state->notify != NULL)
- up(state->notify);
-#endif
return 0;
}
diff --git a/linux/drivers/media/video/mt9m001.c b/linux/drivers/media/video/mt9m001.c
index ee4349954..089ce311f 100644
--- a/linux/drivers/media/video/mt9m001.c
+++ b/linux/drivers/media/video/mt9m001.c
@@ -694,11 +694,13 @@ static int mt9m001_remove(struct i2c_client *client)
return 0;
}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
static const struct i2c_device_id mt9m001_id[] = {
{ "mt9m001", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, mt9m001_id);
+#endif
static struct i2c_driver mt9m001_i2c_driver = {
.driver = {
@@ -706,7 +708,9 @@ static struct i2c_driver mt9m001_i2c_driver = {
},
.probe = mt9m001_probe,
.remove = mt9m001_remove,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
.id_table = mt9m001_id,
+#endif
};
static int __init mt9m001_mod_init(void)
diff --git a/linux/drivers/media/video/mt9v022.c b/linux/drivers/media/video/mt9v022.c
index 1658fe590..1ff36edd7 100644
--- a/linux/drivers/media/video/mt9v022.c
+++ b/linux/drivers/media/video/mt9v022.c
@@ -815,12 +815,13 @@ static int mt9v022_remove(struct i2c_client *client)
return 0;
}
-
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
static const struct i2c_device_id mt9v022_id[] = {
{ "mt9v022", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, mt9v022_id);
+#endif
static struct i2c_driver mt9v022_i2c_driver = {
.driver = {
@@ -828,7 +829,9 @@ static struct i2c_driver mt9v022_i2c_driver = {
},
.probe = mt9v022_probe,
.remove = mt9v022_remove,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
.id_table = mt9v022_id,
+#endif
};
static int __init mt9v022_mod_init(void)
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c
index f78bc351f..cbf848e82 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c
@@ -2030,7 +2030,8 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
case V4L2_CTRL_TYPE_MENU:
ciptr->type = pvr2_ctl_enum;
ciptr->def.type_enum.value_names =
- cx2341x_ctrl_get_menu(ciptr->v4l_id);
+ cx2341x_ctrl_get_menu(&hdw->enc_ctl_state,
+ ciptr->v4l_id);
for (cnt1 = 0;
ciptr->def.type_enum.value_names[cnt1] != NULL;
cnt1++) { }
@@ -2476,22 +2477,38 @@ static int pvr2_hdw_commit_execute(struct pvr2_hdw *hdw)
struct pvr2_ctrl *cptr;
int disruptive_change;
- /* When video standard changes, reset the hres and vres values -
- but if the user has pending changes there, then let the changes
- take priority. */
+ /* Handle some required side effects when the video standard is
+ changed.... */
if (hdw->std_dirty) {
- /* Rewrite the vertical resolution to be appropriate to the
- video standard that has been selected. */
int nvres;
+ int gop_size;
if (hdw->std_mask_cur & V4L2_STD_525_60) {
nvres = 480;
+ gop_size = 15;
} else {
nvres = 576;
+ gop_size = 12;
}
+ /* Rewrite the vertical resolution to be appropriate to the
+ video standard that has been selected. */
if (nvres != hdw->res_ver_val) {
hdw->res_ver_val = nvres;
hdw->res_ver_dirty = !0;
}
+ /* Rewrite the GOP size to be appropriate to the video
+ standard that has been selected. */
+ if (gop_size != hdw->enc_ctl_state.video_gop_size) {
+ struct v4l2_ext_controls cs;
+ struct v4l2_ext_control c1;
+ memset(&cs, 0, sizeof(cs));
+ memset(&c1, 0, sizeof(c1));
+ cs.controls = &c1;
+ cs.count = 1;
+ c1.id = V4L2_CID_MPEG_VIDEO_GOP_SIZE;
+ c1.value = gop_size;
+ cx2341x_ext_ctrls(&hdw->enc_ctl_state, 0, &cs,
+ VIDIOC_S_EXT_CTRLS);
+ }
}
if (hdw->input_dirty && hdw->state_pathway_ok &&
@@ -3103,9 +3120,6 @@ static int pvr2_send_request_ex(struct pvr2_hdw *hdw,
write_len,
pvr2_ctl_write_complete,
hdw);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
- hdw->ctl_write_urb->transfer_flags |= URB_ASYNC_UNLINK;
-#endif
hdw->ctl_write_urb->actual_length = 0;
hdw->ctl_write_pend_flag = !0;
status = usb_submit_urb(hdw->ctl_write_urb,GFP_KERNEL);
@@ -3130,9 +3144,6 @@ static int pvr2_send_request_ex(struct pvr2_hdw *hdw,
read_len,
pvr2_ctl_read_complete,
hdw);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
- hdw->ctl_read_urb->transfer_flags |= URB_ASYNC_UNLINK;
-#endif
hdw->ctl_read_urb->actual_length = 0;
hdw->ctl_read_pend_flag = !0;
status = usb_submit_urb(hdw->ctl_read_urb,GFP_KERNEL);
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
index 362ec49f5..797017066 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
@@ -1017,9 +1017,6 @@ static int pvr2_i2c_detach_inform(struct i2c_client *client)
}
static struct i2c_algorithm pvr2_i2c_algo_template = {
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
- .id = I2C_HW_B_BT848,
-#endif
.master_xfer = pvr2_i2c_xfer,
.functionality = pvr2_i2c_functionality,
};
@@ -1081,9 +1078,6 @@ void pvr2_i2c_core_init(struct pvr2_hdw *hdw)
memcpy(&hdw->i2c_algo,&pvr2_i2c_algo_template,sizeof(hdw->i2c_algo));
strlcpy(hdw->i2c_adap.name,hdw->name,sizeof(hdw->i2c_adap.name));
hdw->i2c_adap.dev.parent = &hdw->usb_dev->dev;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
- strlcpy(hdw->i2c_algo.name,hdw->name,sizeof(hdw->i2c_algo.name));
-#endif
hdw->i2c_adap.algo = &hdw->i2c_algo;
hdw->i2c_adap.algo_data = hdw;
hdw->i2c_pend_mask = 0;
diff --git a/linux/drivers/media/video/pwc/pwc-ctrl.c b/linux/drivers/media/video/pwc/pwc-ctrl.c
index 04fbd2749..1cccd5c77 100644
--- a/linux/drivers/media/video/pwc/pwc-ctrl.c
+++ b/linux/drivers/media/video/pwc/pwc-ctrl.c
@@ -1255,8 +1255,6 @@ int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor)
exactly the same otherwise.
*/
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
-
/* define local variable for arg */
#define ARG_DEF(ARG_type, ARG_name)\
ARG_type *ARG_name = arg;
@@ -1269,25 +1267,6 @@ int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor)
/* copy local variable to arg */
#define ARG_OUT(ARG_name) /* nothing */
-#else
-
-#define ARG_DEF(ARG_type, ARG_name)\
- ARG_type ARG_name;
-#define ARG_IN(ARG_name)\
- if (copy_from_user(&ARG_name, arg, sizeof(ARG_name))) {\
- ret = -EFAULT;\
- break;\
- }
-#define ARGR(ARG_name) ARG_name
-#define ARGA(ARG_name) &ARG_name
-#define ARG_OUT(ARG_name)\
- if (copy_to_user(arg, &ARG_name, sizeof(ARG_name))) {\
- ret = -EFAULT;\
- break;\
- }
-
-#endif
-
int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
{
int ret = 0;
diff --git a/linux/drivers/media/video/pwc/pwc-if.c b/linux/drivers/media/video/pwc/pwc-if.c
index 8236b2b2d..c28490ae5 100644
--- a/linux/drivers/media/video/pwc/pwc-if.c
+++ b/linux/drivers/media/video/pwc/pwc-if.c
@@ -830,13 +830,9 @@ int pwc_isoc_init(struct pwc_device *pdev)
/* Get the current alternate interface, adjust packet size */
if (!udev->actconfig)
return -EFAULT;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,5)
- idesc = &udev->actconfig->interface[0]->altsetting[pdev->valternate];
-#else
intf = usb_ifnum_to_if(udev, 0);
if (intf)
idesc = usb_altnum_to_altsetting(intf, pdev->valternate);
-#endif
if (!idesc)
return -EFAULT;
@@ -845,11 +841,7 @@ int pwc_isoc_init(struct pwc_device *pdev)
pdev->vmax_packet_size = -1;
for (i = 0; i < idesc->desc.bNumEndpoints; i++) {
if ((idesc->endpoint[i].desc.bEndpointAddress & 0xF) == pdev->vendpoint) {
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11)
- pdev->vmax_packet_size = idesc->endpoint[i].desc.wMaxPacketSize;
-#else
pdev->vmax_packet_size = le16_to_cpu(idesc->endpoint[i].desc.wMaxPacketSize);
-#endif
break;
}
}
@@ -1472,15 +1464,9 @@ static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma)
pos += (unsigned long)pdev->image_data;
while (size > 0) {
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
- page = kvirt_to_pa(pos);
- if (remap_page_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
- return -EAGAIN;
-#else
page = vmalloc_to_pfn((void *)pos);
if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
return -EAGAIN;
-#endif
start += PAGE_SIZE;
pos += PAGE_SIZE;
if (size > PAGE_SIZE)
@@ -1508,13 +1494,8 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
int video_nr = -1; /* default: use next available device */
char serial_number[30], *name;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11)
- vendor_id = udev->descriptor.idVendor;
- product_id = udev->descriptor.idProduct;
-#else
vendor_id = le16_to_cpu(udev->descriptor.idVendor);
product_id = le16_to_cpu(udev->descriptor.idProduct);
-#endif
/* Check if we can handle this device */
PWC_DEBUG_PROBE("probe() called [%04X %04X], if %d\n",
@@ -1795,11 +1776,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
pdev->vdev->owner = THIS_MODULE;
video_set_drvdata(pdev->vdev, pdev);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11)
- pdev->release = udev->descriptor.bcdDevice;
-#else
pdev->release = le16_to_cpu(udev->descriptor.bcdDevice);
-#endif
PWC_DEBUG_PROBE("Release: %04x\n", pdev->release);
/* Now search device_hint[] table for a match, so we can hint a node number. */
@@ -1943,13 +1920,8 @@ module_param_named(trace, pwc_trace, int, 0644);
#endif
module_param(power_save, int, 0444);
module_param(compression, int, 0444);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
-module_param_array(leds, int, leds_nargs, 0444);
-module_param_array(dev_hint, charp, dev_hint_nargs, 0444);
-#else
module_param_array(leds, int, &leds_nargs, 0444);
module_param_array(dev_hint, charp, &dev_hint_nargs, 0444);
-#endif
MODULE_PARM_DESC(size, "Initial image size. One of sqcif, qsif, qcif, sif, cif, vga");
MODULE_PARM_DESC(fps, "Initial frames per second. Varies with model, useful range 5-30");
diff --git a/linux/drivers/media/video/pwc/pwc-ioctl.h b/linux/drivers/media/video/pwc/pwc-ioctl.h
index 58904acda..8c0cae7b3 100644
--- a/linux/drivers/media/video/pwc/pwc-ioctl.h
+++ b/linux/drivers/media/video/pwc/pwc-ioctl.h
@@ -54,11 +54,6 @@
#include <linux/types.h>
#include <linux/version.h>
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 10)
-/* Compatibility for older kernel */
-typedef __u16 __le16;
-#endif
-
/* Enumeration of image sizes */
#define PSZ_SQCIF 0x00
#define PSZ_QSIF 0x01
diff --git a/linux/drivers/media/video/pxa_camera.c b/linux/drivers/media/video/pxa_camera.c
index 7cc8e9b19..5ec5bb9a9 100644
--- a/linux/drivers/media/video/pxa_camera.c
+++ b/linux/drivers/media/video/pxa_camera.c
@@ -1019,12 +1019,12 @@ static int pxa_camera_probe(struct platform_device *pdev)
struct pxa_camera_dev *pcdev;
struct resource *res;
void __iomem *base;
- unsigned int irq;
+ int irq;
int err = 0;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_irq(pdev, 0);
- if (!res || !irq) {
+ if (!res || irq < 0) {
err = -ENODEV;
goto exit;
}
diff --git a/linux/drivers/media/video/s2255drv.c b/linux/drivers/media/video/s2255drv.c
new file mode 100644
index 000000000..aca8c3d90
--- /dev/null
+++ b/linux/drivers/media/video/s2255drv.c
@@ -0,0 +1,2487 @@
+/*
+ * s2255drv.c - a driver for the Sensoray 2255 USB video capture device
+ *
+ * Copyright (C) 2007-2008 by Sensoray Company Inc.
+ * Dean Anderson
+ *
+ * Some video buffer code based on vivi driver:
+ *
+ * Sensoray 2255 device supports 4 simultaneous channels.
+ * The channels are not "crossbar" inputs, they are physically
+ * attached to separate video decoders.
+ *
+ * Because of USB2.0 bandwidth limitations. There is only a
+ * certain amount of data which may be transferred at one time.
+ *
+ * Example maximum bandwidth utilization:
+ *
+ * -full size, color mode YUYV or YUV422P: 2 channels at once
+ *
+ * -full or half size Grey scale: all 4 channels at once
+ *
+ * -half size, color mode YUYV or YUV422P: all 4 channels at once
+ *
+ * -full size, color mode YUYV or YUV422P 1/2 frame rate: all 4 channels
+ * at once.
+ * (TODO: Incorporate videodev2 frame rate(FR) enumeration,
+ * which is currently experimental.)
+ *
+ * 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/firmware.h>
+#include <linux/kernel.h>
+#include <linux/mutex.h>
+#include <linux/videodev2.h>
+#include <linux/version.h>
+#include <media/videobuf-vmalloc.h>
+#include <media/v4l2-common.h>
+#include <linux/vmalloc.h>
+#include <linux/usb.h>
+#include "compat.h"
+
+#define FIRMWARE_FILE_NAME "f2255usb.bin"
+
+
+
+/* vendor request in */
+#define S2255_VR_IN 0
+/* vendor request out */
+#define S2255_VR_OUT 1
+/* firmware query */
+#define S2255_VR_FW 0x30
+/* USB endpoint number for configuring the device */
+#define S2255_CONFIG_EP 2
+/* maximum time for DSP to start responding after last FW word loaded(ms) */
+#define S2255_DSP_BOOTTIME 400
+/* maximum time to wait for firmware to load (ms) */
+#define S2255_LOAD_TIMEOUT (5000+S2255_DSP_BOOTTIME)
+#define S2255_DEF_BUFS 16
+#define MAX_CHANNELS 4
+#define FRAME_MARKER 0x2255DA4AL
+#define MAX_PIPE_USBBLOCK (40*1024)
+#define DEFAULT_PIPE_USBBLOCK (16*1024)
+#define MAX_CHANNELS 4
+#define MAX_PIPE_BUFFERS 1
+#define SYS_FRAMES 4
+/* maximum size is PAL full size plus room for the marker header(s) */
+#define SYS_FRAMES_MAXSIZE (720*288*2*2 + 4096)
+#define DEF_USB_BLOCK (4096)
+#define LINE_SZ_4CIFS_NTSC 640
+#define LINE_SZ_2CIFS_NTSC 640
+#define LINE_SZ_1CIFS_NTSC 320
+#define LINE_SZ_4CIFS_PAL 704
+#define LINE_SZ_2CIFS_PAL 704
+#define LINE_SZ_1CIFS_PAL 352
+#define NUM_LINES_4CIFS_NTSC 240
+#define NUM_LINES_2CIFS_NTSC 240
+#define NUM_LINES_1CIFS_NTSC 240
+#define NUM_LINES_4CIFS_PAL 288
+#define NUM_LINES_2CIFS_PAL 288
+#define NUM_LINES_1CIFS_PAL 288
+#define LINE_SZ_DEF 640
+#define NUM_LINES_DEF 240
+
+
+/* predefined settings */
+#define FORMAT_NTSC 1
+#define FORMAT_PAL 2
+
+#define SCALE_4CIFS 1 /* 640x480(NTSC) or 704x576(PAL) */
+#define SCALE_2CIFS 2 /* 640x240(NTSC) or 704x288(PAL) */
+#define SCALE_1CIFS 3 /* 320x240(NTSC) or 352x288(PAL) */
+
+#define COLOR_YUVPL 1 /* YUV planar */
+#define COLOR_YUVPK 2 /* YUV packed */
+#define COLOR_Y8 4 /* monochrome */
+
+/* frame decimation. Not implemented by V4L yet(experimental in V4L) */
+#define FDEC_1 1 /* capture every frame. default */
+#define FDEC_2 2 /* capture every 2nd frame */
+#define FDEC_3 3 /* capture every 3rd frame */
+#define FDEC_5 5 /* capture every 5th frame */
+
+/*-------------------------------------------------------
+ * Default mode parameters.
+ *-------------------------------------------------------*/
+#define DEF_SCALE SCALE_4CIFS
+#define DEF_COLOR COLOR_YUVPL
+#define DEF_FDEC FDEC_1
+#define DEF_BRIGHT 0
+#define DEF_CONTRAST 0x5c
+#define DEF_SATURATION 0x80
+#define DEF_HUE 0
+
+/* usb config commands */
+#define IN_DATA_TOKEN 0x2255c0de
+#define CMD_2255 0xc2255000
+#define CMD_SET_MODE (CMD_2255 | 0x10)
+#define CMD_START (CMD_2255 | 0x20)
+#define CMD_STOP (CMD_2255 | 0x30)
+#define CMD_STATUS (CMD_2255 | 0x40)
+
+struct s2255_mode {
+ u32 format; /* input video format (NTSC, PAL) */
+ u32 scale; /* output video scale */
+ u32 color; /* output video color format */
+ u32 fdec; /* frame decimation */
+ u32 bright; /* brightness */
+ u32 contrast; /* contrast */
+ u32 saturation; /* saturation */
+ u32 hue; /* hue (NTSC only)*/
+ u32 single; /* capture 1 frame at a time (!=0), continuously (==0)*/
+ u32 usb_block; /* block size. should be 4096 of DEF_USB_BLOCK */
+ u32 restart; /* if DSP requires restart */
+};
+
+/* frame structure */
+#define FRAME_STATE_UNUSED 0
+#define FRAME_STATE_FILLING 1
+#define FRAME_STATE_FULL 2
+
+
+struct s2255_framei {
+ unsigned long size;
+
+ unsigned long ulState; /* ulState ==0 unused, 1 being filled, 2 full */
+ void *lpvbits; /* image data */
+ unsigned long cur_size; /* current data copied to it */
+};
+
+/* image buffer structure */
+struct s2255_bufferi {
+ unsigned long dwFrames; /* number of frames in buffer */
+ struct s2255_framei frame[SYS_FRAMES]; /* array of FRAME structures */
+};
+
+#define DEF_MODEI_NTSC_CONT {FORMAT_NTSC, DEF_SCALE, DEF_COLOR, \
+ DEF_FDEC, DEF_BRIGHT, DEF_CONTRAST, DEF_SATURATION, \
+ DEF_HUE, 0, DEF_USB_BLOCK, 0 }
+
+struct s2255_dmaqueue {
+ struct list_head active;
+ /* thread for acquisition */
+ struct task_struct *kthread;
+ int frame;
+ struct s2255_dev *dev;
+ int channel;
+};
+
+/* for firmware loading, fw_state */
+#define S2255_FW_NOTLOADED 0
+#define S2255_FW_LOADED_DSPWAIT 1
+#define S2255_FW_SUCCESS 2
+#define S2255_FW_FAILED 3
+
+struct s2255_fw {
+ int fw_loaded;
+ int fw_size;
+ struct urb *fw_urb;
+ atomic_t fw_state;
+ void *pfw_data;
+ wait_queue_head_t wait_fw;
+ struct timer_list dsp_wait;
+ const struct firmware *fw;
+};
+
+struct s2255_pipeinfo {
+ u32 max_transfer_size;
+ u32 cur_transfer_size;
+ u8 *transfer_buffer;
+ u32 transfer_flags;;
+ u32 state;
+ u32 prev_state;
+ u32 urb_size;
+ void *stream_urb;
+ void *dev; /* back pointer to s2255_dev struct*/
+ u32 err_count;
+ u32 buf_index;
+ u32 idx;
+ u32 priority_set;
+};
+
+struct s2255_fmt; /*forward declaration */
+
+struct s2255_dev {
+ int frames;
+ int users[MAX_CHANNELS];
+ struct mutex lock;
+ struct mutex open_lock;
+ int resources[MAX_CHANNELS];
+ struct usb_device *udev;
+ struct usb_interface *interface;
+ u8 read_endpoint;
+
+ struct s2255_dmaqueue vidq[MAX_CHANNELS];
+ struct video_device *vdev[MAX_CHANNELS];
+ struct list_head s2255_devlist;
+ struct timer_list timer;
+ struct s2255_fw *fw_data;
+ int board_num;
+ int is_open;
+ struct s2255_pipeinfo pipes[MAX_PIPE_BUFFERS];
+ struct s2255_bufferi buffer[MAX_CHANNELS];
+ struct s2255_mode mode[MAX_CHANNELS];
+ const struct s2255_fmt *cur_fmt[MAX_CHANNELS];
+ int cur_frame[MAX_CHANNELS];
+ int last_frame[MAX_CHANNELS];
+ u32 cc; /* current channel */
+ int b_acquire[MAX_CHANNELS];
+ unsigned long req_image_size[MAX_CHANNELS];
+ int bad_payload[MAX_CHANNELS];
+ unsigned long frame_count[MAX_CHANNELS];
+ int frame_ready;
+ struct kref kref;
+ spinlock_t slock;
+};
+#define to_s2255_dev(d) container_of(d, struct s2255_dev, kref)
+
+struct s2255_fmt {
+ char *name;
+ u32 fourcc;
+ int depth;
+};
+
+/* 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 s2255_fh {
+ struct s2255_dev *dev;
+ unsigned int resources;
+ const struct s2255_fmt *fmt;
+ unsigned int width;
+ unsigned int height;
+ struct videobuf_queue vb_vidq;
+ enum v4l2_buf_type type;
+ int channel;
+ /* mode below is the desired mode.
+ mode in s2255_dev is the current mode that was last set */
+ struct s2255_mode mode;
+};
+
+#define S2255_MAX_USERS 1
+
+#define CUR_USB_FWVER 774 /* current cypress EEPROM firmware version */
+#define S2255_MAJOR_VERSION 1
+#define S2255_MINOR_VERSION 13
+#define S2255_RELEASE 0
+#define S2255_VERSION KERNEL_VERSION(S2255_MAJOR_VERSION, \
+ S2255_MINOR_VERSION, \
+ S2255_RELEASE)
+
+/* vendor ids */
+#define USB_S2255_VENDOR_ID 0x1943
+#define USB_S2255_PRODUCT_ID 0x2255
+#define S2255_NORMS (V4L2_STD_PAL | V4L2_STD_NTSC)
+/* frame prefix size (sent once every frame) */
+#define PREFIX_SIZE 512
+
+/* Channels on box are in reverse order */
+static unsigned long G_chnmap[MAX_CHANNELS] = { 3, 2, 1, 0 };
+
+static LIST_HEAD(s2255_devlist);
+
+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_dev *dev, unsigned long chn);
+static int s2255_stop_acquire(struct s2255_dev *dev, unsigned long chn);
+static void s2255_fillbuff(struct s2255_dev *dev, struct s2255_buffer *buf,
+ int chn);
+static int s2255_set_mode(struct s2255_dev *dev, unsigned long chn,
+ struct s2255_mode *mode);
+static int s2255_board_shutdown(struct s2255_dev *dev);
+static void s2255_exit_v4l(struct s2255_dev *dev);
+static void s2255_fwload_start(struct s2255_dev *dev);
+
+#define dprintk(level, fmt, arg...) \
+ do { \
+ if (*s2255_debug >= (level)) { \
+ printk(KERN_DEBUG "s2255: " fmt, ##arg); \
+ } \
+ } while (0)
+
+
+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 */
+
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "Debug level(0-100) default 0");
+module_param(vid_limit, int, 0);
+MODULE_PARM_DESC(vid_limit, "video memory limit(Mb)");
+module_param(video_nr, int, 0);
+MODULE_PARM_DESC(video_nr, "start video minor(-1 default autodetect)");
+
+/* USB device table */
+static struct usb_device_id s2255_table[] = {
+ {USB_DEVICE(USB_S2255_VENDOR_ID, USB_S2255_PRODUCT_ID)},
+ { } /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, s2255_table);
+
+
+#define BUFFER_TIMEOUT msecs_to_jiffies(400)
+
+/* supported controls */
+static struct v4l2_queryctrl s2255_qctrl[] = {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = -127,
+ .maximum = 128,
+ .step = 1,
+ .default_value = 0,
+ .flags = 0,
+ }, {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 0x1,
+ .default_value = DEF_CONTRAST,
+ .flags = 0,
+ }, {
+ .id = V4L2_CID_SATURATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Saturation",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 0x1,
+ .default_value = DEF_SATURATION,
+ .flags = 0,
+ }, {
+ .id = V4L2_CID_HUE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Hue",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 0x1,
+ .default_value = DEF_HUE,
+ .flags = 0,
+ }
+};
+
+static int qctl_regs[ARRAY_SIZE(s2255_qctrl)];
+
+/* image formats. */
+static const struct s2255_fmt formats[] = {
+ {
+ .name = "4:2:2, planar, YUV422P",
+ .fourcc = V4L2_PIX_FMT_YUV422P,
+ .depth = 16
+
+ }, {
+ .name = "4:2:2, packed, YUYV",
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .depth = 16
+
+ }, {
+ .name = "4:2:2, packed, UYVY",
+ .fourcc = V4L2_PIX_FMT_UYVY,
+ .depth = 16
+ }, {
+ .name = "8bpp GREY",
+ .fourcc = V4L2_PIX_FMT_GREY,
+ .depth = 8
+ }
+};
+
+static int norm_maxw(struct video_device *vdev)
+{
+ return (vdev->current_norm & V4L2_STD_NTSC) ?
+ LINE_SZ_4CIFS_NTSC : LINE_SZ_4CIFS_PAL;
+}
+
+static int norm_maxh(struct video_device *vdev)
+{
+ return (vdev->current_norm & V4L2_STD_NTSC) ?
+ (NUM_LINES_1CIFS_NTSC * 2) : (NUM_LINES_1CIFS_PAL * 2);
+}
+
+static int norm_minw(struct video_device *vdev)
+{
+ return (vdev->current_norm & V4L2_STD_NTSC) ?
+ LINE_SZ_1CIFS_NTSC : LINE_SZ_1CIFS_PAL;
+}
+
+static int norm_minh(struct video_device *vdev)
+{
+ return (vdev->current_norm & V4L2_STD_NTSC) ?
+ (NUM_LINES_1CIFS_NTSC) : (NUM_LINES_1CIFS_PAL);
+}
+
+
+/* converts 2255 planar format to yuyv or uyvy */
+static void planar422p_to_yuv_packed(const unsigned char *in,
+ unsigned char *out,
+ int width, int height,
+ int fmt)
+{
+ unsigned char *pY;
+ unsigned char *pCb;
+ unsigned char *pCr;
+ unsigned long size = height * width;
+ unsigned int i;
+ pY = (unsigned char *)in;
+ pCr = (unsigned char *)in + height * width;
+ pCb = (unsigned char *)in + height * width + (height * width / 2);
+ for (i = 0; i < size * 2; i += 4) {
+ out[i] = (fmt == V4L2_PIX_FMT_YUYV) ? *pY++ : *pCr++;
+ out[i + 1] = (fmt == V4L2_PIX_FMT_YUYV) ? *pCr++ : *pY++;
+ out[i + 2] = (fmt == V4L2_PIX_FMT_YUYV) ? *pY++ : *pCb++;
+ out[i + 3] = (fmt == V4L2_PIX_FMT_YUYV) ? *pCb++ : *pY++;
+ }
+ return;
+}
+
+
+/* kickstarts the firmware loading. from probe
+ */
+static void s2255_timer(unsigned long user_data)
+{
+ struct s2255_fw *data = (struct s2255_fw *)user_data;
+ dprintk(100, "s2255 timer\n");
+ if (usb_submit_urb(data->fw_urb, GFP_ATOMIC) < 0) {
+ printk(KERN_ERR "s2255: can't submit urb\n");
+ if (data->fw) {
+ release_firmware(data->fw);
+ data->fw = NULL;
+ }
+ return;
+ }
+}
+
+/* called when DSP is up and running. DSP is guaranteed to
+ be running after S2255_DSP_BOOTTIME */
+static void s2255_dsp_running(unsigned long user_data)
+{
+ struct s2255_fw *data = (struct s2255_fw *)user_data;
+ dprintk(1, "dsp running\n");
+ atomic_set(&data->fw_state, S2255_FW_SUCCESS);
+ wake_up(&data->wait_fw);
+ printk(KERN_INFO "s2255: firmware loaded successfully\n");
+ return;
+}
+
+
+/* this loads the firmware asynchronously.
+ Originally this was done synchroously in probe.
+ But it is better to load it asynchronously here than block
+ inside the probe function. Blocking inside probe affects boot time.
+ FW loading is triggered by the timer in the probe function
+*/
+static void s2255_fwchunk_complete(struct urb *urb)
+{
+ struct s2255_fw *data = urb->context;
+ struct usb_device *udev = urb->dev;
+ int len;
+ dprintk(100, "udev %p urb %p", udev, urb);
+
+ if (urb->status) {
+ dev_err(&udev->dev, "URB failed with status %d", urb->status);
+ return;
+ }
+ if (data->fw_urb == NULL) {
+ dev_err(&udev->dev, "early disconncect\n");
+ return;
+ }
+#define CHUNK_SIZE 512
+ /* all USB transfers must be done with continuous kernel memory.
+ can't allocate more than 128k in current linux kernel, so
+ upload the firmware in chunks
+ */
+ if (data->fw_loaded < data->fw_size) {
+ len = (data->fw_loaded + CHUNK_SIZE) > data->fw_size ?
+ data->fw_size % CHUNK_SIZE : CHUNK_SIZE;
+
+ 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);
+
+ usb_fill_bulk_urb(data->fw_urb, udev, usb_sndbulkpipe(udev, 2),
+ data->pfw_data, CHUNK_SIZE,
+ s2255_fwchunk_complete, data);
+ if (usb_submit_urb(data->fw_urb, GFP_ATOMIC) < 0) {
+ dev_err(&udev->dev, "failed submit URB\n");
+ atomic_set(&data->fw_state, S2255_FW_FAILED);
+ /* wake up anything waiting for the firmware */
+ wake_up(&data->wait_fw);
+ return;
+ }
+ data->fw_loaded += len;
+ } else {
+ init_timer(&data->dsp_wait);
+ data->dsp_wait.function = s2255_dsp_running;
+ data->dsp_wait.data = (unsigned long)data;
+ atomic_set(&data->fw_state, S2255_FW_LOADED_DSPWAIT);
+ mod_timer(&data->dsp_wait, msecs_to_jiffies(S2255_DSP_BOOTTIME)
+ + jiffies);
+ }
+ dprintk(100, "2255 complete done\n");
+ return;
+
+}
+
+static int s2255_got_frame(struct s2255_dev *dev, int chn)
+{
+ struct s2255_dmaqueue *dma_q = &dev->vidq[chn];
+ struct s2255_buffer *buf;
+ unsigned long flags = 0;
+ int rc = 0;
+ dprintk(2, "wakeup: %p channel: %d\n", &dma_q, chn);
+ spin_lock_irqsave(&dev->slock, flags);
+
+ if (list_empty(&dma_q->active)) {
+ dprintk(1, "No active queue to serve\n");
+ rc = -1;
+ goto unlock;
+ }
+ buf = list_entry(dma_q->active.next,
+ struct s2255_buffer, vb.queue);
+
+ if (!waitqueue_active(&buf->vb.done)) {
+ /* no one active */
+ rc = -1;
+ goto unlock;
+ }
+ list_del(&buf->vb.queue);
+ do_gettimeofday(&buf->vb.ts);
+ dprintk(100, "[%p/%d] wakeup\n", buf, buf->vb.i);
+
+ s2255_fillbuff(dev, buf, dma_q->channel);
+ wake_up(&buf->vb.done);
+ dprintk(2, "wakeup [buf/i] [%p/%d]\n", buf, buf->vb.i);
+unlock:
+ spin_unlock_irqrestore(&dev->slock, flags);
+ return 0;
+}
+
+
+static const struct s2255_fmt *format_by_fourcc(int fourcc)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(formats); i++) {
+ if (-1 == formats[i].fourcc)
+ continue;
+ if (formats[i].fourcc == fourcc)
+ return formats + i;
+ }
+ return NULL;
+}
+
+
+
+
+/* video buffer vmalloc implementation based partly on VIVI driver which is
+ * Copyright (c) 2006 by
+ * Mauro Carvalho Chehab <mchehab--a.t--infradead.org>
+ * Ted Walther <ted--a.t--enumera.com>
+ * John Sokol <sokol--a.t--videotechnology.com>
+ * http://v4l.videotechnology.com/
+ *
+ */
+static void s2255_fillbuff(struct s2255_dev *dev, struct s2255_buffer *buf,
+ int chn)
+{
+ int pos = 0;
+ struct timeval ts;
+ const char *tmpbuf;
+ char *vbuf = videobuf_to_vmalloc(&buf->vb);
+ unsigned long last_frame;
+ struct s2255_framei *frm;
+
+ if (!vbuf)
+ return;
+
+ last_frame = dev->last_frame[chn];
+ if (last_frame != -1) {
+ frm = &dev->buffer[chn].frame[last_frame];
+ tmpbuf =
+ (const char *)dev->buffer[chn].frame[last_frame].lpvbits;
+ switch (buf->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);
+ break;
+ case V4L2_PIX_FMT_GREY:
+ memcpy(vbuf, tmpbuf, buf->vb.width * buf->vb.height);
+ break;
+ case V4L2_PIX_FMT_YUV422P:
+ memcpy(vbuf, tmpbuf,
+ buf->vb.width * buf->vb.height * 2);
+ break;
+ default:
+ printk(KERN_DEBUG "s2255: unknown format?\n");
+ }
+ dev->last_frame[chn] = -1;
+ /* done with the frame, free it */
+ frm->ulState = 0;
+ dprintk(4, "freeing buffer\n");
+ } else {
+ printk(KERN_ERR "s2255: =======no frame\n");
+ return;
+
+ }
+ dprintk(2, "s2255fill at : Buffer 0x%08lx size= %d\n",
+ (unsigned long)vbuf, pos);
+ /* tell v4l buffer was filled */
+
+ buf->vb.field_count++;
+ do_gettimeofday(&ts);
+ buf->vb.ts = ts;
+ buf->vb.state = VIDEOBUF_DONE;
+}
+
+
+/* ------------------------------------------------------------------
+ Videobuf operations
+ ------------------------------------------------------------------*/
+
+static int buffer_setup(struct videobuf_queue *vq, unsigned int *count,
+ unsigned int *size)
+{
+ struct s2255_fh *fh = vq->priv_data;
+
+ *size = fh->width * fh->height * (fh->fmt->depth >> 3);
+
+ if (0 == *count)
+ *count = S2255_DEF_BUFS;
+
+ while (*size * *count > vid_limit * 1024 * 1024)
+ (*count)--;
+
+ return 0;
+}
+
+static void free_buffer(struct videobuf_queue *vq, struct s2255_buffer *buf)
+{
+ dprintk(4, "%s\n", __func__);
+
+ videobuf_waiton(&buf->vb, 0, 0);
+ 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)
+{
+ struct s2255_fh *fh = vq->priv_data;
+ struct s2255_buffer *buf = container_of(vb, struct s2255_buffer, vb);
+ int rc;
+ dprintk(4, "%s, field=%d\n", __func__, field);
+ if (fh->fmt == NULL)
+ return -EINVAL;
+
+ if ((fh->width < norm_minw(fh->dev->vdev[fh->channel])) ||
+ (fh->width > norm_maxw(fh->dev->vdev[fh->channel])) ||
+ (fh->height < norm_minh(fh->dev->vdev[fh->channel])) ||
+ (fh->height > norm_maxh(fh->dev->vdev[fh->channel]))) {
+ dprintk(4, "invalid buffer prepare\n");
+ return -EINVAL;
+ }
+
+ buf->vb.size = fh->width * fh->height * (fh->fmt->depth >> 3);
+
+ if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) {
+ dprintk(4, "invalid buffer prepare\n");
+ return -EINVAL;
+ }
+
+ buf->fmt = fh->fmt;
+ buf->vb.width = fh->width;
+ buf->vb.height = fh->height;
+ 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;
+ return 0;
+fail:
+ free_buffer(vq, buf);
+ return rc;
+}
+
+static void buffer_queue(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;
+ struct s2255_dev *dev = fh->dev;
+ struct s2255_dmaqueue *vidq = &dev->vidq[fh->channel];
+
+ dprintk(1, "%s\n", __func__);
+
+ buf->vb.state = VIDEOBUF_QUEUED;
+ list_add_tail(&buf->vb.queue, &vidq->active);
+}
+
+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);
+ free_buffer(vq, buf);
+}
+
+static struct videobuf_queue_ops s2255_video_qops = {
+ .buf_setup = buffer_setup,
+ .buf_prepare = buffer_prepare,
+ .buf_queue = buffer_queue,
+ .buf_release = buffer_release,
+};
+
+
+static int res_get(struct s2255_dev *dev, struct s2255_fh *fh)
+{
+ /* is it free? */
+ mutex_lock(&dev->lock);
+ if (dev->resources[fh->channel]) {
+ /* no, someone else uses it */
+ mutex_unlock(&dev->lock);
+ return 0;
+ }
+ /* it's free, grab it */
+ dev->resources[fh->channel] = 1;
+ dprintk(1, "res: get\n");
+ mutex_unlock(&dev->lock);
+ return 1;
+}
+
+static int res_locked(struct s2255_dev *dev, struct s2255_fh *fh)
+{
+ return (dev->resources[fh->channel]);
+}
+
+static void res_free(struct s2255_dev *dev, struct s2255_fh *fh)
+{
+ dev->resources[fh->channel] = 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;
+ strlcpy(cap->driver, "s2255", sizeof(cap->driver));
+ strlcpy(cap->card, "s2255", sizeof(cap->card));
+ strlcpy(cap->bus_info, dev_name(&dev->udev->dev), sizeof(cap->bus_info));
+ cap->version = S2255_VERSION;
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+ return 0;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ int index = 0;
+ if (f)
+ index = f->index;
+
+ if (index >= ARRAY_SIZE(formats))
+ 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;
+}
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct s2255_fh *fh = priv;
+
+ f->fmt.pix.width = fh->width;
+ f->fmt.pix.height = fh->height;
+ f->fmt.pix.field = fh->vb_vidq.field;
+ f->fmt.pix.pixelformat = fh->fmt->fourcc;
+ f->fmt.pix.bytesperline = f->fmt.pix.width * (fh->fmt->depth >> 3);
+ f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
+
+ return (0);
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ const struct s2255_fmt *fmt;
+ enum v4l2_field field;
+ int b_any_field = 0;
+ struct s2255_fh *fh = priv;
+ struct s2255_dev *dev = fh->dev;
+ int is_ntsc;
+
+ is_ntsc =
+ (dev->vdev[fh->channel]->current_norm & V4L2_STD_NTSC) ? 1 : 0;
+
+ fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+
+ if (fmt == NULL)
+ return -EINVAL;
+
+ field = f->fmt.pix.field;
+ if (field == V4L2_FIELD_ANY)
+ b_any_field = 1;
+
+ dprintk(4, "try format %d \n", is_ntsc);
+ /* supports 3 sizes. see s2255drv.h */
+ dprintk(50, "width test %d, height %d\n",
+ f->fmt.pix.width, f->fmt.pix.height);
+ if (is_ntsc) {
+ /* NTSC */
+ if (f->fmt.pix.height >= NUM_LINES_1CIFS_NTSC * 2) {
+ f->fmt.pix.height = NUM_LINES_1CIFS_NTSC * 2;
+ if (b_any_field) {
+ field = V4L2_FIELD_SEQ_TB;
+ } else if (!((field == V4L2_FIELD_INTERLACED) ||
+ (field == V4L2_FIELD_SEQ_TB) ||
+ (field == V4L2_FIELD_INTERLACED_TB))) {
+ dprintk(1, "unsupported field setting\n");
+ return -EINVAL;
+ }
+ } else {
+ f->fmt.pix.height = NUM_LINES_1CIFS_NTSC;
+ if (b_any_field) {
+ field = V4L2_FIELD_TOP;
+ } else if (!((field == V4L2_FIELD_TOP) ||
+ (field == V4L2_FIELD_BOTTOM))) {
+ dprintk(1, "unsupported field setting\n");
+ return -EINVAL;
+ }
+
+ }
+ if (f->fmt.pix.width >= LINE_SZ_4CIFS_NTSC)
+ f->fmt.pix.width = LINE_SZ_4CIFS_NTSC;
+ else if (f->fmt.pix.width >= LINE_SZ_2CIFS_NTSC)
+ f->fmt.pix.width = LINE_SZ_2CIFS_NTSC;
+ else if (f->fmt.pix.width >= LINE_SZ_1CIFS_NTSC)
+ f->fmt.pix.width = LINE_SZ_1CIFS_NTSC;
+ else
+ f->fmt.pix.width = LINE_SZ_1CIFS_NTSC;
+ } else {
+ /* PAL */
+ if (f->fmt.pix.height >= NUM_LINES_1CIFS_PAL * 2) {
+ f->fmt.pix.height = NUM_LINES_1CIFS_PAL * 2;
+ if (b_any_field) {
+ field = V4L2_FIELD_SEQ_TB;
+ } else if (!((field == V4L2_FIELD_INTERLACED) ||
+ (field == V4L2_FIELD_SEQ_TB) ||
+ (field == V4L2_FIELD_INTERLACED_TB))) {
+ dprintk(1, "unsupported field setting\n");
+ return -EINVAL;
+ }
+ } else {
+ f->fmt.pix.height = NUM_LINES_1CIFS_PAL;
+ if (b_any_field) {
+ field = V4L2_FIELD_TOP;
+ } else if (!((field == V4L2_FIELD_TOP) ||
+ (field == V4L2_FIELD_BOTTOM))) {
+ dprintk(1, "unsupported field setting\n");
+ return -EINVAL;
+ }
+ }
+ if (f->fmt.pix.width >= LINE_SZ_4CIFS_PAL) {
+ dprintk(50, "pal 704\n");
+ f->fmt.pix.width = LINE_SZ_4CIFS_PAL;
+ field = V4L2_FIELD_SEQ_TB;
+ } else if (f->fmt.pix.width >= LINE_SZ_2CIFS_PAL) {
+ dprintk(50, "pal 352A\n");
+ f->fmt.pix.width = LINE_SZ_2CIFS_PAL;
+ field = V4L2_FIELD_TOP;
+ } else if (f->fmt.pix.width >= LINE_SZ_1CIFS_PAL) {
+ dprintk(50, "pal 352B\n");
+ f->fmt.pix.width = LINE_SZ_1CIFS_PAL;
+ field = V4L2_FIELD_TOP;
+ } else {
+ dprintk(50, "pal 352C\n");
+ f->fmt.pix.width = LINE_SZ_1CIFS_PAL;
+ field = V4L2_FIELD_TOP;
+ }
+ }
+
+ dprintk(50, "width %d height %d field %d \n", f->fmt.pix.width,
+ f->fmt.pix.height, f->fmt.pix.field);
+ f->fmt.pix.field = field;
+ f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3;
+ f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
+ return 0;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct s2255_fh *fh = priv;
+ const struct s2255_fmt *fmt;
+ struct videobuf_queue *q = &fh->vb_vidq;
+ int ret;
+ int norm;
+
+ ret = vidioc_try_fmt_vid_cap(file, fh, f);
+
+ if (ret < 0)
+ return (ret);
+
+ fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+
+ 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 (res_locked(fh->dev, fh)) {
+ dprintk(1, "can't change format after started\n");
+ ret = -EBUSY;
+ goto out_s_fmt;
+ }
+
+ fh->fmt = fmt;
+ fh->width = f->fmt.pix.width;
+ fh->height = f->fmt.pix.height;
+ fh->vb_vidq.field = f->fmt.pix.field;
+ fh->type = f->type;
+ norm = norm_minw(fh->dev->vdev[fh->channel]);
+ if (fh->width > norm_minw(fh->dev->vdev[fh->channel])) {
+ if (fh->height > norm_minh(fh->dev->vdev[fh->channel]))
+ fh->mode.scale = SCALE_4CIFS;
+ else
+ fh->mode.scale = SCALE_2CIFS;
+
+ } else {
+ fh->mode.scale = SCALE_1CIFS;
+ }
+
+ /* color mode */
+ switch (fh->fmt->fourcc) {
+ case V4L2_PIX_FMT_GREY:
+ fh->mode.color = COLOR_Y8;
+ break;
+ case V4L2_PIX_FMT_YUV422P:
+ fh->mode.color = COLOR_YUVPL;
+ break;
+ case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_UYVY:
+ default:
+ fh->mode.color = COLOR_YUVPK;
+ break;
+ }
+ 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;
+}
+
+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;
+}
+
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+static int vidioc_cgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
+{
+ struct s2255_fh *fh = priv;
+
+ return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8);
+}
+#endif
+
+/* write to the configuration pipe, synchronously */
+static int s2255_write_config(struct usb_device *udev, unsigned char *pbuf,
+ int size)
+{
+ int pipe;
+ int done;
+ long retval = -1;
+ if (udev) {
+ pipe = usb_sndbulkpipe(udev, S2255_CONFIG_EP);
+ retval = usb_bulk_msg(udev, pipe, pbuf, size, &done, 500);
+ }
+ return retval;
+}
+
+static u32 get_transfer_size(struct s2255_mode *mode)
+{
+ int linesPerFrame = LINE_SZ_DEF;
+ int pixelsPerLine = NUM_LINES_DEF;
+ u32 outImageSize;
+ u32 usbInSize;
+ unsigned int mask_mult;
+
+ if (mode == NULL)
+ return 0;
+
+ if (mode->format == FORMAT_NTSC) {
+ switch (mode->scale) {
+ case SCALE_4CIFS:
+ linesPerFrame = NUM_LINES_4CIFS_NTSC * 2;
+ pixelsPerLine = LINE_SZ_4CIFS_NTSC;
+ break;
+ case SCALE_2CIFS:
+ linesPerFrame = NUM_LINES_2CIFS_NTSC;
+ pixelsPerLine = LINE_SZ_2CIFS_NTSC;
+ break;
+ case SCALE_1CIFS:
+ linesPerFrame = NUM_LINES_1CIFS_NTSC;
+ pixelsPerLine = LINE_SZ_1CIFS_NTSC;
+ break;
+ default:
+ break;
+ }
+ } else if (mode->format == FORMAT_PAL) {
+ switch (mode->scale) {
+ case SCALE_4CIFS:
+ linesPerFrame = NUM_LINES_4CIFS_PAL * 2;
+ pixelsPerLine = LINE_SZ_4CIFS_PAL;
+ break;
+ case SCALE_2CIFS:
+ linesPerFrame = NUM_LINES_2CIFS_PAL;
+ pixelsPerLine = LINE_SZ_2CIFS_PAL;
+ break;
+ case SCALE_1CIFS:
+ linesPerFrame = NUM_LINES_1CIFS_PAL;
+ pixelsPerLine = LINE_SZ_1CIFS_PAL;
+ break;
+ default:
+ break;
+ }
+ }
+ outImageSize = linesPerFrame * pixelsPerLine;
+ if (mode->color != COLOR_Y8) {
+ /* 2 bytes/pixel if not monochrome */
+ outImageSize *= 2;
+ }
+
+ /* total bytes to send including prefix and 4K padding;
+ must be a multiple of USB_READ_SIZE */
+ usbInSize = outImageSize + PREFIX_SIZE; /* always send prefix */
+ mask_mult = 0xffffffffUL - DEF_USB_BLOCK + 1;
+ /* if size not a multiple of USB_READ_SIZE */
+ if (usbInSize & ~mask_mult)
+ usbInSize = (usbInSize & mask_mult) + (DEF_USB_BLOCK);
+ return usbInSize;
+}
+
+static void dump_verify_mode(struct s2255_dev *sdev, struct s2255_mode *mode)
+{
+ struct device *dev = &sdev->udev->dev;
+ dev_info(dev, "------------------------------------------------\n");
+ dev_info(dev, "verify mode\n");
+ dev_info(dev, "format: %d\n", mode->format);
+ dev_info(dev, "scale: %d\n", mode->scale);
+ dev_info(dev, "fdec: %d\n", mode->fdec);
+ dev_info(dev, "color: %d\n", mode->color);
+ dev_info(dev, "bright: 0x%x\n", mode->bright);
+ dev_info(dev, "restart: 0x%x\n", mode->restart);
+ dev_info(dev, "usb_block: 0x%x\n", mode->usb_block);
+ dev_info(dev, "single: 0x%x\n", mode->single);
+ dev_info(dev, "------------------------------------------------\n");
+}
+
+/*
+ * set mode is the function which controls the DSP.
+ * the restart parameter in struct s2255_mode should be set whenever
+ * the image size could change via color format, video system or image
+ * size.
+ * 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_dev *dev, unsigned long chn,
+ struct s2255_mode *mode)
+{
+ int res;
+ u32 *buffer;
+ unsigned long chn_rev;
+
+ chn_rev = G_chnmap[chn];
+ dprintk(3, "mode scale [%ld] %p %d\n", chn, mode, mode->scale);
+ dprintk(3, "mode scale [%ld] %p %d\n", chn, &dev->mode[chn],
+ dev->mode[chn].scale);
+ dprintk(2, "mode contrast %x\n", mode->contrast);
+
+ /* save the mode */
+ dev->mode[chn] = *mode;
+ dev->req_image_size[chn] = get_transfer_size(mode);
+ dprintk(1, "transfer size %ld\n", dev->req_image_size[chn]);
+
+ buffer = kzalloc(512, GFP_KERNEL);
+ if (buffer == NULL) {
+ dev_err(&dev->udev->dev, "out of mem\n");
+ return -ENOMEM;
+ }
+
+ /* set the mode */
+ buffer[0] = IN_DATA_TOKEN;
+ buffer[1] = (u32) chn_rev;
+ buffer[2] = CMD_SET_MODE;
+ memcpy(&buffer[3], &dev->mode[chn], sizeof(struct s2255_mode));
+ res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512);
+ if (debug)
+ dump_verify_mode(dev, mode);
+ kfree(buffer);
+ dprintk(1, "set mode done chn %lu, %d\n", chn, res);
+
+ /* wait at least 3 frames before continuing */
+ if (mode->restart)
+ msleep(125);
+
+ /* clear the restart flag */
+ dev->mode[chn].restart = 0;
+
+ return res;
+}
+
+static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+ int res;
+ struct s2255_fh *fh = priv;
+ struct s2255_dev *dev = fh->dev;
+ struct s2255_mode *new_mode;
+ struct s2255_mode *old_mode;
+ int chn;
+ 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(dev, fh)) {
+ dev_err(&dev->udev->dev, "res get busy\n");
+ return -EBUSY;
+ }
+
+ /* send a set mode command everytime with restart.
+ in case we switch resolutions or other parameters */
+ chn = fh->channel;
+ new_mode = &fh->mode;
+ old_mode = &fh->dev->mode[chn];
+
+ if (new_mode->color != old_mode->color)
+ new_mode->restart = 1;
+ else if (new_mode->scale != old_mode->scale)
+ new_mode->restart = 1;
+ else if (new_mode->format != old_mode->format)
+ new_mode->restart = 1;
+
+ s2255_set_mode(dev, chn, new_mode);
+ new_mode->restart = 0;
+ *old_mode = *new_mode;
+ dev->cur_fmt[chn] = fh->fmt;
+ dprintk(1, "%s[%d]\n", __func__, chn);
+ dev->last_frame[chn] = -1;
+ dev->bad_payload[chn] = 0;
+ dev->cur_frame[chn] = 0;
+ for (j = 0; j < SYS_FRAMES; j++) {
+ dev->buffer[chn].frame[j].ulState = 0;
+ dev->buffer[chn].frame[j].cur_size = 0;
+ }
+ res = videobuf_streamon(&fh->vb_vidq);
+ if (res == 0) {
+ s2255_start_acquire(dev, chn);
+ dev->b_acquire[chn] = 1;
+ } else {
+ res_free(dev, fh);
+ }
+ return res;
+}
+
+static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+ int res;
+ struct s2255_fh *fh = priv;
+ struct s2255_dev *dev = fh->dev;
+
+ dprintk(4, "%s\n, channel: %d", __func__, fh->channel);
+ if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ printk(KERN_ERR "invalid fh type0\n");
+ return -EINVAL;
+ }
+ if (i != fh->type) {
+ printk(KERN_ERR "invalid type i\n");
+ return -EINVAL;
+ }
+ s2255_stop_acquire(dev, fh->channel);
+ res = videobuf_streamoff(&fh->vb_vidq);
+ res_free(dev, fh);
+ return res;
+}
+
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i)
+{
+ struct s2255_fh *fh = priv;
+ struct s2255_mode *mode;
+ struct videobuf_queue *q = &fh->vb_vidq;
+ int ret = 0;
+
+ mutex_lock(&q->vb_lock);
+ if (videobuf_queue_is_busy(q)) {
+ dprintk(1, "queue busy\n");
+ ret = -EBUSY;
+ goto out_s_std;
+ }
+
+ if (res_locked(fh->dev, fh)) {
+ dprintk(1, "can't change standard after started\n");
+ ret = -EBUSY;
+ goto out_s_std;
+ }
+ mode = &fh->mode;
+
+ if (*i & V4L2_STD_NTSC) {
+ dprintk(4, "vidioc_s_std NTSC\n");
+ mode->format = FORMAT_NTSC;
+ } else if (*i & V4L2_STD_PAL) {
+ dprintk(4, "vidioc_s_std PAL\n");
+ mode->format = FORMAT_PAL;
+ } else {
+ ret = -EINVAL;
+ }
+out_s_std:
+ mutex_unlock(&q->vb_lock);
+ return ret;
+}
+
+/* Sensoray 2255 is a multiple channel capture device.
+ It does not have a "crossbar" of inputs.
+ We use one V4L device per channel. The user must
+ be aware that certain combinations are not allowed.
+ For instance, you cannot do full FPS on more than 2 channels(2 videodevs)
+ at once in color(you can do full fps on 4 channels with greyscale.
+*/
+static int vidioc_enum_input(struct file *file, void *priv,
+ struct v4l2_input *inp)
+{
+ if (inp->index != 0)
+ return -EINVAL;
+
+ inp->type = V4L2_INPUT_TYPE_CAMERA;
+ inp->std = S2255_NORMS;
+ strlcpy(inp->name, "Camera", sizeof(inp->name));
+ return (0);
+}
+
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+{
+ *i = 0;
+ return 0;
+}
+static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
+{
+ if (i > 0)
+ return -EINVAL;
+ return 0;
+}
+
+/* --- controls ---------------------------------------------- */
+static int vidioc_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *qc)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(s2255_qctrl); i++)
+ if (qc->id && qc->id == s2255_qctrl[i].id) {
+ memcpy(qc, &(s2255_qctrl[i]), sizeof(*qc));
+ return (0);
+ }
+
+ dprintk(4, "query_ctrl -EINVAL %d\n", qc->id);
+ return -EINVAL;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(s2255_qctrl); i++)
+ if (ctrl->id == s2255_qctrl[i].id) {
+ ctrl->value = qctl_regs[i];
+ return (0);
+ }
+ dprintk(4, "g_ctrl -EINVAL\n");
+
+ return -EINVAL;
+}
+
+static int vidioc_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ int i;
+ struct s2255_fh *fh = priv;
+ struct s2255_dev *dev = fh->dev;
+ struct s2255_mode *mode;
+ mode = &fh->mode;
+ dprintk(4, "vidioc_s_ctrl\n");
+ for (i = 0; i < ARRAY_SIZE(s2255_qctrl); i++) {
+ if (ctrl->id == s2255_qctrl[i].id) {
+ if (ctrl->value < s2255_qctrl[i].minimum ||
+ ctrl->value > s2255_qctrl[i].maximum)
+ return (-ERANGE);
+
+ qctl_regs[i] = ctrl->value;
+ /* update the mode to the corresponding value */
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ mode->bright = ctrl->value;
+ break;
+ case V4L2_CID_CONTRAST:
+ mode->contrast = ctrl->value;
+ break;
+ case V4L2_CID_HUE:
+ mode->hue = ctrl->value;
+ break;
+ case V4L2_CID_SATURATION:
+ mode->saturation = ctrl->value;
+ break;
+ }
+ mode->restart = 0;
+ /* set mode here. Note: stream does not need restarted.
+ some V4L programs restart stream unnecessarily
+ after a s_crtl.
+ */
+ s2255_set_mode(dev, fh->channel, mode);
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+
+static int s2255_open(struct inode *inode, struct file *file)
+{
+ int minor = iminor(inode);
+ struct s2255_dev *h, *dev = NULL;
+ struct s2255_fh *fh;
+ struct list_head *list;
+ enum v4l2_buf_type type = 0;
+ int i = 0;
+ int cur_channel = -1;
+ dprintk(1, "s2255: open called (minor=%d)\n", minor);
+
+ list_for_each(list, &s2255_devlist) {
+ h = list_entry(list, struct s2255_dev, s2255_devlist);
+ for (i = 0; i < MAX_CHANNELS; i++) {
+ if (h->vdev[i]->minor == minor) {
+ cur_channel = i;
+ dev = h;
+ type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ }
+ }
+ }
+
+ if ((NULL == dev) || (cur_channel == -1)) {
+ dprintk(1, "s2255: openv4l no dev\n");
+ return -ENODEV;
+ }
+
+ mutex_lock(&dev->open_lock);
+
+ dev->users[cur_channel]++;
+ if (dev->users[cur_channel] > S2255_MAX_USERS) {
+ dev->users[cur_channel]--;
+ mutex_unlock(&dev->open_lock);
+ printk(KERN_INFO "s2255drv: too many open handles!\n");
+ return -EBUSY;
+ }
+
+ if (atomic_read(&dev->fw_data->fw_state) == S2255_FW_FAILED) {
+ err("2255 firmware load failed. retrying.\n");
+ s2255_fwload_start(dev);
+ wait_event_timeout(dev->fw_data->wait_fw,
+ (atomic_read(&dev->fw_data->fw_state)
+ != S2255_FW_NOTLOADED),
+ msecs_to_jiffies(S2255_LOAD_TIMEOUT));
+ if (atomic_read(&dev->fw_data->fw_state)
+ != S2255_FW_SUCCESS) {
+ printk(KERN_INFO "2255 FW load failed after 2 tries\n");
+ mutex_unlock(&dev->open_lock);
+ return -EFAULT;
+ }
+ } else if (atomic_read(&dev->fw_data->fw_state) == S2255_FW_NOTLOADED) {
+ /* 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__);
+ wait_event_timeout(dev->fw_data->wait_fw,
+ (atomic_read(&dev->fw_data->fw_state)
+ != S2255_FW_NOTLOADED),
+ msecs_to_jiffies(S2255_LOAD_TIMEOUT));
+ if (atomic_read(&dev->fw_data->fw_state)
+ != S2255_FW_SUCCESS) {
+ printk(KERN_INFO "2255 firmware not loaded"
+ "try again\n");
+ mutex_unlock(&dev->open_lock);
+ return -EBUSY;
+ }
+ }
+
+ /* allocate + initialize per filehandle data */
+ fh = kzalloc(sizeof(*fh), GFP_KERNEL);
+ if (NULL == fh) {
+ mutex_unlock(&dev->open_lock);
+ return -ENOMEM;
+ }
+
+ file->private_data = fh;
+ fh->dev = dev;
+ fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ fh->mode = dev->mode[cur_channel];
+ fh->fmt = dev->cur_fmt[cur_channel];
+ /* default 4CIF NTSC */
+ fh->width = LINE_SZ_4CIFS_NTSC;
+ fh->height = NUM_LINES_4CIFS_NTSC * 2;
+ fh->channel = cur_channel;
+
+ /* Put all controls at a sane state */
+ for (i = 0; i < ARRAY_SIZE(s2255_qctrl); i++)
+ qctl_regs[i] = s2255_qctrl[i].default_value;
+
+ dprintk(1, "s2255drv: open minor=%d type=%s users=%d\n",
+ minor, v4l2_type_names[type], dev->users[cur_channel]);
+ dprintk(2, "s2255drv: open: fh=0x%08lx, dev=0x%08lx, vidq=0x%08lx\n",
+ (unsigned long)fh, (unsigned long)dev,
+ (unsigned long)&dev->vidq[cur_channel]);
+ dprintk(4, "s2255drv: open: list_empty active=%d\n",
+ list_empty(&dev->vidq[cur_channel].active));
+
+ videobuf_queue_vmalloc_init(&fh->vb_vidq, &s2255_video_qops,
+ NULL, &dev->slock,
+ fh->type,
+ V4L2_FIELD_INTERLACED,
+ sizeof(struct s2255_buffer), fh);
+
+ kref_get(&dev->kref);
+ mutex_unlock(&dev->open_lock);
+ return 0;
+}
+
+
+static unsigned int s2255_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ struct s2255_fh *fh = file->private_data;
+ int rc;
+ dprintk(100, "%s\n", __func__);
+
+ if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
+ return POLLERR;
+
+ rc = videobuf_poll_stream(file, &fh->vb_vidq, wait);
+ return rc;
+}
+
+static void s2255_destroy(struct kref *kref)
+{
+ struct s2255_dev *dev = to_s2255_dev(kref);
+ if (!dev) {
+ printk(KERN_ERR "s2255drv: kref problem\n");
+ return;
+ }
+ /* prevent s2255_disconnect from racing s2255_open */
+ mutex_lock(&dev->open_lock);
+ s2255_exit_v4l(dev);
+ /* device unregistered so no longer possible to open. open_mutex
+ can be unlocked */
+ mutex_unlock(&dev->open_lock);
+
+ /* board shutdown stops the read pipe if it is running */
+ s2255_board_shutdown(dev);
+
+ /* make sure firmware still not trying to load */
+ if (dev->fw_data->fw_urb) {
+ dprintk(2, "kill fw_urb\n");
+ usb_kill_urb(dev->fw_data->fw_urb);
+ usb_free_urb(dev->fw_data->fw_urb);
+ dev->fw_data->fw_urb = NULL;
+ }
+
+ /* make sure we aren't waiting for the DSP */
+ if (atomic_read(&dev->fw_data->fw_state) == S2255_FW_LOADED_DSPWAIT) {
+ /* if we are, wait for the wakeup for fw_success or timeout */
+ wait_event_timeout(dev->fw_data->wait_fw,
+ (atomic_read(&dev->fw_data->fw_state)
+ == S2255_FW_SUCCESS),
+ msecs_to_jiffies(S2255_LOAD_TIMEOUT));
+ }
+
+ if (dev->fw_data) {
+ kfree(dev->fw_data->pfw_data);
+ kfree(dev->fw_data);
+ }
+
+ if (dev->fw_data->fw) {
+ release_firmware(dev->fw_data->fw);
+ dev->fw_data->fw = NULL;
+ }
+
+ usb_put_dev(dev->udev);
+ dprintk(1, "%s", __func__);
+ kfree(dev);
+}
+
+static int s2255_close(struct inode *inode, struct file *file)
+{
+ struct s2255_fh *fh = file->private_data;
+ struct s2255_dev *dev = fh->dev;
+ int minor = iminor(inode);
+ if (!dev)
+ return -ENODEV;
+
+ mutex_lock(&dev->open_lock);
+
+ if (dev->b_acquire[fh->channel])
+ s2255_stop_acquire(dev, fh->channel);
+ res_free(dev, fh);
+ videobuf_mmap_free(&fh->vb_vidq);
+ kfree(fh);
+ dev->users[fh->channel]--;
+ mutex_unlock(&dev->open_lock);
+
+ kref_put(&dev->kref, s2255_destroy);
+ dprintk(1, "s2255: close called (minor=%d, users=%d)\n",
+ minor, dev->users[fh->channel]);
+ return 0;
+}
+
+static int s2255_mmap_v4l(struct file *file, struct vm_area_struct *vma)
+{
+ struct s2255_fh *fh = file->private_data;
+ int ret;
+
+ if (!fh)
+ return -ENODEV;
+ dprintk(4, "mmap called, vma=0x%08lx\n", (unsigned long)vma);
+
+ ret = videobuf_mmap_mapper(&fh->vb_vidq, vma);
+
+ dprintk(4, "vma start=0x%08lx, size=%ld, ret=%d\n",
+ (unsigned long)vma->vm_start,
+ (unsigned long)vma->vm_end - (unsigned long)vma->vm_start, ret);
+
+ return ret;
+}
+
+static const struct file_operations s2255_fops_v4l = {
+ .owner = THIS_MODULE,
+ .open = s2255_open,
+ .release = s2255_close,
+ .poll = s2255_poll,
+ .ioctl = video_ioctl2, /* V4L2 ioctl handler */
+ .compat_ioctl = v4l_compat_ioctl32,
+ .mmap = s2255_mmap_v4l,
+ .llseek = no_llseek,
+};
+
+static struct video_device template = {
+ .name = "s2255v",
+ .type = VID_TYPE_CAPTURE,
+ .fops = &s2255_fops_v4l,
+ .minor = -1,
+ .release = video_device_release,
+ .vidioc_querycap = vidioc_querycap,
+ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+ .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_s_std = vidioc_s_std,
+ .vidioc_enum_input = vidioc_enum_input,
+ .vidioc_g_input = vidioc_g_input,
+ .vidioc_s_input = vidioc_s_input,
+ .vidioc_queryctrl = vidioc_queryctrl,
+ .vidioc_g_ctrl = vidioc_g_ctrl,
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ .vidioc_streamon = vidioc_streamon,
+ .vidioc_streamoff = vidioc_streamoff,
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+ .vidiocgmbuf = vidioc_cgmbuf,
+#endif
+ .tvnorms = S2255_NORMS,
+ .current_norm = V4L2_STD_NTSC_M,
+};
+
+static int s2255_probe_v4l(struct s2255_dev *dev)
+{
+ int ret;
+ int i;
+ int cur_nr = video_nr;
+
+ /* initialize all video 4 linux */
+ list_add_tail(&dev->s2255_devlist, &s2255_devlist);
+ /* register 4 video devices */
+ for (i = 0; i < MAX_CHANNELS; i++) {
+ INIT_LIST_HEAD(&dev->vidq[i].active);
+ dev->vidq[i].dev = dev;
+ dev->vidq[i].channel = i;
+ dev->vidq[i].kthread = NULL;
+ /* register 4 video devices */
+ dev->vdev[i] = video_device_alloc();
+ memcpy(dev->vdev[i], &template, sizeof(struct video_device));
+ dev->vdev[i]->dev = &dev->interface->dev;
+ if (video_nr == -1)
+ ret = video_register_device(dev->vdev[i],
+ VFL_TYPE_GRABBER,
+ video_nr);
+ else
+ ret = video_register_device(dev->vdev[i],
+ VFL_TYPE_GRABBER,
+ cur_nr + i);
+ dev->vdev[i]->priv = dev;
+
+ if (ret != 0) {
+ dev_err(&dev->udev->dev,
+ "failed to register video device!\n");
+ return ret;
+ }
+ }
+ printk(KERN_INFO "Sensoray 2255 V4L driver\n");
+ return ret;
+}
+
+static void s2255_exit_v4l(struct s2255_dev *dev)
+{
+ struct list_head *list;
+ int i;
+ /* unregister the video devices */
+ while (!list_empty(&s2255_devlist)) {
+ list = s2255_devlist.next;
+ list_del(list);
+ }
+ for (i = 0; i < MAX_CHANNELS; i++) {
+ if (-1 != dev->vdev[i]->minor)
+ video_unregister_device(dev->vdev[i]);
+ else
+ video_device_release(dev->vdev[i]);
+ }
+}
+
+/* this function moves the usb stream read pipe data
+ * into the system buffers.
+ * returns 0 on success, EAGAIN if more data to process( call this
+ * function again).
+ *
+ * Received frame structure:
+ * bytes 0-3: marker : 0x2255DA4AL (FRAME_MARKER)
+ * bytes 4-7: channel: 0-3
+ * bytes 8-11: payload size: size of the frame
+ * bytes 12-payloadsize+12: frame data
+ */
+static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
+{
+ static int dbgsync; /* = 0; */
+ char *pdest;
+ u32 offset = 0;
+ int bsync = 0;
+ int btrunc = 0;
+ char *psrc;
+ unsigned long copy_size;
+ unsigned long size;
+ s32 idx = -1;
+ struct s2255_framei *frm;
+ unsigned char *pdata;
+ unsigned long cur_size;
+ int bsearch = 0;
+ struct s2255_bufferi *buf;
+ dprintk(100, "buffer to user\n");
+
+ idx = dev->cur_frame[dev->cc];
+ buf = &dev->buffer[dev->cc];
+ frm = &buf->frame[idx];
+
+ if (frm->ulState == 0) {
+ frm->ulState = 1;
+ frm->cur_size = 0;
+ bsearch = 1;
+ } else if (frm->ulState == 2) {
+ /* system frame was not freed */
+ dprintk(2, "sys frame not free. overrun ringbuf\n");
+ bsearch = 1;
+ frm->ulState = 1;
+ frm->cur_size = 0;
+ }
+
+ if (bsearch) {
+ if (*(s32 *) pipe_info->transfer_buffer != FRAME_MARKER) {
+ u32 jj;
+ if (dbgsync == 0) {
+ dprintk(3, "not synched, discarding all packets"
+ "until marker\n");
+
+ dbgsync++;
+ }
+ pdata = (unsigned char *)pipe_info->transfer_buffer;
+ for (jj = 0; jj < (pipe_info->cur_transfer_size - 12);
+ jj++) {
+ if (*(s32 *) pdata == FRAME_MARKER) {
+ int cc;
+ dprintk(3,
+ "found frame marker at offset:"
+ " %d [%x %x]\n", jj, pdata[0],
+ pdata[1]);
+ offset = jj;
+ bsync = 1;
+ cc = *(u32 *) (pdata + sizeof(u32));
+ if (cc >= MAX_CHANNELS) {
+ printk(KERN_ERR
+ "bad channel\n");
+ return -EINVAL;
+ }
+ /* reverse it */
+ dev->cc = G_chnmap[cc];
+ break;
+ }
+ pdata++;
+ }
+ if (bsync == 0)
+ return -EINVAL;
+ } else {
+ u32 *pword;
+ u32 payload;
+ int cc;
+ dbgsync = 0;
+ bsync = 1;
+ pword = (u32 *) pipe_info->transfer_buffer;
+ cc = pword[1];
+
+ if (cc >= MAX_CHANNELS) {
+ printk("invalid channel found. "
+ "throwing out data!\n");
+ return -EINVAL;
+ }
+ dev->cc = G_chnmap[cc];
+ payload = pword[2];
+ if (payload != dev->req_image_size[dev->cc]) {
+ dprintk(1, "[%d][%d]unexpected payload: %d"
+ "required: %lu \n", cc, dev->cc,
+ payload, dev->req_image_size[dev->cc]);
+ dev->bad_payload[dev->cc]++;
+ /* discard the bad frame */
+ return -EINVAL;
+ }
+
+ }
+ }
+ /* search done. now find out if should be acquiring
+ on this channel */
+ if (!dev->b_acquire[dev->cc]) {
+ frm->ulState = 0;
+ return -EINVAL;
+ }
+
+ idx = dev->cur_frame[dev->cc];
+ frm = &dev->buffer[dev->cc].frame[idx];
+
+ if (frm->ulState == 0) {
+ frm->ulState = 1;
+ frm->cur_size = 0;
+ } else if (frm->ulState == 2) {
+ /* system frame ring buffer overrun */
+ dprintk(2, "sys frame overrun. overwriting frame %d %d\n",
+ dev->cc, idx);
+ frm->ulState = 1;
+ frm->cur_size = 0;
+ }
+
+ if (bsync) {
+ /* skip the marker 512 bytes (and offset if out of sync) */
+ psrc = (u8 *)pipe_info->transfer_buffer + offset + PREFIX_SIZE;
+ } else {
+ psrc = (u8 *)pipe_info->transfer_buffer;
+ }
+
+ if (frm->lpvbits == NULL) {
+ dprintk(1, "s2255 frame buffer == NULL.%p %p %d %d",
+ frm, dev, dev->cc, idx);
+ return -ENOMEM;
+ }
+
+ pdest = frm->lpvbits + frm->cur_size;
+
+ if (bsync) {
+ copy_size =
+ (pipe_info->cur_transfer_size - offset) - PREFIX_SIZE;
+ if (copy_size > pipe_info->cur_transfer_size) {
+ printk("invalid copy size, overflow!\n");
+ return -ENOMEM;
+ }
+ } else {
+ copy_size = pipe_info->cur_transfer_size;
+ }
+
+ cur_size = frm->cur_size;
+ size = dev->req_image_size[dev->cc];
+
+ if ((copy_size + cur_size) > size) {
+ copy_size = size - cur_size;
+ btrunc = 1;
+ }
+
+ memcpy(pdest, psrc, copy_size);
+ cur_size += copy_size;
+ frm->cur_size += copy_size;
+ dprintk(50, "cur_size size %lu size %lu \n", cur_size, size);
+
+ if (cur_size >= (size - PREFIX_SIZE)) {
+ u32 cc = dev->cc;
+ frm->ulState = 2;
+ dprintk(2, "****************[%d]Buffer[%d]full*************\n",
+ cc, idx);
+ dev->last_frame[cc] = dev->cur_frame[cc];
+ dev->cur_frame[cc]++;
+ /* end of system frame ring buffer, start at zero */
+ if ((dev->cur_frame[cc] == SYS_FRAMES) ||
+ (dev->cur_frame[cc] == dev->buffer[cc].dwFrames))
+ dev->cur_frame[cc] = 0;
+
+ /* signal the semaphore for this channel */
+ if (dev->b_acquire[cc])
+ s2255_got_frame(dev, cc);
+ dev->frame_count[cc]++;
+ }
+ /* frame was truncated */
+ if (btrunc) {
+ /* return more data to process */
+ return EAGAIN;
+ }
+ /* done successfully */
+ return 0;
+}
+
+static void s2255_read_video_callback(struct s2255_dev *dev,
+ struct s2255_pipeinfo *pipe_info)
+{
+ int res;
+ dprintk(50, "callback read video \n");
+
+ if (dev->cc >= MAX_CHANNELS) {
+ dev->cc = 0;
+ dev_err(&dev->udev->dev, "invalid channel\n");
+ return;
+ }
+ /* otherwise copy to the system buffers */
+ res = save_frame(dev, pipe_info);
+ if (res == EAGAIN)
+ save_frame(dev, pipe_info);
+
+ dprintk(50, "callback read video done\n");
+ return;
+}
+
+static long s2255_vendor_req(struct s2255_dev *dev, unsigned char Request,
+ u16 Index, u16 Value, void *TransferBuffer,
+ s32 TransferBufferLength, int bOut)
+{
+ int r;
+ if (!bOut) {
+ r = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
+ Request,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE |
+ USB_DIR_IN,
+ Value, Index, TransferBuffer,
+ TransferBufferLength, HZ * 5);
+ } else {
+ r = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
+ Request, USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ Value, Index, TransferBuffer,
+ TransferBufferLength, HZ * 5);
+ }
+ return r;
+}
+
+/*
+ * retrieve FX2 firmware version. future use.
+ * @param dev pointer to device extension
+ * @return -1 for fail, else returns firmware version as an int(16 bits)
+ */
+static int s2255_get_fx2fw(struct s2255_dev *dev)
+{
+ int fw;
+ int ret;
+ unsigned char transBuffer[64];
+ ret = s2255_vendor_req(dev, S2255_VR_FW, 0, 0, transBuffer, 2,
+ S2255_VR_IN);
+ if (ret < 0)
+ dprintk(2, "get fw error: %x\n", ret);
+ fw = transBuffer[0] + (transBuffer[1] << 8);
+ dprintk(2, "Get FW %x %x\n", transBuffer[0], transBuffer[1]);
+ return fw;
+}
+
+/*
+ * Create the system ring buffer to copy frames into from the
+ * usb read pipe.
+ */
+static int s2255_create_sys_buffers(struct s2255_dev *dev, unsigned long chn)
+{
+ unsigned long i;
+ unsigned long reqsize;
+ dprintk(1, "create sys buffers\n");
+ if (chn >= MAX_CHANNELS)
+ return -1;
+
+ dev->buffer[chn].dwFrames = SYS_FRAMES;
+
+ /* always allocate maximum size(PAL) for system buffers */
+ reqsize = SYS_FRAMES_MAXSIZE;
+
+ if (reqsize > SYS_FRAMES_MAXSIZE)
+ reqsize = SYS_FRAMES_MAXSIZE;
+
+ for (i = 0; i < SYS_FRAMES; i++) {
+ /* allocate the frames */
+ dev->buffer[chn].frame[i].lpvbits = vmalloc(reqsize);
+
+ dprintk(1, "valloc %p chan %lu, idx %lu, pdata %p\n",
+ &dev->buffer[chn].frame[i], chn, i,
+ dev->buffer[chn].frame[i].lpvbits);
+ dev->buffer[chn].frame[i].size = reqsize;
+ if (dev->buffer[chn].frame[i].lpvbits == NULL) {
+ printk(KERN_INFO "out of memory. using less frames\n");
+ dev->buffer[chn].dwFrames = i;
+ break;
+ }
+ }
+
+ /* make sure internal states are set */
+ for (i = 0; i < SYS_FRAMES; i++) {
+ dev->buffer[chn].frame[i].ulState = 0;
+ dev->buffer[chn].frame[i].cur_size = 0;
+ }
+
+ dev->cur_frame[chn] = 0;
+ dev->last_frame[chn] = -1;
+ return 0;
+}
+
+static int s2255_release_sys_buffers(struct s2255_dev *dev,
+ unsigned long channel)
+{
+ unsigned long i;
+ dprintk(1, "release sys buffers\n");
+ for (i = 0; i < SYS_FRAMES; i++) {
+ if (dev->buffer[channel].frame[i].lpvbits) {
+ dprintk(1, "vfree %p\n",
+ dev->buffer[channel].frame[i].lpvbits);
+ vfree(dev->buffer[channel].frame[i].lpvbits);
+ }
+ dev->buffer[channel].frame[i].lpvbits = NULL;
+ }
+ return 0;
+}
+
+static int s2255_board_init(struct s2255_dev *dev)
+{
+ int j;
+ struct s2255_mode mode_def = DEF_MODEI_NTSC_CONT;
+ int fw_ver;
+ dprintk(4, "board init: %p", dev);
+
+ for (j = 0; j < MAX_PIPE_BUFFERS; j++) {
+ struct s2255_pipeinfo *pipe = &dev->pipes[j];
+
+ memset(pipe, 0, sizeof(*pipe));
+ pipe->dev = dev;
+ pipe->cur_transfer_size = DEFAULT_PIPE_USBBLOCK;
+ pipe->max_transfer_size = MAX_PIPE_USBBLOCK;
+
+ if (pipe->cur_transfer_size > pipe->max_transfer_size)
+ pipe->cur_transfer_size = pipe->max_transfer_size;
+ pipe->transfer_buffer = kzalloc(pipe->max_transfer_size,
+ GFP_KERNEL);
+ if (pipe->transfer_buffer == NULL) {
+ dprintk(1, "out of memory!\n");
+ return -ENOMEM;
+ }
+
+ }
+
+ /* query the firmware */
+ fw_ver = s2255_get_fx2fw(dev);
+
+ printk(KERN_INFO "2255 usb firmware version %d \n", fw_ver);
+ if (fw_ver < CUR_USB_FWVER)
+ err("usb firmware not up to date %d\n", fw_ver);
+
+ for (j = 0; j < MAX_CHANNELS; j++) {
+ dev->b_acquire[j] = 0;
+ dev->mode[j] = mode_def;
+ dev->cur_fmt[j] = &formats[0];
+ dev->mode[j].restart = 1;
+ dev->req_image_size[j] = get_transfer_size(&mode_def);
+ dev->frame_count[j] = 0;
+ /* create the system buffers */
+ s2255_create_sys_buffers(dev, j);
+ }
+ /* start read pipe */
+ s2255_start_readpipe(dev);
+
+ dprintk(1, "S2255: board initialized\n");
+ return 0;
+}
+
+static int s2255_board_shutdown(struct s2255_dev *dev)
+{
+ u32 i;
+
+ dprintk(1, "S2255: board shutdown: %p", dev);
+
+ for (i = 0; i < MAX_CHANNELS; i++) {
+ if (dev->b_acquire[i])
+ s2255_stop_acquire(dev, i);
+ }
+
+ s2255_stop_readpipe(dev);
+
+ for (i = 0; i < MAX_CHANNELS; i++)
+ s2255_release_sys_buffers(dev, i);
+
+ /* release transfer buffers */
+ for (i = 0; i < MAX_PIPE_BUFFERS; i++) {
+ struct s2255_pipeinfo *pipe = &dev->pipes[i];
+ kfree(pipe->transfer_buffer);
+ }
+ return 0;
+}
+
+static void read_pipe_completion(struct urb *purb)
+{
+ struct s2255_pipeinfo *pipe_info;
+ struct s2255_dev *dev;
+ int status;
+ int pipe;
+
+ pipe_info = purb->context;
+ dprintk(100, "read pipe completion %p, status %d\n", purb,
+ purb->status);
+ if (pipe_info == NULL) {
+ err("no context !");
+ return;
+ }
+
+ dev = pipe_info->dev;
+ if (dev == NULL) {
+ err("no context !");
+ return;
+ }
+ status = purb->status;
+ if (status != 0) {
+ dprintk(2, "read_pipe_completion: err\n");
+ return;
+ }
+
+ if (pipe_info->state == 0) {
+ dprintk(2, "exiting USB pipe");
+ return;
+ }
+
+ s2255_read_video_callback(dev, pipe_info);
+
+ pipe_info->err_count = 0;
+ pipe = usb_rcvbulkpipe(dev->udev, dev->read_endpoint);
+ /* reuse urb */
+ usb_fill_bulk_urb(pipe_info->stream_urb, dev->udev,
+ pipe,
+ pipe_info->transfer_buffer,
+ pipe_info->cur_transfer_size,
+ read_pipe_completion, pipe_info);
+
+ if (pipe_info->state != 0) {
+ if (usb_submit_urb(pipe_info->stream_urb, GFP_KERNEL)) {
+ dev_err(&dev->udev->dev, "error submitting urb\n");
+ usb_free_urb(pipe_info->stream_urb);
+ }
+ } else {
+ dprintk(2, "read pipe complete state 0\n");
+ }
+ return;
+}
+
+static int s2255_start_readpipe(struct s2255_dev *dev)
+{
+ int pipe;
+ int retval;
+ int i;
+ struct s2255_pipeinfo *pipe_info = dev->pipes;
+ pipe = usb_rcvbulkpipe(dev->udev, dev->read_endpoint);
+ dprintk(2, "start pipe IN %d\n", dev->read_endpoint);
+
+ for (i = 0; i < MAX_PIPE_BUFFERS; i++) {
+ pipe_info->state = 1;
+ pipe_info->buf_index = (u32) i;
+ pipe_info->priority_set = 0;
+ pipe_info->stream_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!pipe_info->stream_urb) {
+ dev_err(&dev->udev->dev,
+ "ReadStream: Unable to alloc URB");
+ return -ENOMEM;
+ }
+ /* transfer buffer allocated in board_init */
+ usb_fill_bulk_urb(pipe_info->stream_urb, dev->udev,
+ pipe,
+ pipe_info->transfer_buffer,
+ pipe_info->cur_transfer_size,
+ read_pipe_completion, pipe_info);
+
+ pipe_info->urb_size = sizeof(pipe_info->stream_urb);
+ dprintk(4, "submitting URB %p\n", pipe_info->stream_urb);
+ retval = usb_submit_urb(pipe_info->stream_urb, GFP_KERNEL);
+ if (retval) {
+ printk(KERN_ERR "s2255: start read pipe failed\n");
+ return retval;
+ }
+ }
+
+ return 0;
+}
+
+/* starts acquisition process */
+static int s2255_start_acquire(struct s2255_dev *dev, unsigned long chn)
+{
+ unsigned char *buffer;
+ int res;
+ unsigned long chn_rev;
+ int j;
+ if (chn >= MAX_CHANNELS) {
+ dprintk(2, "start acquire failed, bad channel %lu\n", chn);
+ return -1;
+ }
+
+ chn_rev = G_chnmap[chn];
+ dprintk(1, "S2255: start acquire %lu \n", chn);
+
+ buffer = kzalloc(512, GFP_KERNEL);
+ if (buffer == NULL) {
+ dev_err(&dev->udev->dev, "out of mem\n");
+ return -ENOMEM;
+ }
+
+ dev->last_frame[chn] = -1;
+ dev->bad_payload[chn] = 0;
+ dev->cur_frame[chn] = 0;
+ for (j = 0; j < SYS_FRAMES; j++) {
+ dev->buffer[chn].frame[j].ulState = 0;
+ dev->buffer[chn].frame[j].cur_size = 0;
+ }
+
+ /* send the start command */
+ *(u32 *) buffer = IN_DATA_TOKEN;
+ *((u32 *) buffer + 1) = (u32) chn_rev;
+ *((u32 *) buffer + 2) = (u32) 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[%lu] %d \n", chn, res);
+ kfree(buffer);
+ return 0;
+}
+
+static int s2255_stop_acquire(struct s2255_dev *dev, unsigned long chn)
+{
+ unsigned char *buffer;
+ int res;
+ unsigned long chn_rev;
+
+ if (chn >= MAX_CHANNELS) {
+ dprintk(2, "stop acquire failed, bad channel %lu\n", chn);
+ return -1;
+ }
+ chn_rev = G_chnmap[chn];
+
+ buffer = kzalloc(512, GFP_KERNEL);
+ if (buffer == NULL) {
+ dev_err(&dev->udev->dev, "out of mem\n");
+ return -ENOMEM;
+ }
+
+ /* send the stop command */
+ dprintk(4, "stop acquire %lu\n", chn);
+ *(u32 *) buffer = IN_DATA_TOKEN;
+ *((u32 *) buffer + 1) = (u32) chn_rev;
+ *((u32 *) 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");
+
+ dprintk(4, "stop acquire: releasing states \n");
+
+ kfree(buffer);
+ dev->b_acquire[chn] = 0;
+
+ return 0;
+}
+
+static void s2255_stop_readpipe(struct s2255_dev *dev)
+{
+ int j;
+
+ if (dev == NULL) {
+ err("s2255: invalid device");
+ return;
+ }
+ dprintk(4, "stop read pipe\n");
+ for (j = 0; j < MAX_PIPE_BUFFERS; j++) {
+ struct s2255_pipeinfo *pipe_info = &dev->pipes[j];
+ if (pipe_info) {
+ if (pipe_info->state == 0)
+ continue;
+ pipe_info->state = 0;
+ pipe_info->prev_state = 1;
+
+ }
+ }
+
+ for (j = 0; j < MAX_PIPE_BUFFERS; j++) {
+ struct s2255_pipeinfo *pipe_info = &dev->pipes[j];
+ if (pipe_info->stream_urb) {
+ /* cancel urb */
+ usb_kill_urb(pipe_info->stream_urb);
+ usb_free_urb(pipe_info->stream_urb);
+ pipe_info->stream_urb = NULL;
+ }
+ }
+ dprintk(2, "s2255 stop read pipe: %d\n", j);
+ return;
+}
+
+static void s2255_fwload_start(struct s2255_dev *dev)
+{
+ dev->fw_data->fw_size = dev->fw_data->fw->size;
+ atomic_set(&dev->fw_data->fw_state, S2255_FW_NOTLOADED);
+ memcpy(dev->fw_data->pfw_data,
+ dev->fw_data->fw->data, CHUNK_SIZE);
+ dev->fw_data->fw_loaded = CHUNK_SIZE;
+ usb_fill_bulk_urb(dev->fw_data->fw_urb, dev->udev,
+ usb_sndbulkpipe(dev->udev, 2),
+ dev->fw_data->pfw_data,
+ CHUNK_SIZE, s2255_fwchunk_complete,
+ dev->fw_data);
+ mod_timer(&dev->timer, jiffies + HZ);
+}
+
+/* standard usb probe function */
+static int s2255_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ struct s2255_dev *dev = NULL;
+ struct usb_host_interface *iface_desc;
+ struct usb_endpoint_descriptor *endpoint;
+ int i;
+ int retval = -ENOMEM;
+
+ dprintk(2, "s2255: probe\n");
+
+ /* allocate memory for our device state and initialize it to zero */
+ dev = kzalloc(sizeof(struct s2255_dev), GFP_KERNEL);
+ if (dev == NULL) {
+ err("s2255: out of memory");
+ goto error;
+ }
+
+ dev->fw_data = kzalloc(sizeof(struct s2255_fw), GFP_KERNEL);
+ if (!dev->fw_data)
+ goto error;
+
+ mutex_init(&dev->lock);
+ mutex_init(&dev->open_lock);
+
+ /* grab usb_device and save it */
+ dev->udev = usb_get_dev(interface_to_usbdev(interface));
+ if (dev->udev == NULL) {
+ dev_err(&interface->dev, "null usb device\n");
+ retval = -ENODEV;
+ goto error;
+ }
+ kref_init(&dev->kref);
+ dprintk(1, "dev: %p, kref: %p udev %p interface %p\n", dev, &dev->kref,
+ 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);
+ 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)) {
+ /* we found the bulk in endpoint */
+ dev->read_endpoint = endpoint->bEndpointAddress;
+ }
+ }
+
+ if (!dev->read_endpoint) {
+ dev_err(&interface->dev, "Could not find bulk-in endpoint");
+ goto error;
+ }
+
+ /* set intfdata */
+ usb_set_intfdata(interface, dev);
+
+ dprintk(100, "after intfdata %p\n", dev);
+
+ init_timer(&dev->timer);
+ dev->timer.function = s2255_timer;
+ dev->timer.data = (unsigned long)dev->fw_data;
+
+ init_waitqueue_head(&dev->fw_data->wait_fw);
+
+
+ dev->fw_data->fw_urb = usb_alloc_urb(0, GFP_KERNEL);
+
+ if (!dev->fw_data->fw_urb) {
+ dev_err(&interface->dev, "out of memory!\n");
+ goto error;
+ }
+ dev->fw_data->pfw_data = kzalloc(CHUNK_SIZE, GFP_KERNEL);
+ if (!dev->fw_data->pfw_data) {
+ dev_err(&interface->dev, "out of memory!\n");
+ goto error;
+ }
+ /* 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");
+ goto error;
+ }
+
+ /* loads v4l specific */
+ s2255_probe_v4l(dev);
+ /* load 2255 board specific */
+ s2255_board_init(dev);
+
+ dprintk(4, "before probe done %p\n", dev);
+ spin_lock_init(&dev->slock);
+
+ s2255_fwload_start(dev);
+ dev_info(&interface->dev, "Sensoray 2255 detected\n");
+ return 0;
+error:
+ return retval;
+}
+
+/* disconnect routine. when board is removed physically or with rmmod */
+static void s2255_disconnect(struct usb_interface *interface)
+{
+ struct s2255_dev *dev = NULL;
+ dprintk(1, "s2255: disconnect interface %p\n", interface);
+ dev = usb_get_intfdata(interface);
+ if (dev) {
+ kref_put(&dev->kref, s2255_destroy);
+ dprintk(1, "s2255drv: disconnect\n");
+ dev_info(&interface->dev, "s2255usb now disconnected\n");
+ }
+ usb_set_intfdata(interface, NULL);
+}
+
+static struct usb_driver s2255_driver = {
+ .name = "s2255",
+ .probe = s2255_probe,
+ .disconnect = s2255_disconnect,
+ .id_table = s2255_table,
+};
+
+static int __init usb_s2255_init(void)
+{
+ int result;
+
+ /* register this driver with the USB subsystem */
+ result = usb_register(&s2255_driver);
+
+ if (result)
+ err("usb_register failed. Error number %d", result);
+
+ dprintk(2, "s2255_init: done\n");
+ return result;
+}
+
+static void __exit usb_s2255_exit(void)
+{
+ usb_deregister(&s2255_driver);
+}
+
+module_init(usb_s2255_init);
+module_exit(usb_s2255_exit);
+
+MODULE_DESCRIPTION("Sensoray 2255 Video for Linux driver");
+MODULE_AUTHOR("Dean Anderson (Sensoray Company Inc.)");
+MODULE_LICENSE("GPL");
diff --git a/linux/drivers/media/video/saa5246a.c b/linux/drivers/media/video/saa5246a.c
index 900185cf2..2ea5d70a9 100644
--- a/linux/drivers/media/video/saa5246a.c
+++ b/linux/drivers/media/video/saa5246a.c
@@ -73,9 +73,7 @@ static struct video_device saa_template; /* Declared near bottom */
/* Addresses to scan */
static unsigned short normal_i2c[] = { I2C_ADDRESS, I2C_CLIENT_END };
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13)
-static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
-#endif
+
I2C_CLIENT_INSMOD;
static struct i2c_client client_template;
diff --git a/linux/drivers/media/video/saa5249.c b/linux/drivers/media/video/saa5249.c
index be71833d0..4443a023c 100644
--- a/linux/drivers/media/video/saa5249.c
+++ b/linux/drivers/media/video/saa5249.c
@@ -137,9 +137,7 @@ static struct video_device saa_template; /* Declared near bottom */
/* Addresses to scan */
static unsigned short normal_i2c[] = {34>>1,I2C_CLIENT_END};
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13)
-static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
-#endif
+
I2C_CLIENT_INSMOD;
static struct i2c_client client_template;
diff --git a/linux/drivers/media/video/saa6588.c b/linux/drivers/media/video/saa6588.c
index 0774c351a..5efa5ab66 100644
--- a/linux/drivers/media/video/saa6588.c
+++ b/linux/drivers/media/video/saa6588.c
@@ -31,10 +31,6 @@
#include <linux/wait.h>
#include <asm/uaccess.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-#include "i2c-compat.h"
-#endif
-
#include <media/rds.h>
#include "compat.h"
@@ -45,9 +41,6 @@ static unsigned short normal_i2c[] = {
I2C_CLIENT_END,
};
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13)
-static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
-#endif
I2C_CLIENT_INSMOD;
/* insmod options */
@@ -404,11 +397,7 @@ static int saa6588_configure(struct saa6588 *s)
/* ---------------------------------------------------------------------- */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
static int saa6588_attach(struct i2c_adapter *adap, int addr, int kind)
-#else
-static int saa6588_attach(struct i2c_adapter *adap, int addr, unsigned short flags, int kind)
-#endif
{
struct saa6588 *s;
client_template.adapter = adap;
@@ -448,28 +437,13 @@ static int saa6588_attach(struct i2c_adapter *adap, int addr, unsigned short fla
s->timer.function = saa6588_timer;
s->timer.data = (unsigned long)s;
schedule_work(&s->work);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
- MOD_INC_USE_COUNT;
-#endif
return 0;
}
static int saa6588_probe(struct i2c_adapter *adap)
{
-#ifdef I2C_CLASS_TV_ANALOG
if (adap->class & I2C_CLASS_TV_ANALOG)
return i2c_probe(adap, &addr_data, saa6588_attach);
-#else
- switch (adap->id) {
- case I2C_HW_B_BT848:
- case I2C_HW_B_RIVA:
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
- case I2C_HW_SAA7134:
-#endif
- return i2c_probe(adap, &addr_data, saa6588_attach);
- break;
- }
-#endif
return 0;
}
@@ -526,10 +500,8 @@ static int saa6588_command(struct i2c_client *client, unsigned int cmd,
/* ----------------------------------------------------------------------- */
static struct i2c_driver driver = {
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)) && ( LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15))
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15)
.owner = THIS_MODULE,
-#endif
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15)
.name = "saa6588",
.flags = I2C_DF_NOTIFY,
#else
diff --git a/linux/drivers/media/video/saa7115.c b/linux/drivers/media/video/saa7115.c
index b02c43278..5d99f8455 100644
--- a/linux/drivers/media/video/saa7115.c
+++ b/linux/drivers/media/video/saa7115.c
@@ -48,9 +48,6 @@
#include <media/v4l2-chip-ident.h>
#include <media/v4l2-i2c-drv-legacy.h>
#include <media/saa7115.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-#include "i2c-compat.h"
-#endif
#include <asm/div64.h>
#include "compat.h"
@@ -62,11 +59,7 @@ MODULE_AUTHOR( "Maxim Yevtyushkin, Kevin Thayer, Chris Kennedy, "
MODULE_LICENSE("GPL");
static int debug;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
module_param(debug, bool, 0644);
-#else
-MODULE_PARM(debug, "i");
-#endif
MODULE_PARM_DESC(debug, "Debug level (0-1)");
@@ -75,10 +68,6 @@ static unsigned short normal_i2c[] = {
0x42 >> 1, 0x40 >> 1, /* SAA7114, SAA7115 and SAA7118 */
I2C_CLIENT_END };
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13)
-static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
-#endif
-
I2C_CLIENT_INSMOD;
struct saa711x_state {
@@ -1467,14 +1456,19 @@ static int saa7115_probe(struct i2c_client *client,
struct saa711x_state *state;
int i;
char name[17];
- u8 chip_id;
+ char chip_id;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ int autodetect = !id || id->driver_data == 1;
+#endif
/* Check if the adapter supports the needed features */
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -EIO;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
snprintf(client->name, sizeof(client->name) - 1, "saa7115");
+#endif
for (i = 0; i < 0x0f; i++) {
saa711x_write(client, 0, i);
name[i] = (saa711x_read(client, 0) & 0x0f) + '0';
@@ -1483,8 +1477,7 @@ static int saa7115_probe(struct i2c_client *client,
}
name[i] = '\0';
- saa711x_write(client, 0, 5);
- chip_id = saa711x_read(client, 0) & 0x0f;
+ chip_id = name[5];
/* Check whether this chip is part of the saa711x series */
if (memcmp(name, "1f711", 5)) {
@@ -1493,8 +1486,16 @@ static int saa7115_probe(struct i2c_client *client,
return -ENODEV;
}
- snprintf(client->name, sizeof(client->name) - 1, "saa711%d",chip_id);
- v4l_info(client, "saa711%d found (%s) @ 0x%x (%s)\n", chip_id, name, client->addr << 1, client->adapter->name);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ /* Safety check */
+ if (!autodetect && id->name[6] != chip_id) {
+ v4l_warn(client, "found saa711%c while %s was expected\n",
+ chip_id, id->name);
+ }
+#endif
+ snprintf(client->name, sizeof(client->name), "saa711%c", chip_id);
+ v4l_info(client, "saa711%c found (%s) @ 0x%x (%s)\n", chip_id, name,
+ client->addr << 1, client->adapter->name);
state = kzalloc(sizeof(struct saa711x_state), GFP_KERNEL);
i2c_set_clientdata(client, state);
@@ -1510,19 +1511,19 @@ static int saa7115_probe(struct i2c_client *client,
state->hue = 0;
state->sat = 64;
switch (chip_id) {
- case 1:
+ case '1':
state->ident = V4L2_IDENT_SAA7111;
break;
- case 3:
+ case '3':
state->ident = V4L2_IDENT_SAA7113;
break;
- case 4:
+ case '4':
state->ident = V4L2_IDENT_SAA7114;
break;
- case 5:
+ case '5':
state->ident = V4L2_IDENT_SAA7115;
break;
- case 8:
+ case '8':
state->ident = V4L2_IDENT_SAA7118;
break;
default:
@@ -1564,17 +1565,27 @@ static int saa7115_remove(struct i2c_client *client)
return 0;
}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+static const struct i2c_device_id saa7115_id[] = {
+ { "saa711x", 1 }, /* autodetect */
+ { "saa7111", 0 },
+ { "saa7113", 0 },
+ { "saa7114", 0 },
+ { "saa7115", 0 },
+ { "saa7118", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, saa7115_id);
+
+#endif
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.name = "saa7115",
.driverid = I2C_DRIVERID_SAA711X,
.command = saa7115_command,
.probe = saa7115_probe,
.remove = saa7115_remove,
-#ifdef I2C_CLASS_TV_ANALOG
.legacy_class = I2C_CLASS_TV_ANALOG | I2C_CLASS_TV_DIGITAL,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ .id_table = saa7115_id,
#endif
};
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-EXPORT_NO_SYMBOLS;
-#endif
diff --git a/linux/drivers/media/video/saa711x.c b/linux/drivers/media/video/saa711x.c
deleted file mode 100644
index 28e0c5711..000000000
--- a/linux/drivers/media/video/saa711x.c
+++ /dev/null
@@ -1,618 +0,0 @@
-/*
- * saa711x - Philips SAA711x video decoder driver version 0.0.1
- *
- * To do: Now, it handles only saa7113/7114. Should be improved to
- * handle all Philips saa711x devices.
- *
- * Based on saa7113 driver from Dave Perks <dperks@ibm.net>
- *
- * 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/delay.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/signal.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <linux/types.h>
-#include <asm/uaccess.h>
-#include "compat.h"
-#include <linux/videodev.h>
-
-MODULE_DESCRIPTION("Philips SAA711x video decoder driver");
-MODULE_AUTHOR("Dave Perks, Jose Ignacio Gijon, Joerg Heckenbach, Mark McClelland, Dwaine Garden");
-MODULE_LICENSE("GPL");
-
-#include <linux/i2c.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-#include "i2c-compat.h"
-#endif
-
-#define I2C_NAME(s) (s)->name
-
-#include <linux/video_decoder.h>
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, " Set the default Debug level. Default: 0 (Off) - (0-1)");
-
-
-#define dprintk(num, format, args...) \
- do { \
- if (debug >= num) \
- printk(format, ##args); \
- } while (0)
-
-/* ----------------------------------------------------------------------- */
-
-struct saa711x {
- unsigned char reg[32];
-
- int norm;
- int input;
- int enable;
- int bright;
- int contrast;
- int hue;
- int sat;
-};
-
-#define I2C_SAA7113 0x4A
-#define I2C_SAA7114 0x42
-
-/* ----------------------------------------------------------------------- */
-
-static inline int
-saa711x_write (struct i2c_client *client,
- u8 reg,
- u8 value)
-{
- struct saa711x *decoder = i2c_get_clientdata(client);
-
- decoder->reg[reg] = value;
- return i2c_smbus_write_byte_data(client, reg, value);
-}
-
-static int
-saa711x_write_block (struct i2c_client *client,
- const u8 *data,
- unsigned int len)
-{
- int ret = -1;
- u8 reg;
-
- /* the saa711x has an autoincrement function, use it if
- * the adapter understands raw I2C */
- if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
- /* do raw I2C, not smbus compatible */
- struct saa711x *decoder = i2c_get_clientdata(client);
- struct i2c_msg msg;
- u8 block_data[32];
-
- msg.addr = client->addr;
- msg.flags = 0;
- while (len >= 2) {
- msg.buf = (char *) block_data;
- msg.len = 0;
- block_data[msg.len++] = reg = data[0];
- do {
- block_data[msg.len++] =
- decoder->reg[reg++] = data[1];
- len -= 2;
- data += 2;
- } while (len >= 2 && data[0] == reg &&
- msg.len < 32);
- if ((ret = i2c_transfer(client->adapter,
- &msg, 1)) < 0)
- break;
- }
- } else {
- /* do some slow I2C emulation kind of thing */
- while (len >= 2) {
- reg = *data++;
- if ((ret = saa711x_write(client, reg,
- *data++)) < 0)
- break;
- len -= 2;
- }
- }
-
- return ret;
-}
-
-static int
-saa711x_init_decoder (struct i2c_client *client,
- struct video_decoder_init *init)
-{
- return saa711x_write_block(client, init->data, init->len);
-}
-
-static inline int
-saa711x_read (struct i2c_client *client,
- u8 reg)
-{
- return i2c_smbus_read_byte_data(client, reg);
-}
-
-/* ----------------------------------------------------------------------- */
-
-static const unsigned char saa711x_i2c_init[] = {
- 0x00, 0x00, /* PH711x_CHIP_VERSION 00 - ID byte */
- 0x01, 0x08, /* PH711x_INCREMENT_DELAY - (1) (1) (1) (1) IDEL3 IDEL2 IDELL1 IDEL0 */
- 0x02, 0xc0, /* PH711x_ANALOG_INPUT_CONTR_1 - FUSE1 FUSE0 GUDL1 GUDL0 MODE3 MODE2 MODE1 MODE0 */
- 0x03, 0x23, /* PH711x_ANALOG_INPUT_CONTR_2 - (1) HLNRS VBSL WPOFF HOLDG GAFIX GAI28 GAI18 */
- 0x04, 0x00, /* PH711x_ANALOG_INPUT_CONTR_3 - GAI17 GAI16 GAI15 GAI14 GAI13 GAI12 GAI11 GAI10 */
- 0x05, 0x00, /* PH711x_ANALOG_INPUT_CONTR_4 - GAI27 GAI26 GAI25 GAI24 GAI23 GAI22 GAI21 GAI20 */
- 0x06, 0xeb, /* PH711x_HORIZONTAL_SYNC_START - HSB7 HSB6 HSB5 HSB4 HSB3 HSB2 HSB1 HSB0 */
- 0x07, 0xe0, /* PH711x_HORIZONTAL_SYNC_STOP - HSS7 HSS6 HSS5 HSS4 HSS3 HSS2 HSS1 HSS0 */
- 0x08, 0x88, /* PH711x_SYNC_CONTROL - AUFD FSEL FOET HTC1 HTC0 HPLL VNOI1 VNOI0 */
- 0x09, 0x00, /* PH711x_LUMINANCE_CONTROL - BYPS PREF BPSS1 BPSS0 VBLB UPTCV APER1 APER0 */
- 0x0a, 0x80, /* PH711x_LUMINANCE_BRIGHTNESS - BRIG7 BRIG6 BRIG5 BRIG4 BRIG3 BRIG2 BRIG1 BRIG0 */
- 0x0b, 0x47, /* PH711x_LUMINANCE_CONTRAST - CONT7 CONT6 CONT5 CONT4 CONT3 CONT2 CONT1 CONT0 */
- 0x0c, 0x40, /* PH711x_CHROMA_SATURATION - SATN7 SATN6 SATN5 SATN4 SATN3 SATN2 SATN1 SATN0 */
- 0x0d, 0x00, /* PH711x_CHROMA_HUE_CONTROL - HUEC7 HUEC6 HUEC5 HUEC4 HUEC3 HUEC2 HUEC1 HUEC0 */
- 0x0e, 0x01, /* PH711x_CHROMA_CONTROL - CDTO CSTD2 CSTD1 CSTD0 DCCF FCTC CHBW1 CHBW0 */
- 0x0f, 0xaa, /* PH711x_CHROMA_GAIN_CONTROL - ACGC CGAIN6 CGAIN5 CGAIN4 CGAIN3 CGAIN2 CGAIN1 CGAIN0 */
- 0x10, 0x00, /* PH711x_FORMAT_DELAY_CONTROL - OFTS1 OFTS0 HDEL1 HDEL0 VRLN YDEL2 YDEL1 YDEL0 */
- 0x11, 0x1C, /* PH711x_OUTPUT_CONTROL_1 - GPSW1 CM99 GPSW0 HLSEL OEYC OERT VIPB COLO */
- 0x12, 0x01, /* PH711x_OUTPUT_CONTROL_2 - RTSE13 RTSE12 RTSE11 RTSE10 RTSE03 RTSE02 RTSE01 RTSE00 */
- 0x13, 0x00, /* PH711x_OUTPUT_CONTROL_3 - ADLSB (1) (1) OLDSB FIDP (1) AOSL1 AOSL0 */
- 0x14, 0x00, /* RESERVED 14 - (1) (1) (1) (1) (1) (1) (1) (1) */
- 0x15, 0x00, /* PH711x_V_GATE1_START - VSTA7 VSTA6 VSTA5 VSTA4 VSTA3 VSTA2 VSTA1 VSTA0 */
- 0x16, 0x00, /* PH711x_V_GATE1_STOP - VSTO7 VSTO6 VSTO5 VSTO4 VSTO3 VSTO2 VSTO1 VSTO0 */
- 0x17, 0x00, /* PH711x_V_GATE1_MSB - (1) (1) (1) (1) (1) (1) VSTO8 VSTA8 */
-};
-
-static int
-saa711x_command (struct i2c_client *client,
- unsigned int cmd,
- void *arg)
-{
- struct saa711x *decoder = i2c_get_clientdata(client);
-
- switch (cmd) {
-
- case 0:
- case DECODER_INIT:
- {
- struct video_decoder_init *init = arg;
- if (NULL != init)
- return saa711x_init_decoder(client, init);
- else {
- struct video_decoder_init vdi;
- vdi.data = saa711x_i2c_init;
- vdi.len = sizeof(saa711x_i2c_init);
- return saa711x_init_decoder(client, &vdi);
- }
- }
-
- case DECODER_DUMP:
- {
- int i;
-
- for (i = 0; i < 32; i += 16) {
- int j;
-
- printk(KERN_DEBUG "%s: %03x", I2C_NAME(client), i);
- for (j = 0; j < 16; ++j) {
- printk(" %02x",
- saa711x_read(client, i + j));
- }
- printk("\n");
- }
- }
- break;
-
- case DECODER_GET_CAPABILITIES:
- {
- struct video_decoder_capability *cap = arg;
-
- cap->flags = VIDEO_DECODER_PAL |
- VIDEO_DECODER_NTSC |
- VIDEO_DECODER_SECAM |
- VIDEO_DECODER_AUTO |
- VIDEO_DECODER_CCIR;
- cap->inputs = 8;
- cap->outputs = 1;
- }
- break;
-
- case DECODER_GET_STATUS:
- {
- int *iarg = arg;
- int status;
- int res;
-
- status = saa711x_read(client, 0x1f);
- dprintk(1, KERN_DEBUG "%s status: 0x%02x\n", I2C_NAME(client),
- status);
- res = 0;
- if ((status & (1 << 6)) == 0) {
- res |= DECODER_STATUS_GOOD;
- }
- switch (decoder->norm) {
- case VIDEO_MODE_NTSC:
- res |= DECODER_STATUS_NTSC;
- break;
- case VIDEO_MODE_PAL:
- res |= DECODER_STATUS_PAL;
- break;
- case VIDEO_MODE_SECAM:
- res |= DECODER_STATUS_SECAM;
- break;
- default:
- case VIDEO_MODE_AUTO:
- if ((status & (1 << 5)) != 0) {
- res |= DECODER_STATUS_NTSC;
- } else {
- res |= DECODER_STATUS_PAL;
- }
- break;
- }
- if ((status & (1 << 0)) != 0) {
- res |= DECODER_STATUS_COLOR;
- }
- *iarg = res;
- }
- break;
-
- case DECODER_SET_GPIO:
- {
- int *iarg = arg;
- if (0 != *iarg) {
- saa711x_write(client, 0x11,
- (decoder->reg[0x11] | 0x80));
- } else {
- saa711x_write(client, 0x11,
- (decoder->reg[0x11] & 0x7f));
- }
- break;
- }
-
- case DECODER_SET_VBI_BYPASS:
- {
- int *iarg = arg;
- if (0 != *iarg) {
- saa711x_write(client, 0x13,
- (decoder->reg[0x13] & 0xf0) | 0x0a);
- } else {
- saa711x_write(client, 0x13,
- (decoder->reg[0x13] & 0xf0));
- }
- break;
- }
-
- case DECODER_SET_NORM:
- {
- int *iarg = arg;
-
- switch (*iarg) {
-
- case VIDEO_MODE_NTSC:
- saa711x_write(client, 0x08,
- (decoder->reg[0x08] & 0x3f) | 0x40);
- saa711x_write(client, 0x0e,
- (decoder->reg[0x0e] & 0x8f));
- break;
-
- case VIDEO_MODE_PAL:
- saa711x_write(client, 0x08,
- (decoder->reg[0x08] & 0x3f) | 0x00);
- saa711x_write(client, 0x0e,
- (decoder->reg[0x0e] & 0x8f));
- break;
-
- case VIDEO_MODE_SECAM:
- saa711x_write(client, 0x08,
- (decoder->reg[0x08] & 0x3f) | 0x00);
- saa711x_write(client, 0x0e,
- (decoder->reg[0x0e] & 0x8f) | 0x50);
- break;
-
- case VIDEO_MODE_AUTO:
- saa711x_write(client, 0x08,
- (decoder->reg[0x08] & 0x3f) | 0x80);
- saa711x_write(client, 0x0e,
- (decoder->reg[0x0e] & 0x8f));
- break;
-
- default:
- return -EINVAL;
-
- }
- decoder->norm = *iarg;
- }
- break;
-
- case DECODER_SET_INPUT:
- {
- int *iarg = arg;
- if (*iarg < 0 || *iarg > 9) {
- return -EINVAL;
- }
- if (decoder->input != *iarg) {
- decoder->input = *iarg;
- /* select mode */
- saa711x_write(client, 0x02,
- (decoder->reg[0x02] & 0xf0) | decoder->input);
- /* bypass chrominance trap for modes 4..7 */
- saa711x_write(client, 0x09,
- (decoder->reg[0x09] & 0x7f) | ((decoder->input > 3) ? 0x80 : 0));
- }
- }
- break;
-
- case DECODER_SET_OUTPUT:
- {
- int *iarg = arg;
-
- /* not much choice of outputs */
- if (*iarg != 0) {
- return -EINVAL;
- }
- }
- break;
-
- case DECODER_ENABLE_OUTPUT:
- {
- int *iarg = arg;
- int enable = (*iarg != 0);
-
- if (decoder->enable != enable) {
- decoder->enable = enable;
-
- /* RJ: If output should be disabled (for
- * playing videos), we also need a open PLL.
- * The input is set to 0 (where no input
- * source is connected), although this
- * is not necessary.
- *
- * If output should be enabled, we have to
- * reverse the above.
- */
-
- if (decoder->enable) {
- saa711x_write(client, 0x02,
- (decoder->
- reg[0x02] & 0xf8) |
- decoder->input);
- saa711x_write(client, 0x08,
- (decoder->reg[0x08] & 0xfb));
- saa711x_write(client, 0x11,
- (decoder->
- reg[0x11] & 0xf3) | 0x0c);
- } else {
- saa711x_write(client, 0x02,
- (decoder->reg[0x02] & 0xf8));
- saa711x_write(client, 0x08,
- (decoder->
- reg[0x08] & 0xfb) | 0x04);
- saa711x_write(client, 0x11,
- (decoder->reg[0x11] & 0xf3));
- }
- }
- }
- break;
-
- case DECODER_SET_PICTURE:
- {
- struct video_picture *pic = arg;
-
- if (decoder->bright != pic->brightness) {
- /* We want 0 to 255 we get 0-65535 */
- decoder->bright = pic->brightness;
- saa711x_write(client, 0x0a, decoder->bright >> 8);
- }
- if (decoder->contrast != pic->contrast) {
- /* We want 0 to 127 we get 0-65535 */
- decoder->contrast = pic->contrast;
- saa711x_write(client, 0x0b,
- decoder->contrast >> 9);
- }
- if (decoder->sat != pic->colour) {
- /* We want 0 to 127 we get 0-65535 */
- decoder->sat = pic->colour;
- saa711x_write(client, 0x0c, decoder->sat >> 9);
- }
- if (decoder->hue != pic->hue) {
- /* We want -128 to 127 we get 0-65535 */
- decoder->hue = pic->hue;
- saa711x_write(client, 0x0d,
- (decoder->hue - 32768) >> 8);
- }
- }
- break;
-
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-
-/*
- * Generic i2c probe
- * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
- */
-
-/* standard i2c insmod options */
-static unsigned short normal_i2c[] = {
- I2C_SAA7113>>1, /* saa7113 */
- I2C_SAA7114>>1, /* saa7114 */
- I2C_CLIENT_END
-};
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13)
-static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
-#endif
-I2C_CLIENT_INSMOD;
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 11)
-static int saa711x_i2c_id;
-#endif
-
-static struct i2c_driver i2c_driver_saa711x;
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
-static int
-saa711x_detect_client (struct i2c_adapter *adapter,
- int address,
- int kind)
-#else
-static int
-saa711x_detect_client (struct i2c_adapter *adapter,
- int address,
- unsigned short flags, int kind)
-#endif
-{
- int i;
- struct i2c_client *client;
- struct saa711x *decoder;
- struct video_decoder_init vdi;
-
- dprintk(1,
- KERN_INFO
- "saa711x.c: detecting saa711x client on address 0x%x\n",
- address << 1);
-
- /* Check if the adapter supports the needed features */
- if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
- return 0;
-
- client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
- if (client == 0)
- return -ENOMEM;
- client->addr = address;
- client->adapter = adapter;
- client->driver = &i2c_driver_saa711x;
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15)
- client->flags = I2C_CLIENT_ALLOW_USE;
-#endif
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 11)
- client->id = saa711x_i2c_id++;
- snprintf(I2C_NAME(client), sizeof(I2C_NAME(client)) - 1,
- "saa7111[%d]", client->id);
-#else
- strlcpy(I2C_NAME(client), "saa711x", sizeof(I2C_NAME(client)));
-#endif
- decoder = kzalloc(sizeof(struct saa711x), GFP_KERNEL);
- if (decoder == NULL) {
- kfree(client);
- return -ENOMEM;
- }
- decoder->norm = VIDEO_MODE_NTSC;
- decoder->input = 0;
- decoder->enable = 1;
- decoder->bright = 32768;
- decoder->contrast = 32768;
- decoder->hue = 32768;
- decoder->sat = 32768;
- i2c_set_clientdata(client, decoder);
-
- i = i2c_attach_client(client);
- if (i) {
- kfree(client);
- kfree(decoder);
- return i;
- }
-
- vdi.data = saa711x_i2c_init;
- vdi.len = sizeof(saa711x_i2c_init);
- i = saa711x_init_decoder(client, &vdi);
- if (i < 0) {
- dprintk(1, KERN_ERR "%s_attach error: init status %d\n",
- I2C_NAME(client), i);
- } else {
- dprintk(1,
- KERN_INFO
- "%s_attach: chip version %x at address 0x%x\n",
- I2C_NAME(client), saa711x_read(client, 0x00) >> 4,
- client->addr << 1);
- }
-
- return 0;
-}
-
-static int
-saa711x_attach_adapter (struct i2c_adapter *adapter)
-{
- dprintk(1,
- KERN_INFO
- "saa711x.c: starting probe for adapter %s (0x%x)\n",
- I2C_NAME(adapter), adapter->id);
- return i2c_probe(adapter, &addr_data, &saa711x_detect_client);
-}
-
-static int
-saa711x_detach_client (struct i2c_client *client)
-{
- struct saa711x *decoder = i2c_get_clientdata(client);
- int err;
-
- err = i2c_detach_client(client);
- if (err) {
- return err;
- }
-
- kfree(decoder);
- kfree(client);
-
- return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-
-static struct i2c_driver i2c_driver_saa711x = {
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))&&(LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15))
- .owner = THIS_MODULE,
-#endif
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15)
- .name = "saa711x",
- .flags = I2C_DF_NOTIFY,
-#else
- .driver = {
- .name = "saa711x",
- },
-#endif
- .id = I2C_DRIVERID_SAA711X,
- .attach_adapter = saa711x_attach_adapter,
- .detach_client = saa711x_detach_client,
- .command = saa711x_command,
-};
-
-static int __init
-saa711x_init (void)
-{
- return i2c_add_driver(&i2c_driver_saa711x);
-}
-
-static void __exit
-saa711x_exit (void)
-{
- i2c_del_driver(&i2c_driver_saa711x);
-}
-
-module_init(saa711x_init);
-module_exit(saa711x_exit);
diff --git a/linux/drivers/media/video/saa7127.c b/linux/drivers/media/video/saa7127.c
index 3acc869b7..28905adfb 100644
--- a/linux/drivers/media/video/saa7127.c
+++ b/linux/drivers/media/video/saa7127.c
@@ -57,9 +57,6 @@
#include <media/v4l2-chip-ident.h>
#include <media/v4l2-i2c-drv.h>
#include <media/saa7127.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
-#include "i2c-compat.h"
-#endif
#include "compat.h"
static int debug;
@@ -68,23 +65,14 @@ static int test_image;
MODULE_DESCRIPTION("Philips SAA7127/9 video encoder driver");
MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil");
MODULE_LICENSE("GPL");
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
module_param(debug, int, 0644);
module_param(test_image, int, 0644);
-#else
-MODULE_PARM(debug, "i");
-MODULE_PARM(test_image, "i");
-#endif
MODULE_PARM_DESC(debug, "debug level (0-2)");
MODULE_PARM_DESC(test_image, "test_image (0-1)");
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
static unsigned short normal_i2c[] = { 0x88 >> 1, I2C_CLIENT_END };
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 13)
-static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
-#endif
-
I2C_CLIENT_INSMOD;
#endif
@@ -690,8 +678,10 @@ static int saa7127_probe(struct i2c_client *client,
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -EIO;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
snprintf(client->name, sizeof(client->name) - 1, "saa7127");
+#endif
v4l_dbg(1, debug, client, "detecting saa7127 client on address 0x%x\n",
client->addr << 1);
@@ -759,14 +749,21 @@ static int saa7127_remove(struct i2c_client *client)
/* ----------------------------------------------------------------------- */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+static struct i2c_device_id saa7127_id[] = {
+ { "saa7127", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, saa7127_id);
+
+#endif
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.name = "saa7127",
.driverid = I2C_DRIVERID_SAA7127,
.command = saa7127_command,
.probe = saa7127_probe,
.remove = saa7127_remove,
-};
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
-EXPORT_NO_SYMBOLS;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ .id_table = saa7127_id,
#endif
+};
diff --git a/linux/drivers/media/video/saa7134/saa6752hs.c b/linux/drivers/media/video/saa7134/saa6752hs.c
index 1ea15594d..0143c8b28 100644
--- a/linux/drivers/media/video/saa7134/saa6752hs.c
+++ b/linux/drivers/media/video/saa7134/saa6752hs.c
@@ -14,10 +14,6 @@
#include <linux/init.h>
#include <linux/crc32.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-#include "i2c-compat.h"
-#endif
-
#define MPEG_VIDEO_TARGET_BITRATE_MAX 27000
#define MPEG_VIDEO_MAX_BITRATE_MAX 27000
#define MPEG_TOTAL_TARGET_BITRATE_MAX 27000
@@ -25,9 +21,7 @@
/* Addresses to scan */
static unsigned short normal_i2c[] = {0x20, I2C_CLIENT_END};
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13)
-static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
-#endif
+
I2C_CLIENT_INSMOD;
MODULE_DESCRIPTION("device driver for saa6752hs MPEG2 encoder");
@@ -455,6 +449,104 @@ static int handle_ctrl(struct saa6752hs_mpeg_params *params,
return 0;
}
+static int saa6752hs_qctrl(struct saa6752hs_mpeg_params *params,
+ struct v4l2_queryctrl *qctrl)
+{
+ int err;
+
+ switch (qctrl->id) {
+ case V4L2_CID_MPEG_AUDIO_ENCODING:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
+ V4L2_MPEG_AUDIO_ENCODING_LAYER_2, 1,
+ V4L2_MPEG_AUDIO_ENCODING_LAYER_2);
+
+ case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_AUDIO_L2_BITRATE_256K,
+ V4L2_MPEG_AUDIO_L2_BITRATE_384K, 1,
+ V4L2_MPEG_AUDIO_L2_BITRATE_256K);
+
+ case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000,
+ V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000, 1,
+ V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000);
+
+ case V4L2_CID_MPEG_VIDEO_ENCODING:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_VIDEO_ENCODING_MPEG_2,
+ V4L2_MPEG_VIDEO_ENCODING_MPEG_2, 1,
+ V4L2_MPEG_VIDEO_ENCODING_MPEG_2);
+
+ case V4L2_CID_MPEG_VIDEO_ASPECT:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_VIDEO_ASPECT_4x3,
+ V4L2_MPEG_VIDEO_ASPECT_16x9, 1,
+ V4L2_MPEG_VIDEO_ASPECT_4x3);
+
+ case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+ err = v4l2_ctrl_query_fill_std(qctrl);
+ if (err == 0 &&
+ params->vi_bitrate_mode ==
+ V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
+ qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ return err;
+
+ case V4L2_CID_MPEG_STREAM_TYPE:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_STREAM_TYPE_MPEG2_TS,
+ V4L2_MPEG_STREAM_TYPE_MPEG2_TS, 1,
+ V4L2_MPEG_STREAM_TYPE_MPEG2_TS);
+
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+ case V4L2_CID_MPEG_VIDEO_BITRATE:
+ case V4L2_CID_MPEG_STREAM_PID_PMT:
+ case V4L2_CID_MPEG_STREAM_PID_AUDIO:
+ case V4L2_CID_MPEG_STREAM_PID_VIDEO:
+ case V4L2_CID_MPEG_STREAM_PID_PCR:
+ return v4l2_ctrl_query_fill_std(qctrl);
+
+ default:
+ break;
+ }
+ return -EINVAL;
+}
+
+static int saa6752hs_qmenu(struct saa6752hs_mpeg_params *params,
+ struct v4l2_querymenu *qmenu)
+{
+ static const char *mpeg_audio_l2_bitrate[] = {
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "256 kbps",
+ "",
+ "384 kbps",
+ NULL
+ };
+ struct v4l2_queryctrl qctrl;
+ int err;
+
+ qctrl.id = qmenu->id;
+ err = saa6752hs_qctrl(params, &qctrl);
+ if (err)
+ return err;
+ if (qmenu->id == V4L2_CID_MPEG_AUDIO_L2_BITRATE)
+ return v4l2_ctrl_query_menu(qmenu, &qctrl,
+ mpeg_audio_l2_bitrate);
+ return v4l2_ctrl_query_menu(qmenu, &qctrl,
+ v4l2_ctrl_get_menu(qmenu->id));
+}
+
static int saa6752hs_init(struct i2c_client* client)
{
unsigned char buf[9], buf2[4];
@@ -597,11 +689,7 @@ static int saa6752hs_init(struct i2c_client* client)
return 0;
}
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
static int saa6752hs_attach(struct i2c_adapter *adap, int addr, int kind)
-#else
-static int saa6752hs_attach(struct i2c_adapter *adap, int addr, unsigned short flags, int kind)
-#endif
{
struct saa6752hs_state *h;
@@ -620,21 +708,13 @@ static int saa6752hs_attach(struct i2c_adapter *adap, int addr, unsigned short f
i2c_attach_client(&h->client);
v4l_info(&h->client,"saa6752hs: chip found @ 0x%x\n", addr<<1);
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
- MOD_INC_USE_COUNT;
-#endif
return 0;
}
static int saa6752hs_probe(struct i2c_adapter *adap)
{
-#if I2C_CLASS_TV_ANALOG
if (adap->class & I2C_CLASS_TV_ANALOG)
return i2c_probe(adap, &addr_data, saa6752hs_attach);
-#else
- return i2c_probe(adap, &addr_data, saa6752hs_attach);
-#endif
return 0;
}
@@ -680,6 +760,10 @@ saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg)
}
h->params = params;
break;
+ case VIDIOC_QUERYCTRL:
+ return saa6752hs_qctrl(&h->params, arg);
+ case VIDIOC_QUERYMENU:
+ return saa6752hs_qmenu(&h->params, arg);
case VIDIOC_G_FMT:
{
struct v4l2_format *f = arg;
@@ -713,10 +797,8 @@ saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg)
/* ----------------------------------------------------------------------- */
static struct i2c_driver driver = {
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))&&(LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15))
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15)
.owner = THIS_MODULE,
-#endif
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15)
.name = "saa6752hs",
.flags = I2C_DF_NOTIFY,
#else
diff --git a/linux/drivers/media/video/saa7134/saa7134-alsa.c b/linux/drivers/media/video/saa7134/saa7134-alsa.c
index 58670f9ea..6293eba34 100644
--- a/linux/drivers/media/video/saa7134/saa7134-alsa.c
+++ b/linux/drivers/media/video/saa7134/saa7134-alsa.c
@@ -16,7 +16,6 @@
*
*/
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/time.h>
@@ -52,14 +51,8 @@ static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 1};
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
-static int dummy;
-module_param_array(index, int, dummy, 0444);
-module_param_array(enable, int, dummy, 0444);
-#else
module_param_array(index, int, NULL, 0444);
module_param_array(enable, int, NULL, 0444);
-#endif
MODULE_PARM_DESC(index, "Index value for SAA7134 capture interface(s).");
MODULE_PARM_DESC(enable, "Enable (or not) the SAA7134 capture interface(s).");
@@ -88,10 +81,6 @@ typedef struct snd_card_saa7134 {
} snd_card_saa7134_t;
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,8)
-#define chip_t snd_card_saa7134_t
-#endif
-
/*
* PCM structure
*/
@@ -628,9 +617,15 @@ static int snd_card_saa7134_capture_open(struct snd_pcm_substream * substream)
struct snd_pcm_runtime *runtime = substream->runtime;
snd_card_saa7134_pcm_t *pcm;
snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream);
- struct saa7134_dev *dev = saa7134->dev;
+ struct saa7134_dev *dev;
int amux, err;
+ if (!saa7134) {
+ printk(KERN_ERR "BUG: saa7134 can't find device struct."
+ " Can't proceed with open\n");
+ return -ENODEV;
+ }
+ dev = saa7134->dev;
mutex_lock(&dev->dmasound.lock);
dev->dmasound.read_count = 0;
@@ -1130,7 +1125,3 @@ late_initcall(saa7134_alsa_init);
module_exit(saa7134_alsa_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Ricardo Cerqueira");
-
-
-#endif /* LINUX_VERSION_CODE */
-
diff --git a/linux/drivers/media/video/saa7134/saa7134-cards.c b/linux/drivers/media/video/saa7134/saa7134-cards.c
index 49bf24e7b..f772e9da9 100644
--- a/linux/drivers/media/video/saa7134/saa7134-cards.c
+++ b/linux/drivers/media/video/saa7134/saa7134-cards.c
@@ -3979,32 +3979,111 @@ struct saa7134_board saa7134_boards[] = {
[SAA7134_BOARD_BEHOLD_M6] = {
/* Igor Kuznetsov <igk@igk.ru> */
/* Andrey Melnikoff <temnota@kmv.ru> */
- .name = "Beholder BeholdTV M6 / BeholdTV M6 Extra",
+ /* Beholder Intl. Ltd. Dmitry Belimov <d.belimov@gmail.com> */
+ .name = "Beholder BeholdTV M6",
.audio_clock = 0x00187de7,
.tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
- .inputs = {{
+ .inputs = { {
.name = name_tv,
.vmux = 3,
.amux = TV,
.tv = 1,
- },{
+ }, {
.name = name_comp1,
.vmux = 1,
.amux = LINE1,
- },{
+ }, {
.name = name_svideo,
.vmux = 8,
.amux = LINE1,
- }},
+ } },
+ .radio = {
+ .name = name_radio,
+ .amux = LINE2,
+ },
+ .mpeg = SAA7134_MPEG_EMPRESS,
+ .video_out = CCIR656,
+ .vid_port_opts = (SET_T_CODE_POLARITY_NON_INVERTED |
+ SET_CLOCK_NOT_DELAYED |
+ SET_CLOCK_INVERTED |
+ SET_VSYNC_OFF),
+ },
+ [SAA7134_BOARD_BEHOLD_M63] = {
+ /* Igor Kuznetsov <igk@igk.ru> */
+ /* Andrey Melnikoff <temnota@kmv.ru> */
+ /* Beholder Intl. Ltd. Dmitry Belimov <d.belimov@gmail.com> */
+ .name = "Beholder BeholdTV M63",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .inputs = { {
+ .name = name_tv,
+ .vmux = 3,
+ .amux = TV,
+ .tv = 1,
+ }, {
+ .name = name_comp1,
+ .vmux = 1,
+ .amux = LINE1,
+ }, {
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
+ } },
+ .radio = {
+ .name = name_radio,
+ .amux = LINE2,
+ },
+ .mpeg = SAA7134_MPEG_EMPRESS,
+ .video_out = CCIR656,
+ .vid_port_opts = (SET_T_CODE_POLARITY_NON_INVERTED |
+ SET_CLOCK_NOT_DELAYED |
+ SET_CLOCK_INVERTED |
+ SET_VSYNC_OFF),
+ },
+ [SAA7134_BOARD_BEHOLD_M6_EXTRA] = {
+ /* Igor Kuznetsov <igk@igk.ru> */
+ /* Andrey Melnikoff <temnota@kmv.ru> */
+ /* Beholder Intl. Ltd. Dmitry Belimov <d.belimov@gmail.com> */
+ .name = "Beholder BeholdTV M6 Extra",
+ .audio_clock = 0x00187de7,
+ /* FIXME: Must be PHILIPS_FM1216ME_MK5*/
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .inputs = { {
+ .name = name_tv,
+ .vmux = 3,
+ .amux = TV,
+ .tv = 1,
+ }, {
+ .name = name_comp1,
+ .vmux = 1,
+ .amux = LINE1,
+ }, {
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
+ } },
.radio = {
.name = name_radio,
.amux = LINE2,
},
.mpeg = SAA7134_MPEG_EMPRESS,
+ .video_out = CCIR656,
+ .vid_port_opts = (SET_T_CODE_POLARITY_NON_INVERTED |
+ SET_CLOCK_NOT_DELAYED |
+ SET_CLOCK_INVERTED |
+ SET_VSYNC_OFF),
},
[SAA7134_BOARD_TWINHAN_DTV_DVB_3056] = {
.name = "Twinhan Hybrid DTV-DVB 3056 PCI",
@@ -4153,20 +4232,16 @@ struct saa7134_board saa7134_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- /*
- TODO:
.mpeg = SAA7134_MPEG_DVB,
- */
-
.inputs = {{
.name = name_tv,
.vmux = 1,
.amux = TV,
.tv = 1,
}, {
- .name = name_comp1,
- .vmux = 3,
- .amux = LINE2,
+ .name = name_comp,
+ .vmux = 0,
+ .amux = LINE1,
}, {
.name = name_svideo,
.vmux = 8,
@@ -4184,10 +4259,7 @@ struct saa7134_board saa7134_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
-#if 0
- /* Not working yet */
.mpeg = SAA7134_MPEG_DVB,
-#endif
.inputs = {{
.name = name_tv,
.vmux = 1,
@@ -4197,10 +4269,14 @@ struct saa7134_board saa7134_boards[] = {
.name = name_svideo,
.vmux = 8,
.amux = LINE1,
+ }, {
+ .name = name_comp,
+ .vmux = 0,
+ .amux = LINE1,
} },
.radio = {
.name = name_radio,
- .amux = LINE1,
+ .amux = TV,
},
},
[SAA7134_BOARD_AVERMEDIA_M115] = {
@@ -5272,13 +5348,13 @@ struct pci_device_id saa7134_pci_tbl[] = {
.device = PCI_DEVICE_ID_PHILIPS_SAA7133,
.subvendor = 0x5ace,
.subdevice = 0x6193,
- .driver_data = SAA7134_BOARD_BEHOLD_M6,
+ .driver_data = SAA7134_BOARD_BEHOLD_M6_EXTRA,
}, {
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7133,
.subvendor = 0x5ace,
.subdevice = 0x6191,
- .driver_data = SAA7134_BOARD_BEHOLD_M6,
+ .driver_data = SAA7134_BOARD_BEHOLD_M63,
},{
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7133,
@@ -5330,6 +5406,12 @@ struct pci_device_id saa7134_pci_tbl[] = {
}, {
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x5169,
+ .subdevice = 0x1502,
+ .driver_data = SAA7134_BOARD_FLYTVPLATINUM_MINI,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
.subvendor = 0x5ace,
.subdevice = 0x6290,
.driver_data = SAA7134_BOARD_BEHOLD_H6,
@@ -5431,22 +5513,21 @@ static int saa7134_xc2028_callback(struct saa7134_dev *dev,
{
switch (command) {
case XC2028_TUNER_RESET:
- saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x06e20000, 0x06e20000);
- saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x06a20000, 0x06a20000);
- mdelay(250);
- saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x06e20000, 0);
- saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x06a20000, 0);
- mdelay(250);
- saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x06e20000, 0x06e20000);
- saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x06a20000, 0x06a20000);
- mdelay(250);
- saa_andorl(SAA7133_ANALOG_IO_SELECT >> 2, 0x02, 0x02);
- saa_andorl(SAA7134_ANALOG_IN_CTRL1 >> 2, 0x81, 0x81);
- saa_andorl(SAA7134_AUDIO_CLOCK0 >> 2, 0x03187de7, 0x03187de7);
- saa_andorl(SAA7134_AUDIO_PLL_CTRL >> 2, 0x03, 0x03);
- saa_andorl(SAA7134_AUDIO_CLOCKS_PER_FIELD0 >> 2,
- 0x0001e000, 0x0001e000);
- return 0;
+ saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x00008000, 0x00000000);
+ saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x00008000, 0x00008000);
+ switch (dev->board) {
+ case SAA7134_BOARD_AVERMEDIA_CARDBUS_506:
+ saa7134_set_gpio(dev, 23, 0);
+ msleep(10);
+ saa7134_set_gpio(dev, 23, 1);
+ break;
+ case SAA7134_BOARD_AVERMEDIA_A16D:
+ saa7134_set_gpio(dev, 21, 0);
+ msleep(10);
+ saa7134_set_gpio(dev, 21, 1);
+ break;
+ }
+ return 0;
}
return -EINVAL;
}
@@ -5656,9 +5737,7 @@ int saa7134_board_init1(struct saa7134_dev *dev)
saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x08000000, 0x00000000);
break;
case SAA7134_BOARD_AVERMEDIA_CARDBUS:
- case SAA7134_BOARD_AVERMEDIA_CARDBUS_506:
case SAA7134_BOARD_AVERMEDIA_M115:
- case SAA7134_BOARD_AVERMEDIA_A16D:
#if 1
/* power-down tuner chip */
saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0xffffffff, 0);
@@ -5670,6 +5749,18 @@ int saa7134_board_init1(struct saa7134_dev *dev)
saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0xffffffff, 0xffffffff);
msleep(10);
break;
+ case SAA7134_BOARD_AVERMEDIA_CARDBUS_506:
+ saa7134_set_gpio(dev, 23, 0);
+ msleep(10);
+ saa7134_set_gpio(dev, 23, 1);
+ break;
+ case SAA7134_BOARD_AVERMEDIA_A16D:
+ saa7134_set_gpio(dev, 21, 0);
+ msleep(10);
+ saa7134_set_gpio(dev, 21, 1);
+ msleep(1);
+ dev->has_remote = SAA7134_REMOTE_GPIO;
+ break;
case SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM:
#if 1
/* power-down tuner chip */
@@ -5702,6 +5793,8 @@ int saa7134_board_init1(struct saa7134_dev *dev)
case SAA7134_BOARD_HAUPPAUGE_HVR1110:
case SAA7134_BOARD_BEHOLD_607_9FM:
case SAA7134_BOARD_BEHOLD_M6:
+ case SAA7134_BOARD_BEHOLD_M63:
+ case SAA7134_BOARD_BEHOLD_M6_EXTRA:
dev->has_remote = SAA7134_REMOTE_I2C;
break;
case SAA7134_BOARD_AVERMEDIA_A169_B:
@@ -5722,7 +5815,8 @@ int saa7134_board_init1(struct saa7134_dev *dev)
saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x80040100, 0x80040100);
saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x80040100, 0x00040100);
printk("%s: %s: hybrid analog/dvb card\n"
- "%s: Sorry, only the analog inputs are supported for now.\n",
+ "%s: Sorry, only analog s-video and composite input "
+ "are supported for now.\n",
dev->name, card(dev).name, dev->name);
break;
}
@@ -5782,6 +5876,7 @@ static void saa7134_tuner_setup(struct saa7134_dev *dev)
switch (dev->board) {
case SAA7134_BOARD_AVERMEDIA_A16D:
+ case SAA7134_BOARD_AVERMEDIA_CARDBUS_506:
ctl.demod = XC3028_FE_ZARLINK456;
break;
default:
diff --git a/linux/drivers/media/video/saa7134/saa7134-core.c b/linux/drivers/media/video/saa7134/saa7134-core.c
index 9ed2997f7..511941bca 100644
--- a/linux/drivers/media/video/saa7134/saa7134-core.c
+++ b/linux/drivers/media/video/saa7134/saa7134-core.c
@@ -80,28 +80,11 @@ static unsigned int tuner[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
static unsigned int card[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-MODULE_PARM(video_nr,"1-" __stringify(SAA7134_MAXBOARDS) "i");
-MODULE_PARM(vbi_nr,"1-" __stringify(SAA7134_MAXBOARDS) "i");
-MODULE_PARM(radio_nr,"1-" __stringify(SAA7134_MAXBOARDS) "i");
-MODULE_PARM(tuner_nr,"1-" __stringify(SAA7134_MAXBOARDS) "i");
-MODULE_PARM(card,"1-" __stringify(SAA7134_MAXBOARDS) "i");
-#else
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
-static int dummy;
-module_param_array(video_nr, int, dummy, 0444);
-module_param_array(vbi_nr, int, dummy, 0444);
-module_param_array(radio_nr, int, dummy, 0444);
-module_param_array(tuner, int, dummy, 0444);
-module_param_array(card, int, dummy, 0444);
-#else
module_param_array(video_nr, int, NULL, 0444);
module_param_array(vbi_nr, int, NULL, 0444);
module_param_array(radio_nr, int, NULL, 0444);
module_param_array(tuner, int, NULL, 0444);
module_param_array(card, int, NULL, 0444);
-#endif
-#endif
MODULE_PARM_DESC(video_nr, "video device number");
MODULE_PARM_DESC(vbi_nr, "vbi device number");
@@ -209,20 +192,6 @@ static void dump_statusregs(struct saa7134_dev *dev)
#if defined(CONFIG_MODULES) && defined(MODULE)
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-
-static void request_submodules(struct saa7134_dev *dev){
- if (card_is_empress(dev))
- request_module("saa7134-empress");
- if (card_is_dvb(dev))
- request_module("saa7134-dvb");
- if (alsa)
- request_module("saa7134-alsa");
- if (oss)
- request_module("saa7134-oss");
-}
-#else
-
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
static void request_module_async(void *ptr){
struct saa7134_dev* dev=(struct saa7134_dev*)ptr;
@@ -249,7 +218,6 @@ static void request_submodules(struct saa7134_dev *dev)
#endif
schedule_work(&dev->request_module_wk);
}
-#endif
#else
#define request_submodules(dev)
@@ -893,10 +861,8 @@ static struct video_device *vdev_init(struct saa7134_dev *dev,
return NULL;
*vfd = *template;
vfd->minor = -1;
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
vfd->dev = &dev->pci->dev;
vfd->release = video_device_release;
-#endif
vfd->debug = video_debug;
snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)",
dev->name, type, saa7134_boards[dev->board].name);
diff --git a/linux/drivers/media/video/saa7134/saa7134-dvb.c b/linux/drivers/media/video/saa7134/saa7134-dvb.c
index 2659d2a60..3cadbad1d 100644
--- a/linux/drivers/media/video/saa7134/saa7134-dvb.c
+++ b/linux/drivers/media/video/saa7134/saa7134-dvb.c
@@ -153,12 +153,12 @@ static int mt352_aver777_init(struct dvb_frontend* fe)
return 0;
}
-static int mt352_aver_a16d_init(struct dvb_frontend *fe)
+static int mt352_avermedia_xc3028_init(struct dvb_frontend *fe)
{
- static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x2d };
- static u8 reset [] = { RESET, 0x80 };
- static u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 };
- static u8 agc_cfg [] = { AGC_TARGET, 0x28, 0xa0 };
+ static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x2d };
+ static u8 reset [] = { RESET, 0x80 };
+ static u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 };
+ static u8 agc_cfg [] = { AGC_TARGET, 0xe };
static u8 capt_range_cfg[] = { CAPT_RANGE, 0x33 };
mt352_write(fe, clock_config, sizeof(clock_config));
@@ -167,12 +167,9 @@ static int mt352_aver_a16d_init(struct dvb_frontend *fe)
mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg));
mt352_write(fe, agc_cfg, sizeof(agc_cfg));
mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
-
return 0;
}
-
-
static int mt352_pinnacle_tuner_set_params(struct dvb_frontend* fe,
struct dvb_frontend_parameters* params)
{
@@ -215,17 +212,10 @@ static struct mt352_config avermedia_777 = {
.demod_init = mt352_aver777_init,
};
-static struct mt352_config avermedia_16d = {
- .demod_address = 0xf,
- .demod_init = mt352_aver_a16d_init,
-};
-
-static struct mt352_config avermedia_e506r_mt352_dev = {
+static struct mt352_config avermedia_xc3028_mt352_dev = {
.demod_address = (0x1e >> 1),
-#if 0
- .input_frequency = 0x31b8,
-#endif
.no_tuner = 1,
+ .demod_init = mt352_avermedia_xc3028_init,
};
/* ==================================================================
@@ -978,9 +968,10 @@ static int dvb_init(struct saa7134_dev *dev)
}
break;
case SAA7134_BOARD_AVERMEDIA_A16D:
- dprintk("avertv A16D dvb setup\n");
- dev->dvb.frontend = dvb_attach(mt352_attach, &avermedia_16d,
- &dev->i2c_adap);
+ dprintk("AverMedia A16D dvb setup\n");
+ dev->dvb.frontend = dvb_attach(mt352_attach,
+ &avermedia_xc3028_mt352_dev,
+ &dev->i2c_adap);
attach_xc3028 = 1;
break;
case SAA7134_BOARD_MD7134:
@@ -1094,7 +1085,8 @@ static int dvb_init(struct saa7134_dev *dev)
ads_tech_duo_config.tuner_address);
goto dettach_frontend;
}
- }
+ } else
+ wprintk("failed to attach tda10046\n");
break;
case SAA7134_BOARD_TEVION_DVBT_220RF:
if (configure_tda827x_fe(dev, &tevion_dvbt220rf_config,
@@ -1263,15 +1255,18 @@ static int dvb_init(struct saa7134_dev *dev)
goto dettach_frontend;
break;
case SAA7134_BOARD_AVERMEDIA_CARDBUS_506:
+ dprintk("AverMedia E506R dvb setup\n");
+ saa7134_set_gpio(dev, 25, 0);
+ msleep(10);
+ saa7134_set_gpio(dev, 25, 1);
+ dev->dvb.frontend = dvb_attach(mt352_attach,
+ &avermedia_xc3028_mt352_dev,
+ &dev->i2c_adap);
+ attach_xc3028 = 1;
#if 0
/*FIXME: What frontend does Videomate T750 use? */
case SAA7134_BOARD_VIDEOMATE_T750:
#endif
- dev->dvb.frontend = dvb_attach(mt352_attach,
- &avermedia_e506r_mt352_dev,
- &dev->i2c_adap);
- attach_xc3028 = 1;
- break;
case SAA7134_BOARD_MD7134_BRIDGE_2:
dev->dvb.frontend = dvb_attach(tda10086_attach,
&sd1878_4m, &dev->i2c_adap);
@@ -1345,7 +1340,8 @@ static int dvb_init(struct saa7134_dev *dev)
return ret;
dettach_frontend:
- dvb_frontend_detach(dev->dvb.frontend);
+ if (dev->dvb.frontend)
+ dvb_frontend_detach(dev->dvb.frontend);
dev->dvb.frontend = NULL;
return -1;
diff --git a/linux/drivers/media/video/saa7134/saa7134-empress.c b/linux/drivers/media/video/saa7134/saa7134-empress.c
index ba32fd8f6..d4afbce9d 100644
--- a/linux/drivers/media/video/saa7134/saa7134-empress.c
+++ b/linux/drivers/media/video/saa7134/saa7134-empress.c
@@ -37,16 +37,7 @@ MODULE_LICENSE("GPL");
static unsigned int empress_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-MODULE_PARM(empress_nr,"1-" __stringify(SAA7134_MAXBOARDS) "i");
-#else
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
-static int dummy;
-module_param_array(empress_nr, int, dummy, 0444);
-#else
module_param_array(empress_nr, int, NULL, 0444);
-#endif
-#endif
MODULE_PARM_DESC(empress_nr,"ts device number");
static unsigned int debug;
@@ -119,9 +110,10 @@ static int ts_release(struct inode *inode, struct file *file)
{
struct saa7134_dev *dev = file->private_data;
+ mutex_lock(&dev->empress_tsq.vb_lock);
+
videobuf_stop(&dev->empress_tsq);
videobuf_mmap_free(&dev->empress_tsq);
- dev->empress_users--;
/* stop the encoder */
ts_reset_encoder(dev);
@@ -130,6 +122,10 @@ static int ts_release(struct inode *inode, struct file *file)
saa_writeb(SAA7134_AUDIO_MUTE_CTRL,
saa_readb(SAA7134_AUDIO_MUTE_CTRL) | (1 << 6));
+ dev->empress_users--;
+
+ mutex_unlock(&dev->empress_tsq.vb_lock);
+
return 0;
}
@@ -172,8 +168,7 @@ ts_mmap(struct file *file, struct vm_area_struct * vma)
static int empress_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
- struct saa7134_fh *fh = priv;
- struct saa7134_dev *dev = fh->dev;
+ struct saa7134_dev *dev = file->private_data;
strcpy(cap->driver, "saa7134");
strlcpy(cap->card, saa7134_boards[dev->board].name,
@@ -228,8 +223,7 @@ static int empress_enum_fmt_vid_cap(struct file *file, void *priv,
static int empress_g_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct saa7134_fh *fh = priv;
- struct saa7134_dev *dev = fh->dev;
+ struct saa7134_dev *dev = file->private_data;
saa7134_i2c_call_clients(dev, VIDIOC_G_FMT, f);
@@ -242,8 +236,7 @@ static int empress_g_fmt_vid_cap(struct file *file, void *priv,
static int empress_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct saa7134_fh *fh = priv;
- struct saa7134_dev *dev = fh->dev;
+ struct saa7134_dev *dev = file->private_data;
saa7134_i2c_call_clients(dev, VIDIOC_S_FMT, f);
@@ -257,8 +250,7 @@ static int empress_s_fmt_vid_cap(struct file *file, void *priv,
static int empress_reqbufs(struct file *file, void *priv,
struct v4l2_requestbuffers *p)
{
- struct saa7134_fh *fh = priv;
- struct saa7134_dev *dev = fh->dev;
+ struct saa7134_dev *dev = file->private_data;
return videobuf_reqbufs(&dev->empress_tsq, p);
}
@@ -266,24 +258,21 @@ static int empress_reqbufs(struct file *file, void *priv,
static int empress_querybuf(struct file *file, void *priv,
struct v4l2_buffer *b)
{
- struct saa7134_fh *fh = priv;
- struct saa7134_dev *dev = fh->dev;
+ struct saa7134_dev *dev = file->private_data;
return videobuf_querybuf(&dev->empress_tsq, b);
}
static int empress_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
{
- struct saa7134_fh *fh = priv;
- struct saa7134_dev *dev = fh->dev;
+ struct saa7134_dev *dev = file->private_data;
return videobuf_qbuf(&dev->empress_tsq, b);
}
static int empress_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
{
- struct saa7134_fh *fh = priv;
- struct saa7134_dev *dev = fh->dev;
+ struct saa7134_dev *dev = file->private_data;
return videobuf_dqbuf(&dev->empress_tsq, b,
file->f_flags & O_NONBLOCK);
@@ -292,8 +281,7 @@ static int empress_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
static int empress_streamon(struct file *file, void *priv,
enum v4l2_buf_type type)
{
- struct saa7134_fh *fh = priv;
- struct saa7134_dev *dev = fh->dev;
+ struct saa7134_dev *dev = file->private_data;
return videobuf_streamon(&dev->empress_tsq);
}
@@ -301,17 +289,25 @@ static int empress_streamon(struct file *file, void *priv,
static int empress_streamoff(struct file *file, void *priv,
enum v4l2_buf_type type)
{
- struct saa7134_fh *fh = priv;
- struct saa7134_dev *dev = fh->dev;
+ struct saa7134_dev *dev = file->private_data;
return videobuf_streamoff(&dev->empress_tsq);
}
+static int saa7134_i2c_call_saa6752(struct saa7134_dev *dev,
+ unsigned int cmd, void *arg)
+{
+ if (dev->mpeg_i2c_client == NULL)
+ return -EINVAL;
+ return dev->mpeg_i2c_client->driver->command(dev->mpeg_i2c_client,
+ cmd, arg);
+}
+
static int empress_s_ext_ctrls(struct file *file, void *priv,
struct v4l2_ext_controls *ctrls)
{
- struct saa7134_fh *fh = priv;
- struct saa7134_dev *dev = fh->dev;
+ struct saa7134_dev *dev = file->private_data;
+ int err;
/* count == 0 is abused in saa6752hs.c, so that special
case is handled here explicitly. */
@@ -321,23 +317,75 @@ static int empress_s_ext_ctrls(struct file *file, void *priv,
if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
return -EINVAL;
- saa7134_i2c_call_clients(dev, VIDIOC_S_EXT_CTRLS, ctrls);
+ err = saa7134_i2c_call_saa6752(dev, VIDIOC_S_EXT_CTRLS, ctrls);
ts_init_encoder(dev);
- return 0;
+ return err;
}
static int empress_g_ext_ctrls(struct file *file, void *priv,
struct v4l2_ext_controls *ctrls)
{
- struct saa7134_fh *fh = priv;
- struct saa7134_dev *dev = fh->dev;
+ struct saa7134_dev *dev = file->private_data;
if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
return -EINVAL;
- saa7134_i2c_call_clients(dev, VIDIOC_G_EXT_CTRLS, ctrls);
+ return saa7134_i2c_call_saa6752(dev, VIDIOC_G_EXT_CTRLS, ctrls);
+}
- return 0;
+static int empress_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *c)
+{
+ static const u32 user_ctrls[] = {
+ V4L2_CID_USER_CLASS,
+ V4L2_CID_BRIGHTNESS,
+ V4L2_CID_CONTRAST,
+ V4L2_CID_SATURATION,
+ V4L2_CID_HUE,
+ V4L2_CID_AUDIO_VOLUME,
+ V4L2_CID_AUDIO_MUTE,
+ V4L2_CID_HFLIP,
+ 0
+ };
+
+ static const u32 mpeg_ctrls[] = {
+ V4L2_CID_MPEG_CLASS,
+ V4L2_CID_MPEG_STREAM_TYPE,
+ V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ,
+ V4L2_CID_MPEG_AUDIO_ENCODING,
+ V4L2_CID_MPEG_AUDIO_L2_BITRATE,
+ V4L2_CID_MPEG_VIDEO_ENCODING,
+ V4L2_CID_MPEG_VIDEO_ASPECT,
+ V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
+ V4L2_CID_MPEG_VIDEO_BITRATE,
+ V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
+ 0
+ };
+ static const u32 *ctrl_classes[] = {
+ user_ctrls,
+ mpeg_ctrls,
+ NULL
+ };
+ struct saa7134_dev *dev = file->private_data;
+
+ c->id = v4l2_ctrl_next(ctrl_classes, c->id);
+ if (c->id == 0)
+ return -EINVAL;
+ if (c->id == V4L2_CID_USER_CLASS || c->id == V4L2_CID_MPEG_CLASS)
+ return v4l2_ctrl_query_fill_std(c);
+ if (V4L2_CTRL_ID2CLASS(c->id) != V4L2_CTRL_CLASS_MPEG)
+ return saa7134_queryctrl(file, priv, c);
+ return saa7134_i2c_call_saa6752(dev, VIDIOC_QUERYCTRL, c);
+}
+
+static int empress_querymenu(struct file *file, void *priv,
+ struct v4l2_querymenu *c)
+{
+ struct saa7134_dev *dev = file->private_data;
+
+ if (V4L2_CTRL_ID2CLASS(c->id) != V4L2_CTRL_CLASS_MPEG)
+ return -EINVAL;
+ return saa7134_i2c_call_saa6752(dev, VIDIOC_QUERYMENU, c);
}
static const struct file_operations ts_fops =
@@ -378,7 +426,8 @@ static struct video_device saa7134_empress_template =
.vidioc_g_input = empress_g_input,
.vidioc_s_input = empress_s_input,
- .vidioc_queryctrl = saa7134_queryctrl,
+ .vidioc_queryctrl = empress_queryctrl,
+ .vidioc_querymenu = empress_querymenu,
.vidioc_g_ctrl = saa7134_g_ctrl,
.vidioc_s_ctrl = saa7134_s_ctrl,
@@ -424,10 +473,8 @@ static int empress_init(struct saa7134_dev *dev)
if (NULL == dev->empress_dev)
return -ENOMEM;
*(dev->empress_dev) = saa7134_empress_template;
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
dev->empress_dev->dev = &dev->pci->dev;
dev->empress_dev->release = video_device_release;
-#endif
snprintf(dev->empress_dev->name, sizeof(dev->empress_dev->name),
"%s empress (%s)", dev->name,
saa7134_boards[dev->board].name);
diff --git a/linux/drivers/media/video/saa7134/saa7134-i2c.c b/linux/drivers/media/video/saa7134/saa7134-i2c.c
index c222313fc..610e506b5 100644
--- a/linux/drivers/media/video/saa7134/saa7134-i2c.c
+++ b/linux/drivers/media/video/saa7134/saa7134-i2c.c
@@ -336,6 +336,8 @@ static int attach_inform(struct i2c_client *client)
#else
client->driver->driver.name, client->addr, client->name);
#endif
+ if (client->addr == 0x20 && client->driver && client->driver->command)
+ dev->mpeg_i2c_client = client;
/* Am I an i2c remote control? */
@@ -366,12 +368,8 @@ static struct i2c_algorithm saa7134_algo = {
};
static struct i2c_adapter saa7134_adap_template = {
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
.owner = THIS_MODULE,
-#endif
-#ifdef I2C_CLASS_TV_ANALOG
.class = I2C_CLASS_TV_ANALOG,
-#endif
.name = "saa7134",
.id = I2C_HW_SAA7134,
.algo = &saa7134_algo,
@@ -445,9 +443,7 @@ void saa7134_i2c_call_clients(struct saa7134_dev *dev,
int saa7134_i2c_register(struct saa7134_dev *dev)
{
dev->i2c_adap = saa7134_adap_template;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,66)
dev->i2c_adap.dev.parent = &dev->pci->dev;
-#endif
strcpy(dev->i2c_adap.name,dev->name);
dev->i2c_adap.algo_data = dev;
i2c_add_adapter(&dev->i2c_adap);
diff --git a/linux/drivers/media/video/saa7134/saa7134-input.c b/linux/drivers/media/video/saa7134/saa7134-input.c
index 45c4c8125..c12184a38 100644
--- a/linux/drivers/media/video/saa7134/saa7134-input.c
+++ b/linux/drivers/media/video/saa7134/saa7134-input.c
@@ -323,6 +323,15 @@ int saa7134_input_init1(struct saa7134_dev *dev)
saa_setb(SAA7134_GPIO_GPMODE1, 0x1);
saa_setb(SAA7134_GPIO_GPSTATUS1, 0x1);
break;
+ case SAA7134_BOARD_AVERMEDIA_A16D:
+ ir_codes = ir_codes_avermedia_a16d;
+ mask_keycode = 0x02F200;
+ mask_keydown = 0x000400;
+ polling = 50; /* ms */
+ /* Without this we won't receive key up events */
+ saa_setb(SAA7134_GPIO_GPMODE1, 0x1);
+ saa_setb(SAA7134_GPIO_GPSTATUS1, 0x1);
+ break;
case SAA7134_BOARD_KWORLD_TERMINATOR:
ir_codes = ir_codes_pixelview;
mask_keycode = 0x00001f;
@@ -454,7 +463,6 @@ int saa7134_input_init1(struct saa7134_dev *dev)
ir_input_init(input_dev, &ir->ir, ir_type, ir_codes);
input_dev->name = ir->name;
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
input_dev->phys = ir->phys;
input_dev->id.bustype = BUS_PCI;
input_dev->id.version = 1;
@@ -474,7 +482,6 @@ int saa7134_input_init1(struct saa7134_dev *dev)
input_dev->dev = &dev->pci->dev;
#endif
#endif
-#endif
dev->remote = ir;
saa7134_ir_start(dev, ir);
@@ -541,6 +548,8 @@ void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir)
break;
case SAA7134_BOARD_BEHOLD_607_9FM:
case SAA7134_BOARD_BEHOLD_M6:
+ case SAA7134_BOARD_BEHOLD_M63:
+ case SAA7134_BOARD_BEHOLD_M6_EXTRA:
case SAA7134_BOARD_BEHOLD_H6:
snprintf(ir->c.name, sizeof(ir->c.name), "BeholdTV");
ir->get_key = get_key_beholdm6xx;
diff --git a/linux/drivers/media/video/saa7134/saa7134-reg.h b/linux/drivers/media/video/saa7134/saa7134-reg.h
index 86f5eefdb..cf89d96d7 100644
--- a/linux/drivers/media/video/saa7134/saa7134-reg.h
+++ b/linux/drivers/media/video/saa7134/saa7134-reg.h
@@ -368,6 +368,7 @@
#define SAA7135_DSP_RWCLEAR 0x586
#define SAA7135_DSP_RWCLEAR_RERR 1
+#define SAA7133_I2S_AUDIO_CONTROL 0x591
/* ------------------------------------------------------------------ */
/*
* Local variables:
diff --git a/linux/drivers/media/video/saa7134/saa7134-tvaudio.c b/linux/drivers/media/video/saa7134/saa7134-tvaudio.c
index 0d24ab598..f7a3f1d0a 100644
--- a/linux/drivers/media/video/saa7134/saa7134-tvaudio.c
+++ b/linux/drivers/media/video/saa7134/saa7134-tvaudio.c
@@ -496,14 +496,6 @@ static int tvaudio_thread(void *data)
unsigned int i, audio, nscan;
int max1,max2,carrier,rx,mode,lastmode,default_carrier;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,61)
- lock_kernel();
- daemonize();
- sigfillset(&current->blocked);
- sprintf(current->comm, "%s", dev->name);
- unlock_kernel();
-#endif
-
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23)
set_freezable();
#endif
@@ -821,14 +813,6 @@ static int tvaudio_thread_ddep(void *data)
struct saa7134_dev *dev = data;
u32 value, norms;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,61)
- lock_kernel();
- daemonize();
- sigfillset(&current->blocked);
- sprintf(current->comm, "%s", dev->name);
- unlock_kernel();
-#endif
-
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23)
set_freezable();
#endif
@@ -928,13 +912,34 @@ void saa7134_enable_i2s(struct saa7134_dev *dev)
if (!card_is_empress(dev))
return;
- i2s_format = (dev->input->amux == TV) ? 0x00 : 0x01;
- /* enable I2S audio output for the mpeg encoder */
- saa_writeb(SAA7134_I2S_OUTPUT_SELECT, 0x80);
- saa_writeb(SAA7134_I2S_OUTPUT_FORMAT, i2s_format);
- saa_writeb(SAA7134_I2S_OUTPUT_LEVEL, 0x0F);
- saa_writeb(SAA7134_I2S_AUDIO_OUTPUT, 0x01);
+ if (dev->pci->device == PCI_DEVICE_ID_PHILIPS_SAA7130)
+ return;
+
+ /* configure GPIO for out */
+ saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x0E000000, 0x00000000);
+
+ switch (dev->pci->device) {
+ case PCI_DEVICE_ID_PHILIPS_SAA7133:
+ case PCI_DEVICE_ID_PHILIPS_SAA7135:
+ /* Set I2S format (SONY)  */
+ saa_writeb(SAA7133_I2S_AUDIO_CONTROL, 0x00);
+ /* Start I2S */
+ saa_writeb(SAA7134_I2S_AUDIO_OUTPUT, 0x11);
+ break;
+
+ case PCI_DEVICE_ID_PHILIPS_SAA7134:
+ i2s_format = (dev->input->amux == TV) ? 0x00 : 0x01;
+
+ /* enable I2S audio output for the mpeg encoder */
+ saa_writeb(SAA7134_I2S_OUTPUT_SELECT, 0x80);
+ saa_writeb(SAA7134_I2S_OUTPUT_FORMAT, i2s_format);
+ saa_writeb(SAA7134_I2S_OUTPUT_LEVEL, 0x0F);
+ saa_writeb(SAA7134_I2S_AUDIO_OUTPUT, 0x01);
+
+ default:
+ break;
+ }
}
int saa7134_tvaudio_rx2mode(u32 rx)
diff --git a/linux/drivers/media/video/saa7134/saa7134-video.c b/linux/drivers/media/video/saa7134/saa7134-video.c
index 353679fef..e02bd2659 100644
--- a/linux/drivers/media/video/saa7134/saa7134-video.c
+++ b/linux/drivers/media/video/saa7134/saa7134-video.c
@@ -2215,6 +2215,32 @@ static int saa7134_g_parm(struct file *file, void *fh,
return 0;
}
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int vidioc_g_register (struct file *file, void *priv,
+ struct v4l2_register *reg)
+{
+ struct saa7134_fh *fh = priv;
+ struct saa7134_dev *dev = fh->dev;
+
+ if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
+ return -EINVAL;
+ reg->val = saa_readb(reg->reg);
+ return 0;
+}
+
+static int vidioc_s_register (struct file *file, void *priv,
+ struct v4l2_register *reg)
+{
+ struct saa7134_fh *fh = priv;
+ struct saa7134_dev *dev = fh->dev;
+
+ if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
+ return -EINVAL;
+ saa_writeb(reg->reg&0xffffff, reg->val);
+ return 0;
+}
+#endif
+
static int radio_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
@@ -2330,9 +2356,7 @@ static const struct file_operations video_fops =
.poll = video_poll,
.mmap = video_mmap,
.ioctl = video_ioctl2,
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11)
.compat_ioctl = v4l_compat_ioctl32,
-#endif
.llseek = no_llseek,
};
@@ -2342,9 +2366,7 @@ static const struct file_operations radio_fops =
.open = video_open,
.release = video_release,
.ioctl = video_ioctl2,
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11)
.compat_ioctl = v4l_compat_ioctl32,
-#endif
.llseek = no_llseek,
};
@@ -2402,6 +2424,10 @@ struct video_device saa7134_video_template =
.vidioc_g_parm = saa7134_g_parm,
.vidioc_g_frequency = saa7134_g_frequency,
.vidioc_s_frequency = saa7134_s_frequency,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .vidioc_g_register = vidioc_g_register,
+ .vidioc_s_register = vidioc_s_register,
+#endif
.tvnorms = SAA7134_NORMS,
.current_norm = V4L2_STD_PAL,
};
@@ -2469,13 +2495,14 @@ int saa7134_videoport_init(struct saa7134_dev *dev)
int vo = saa7134_boards[dev->board].video_out;
int video_reg;
unsigned int vid_port_opts = saa7134_boards[dev->board].vid_port_opts;
+
+ /* Configure videoport */
saa_writeb(SAA7134_VIDEO_PORT_CTRL0, video_out[vo][0]);
video_reg = video_out[vo][1];
if (vid_port_opts & SET_T_CODE_POLARITY_NON_INVERTED)
video_reg &= ~VP_T_CODE_P_INVERTED;
saa_writeb(SAA7134_VIDEO_PORT_CTRL1, video_reg);
saa_writeb(SAA7134_VIDEO_PORT_CTRL2, video_out[vo][2]);
- saa_writeb(SAA7134_VIDEO_PORT_CTRL3, video_out[vo][3]);
saa_writeb(SAA7134_VIDEO_PORT_CTRL4, video_out[vo][4]);
video_reg = video_out[vo][5];
if (vid_port_opts & SET_CLOCK_NOT_DELAYED)
@@ -2492,6 +2519,9 @@ int saa7134_videoport_init(struct saa7134_dev *dev)
saa_writeb(SAA7134_VIDEO_PORT_CTRL7, video_out[vo][7]);
saa_writeb(SAA7134_VIDEO_PORT_CTRL8, video_out[vo][8]);
+ /* Start videoport */
+ saa_writeb(SAA7134_VIDEO_PORT_CTRL3, video_out[vo][3]);
+
return 0;
}
diff --git a/linux/drivers/media/video/saa7134/saa7134.h b/linux/drivers/media/video/saa7134/saa7134.h
index 2aa30895f..08bc1d0fa 100644
--- a/linux/drivers/media/video/saa7134/saa7134.h
+++ b/linux/drivers/media/video/saa7134/saa7134.h
@@ -41,12 +41,8 @@
#include <media/ir-common.h>
#include <media/ir-kbd-i2c.h>
#include <media/videobuf-dma-sg.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,64)
-#include "i2c-compat.h"
-#else
#include <sound/core.h>
#include <sound/pcm.h>
-#endif
#if defined(CONFIG_VIDEO_SAA7134_DVB) || defined(CONFIG_VIDEO_SAA7134_DVB_MODULE)
#include <media/videobuf-dvb.h>
#endif
@@ -271,7 +267,8 @@ struct saa7134_format {
#define SAA7134_BOARD_AVERMEDIA_A700_PRO 140
#define SAA7134_BOARD_AVERMEDIA_A700_HYBRID 141
#define SAA7134_BOARD_BEHOLD_H6 142
-
+#define SAA7134_BOARD_BEHOLD_M63 143
+#define SAA7134_BOARD_BEHOLD_M6_EXTRA 144
#define SAA7134_MAXBOARDS 8
#define SAA7134_INPUT_MAX 8
@@ -449,13 +446,11 @@ struct saa7134_dmasound {
unsigned int read_offset;
unsigned int read_count;
void * priv_data;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,16)
snd_pcm_substream_t *substream;
#else
struct snd_pcm_substream *substream;
#endif
-#endif
};
/* ts/mpeg status */
@@ -573,6 +568,7 @@ struct saa7134_dev {
struct saa7134_ts ts;
struct saa7134_dmaqueue ts_q;
struct saa7134_mpeg_ops *mops;
+ struct i2c_client *mpeg_i2c_client;
/* SAA7134_MPEG_EMPRESS only */
struct video_device *empress_dev;
diff --git a/linux/drivers/media/video/saa717x.c b/linux/drivers/media/video/saa717x.c
index 98e0ec245..a478bf25e 100644
--- a/linux/drivers/media/video/saa717x.c
+++ b/linux/drivers/media/video/saa717x.c
@@ -47,11 +47,7 @@ MODULE_AUTHOR("K. Ohta, T. Adachi, Hans Verkuil");
MODULE_LICENSE("GPL");
static int debug;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
module_param(debug, int, 0644);
-#else
-MODULE_PARM(debug, "i");
-#endif
MODULE_PARM_DESC(debug, "Debug level (0-1)");
/*
@@ -60,9 +56,6 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)");
*/
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
static unsigned short normal_i2c[] = { 0x42 >> 1, I2C_CLIENT_END };
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 13)
-static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
-#endif
I2C_CLIENT_INSMOD;
#endif
@@ -1442,8 +1435,9 @@ static int saa717x_probe(struct i2c_client *client,
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -EIO;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
snprintf(client->name, sizeof(client->name) - 1, "saa717x");
-
+#endif
if (saa717x_write(client, 0x5a4, 0xfe) &&
saa717x_write(client, 0x5a5, 0x0f) &&
saa717x_write(client, 0x5a6, 0x00) &&
@@ -1520,16 +1514,22 @@ static int saa717x_remove(struct i2c_client *client)
/* ----------------------------------------------------------------------- */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+static const struct i2c_device_id saa717x_id[] = {
+ { "saa717x", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, saa717x_id);
+
+#endif
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.name = "saa717x",
.driverid = I2C_DRIVERID_SAA717X,
.command = saa717x_command,
.probe = saa717x_probe,
.remove = saa717x_remove,
-#ifdef I2C_CLASS_TV_ANALOG
.legacy_class = I2C_CLASS_TV_ANALOG | I2C_CLASS_TV_DIGITAL,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ .id_table = saa717x_id,
#endif
};
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
-EXPORT_NO_SYMBOLS;
-#endif
diff --git a/linux/drivers/media/video/sn9c102/sn9c102_core.c b/linux/drivers/media/video/sn9c102/sn9c102_core.c
index b1a7e36d2..6747c4d7c 100644
--- a/linux/drivers/media/video/sn9c102/sn9c102_core.c
+++ b/linux/drivers/media/video/sn9c102/sn9c102_core.c
@@ -34,7 +34,7 @@
#include <linux/mm.h>
#include <linux/vmalloc.h>
#include <linux/page-flags.h>
-#include <linux/byteorder/generic.h>
+#include <asm/byteorder.h>
#include <asm/page.h>
#include <asm/uaccess.h>
diff --git a/linux/drivers/media/video/soc_camera.c b/linux/drivers/media/video/soc_camera.c
index a1b92446c..8ae2d9916 100644
--- a/linux/drivers/media/video/soc_camera.c
+++ b/linux/drivers/media/video/soc_camera.c
@@ -44,7 +44,7 @@ format_by_fourcc(struct soc_camera_device *icd, unsigned int fourcc)
return NULL;
}
-static int soc_camera_try_fmt_cap(struct file *file, void *priv,
+static int soc_camera_try_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct soc_camera_file *icf = file->private_data;
@@ -342,7 +342,7 @@ static struct file_operations soc_camera_fops = {
};
-static int soc_camera_s_fmt_cap(struct file *file, void *priv,
+static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct soc_camera_file *icf = file->private_data;
@@ -362,7 +362,7 @@ static int soc_camera_s_fmt_cap(struct file *file, void *priv,
/* buswidth may be further adjusted by the ici */
icd->buswidth = data_fmt->depth;
- ret = soc_camera_try_fmt_cap(file, icf, f);
+ ret = soc_camera_try_fmt_vid_cap(file, icf, f);
if (ret < 0)
return ret;
@@ -389,7 +389,7 @@ static int soc_camera_s_fmt_cap(struct file *file, void *priv,
return ici->ops->set_bus_param(icd, f->fmt.pix.pixelformat);
}
-static int soc_camera_enum_fmt_cap(struct file *file, void *priv,
+static int soc_camera_enum_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
struct soc_camera_file *icf = file->private_data;
@@ -408,7 +408,7 @@ static int soc_camera_enum_fmt_cap(struct file *file, void *priv,
return 0;
}
-static int soc_camera_g_fmt_cap(struct file *file, void *priv,
+static int soc_camera_g_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct soc_camera_file *icf = file->private_data;
@@ -763,15 +763,6 @@ static struct device_driver ic_drv = {
.owner = THIS_MODULE,
};
-/*
- * Image capture host - this is a host device, not a bus device, so,
- * no bus reference, no probing.
- */
-static struct class soc_camera_host_class = {
- .owner = THIS_MODULE,
- .name = "camera_host",
-};
-
static void dummy_release(struct device *dev)
{
}
@@ -801,7 +792,6 @@ int soc_camera_host_register(struct soc_camera_host *ici)
/* Number might be equal to the platform device ID */
sprintf(ici->dev.bus_id, "camera_host%d", ici->nr);
- ici->dev.class = &soc_camera_host_class;
mutex_lock(&list_lock);
list_for_each_entry(ix, &hosts, list) {
@@ -935,15 +925,15 @@ int soc_camera_video_start(struct soc_camera_device *icd)
vdev->minor = -1;
vdev->tvnorms = V4L2_STD_UNKNOWN,
vdev->vidioc_querycap = soc_camera_querycap;
- vdev->vidioc_g_fmt_cap = soc_camera_g_fmt_cap;
- vdev->vidioc_enum_fmt_cap = soc_camera_enum_fmt_cap;
- vdev->vidioc_s_fmt_cap = soc_camera_s_fmt_cap;
+ vdev->vidioc_g_fmt_vid_cap = soc_camera_g_fmt_vid_cap;
+ vdev->vidioc_enum_fmt_vid_cap = soc_camera_enum_fmt_vid_cap;
+ vdev->vidioc_s_fmt_vid_cap = soc_camera_s_fmt_vid_cap;
vdev->vidioc_enum_input = soc_camera_enum_input;
vdev->vidioc_g_input = soc_camera_g_input;
vdev->vidioc_s_input = soc_camera_s_input;
vdev->vidioc_s_std = soc_camera_s_std;
vdev->vidioc_reqbufs = soc_camera_reqbufs;
- vdev->vidioc_try_fmt_cap = soc_camera_try_fmt_cap;
+ vdev->vidioc_try_fmt_vid_cap = soc_camera_try_fmt_vid_cap;
vdev->vidioc_querybuf = soc_camera_querybuf;
vdev->vidioc_qbuf = soc_camera_qbuf;
vdev->vidioc_dqbuf = soc_camera_dqbuf;
@@ -1003,14 +993,9 @@ static int __init soc_camera_init(void)
ret = driver_register(&ic_drv);
if (ret)
goto edrvr;
- ret = class_register(&soc_camera_host_class);
- if (ret)
- goto eclr;
return 0;
-eclr:
- driver_unregister(&ic_drv);
edrvr:
bus_unregister(&soc_camera_bus_type);
return ret;
@@ -1018,7 +1003,6 @@ edrvr:
static void __exit soc_camera_exit(void)
{
- class_unregister(&soc_camera_host_class);
driver_unregister(&ic_drv);
bus_unregister(&soc_camera_bus_type);
}
diff --git a/linux/drivers/media/video/tcm825x.c b/linux/drivers/media/video/tcm825x.c
index 216638e00..2f823f27a 100644
--- a/linux/drivers/media/video/tcm825x.c
+++ b/linux/drivers/media/video/tcm825x.c
@@ -846,8 +846,12 @@ static struct v4l2_int_device tcm825x_int_device = {
},
};
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
+static int tcm825x_probe(struct i2c_client *client)
+#else
static int tcm825x_probe(struct i2c_client *client,
const struct i2c_device_id *did)
+#endif
{
struct tcm825x_sensor *sensor = &tcm825x;
int rval;
@@ -891,12 +895,23 @@ static int __exit tcm825x_remove(struct i2c_client *client)
return 0;
}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+static const struct i2c_device_id tcm825x_id[] = {
+ { "tcm825x", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, tcm825x_id);
+#endif
+
static struct i2c_driver tcm825x_i2c_driver = {
.driver = {
.name = TCM825X_NAME,
},
.probe = tcm825x_probe,
.remove = __exit_p(tcm825x_remove),
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ .id_table = tcm825x_id,
+#endif
};
static struct tcm825x_sensor tcm825x = {
diff --git a/linux/drivers/media/video/tda7432.c b/linux/drivers/media/video/tda7432.c
index 5c58967ce..1305820d2 100644
--- a/linux/drivers/media/video/tda7432.c
+++ b/linux/drivers/media/video/tda7432.c
@@ -47,10 +47,6 @@
#include <linux/videodev.h>
#include <linux/i2c.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-#include "i2c-compat.h"
-#else
-#endif
#include <media/v4l2-common.h>
#include <media/i2c-addr.h>
#include "compat.h"
@@ -77,9 +73,7 @@ static unsigned short normal_i2c[] = {
I2C_ADDR_TDA7432 >> 1,
I2C_CLIENT_END,
};
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13)
-static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
-#endif
+
I2C_CLIENT_INSMOD;
/* Structure of address and subaddresses for the tda7432 */
@@ -314,12 +308,7 @@ static void do_tda7432_init(struct i2c_client *client)
* i2c interface functions *
* *********************** */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
static int tda7432_attach(struct i2c_adapter *adap, int addr, int kind)
-#else
-static int tda7432_attach(struct i2c_adapter *adap, int addr,
- unsigned short flags, int kind)
-#endif
{
struct tda7432 *t;
struct i2c_client *client;
@@ -335,9 +324,6 @@ static int tda7432_attach(struct i2c_adapter *adap, int addr,
i2c_set_clientdata(client, t);
do_tda7432_init(client);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
- MOD_INC_USE_COUNT;
-#endif
i2c_attach_client(client);
v4l_info(client, "chip found @ 0x%x (%s)\n", addr << 1, adap->name);
@@ -346,13 +332,8 @@ static int tda7432_attach(struct i2c_adapter *adap, int addr,
static int tda7432_probe(struct i2c_adapter *adap)
{
-#ifdef I2C_CLASS_TV_ANALOG
if (adap->class & I2C_CLASS_TV_ANALOG)
return i2c_probe(adap, &addr_data, tda7432_attach);
-#else
- if (adap->id == I2C_HW_B_BT848)
- return i2c_probe(adap, &addr_data, tda7432_attach);
-#endif
return 0;
}
@@ -364,9 +345,6 @@ static int tda7432_detach(struct i2c_client *client)
i2c_detach_client(client);
kfree(t);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
- MOD_DEC_USE_COUNT;
-#endif
return 0;
}
@@ -531,10 +509,8 @@ static int tda7432_command(struct i2c_client *client,
}
static struct i2c_driver driver = {
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))&&(LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15))
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15)
.owner = THIS_MODULE,
-#endif
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15)
.name = "tda7432",
.flags = I2C_DF_NOTIFY,
#else
diff --git a/linux/drivers/media/video/tda9840.c b/linux/drivers/media/video/tda9840.c
index c41e50ba6..537a06492 100644
--- a/linux/drivers/media/video/tda9840.c
+++ b/linux/drivers/media/video/tda9840.c
@@ -51,9 +51,6 @@ MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off).");
/* addresses to scan, found only at 0x42 (7-Bit) */
static unsigned short normal_i2c[] = { I2C_ADDR_TDA9840, I2C_CLIENT_END };
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13)
-static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
-#endif
/* magic definition of all other variables and things */
I2C_CLIENT_INSMOD;
@@ -231,10 +228,8 @@ static int detach(struct i2c_client *client)
}
static struct i2c_driver driver = {
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) &&(LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15))
- .owner = THIS_MODULE,
-#endif
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15)
+ .owner = THIS_MODULE,
.name = "tda9840",
.flags = I2C_DF_NOTIFY,
#else
diff --git a/linux/drivers/media/video/tda9875.c b/linux/drivers/media/video/tda9875.c
index 340ea2300..86e721656 100644
--- a/linux/drivers/media/video/tda9875.c
+++ b/linux/drivers/media/video/tda9875.c
@@ -31,11 +31,6 @@
#include <linux/init.h>
#include "compat.h"
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-#include "id.h"
-#include "i2c-compat.h"
-#endif
-
#include <media/i2c-addr.h>
static int debug; /* insmod parameter */
@@ -47,9 +42,7 @@ static unsigned short normal_i2c[] = {
I2C_ADDR_TDA9875 >> 1,
I2C_CLIENT_END
};
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13)
-static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
-#endif
+
I2C_CLIENT_INSMOD;
/* This is a superset of the TDA9875 */
@@ -244,12 +237,7 @@ static int tda9875_checkit(struct i2c_adapter *adap, int addr)
return(0);
}
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
static int tda9875_attach(struct i2c_adapter *adap, int addr, int kind)
-#else
-static int tda9875_attach(struct i2c_adapter *adap, int addr,
- unsigned short flags, int kind)
-#endif
{
struct tda9875 *t;
struct i2c_client *client;
@@ -271,9 +259,6 @@ static int tda9875_attach(struct i2c_adapter *adap, int addr,
}
do_tda9875_init(client);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
- MOD_INC_USE_COUNT;
-#endif
printk(KERN_INFO "tda9875: init\n");
i2c_attach_client(client);
@@ -282,13 +267,8 @@ static int tda9875_attach(struct i2c_adapter *adap, int addr,
static int tda9875_probe(struct i2c_adapter *adap)
{
-#ifdef I2C_CLASS_TV_ANALOG
if (adap->class & I2C_CLASS_TV_ANALOG)
return i2c_probe(adap, &addr_data, tda9875_attach);
-#else
- if (adap->id == I2C_HW_B_BT848)
- return i2c_probe(adap, &addr_data, tda9875_attach);
-#endif
return 0;
}
@@ -300,9 +280,6 @@ static int tda9875_detach(struct i2c_client *client)
i2c_detach_client(client);
kfree(t);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
- MOD_DEC_USE_COUNT;
-#endif
return 0;
}
@@ -456,10 +433,8 @@ static int tda9875_command(struct i2c_client *client,
static struct i2c_driver driver = {
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))&&(LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15))
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15)
.owner = THIS_MODULE,
-#endif
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15)
.name = "tda9875",
.flags = I2C_DF_NOTIFY,
#else
diff --git a/linux/drivers/media/video/tea6415c.c b/linux/drivers/media/video/tea6415c.c
index 16f369195..cb700dde7 100644
--- a/linux/drivers/media/video/tea6415c.c
+++ b/linux/drivers/media/video/tea6415c.c
@@ -51,9 +51,6 @@ MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off).");
/* addresses to scan, found only at 0x03 and/or 0x43 (7-bit) */
static unsigned short normal_i2c[] = { I2C_TEA6415C_1, I2C_TEA6415C_2, I2C_CLIENT_END };
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13)
-static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
-#endif
/* magic definition of all other variables and things */
I2C_CLIENT_INSMOD;
@@ -200,10 +197,8 @@ static int command(struct i2c_client *client, unsigned int cmd, void *arg)
}
static struct i2c_driver driver = {
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) &&(LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15))
- .owner = THIS_MODULE,
-#endif
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15)
+ .owner = THIS_MODULE,
.name = "tea6415c",
.flags = I2C_DF_NOTIFY,
#else
diff --git a/linux/drivers/media/video/tea6420.c b/linux/drivers/media/video/tea6420.c
index 7a8fec9cf..f1bba1568 100644
--- a/linux/drivers/media/video/tea6420.c
+++ b/linux/drivers/media/video/tea6420.c
@@ -48,9 +48,6 @@ MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off).");
/* addresses to scan, found only at 0x4c and/or 0x4d (7-Bit) */
static unsigned short normal_i2c[] = { I2C_ADDR_TEA6420_1, I2C_ADDR_TEA6420_2, I2C_CLIENT_END };
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13)
-static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
-#endif
/* magic definition of all other variables and things */
I2C_CLIENT_INSMOD;
@@ -176,10 +173,8 @@ static int command(struct i2c_client *client, unsigned int cmd, void *arg)
}
static struct i2c_driver driver = {
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) &&(LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15))
- .owner = THIS_MODULE,
-#endif
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15)
+ .owner = THIS_MODULE,
.name = "tea6420",
.flags = I2C_DF_NOTIFY,
#else
diff --git a/linux/drivers/media/video/tlv320aic23b.c b/linux/drivers/media/video/tlv320aic23b.c
index a7453ed6d..b601c232a 100644
--- a/linux/drivers/media/video/tlv320aic23b.c
+++ b/linux/drivers/media/video/tlv320aic23b.c
@@ -32,10 +32,6 @@
#include <linux/videodev.h>
#include <media/v4l2-common.h>
#include <media/v4l2-i2c-drv-legacy.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
-#include "i2c-compat.h"
-#include <linux/slab.h>
-#endif
#include "compat.h"
MODULE_DESCRIPTION("tlv320aic23b driver");
@@ -44,10 +40,6 @@ MODULE_LICENSE("GPL");
static unsigned short normal_i2c[] = { 0x34 >> 1, I2C_CLIENT_END };
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 13)
-static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
-#endif
-
I2C_CLIENT_INSMOD;
/* ----------------------------------------------------------------------- */
@@ -176,8 +168,12 @@ static int tlv320aic23b_remove(struct i2c_client *client)
/* ----------------------------------------------------------------------- */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
-EXPORT_NO_SYMBOLS;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+static const struct i2c_device_id tlv320aic23b_id[] = {
+ { "tlv320aic23b", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, tlv320aic23b_id);
#endif
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
@@ -186,4 +182,7 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.command = tlv320aic23b_command,
.probe = tlv320aic23b_probe,
.remove = tlv320aic23b_remove,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ .id_table = tlv320aic23b_id,
+#endif
};
diff --git a/linux/drivers/media/video/tuner-core.c b/linux/drivers/media/video/tuner-core.c
index 314d89cef..d80f7ee91 100644
--- a/linux/drivers/media/video/tuner-core.c
+++ b/linux/drivers/media/video/tuner-core.c
@@ -21,9 +21,6 @@
#include <media/tuner-types.h>
#include <media/v4l2-common.h>
#include <media/v4l2-i2c-drv-legacy.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-#include "i2c-compat.h"
-#endif
#include "mt20xx.h"
#include "tda8290.h"
#include "tea5761.h"
@@ -100,6 +97,7 @@ struct tuner {
unsigned int type; /* chip type id */
unsigned int config;
int (*tuner_callback) (void *dev, int command, int arg);
+ const char *name;
};
/* standard i2c insmod options */
@@ -113,9 +111,6 @@ static unsigned short normal_i2c[] = {
I2C_CLIENT_END
};
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13)
-static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
-#endif
I2C_CLIENT_INSMOD;
/* insmod options used at init time => read/only */
@@ -161,17 +156,6 @@ static char secam[] = "--";
static char ntsc[] = "-";
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-MODULE_PARM(pal,"s");
-MODULE_PARM(secam,"s");
-MODULE_PARM(ntsc,"s");
-MODULE_PARM(tv_range,"2i");
-MODULE_PARM(radio_range,"2i");
-MODULE_PARM(no_autodetect, "i");
-MODULE_PARM(tuner_debug, "i");
-MODULE_PARM(addr, "i");
-MODULE_PARM(show_i2c, "i");
-#else
module_param(addr, int, 0444);
module_param(no_autodetect, int, 0444);
module_param(show_i2c, int, 0444);
@@ -179,15 +163,8 @@ module_param_named(debug,tuner_debug, int, 0644);
module_param_string(pal, pal, sizeof(pal), 0644);
module_param_string(secam, secam, sizeof(secam), 0644);
module_param_string(ntsc, ntsc, sizeof(ntsc), 0644);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
-static unsigned int dummy;
-module_param_array(tv_range, int, dummy, 0644);
-module_param_array(radio_range, int, dummy, 0644);
-#else
module_param_array(tv_range, int, NULL, 0644);
module_param_array(radio_range, int, NULL, 0644);
-#endif
-#endif
MODULE_DESCRIPTION("device driver for various TV and TV+FM radio tuners");
MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer");
@@ -359,13 +336,13 @@ static void tuner_i2c_address_check(struct tuner *t)
tuner_warn("Support for tuners in i2c address range 0x64 thru 0x6f\n");
tuner_warn("will soon be dropped. This message indicates that your\n");
tuner_warn("hardware has a %s tuner at i2c address 0x%02x.\n",
- t->i2c->name, t->i2c->addr);
+ t->name, t->i2c->addr);
tuner_warn("To ensure continued support for your device, please\n");
tuner_warn("send a copy of this message, along with full dmesg\n");
tuner_warn("output to v4l-dvb-maintainer@linuxtv.org\n");
tuner_warn("Please use subject line: \"obsolete tuner i2c address.\"\n");
tuner_warn("driver: %s, addr: 0x%02x, type: %d (%s)\n",
- t->i2c->adapter->name, t->i2c->addr, t->type, t->i2c->name);
+ t->i2c->adapter->name, t->i2c->addr, t->type, t->name);
tuner_warn("====================== WARNING! ======================\n");
}
@@ -499,19 +476,17 @@ static void set_type(struct i2c_client *c, unsigned int type,
if ((NULL == analog_ops->set_params) &&
(fe_tuner_ops->set_analog_params)) {
- strlcpy(t->i2c->name, fe_tuner_ops->info.name,
- sizeof(t->i2c->name));
+ t->name = fe_tuner_ops->info.name;
t->fe.analog_demod_priv = t;
memcpy(analog_ops, &tuner_core_ops,
sizeof(struct analog_demod_ops));
} else {
- strlcpy(t->i2c->name, analog_ops->info.name,
- sizeof(t->i2c->name));
+ t->name = analog_ops->info.name;
}
- tuner_dbg("type set to %s\n", t->i2c->name);
+ tuner_dbg("type set to %s\n", t->name);
if (t->mode_mask == T_UNINITIALIZED)
t->mode_mask = new_mode_mask;
@@ -1159,7 +1134,7 @@ static int tuner_probe(struct i2c_client *client,
if (NULL == t)
return -ENOMEM;
t->i2c = client;
- strlcpy(client->name, "(tuner unset)", sizeof(client->name));
+ t->name = "(tuner unset)";
i2c_set_clientdata(client, t);
t->type = UNSET;
t->audmode = V4L2_TUNER_MODE_STEREO;
@@ -1281,11 +1256,7 @@ static int tuner_legacy_probe(struct i2c_adapter *adap)
normal_i2c[1] = I2C_CLIENT_END;
}
-#ifdef I2C_CLASS_TV_ANALOG
if ((adap->class & I2C_CLASS_TV_ANALOG) == 0)
-#else
- if (adap->id != I2C_HW_B_BT848)
-#endif
return 0;
/* HACK: Ignore 0x6b and 0x6f on cx88 boards.
@@ -1326,6 +1297,17 @@ static int tuner_remove(struct i2c_client *client)
/* ----------------------------------------------------------------------- */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+/* This driver supports many devices and the idea is to let the driver
+ detect which device is present. So rather than listing all supported
+ devices here, we pretend to support a single, fake device type. */
+static const struct i2c_device_id tuner_id[] = {
+ { "tuner", }, /* autodetect */
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, tuner_id);
+#endif
+
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.name = "tuner",
.driverid = I2C_DRIVERID_TUNER,
@@ -1335,11 +1317,10 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.suspend = tuner_suspend,
.resume = tuner_resume,
.legacy_probe = tuner_legacy_probe,
-};
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
-EXPORT_NO_SYMBOLS;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ .id_table = tuner_id,
#endif
+};
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
diff --git a/linux/drivers/media/video/tvaudio.c b/linux/drivers/media/video/tvaudio.c
index 7b7cfa3b6..84e2c43b7 100644
--- a/linux/drivers/media/video/tvaudio.c
+++ b/linux/drivers/media/video/tvaudio.c
@@ -31,10 +31,6 @@
#endif
#include "compat.h"
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-#include "i2c-compat.h"
-#else
-#endif
#include <media/tvaudio.h>
#include <media/v4l2-common.h>
#include <media/v4l2-chip-ident.h>
@@ -151,9 +147,6 @@ static unsigned short normal_i2c[] = {
I2C_ADDR_TDA9874 >> 1,
I2C_ADDR_PIC16C54 >> 1,
I2C_CLIENT_END };
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13)
-static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
-#endif
I2C_CLIENT_INSMOD;
/* ---------------------------------------------------------------------- */
@@ -283,9 +276,7 @@ static int chip_thread(void *data)
if (!kthread_should_stop())
schedule();
set_current_state(TASK_RUNNING);
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,12)
try_to_freeze();
-#endif
if (kthread_should_stop())
break;
v4l_dbg(1, debug, chip->c, "%s: thread wakeup\n", chip->c->name);
@@ -1522,7 +1513,12 @@ static int chip_probe(struct i2c_client *client, const struct i2c_device_id *id)
}
/* fill required data structures */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
strcpy(client->name, desc->name);
+#else
+ if (!id)
+ strlcpy(client->name, desc->name, I2C_NAME_SIZE);
+#endif
chip->type = desc-chiplist;
chip->shadow.count = desc->registers+1;
chip->prevmode = -1;
@@ -1842,22 +1838,22 @@ static int chip_legacy_probe(struct i2c_adapter *adap)
because dedicated drivers are used */
if ((adap->id == I2C_HW_SAA7146))
return 0;
-#ifdef I2C_CLASS_TV_ANALOG
if (adap->class & I2C_CLASS_TV_ANALOG)
return 1;
-#else
- switch (adap->id) {
- case I2C_HW_B_BT848:
- case I2C_HW_B_RIVA:
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
- case I2C_HW_SAA7134:
-#endif
- return 1;
- }
-#endif
return 0;
}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+/* This driver supports many devices and the idea is to let the driver
+ detect which device is present. So rather than listing all supported
+ devices here, we pretend to support a single, fake device type. */
+static const struct i2c_device_id chip_id[] = {
+ { "tvaudio", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, chip_id);
+#endif
+
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.name = "tvaudio",
.driverid = I2C_DRIVERID_TVAUDIO,
@@ -1865,6 +1861,9 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.probe = chip_probe,
.remove = chip_remove,
.legacy_probe = chip_legacy_probe,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ .id_table = chip_id,
+#endif
};
/*
diff --git a/linux/drivers/media/video/tveeprom.c b/linux/drivers/media/video/tveeprom.c
index e38bda67a..dc0bd9fda 100644
--- a/linux/drivers/media/video/tveeprom.c
+++ b/linux/drivers/media/video/tveeprom.c
@@ -36,9 +36,6 @@
#include <linux/types.h>
#include <linux/videodev.h>
#include <linux/i2c.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
-#include <linux/slab.h>
-#endif
#include <media/tuner.h>
#include <media/tveeprom.h>
diff --git a/linux/drivers/media/video/tvmixer.c b/linux/drivers/media/video/tvmixer.c
index ca7330e10..2862efa93 100644
--- a/linux/drivers/media/video/tvmixer.c
+++ b/linux/drivers/media/video/tvmixer.c
@@ -19,16 +19,6 @@
#include <asm/semaphore.h>
#include <asm/uaccess.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-# include "i2c-compat.h"
-#endif
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,71)
-# define strlcpy(dest,src,len) strncpy(dest,src,(len)-1)
-#endif
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
-# define iminor(inode) minor(inode->i_rdev)
-#endif
-
#define DEV_MAX 4
static int devnr = -1;
@@ -206,14 +196,8 @@ static int tvmixer_open(struct inode *inode, struct file *file)
/* lock bttv in memory while the mixer is in use */
file->private_data = mix;
-#ifndef I2C_PEC
- if (client->adapter->inc_use)
- client->adapter->inc_use(client->adapter);
-#endif
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,54)
if (client->adapter->owner)
try_module_get(client->adapter->owner);
-#endif
return 0;
}
@@ -227,21 +211,13 @@ static int tvmixer_release(struct inode *inode, struct file *file)
return -ENODEV;
}
-#ifndef I2C_PEC
- if (client->adapter->dec_use)
- client->adapter->dec_use(client->adapter);
-#endif
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,54)
module_put(client->adapter->owner);
-#endif
return 0;
}
static struct i2c_driver driver = {
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))&&(LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15))
- .owner = THIS_MODULE,
-#endif
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15)
+ .owner = THIS_MODULE,
.name = "tvmixer",
.flags = I2C_DF_NOTIFY,
#else
@@ -269,20 +245,10 @@ static const struct file_operations tvmixer_fops = {
static int tvmixer_adapters(struct i2c_adapter *adap)
{
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,54)
struct i2c_client *client;
list_for_each_entry(client, &adap->clients, list)
tvmixer_clients(client);
-#else
- int i;
-
- for (i=0; i<I2C_CLIENT_MAX; i++) {
- if (!adap->clients[i])
- continue;
- tvmixer_clients(adap->clients[i]);
- }
-#endif
return 0;
}
@@ -291,22 +257,8 @@ static int tvmixer_clients(struct i2c_client *client)
struct video_audio va;
int i,minor;
-#ifdef I2C_CLASS_TV_ANALOG
if (!(client->adapter->class & I2C_CLASS_TV_ANALOG))
return -1;
-#else
- /* TV card ??? */
- switch (client->adapter->id) {
- case I2C_HW_SMBUS_VOODOO3:
- case I2C_HW_B_BT848:
- case I2C_HW_B_RIVA:
- /* ok, have a look ... */
- break;
- default:
- /* ignore that one */
- return -1;
- }
-#endif
/* unregister ?? */
for (i = 0; i < DEV_MAX; i++) {
diff --git a/linux/drivers/media/video/tvp5150.c b/linux/drivers/media/video/tvp5150.c
index 7dc6623cc..3c0e2b316 100644
--- a/linux/drivers/media/video/tvp5150.c
+++ b/linux/drivers/media/video/tvp5150.c
@@ -12,12 +12,6 @@
#include <linux/video_decoder.h>
#include <media/v4l2-common.h>
#include <media/tvp5150.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include "i2c-compat.h"
-#endif
#include "tvp5150_reg.h"
@@ -32,9 +26,6 @@ static unsigned short normal_i2c[] = {
I2C_CLIENT_END
};
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13)
-static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
-#endif
I2C_CLIENT_INSMOD;
static int debug;
@@ -1148,13 +1139,8 @@ static struct i2c_client client_template = {
.driver = &driver,
};
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
static int tvp5150_detect_client(struct i2c_adapter *adapter,
int address, int kind)
-#else
-static int tvp5150_detect_client(struct i2c_adapter *adapter,
- int address, unsigned short flags, int kind)
-#endif
{
struct i2c_client *c;
struct tvp5150 *core;
@@ -1204,9 +1190,6 @@ static int tvp5150_detect_client(struct i2c_adapter *adapter,
if (debug > 1)
dump_reg(c);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
- MOD_INC_USE_COUNT;
-#endif
return 0;
}
@@ -1242,10 +1225,8 @@ static int tvp5150_detach_client(struct i2c_client *c)
/* ----------------------------------------------------------------------- */
static struct i2c_driver driver = {
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))&&(LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15))
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15)
.owner = THIS_MODULE,
-#endif
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15)
.name = "tvp5150",
.flags = I2C_DF_NOTIFY,
#else
diff --git a/linux/drivers/media/video/upd64031a.c b/linux/drivers/media/video/upd64031a.c
index 5408309cb..dfca5ed6e 100644
--- a/linux/drivers/media/video/upd64031a.c
+++ b/linux/drivers/media/video/upd64031a.c
@@ -46,21 +46,13 @@ MODULE_AUTHOR("T. Adachi, Takeru KOMORIYA, Hans Verkuil");
MODULE_LICENSE("GPL");
static int debug;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
module_param(debug, int, 0644);
-#else
-MODULE_PARM(debug, "i");
-#endif
MODULE_PARM_DESC(debug, "Debug level (0-1)");
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
static unsigned short normal_i2c[] = { 0x24 >> 1, 0x26 >> 1, I2C_CLIENT_END };
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 13)
-static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
-#endif
-
I2C_CLIENT_INSMOD;
#endif
@@ -242,8 +234,12 @@ static int upd64031a_remove(struct i2c_client *client)
/* ----------------------------------------------------------------------- */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
-EXPORT_NO_SYMBOLS;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+static const struct i2c_device_id upd64031a_id[] = {
+ { "upd64031a", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, upd64031a_id);
#endif
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
@@ -252,4 +248,7 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.command = upd64031a_command,
.probe = upd64031a_probe,
.remove = upd64031a_remove,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ .id_table = upd64031a_id,
+#endif
};
diff --git a/linux/drivers/media/video/upd64083.c b/linux/drivers/media/video/upd64083.c
index e43cc103f..5f0c6919d 100644
--- a/linux/drivers/media/video/upd64083.c
+++ b/linux/drivers/media/video/upd64083.c
@@ -37,21 +37,13 @@ MODULE_AUTHOR("T. Adachi, Takeru KOMORIYA, Hans Verkuil");
MODULE_LICENSE("GPL");
static int debug;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
module_param(debug, bool, 0644);
-#else
-MODULE_PARM(debug, "i");
-#endif
MODULE_PARM_DESC(debug, "Debug level (0-1)");
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
static unsigned short normal_i2c[] = { 0xb8 >> 1, 0xba >> 1, I2C_CLIENT_END };
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 13)
-static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
-#endif
-
I2C_CLIENT_INSMOD;
#endif
@@ -219,8 +211,12 @@ static int upd64083_remove(struct i2c_client *client)
/* ----------------------------------------------------------------------- */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
-EXPORT_NO_SYMBOLS;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+static const struct i2c_device_id upd64083_id[] = {
+ { "upd64083", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, upd64083_id);
#endif
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
@@ -229,4 +225,7 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.command = upd64083_command,
.probe = upd64083_probe,
.remove = upd64083_remove,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ .id_table = upd64083_id,
+#endif
};
diff --git a/linux/drivers/media/video/usbvideo/konicawc.c b/linux/drivers/media/video/usbvideo/konicawc.c
index 7e2f04fb4..6fef59557 100644
--- a/linux/drivers/media/video/usbvideo/konicawc.c
+++ b/linux/drivers/media/video/usbvideo/konicawc.c
@@ -17,10 +17,8 @@
#include <linux/init.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18)
#include <linux/usb/input.h>
-#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13)
-#include <linux/usb_input.h>
#else
-#include <linux/input.h>
+#include <linux/usb_input.h>
#endif
#include "usbvideo.h"
diff --git a/linux/drivers/media/video/usbvideo/quickcam_messenger.c b/linux/drivers/media/video/usbvideo/quickcam_messenger.c
index 8cab43ab7..69f0fc770 100644
--- a/linux/drivers/media/video/usbvideo/quickcam_messenger.c
+++ b/linux/drivers/media/video/usbvideo/quickcam_messenger.c
@@ -35,7 +35,7 @@
#include <linux/input.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18)
#include <linux/usb/input.h>
-#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13)
+#else
#include <linux/usb_input.h>
#endif
@@ -227,7 +227,7 @@ static int qcm_stv_setb(struct usb_device *dev, u16 reg, u8 val)
return ret;
}
-static int qcm_stv_setw(struct usb_device *dev, u16 reg, u16 val)
+static int qcm_stv_setw(struct usb_device *dev, u16 reg, __le16 val)
{
int ret;
diff --git a/linux/drivers/media/video/usbvision/usbvision-core.c b/linux/drivers/media/video/usbvision/usbvision-core.c
index ce9348a07..bf464540c 100644
--- a/linux/drivers/media/video/usbvision/usbvision-core.c
+++ b/linux/drivers/media/video/usbvision/usbvision-core.c
@@ -45,13 +45,7 @@
#include <media/tuner.h>
#include <media/audiochip.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
-#include <linux/proc_fs.h>
-#include <linux/tqueue.h>
-#include <linux/wrapper.h>
-#else
#include <linux/workqueue.h>
-#endif
#ifdef CONFIG_KMOD
#include <linux/kmod.h>
@@ -174,40 +168,6 @@ static void usbvision_rvfree(void *mem, unsigned long size)
vfree(mem);
}
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,24)
-/* helper functions to access driver private data. */
-static inline void *video_get_drvdata(struct video_device *dev)
-{
- return dev->priv;
-}
-
-static inline void video_set_drvdata(struct video_device *dev, void *data)
-{
- dev->priv = data;
-}
-
-struct video_device *video_device_alloc(void)
-{
- struct video_device *vfd;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)
- vfd = kmalloc(sizeof(*vfd),GFP_KERNEL);
- if (NULL == vfd)
- return NULL;
- memset(vfd,0,sizeof(*vfd));
-#else
- vfd = kzalloc(sizeof(*vfd),GFP_KERNEL);
- if (NULL == vfd)
- return NULL;
-#endif
- return vfd;
-}
-
-void video_device_release(struct video_device *vfd)
-{
- kfree(vfd);
-}
-#endif
-
#if ENABLE_HEXDUMP
static void usbvision_hexdump(const unsigned char *data, int len)
@@ -1485,7 +1445,7 @@ static int usbvision_compress_isochronous(struct usb_usbvision *usbvision,
return totlen;
}
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) || LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)
static void usbvision_isocIrq(struct urb *urb)
{
#else
@@ -1559,7 +1519,6 @@ static void usbvision_isocIrq(struct urb *urb, struct pt_regs *regs)
urb->iso_frame_desc[i].actual_length = 0;
}
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
urb->status = 0;
urb->dev = usbvision->dev;
errCode = usb_submit_urb (urb, GFP_ATOMIC);
@@ -1568,7 +1527,6 @@ static void usbvision_isocIrq(struct urb *urb, struct pt_regs *regs)
err("%s: usb_submit_urb failed: error %d",
__func__, errCode);
}
-#endif
return;
}
@@ -1632,7 +1590,7 @@ int usbvision_write_reg(struct usb_usbvision *usbvision, unsigned char reg,
}
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) || LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)
static void usbvision_ctrlUrb_complete(struct urb *urb)
#else
static void usbvision_ctrlUrb_complete(struct urb *urb, struct pt_regs *regs)
@@ -1662,19 +1620,11 @@ static int usbvision_write_reg_irq(struct usb_usbvision *usbvision,int address,
}
usbvision->ctrlUrbBusy = 1;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,20)
- usbvision->ctrlUrbSetup.requesttype = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT;
- usbvision->ctrlUrbSetup.request = USBVISION_OP_CODE;
- usbvision->ctrlUrbSetup.value = 0;
- usbvision->ctrlUrbSetup.index = cpu_to_le16(address);
- usbvision->ctrlUrbSetup.length = cpu_to_le16(len);
-#else
usbvision->ctrlUrbSetup.bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT;
usbvision->ctrlUrbSetup.bRequest = USBVISION_OP_CODE;
usbvision->ctrlUrbSetup.wValue = 0;
usbvision->ctrlUrbSetup.wIndex = cpu_to_le16(address);
usbvision->ctrlUrbSetup.wLength = cpu_to_le16(len);
-#endif
usb_fill_control_urb (usbvision->ctrlUrb, usbvision->dev,
usb_sndctrlpipe(usbvision->dev, 1),
(unsigned char *)&usbvision->ctrlUrbSetup,
@@ -1684,11 +1634,7 @@ static int usbvision_write_reg_irq(struct usb_usbvision *usbvision,int address,
memcpy(usbvision->ctrlUrbBuffer, data, len);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
- errCode = usb_submit_urb(usbvision->ctrlUrb);
-#else
errCode = usb_submit_urb(usbvision->ctrlUrb, GFP_ATOMIC);
-#endif
if (errCode < 0) {
// error in usb_submit_urb()
usbvision->ctrlUrbBusy = 0;
@@ -2385,18 +2331,12 @@ static void usbvision_powerOffTimer(unsigned long data)
PDEBUG(DBG_FUNC, "");
del_timer(&usbvision->powerOffTimer);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
- INIT_TQUEUE(&usbvision->powerOffTask, call_usbvision_power_off, usbvision);
- (void) schedule_task(&usbvision->powerOffTask);
-#else
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
INIT_WORK(&usbvision->powerOffWork, call_usbvision_power_off, usbvision);
#else
INIT_WORK(&usbvision->powerOffWork, call_usbvision_power_off);
#endif
(void) schedule_work(&usbvision->powerOffWork);
-#endif
-
}
void usbvision_init_powerOffTimer(struct usb_usbvision *usbvision)
@@ -2568,11 +2508,7 @@ int usbvision_init_isoc(struct usb_usbvision *usbvision)
int j, k;
struct urb *urb;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
- urb = usb_alloc_urb(USBVISION_URB_FRAMES);
-#else
urb = usb_alloc_urb(USBVISION_URB_FRAMES, GFP_KERNEL);
-#endif
if (urb == NULL) {
err("%s: usb_alloc_urb() failed", __func__);
return -ENOMEM;
@@ -2586,12 +2522,8 @@ int usbvision_init_isoc(struct usb_usbvision *usbvision)
urb->dev = dev;
urb->context = usbvision;
urb->pipe = usb_rcvisocpipe(dev, usbvision->video_endp);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
- urb->transfer_flags = USB_ISO_ASAP;
-#else
urb->transfer_flags = URB_ISO_ASAP;
urb->interval = 1;
-#endif
urb->transfer_buffer = usbvision->sbuf[bufIdx].data;
urb->complete = usbvision_isocIrq;
urb->number_of_packets = USBVISION_URB_FRAMES;
@@ -2605,28 +2537,10 @@ int usbvision_init_isoc(struct usb_usbvision *usbvision)
}
}
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
- /* Link URBs into a ring so that they invoke each other infinitely */
- for (bufIdx = 0; bufIdx < USBVISION_NUMSBUF; bufIdx++) {
- if ((bufIdx + 1) < USBVISION_NUMSBUF) {
- usbvision->sbuf[bufIdx].urb->next =
- usbvision->sbuf[bufIdx + 1].urb;
- }
- else {
- usbvision->sbuf[bufIdx].urb->next =
- usbvision->sbuf[0].urb;
- }
- }
-#endif
-
/* Submit all URBs */
for (bufIdx = 0; bufIdx < USBVISION_NUMSBUF; bufIdx++) {
- #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
- errCode = usb_submit_urb(usbvision->sbuf[bufIdx].urb);
- #else
errCode = usb_submit_urb(usbvision->sbuf[bufIdx].urb,
GFP_KERNEL);
- #endif
if (errCode) {
err("%s: usb_submit_urb(%d) failed: error %d",
__func__, bufIdx, errCode);
@@ -2656,7 +2570,6 @@ void usbvision_stop_isoc(struct usb_usbvision *usbvision)
return;
/* Unschedule all of the iso td's */
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9)
for (bufIdx = 0; bufIdx < USBVISION_NUMSBUF; bufIdx++) {
usb_kill_urb(usbvision->sbuf[bufIdx].urb);
if (usbvision->sbuf[bufIdx].data){
@@ -2668,25 +2581,6 @@ void usbvision_stop_isoc(struct usb_usbvision *usbvision)
usb_free_urb(usbvision->sbuf[bufIdx].urb);
usbvision->sbuf[bufIdx].urb = NULL;
}
-#else
- for (bufIdx = 0; bufIdx < USBVISION_NUMSBUF; bufIdx++) {
- errCode = usb_unlink_urb(usbvision->sbuf[bufIdx].urb);
- if (errCode < 0)
- err("%s: usb_unlink_urb() failed: error %d",
- __func__, errCode);
- }
-
- if (usbvision->sbuf[bufIdx].data){
- usb_buffer_free(usbvision->dev,
- sb_size,
- usbvision->sbuf[bufIdx].data,
- usbvision->sbuf[bufIdx].urb->transfer_dma);
- }
- /* Delete them all */
- for (bufIdx = 0; bufIdx < USBVISION_NUMSBUF; bufIdx++)
- usb_free_urb(usbvision->sbuf[bufIdx].urb);
-#endif
-
PDEBUG(DBG_ISOC, "%s: streaming=Stream_Off\n", __func__);
usbvision->streaming = Stream_Off;
diff --git a/linux/drivers/media/video/usbvision/usbvision-i2c.c b/linux/drivers/media/video/usbvision/usbvision-i2c.c
index 67efd7821..1b6180573 100644
--- a/linux/drivers/media/video/usbvision/usbvision-i2c.c
+++ b/linux/drivers/media/video/usbvision/usbvision-i2c.c
@@ -193,28 +193,9 @@ static u32 functionality(struct i2c_adapter *adap)
return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR;
}
-#ifndef I2C_PEC
-static void inc_use(struct i2c_adapter *adap)
-{
- MOD_INC_USE_COUNT;
-}
-
-static void dec_use(struct i2c_adapter *adap)
-{
- MOD_DEC_USE_COUNT;
-}
-#endif
-
/* -----exported algorithm data: ------------------------------------- */
static struct i2c_algorithm usbvision_algo = {
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)) && (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,30))
- .owner = THIS_MODULE,
-#endif
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
- .name = "USB algorithm",
- .id = I2C_ALGO_BIT, /* FIXME */
-#endif
.master_xfer = usbvision_i2c_xfer,
.smbus_xfer = NULL,
.functionality = functionality,
@@ -231,9 +212,6 @@ static int usbvision_i2c_usb_add_bus(struct i2c_adapter *adap)
/* register new adapter to i2c module... */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
- adap->id |= usbvision_algo.id;
-#endif
adap->algo = &usbvision_algo;
adap->timeout = 100; /* default values, should */
@@ -533,30 +511,16 @@ static int usbvision_i2c_read(struct usb_usbvision *usbvision, unsigned char add
}
static struct i2c_adapter i2c_adap_template = {
-#ifdef I2C_PEC
.owner = THIS_MODULE,
-#else
- .inc_use = inc_use,
- .dec_use = dec_use,
-#endif
.name = "usbvision",
.id = I2C_HW_B_BT848, /* FIXME */
.client_register = attach_inform,
.client_unregister = detach_inform,
-#ifdef I2C_ADAP_CLASS_TV_ANALOG
- .class = I2C_ADAP_CLASS_TV_ANALOG,
-#else
-#ifdef I2C_CLASS_TV_ANALOG
.class = I2C_CLASS_TV_ANALOG,
-#endif
-#endif
};
static struct i2c_client i2c_client_template = {
.name = "usbvision internal",
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 11)
- .id = -1,
-#endif
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15)
.flags = I2C_CLIENT_ALLOW_USE,
#endif
diff --git a/linux/drivers/media/video/usbvision/usbvision-video.c b/linux/drivers/media/video/usbvision/usbvision-video.c
index 55b3f5e60..073d30454 100644
--- a/linux/drivers/media/video/usbvision/usbvision-video.c
+++ b/linux/drivers/media/video/usbvision/usbvision-video.c
@@ -68,13 +68,7 @@
#include <media/tuner.h>
#include <media/audiochip.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
-#include <linux/proc_fs.h>
-#include <linux/tqueue.h>
-#include <linux/wrapper.h>
-#else
#include <linux/workqueue.h>
-#endif
#ifdef CONFIG_KMOD
#include <linux/kmod.h>
@@ -173,10 +167,8 @@ MODULE_PARM_DESC(vbi_nr, "Set vbi device number (/dev/vbiX). Default: -1 (autod
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE(DRIVER_LICENSE);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
MODULE_VERSION(USBVISION_VERSION_STRING);
MODULE_ALIAS(DRIVER_ALIAS);
-#endif
/*****************************************************************************/
@@ -187,8 +179,6 @@ MODULE_ALIAS(DRIVER_ALIAS);
/* /sys/bus/usb/drivers/USBVision Video Grabber */
/*****************************************************************************/
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
-
#define YES_NO(x) ((x) ? "Yes" : "No")
static inline struct usb_usbvision *cd_to_usbvision(struct device *cd)
@@ -379,8 +369,6 @@ static void usbvision_remove_sysfs(struct video_device *vdev)
}
}
-#endif
-
/*
* usbvision_open()
*
@@ -389,25 +377,15 @@ static void usbvision_remove_sysfs(struct video_device *vdev)
* then allocates buffers needed for video processing.
*
*/
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,19)
-static int usbvision_v4l2_open(struct video_device *dev, int flags)
-{
- struct usb_usbvision *usbvision = (struct usb_usbvision *) dev;
-#else
static int usbvision_v4l2_open(struct inode *inode, struct file *file)
{
struct video_device *dev = video_devdata(file);
struct usb_usbvision *usbvision =
(struct usb_usbvision *) video_get_drvdata(dev);
-#endif
int errCode = 0;
PDEBUG(DBG_IO, "open");
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
- MOD_INC_USE_COUNT;
-#endif
-
usbvision_reset_powerOffTimer(usbvision);
if (usbvision->user)
@@ -461,12 +439,6 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file)
mutex_unlock(&usbvision->lock);
}
- if (errCode) {
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
- MOD_DEC_USE_COUNT;
-#endif
- }
-
/* prepare queues */
usbvision_empty_framequeues(usbvision);
@@ -482,17 +454,11 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file)
* allocated in usbvision_v4l2_open().
*
*/
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,19)
-static void usbvision_v4l2_close(struct video_device *dev)
-{
- struct usb_usbvision *usbvision = (struct usb_usbvision *) dev;
-#else
static int usbvision_v4l2_close(struct inode *inode, struct file *file)
{
struct video_device *dev = video_devdata(file);
struct usb_usbvision *usbvision =
(struct usb_usbvision *) video_get_drvdata(dev);
-#endif
PDEBUG(DBG_IO, "close");
mutex_lock(&usbvision->lock);
@@ -523,14 +489,7 @@ static int usbvision_v4l2_close(struct inode *inode, struct file *file)
}
PDEBUG(DBG_IO, "success");
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
- MOD_DEC_USE_COUNT;
-#endif
-
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,19)
return 0;
-#endif
}
@@ -1123,12 +1082,6 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
return 0;
}
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,19)
-static long usbvision_v4l2_read(struct video_device *dev, char *buf,
- unsigned long count, int noblock)
-{
- struct usb_usbvision *usbvision = (struct usb_usbvision *) dev;
-#else
static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
@@ -1136,7 +1089,6 @@ static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf,
struct usb_usbvision *usbvision =
(struct usb_usbvision *) video_get_drvdata(dev);
int noblock = file->f_flags & O_NONBLOCK;
-#endif
unsigned long lock_flags;
int ret,i;
@@ -1302,24 +1254,15 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
* Here comes the stuff for radio on usbvision based devices
*
*/
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,19)
-static int usbvision_radio_open(struct video_device *dev, int flags)
-{
- struct usb_usbvision *usbvision = (struct usb_usbvision *)dev->priv;
-#else
static int usbvision_radio_open(struct inode *inode, struct file *file)
{
struct video_device *dev = video_devdata(file);
struct usb_usbvision *usbvision =
(struct usb_usbvision *) video_get_drvdata(dev);
-#endif
int errCode = 0;
PDEBUG(DBG_IO, "%s:", __func__);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
- MOD_INC_USE_COUNT;
-#endif
mutex_lock(&usbvision->lock);
if (usbvision->user) {
@@ -1351,9 +1294,6 @@ static int usbvision_radio_open(struct inode *inode, struct file *file)
}
if (errCode) {
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
- MOD_DEC_USE_COUNT;
-#endif
if (PowerOnAtOpen) {
usbvision_i2c_unregister(usbvision);
usbvision_power_off(usbvision);
@@ -1366,18 +1306,12 @@ out:
}
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,19)
-static void usbvision_radio_close(struct video_device *dev)
-{
- struct usb_usbvision *usbvision = (struct usb_usbvision *)dev->priv;
-#else
static int usbvision_radio_close(struct inode *inode, struct file *file)
{
struct video_device *dev = video_devdata(file);
struct usb_usbvision *usbvision =
(struct usb_usbvision *) video_get_drvdata(dev);
int errCode = 0;
-#endif
PDEBUG(DBG_IO, "");
@@ -1404,42 +1338,22 @@ static int usbvision_radio_close(struct inode *inode, struct file *file)
usbvision_release(usbvision);
}
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
- MOD_DEC_USE_COUNT;
-#endif
-
PDEBUG(DBG_IO, "success");
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,19)
return errCode;
-#endif
}
/*
* Here comes the stuff for vbi on usbvision based devices
*
*/
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,19)
-static int usbvision_vbi_open(struct video_device *dev, int flags)
-{
- struct usb_usbvision *usbvision = (struct usb_usbvision *)dev->priv;
-#else
static int usbvision_vbi_open(struct inode *inode, struct file *file)
{
-#endif
/* TODO */
return -ENODEV;
-
}
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,19)
-static void usbvision_vbi_close(struct video_device *dev)
-{
- struct usb_usbvision *usbvision = (struct usb_usbvision *)dev->priv;
-#else
static int usbvision_vbi_close(struct inode *inode, struct file *file)
{
-#endif
/* TODO */
return -ENODEV;
}
@@ -1463,21 +1377,8 @@ static int usbvision_vbi_ioctl(struct inode *inode, struct file *file,
//
// Video template
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,19)
-static struct video_device usbvision_video_template = {
- .type = VID_TYPE_TUNER | VID_TYPE_CAPTURE,
- .open = usbvision_v4l2_open,
- .close = usbvision_v4l2_close,
- .read = usbvision_v4l2_read,
- .mmap = usbvision_v4l2_mmap,
- .ioctl = video_ioctl2,
- .minor = -1,
-};
-#else
static const struct file_operations usbvision_fops = {
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,31)
.owner = THIS_MODULE,
-#endif
.open = usbvision_v4l2_open,
.release = usbvision_v4l2_close,
.read = usbvision_v4l2_read,
@@ -1485,20 +1386,14 @@ static const struct file_operations usbvision_fops = {
.ioctl = video_ioctl2,
.llseek = no_llseek,
/* .poll = video_poll, */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11)
.compat_ioctl = v4l_compat_ioctl32,
-#endif
};
static struct video_device usbvision_video_template = {
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,31)
.owner = THIS_MODULE,
-#endif
.type = VID_TYPE_TUNER | VID_TYPE_CAPTURE,
.fops = &usbvision_fops,
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
.name = "usbvision-video",
.release = video_device_release,
-#endif
.minor = -1,
.vidioc_querycap = vidioc_querycap,
.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
@@ -1534,44 +1429,25 @@ static struct video_device usbvision_video_template = {
.tvnorms = USBVISION_NORMS,
.current_norm = V4L2_STD_PAL
};
-#endif
// Radio template
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,19)
-static struct video_device usbvision_radio_template=
-{
- .type = VID_TYPE_TUNER,
- .open = usbvision_radio_open,
- .close = usbvision_radio_close,
- .ioctl = video_ioctl2,
- .minor -1,
-};
-#else
static const struct file_operations usbvision_radio_fops = {
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,31)
.owner = THIS_MODULE,
-#endif
.open = usbvision_radio_open,
.release = usbvision_radio_close,
.ioctl = video_ioctl2,
.llseek = no_llseek,
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11)
.compat_ioctl = v4l_compat_ioctl32,
-#endif
};
static struct video_device usbvision_radio_template=
{
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,31)
.owner = THIS_MODULE,
-#endif
.type = VID_TYPE_TUNER,
.fops = &usbvision_radio_fops,
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
.name = "usbvision-radio",
.release = video_device_release,
-#endif
.minor = -1,
.vidioc_querycap = vidioc_querycap,
.vidioc_enum_input = vidioc_enum_input,
@@ -1590,46 +1466,26 @@ static struct video_device usbvision_radio_template=
.tvnorms = USBVISION_NORMS,
.current_norm = V4L2_STD_PAL
};
-#endif
// vbi template
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,19)
-static struct video_device usbvision_vbi_template=
-{
- type: VID_TYPE_TELETEXT,
- open: usbvision_vbi_open,
- close: usbvision_vbi_close,
- ioctl: usbvision_vbi_ioctl,
- minor: -1,
-};
-#else
static const struct file_operations usbvision_vbi_fops = {
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,31)
.owner = THIS_MODULE,
-#endif
.open = usbvision_vbi_open,
.release = usbvision_vbi_close,
.ioctl = usbvision_vbi_ioctl,
.llseek = no_llseek,
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11)
.compat_ioctl = v4l_compat_ioctl32,
-#endif
};
static struct video_device usbvision_vbi_template=
{
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,31)
.owner = THIS_MODULE,
-#endif
.type = VID_TYPE_TUNER,
.fops = &usbvision_vbi_fops,
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
.release = video_device_release,
.name = "usbvision-vbi",
-#endif
.minor = -1,
};
-#endif
static struct video_device *usbvision_vdev_init(struct usb_usbvision *usbvision,
@@ -1650,9 +1506,7 @@ static struct video_device *usbvision_vdev_init(struct usb_usbvision *usbvision,
}
*vdev = *vdev_template;
// vdev->minor = -1;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
vdev->dev = &usb_dev->dev;
-#endif
snprintf(vdev->name, sizeof(vdev->name), "%s", name);
video_set_drvdata(vdev, usbvision);
return vdev;
@@ -1667,9 +1521,6 @@ static void usbvision_unregister_video(struct usb_usbvision *usbvision)
usbvision->vbi->minor & 0x1f);
if (usbvision->vbi->minor != -1) {
video_unregister_device(usbvision->vbi);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
- video_device_release(usbvision->vbi);
-#endif
} else {
video_device_release(usbvision->vbi);
}
@@ -1682,9 +1533,6 @@ static void usbvision_unregister_video(struct usb_usbvision *usbvision)
usbvision->rdev->minor & 0x1f);
if (usbvision->rdev->minor != -1) {
video_unregister_device(usbvision->rdev);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
- video_device_release(usbvision->rdev);
-#endif
} else {
video_device_release(usbvision->rdev);
}
@@ -1697,9 +1545,6 @@ static void usbvision_unregister_video(struct usb_usbvision *usbvision)
usbvision->vdev->minor & 0x1f);
if (usbvision->vdev->minor != -1) {
video_unregister_device(usbvision->vdev);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
- video_device_release(usbvision->vdev);
-#endif
} else {
video_device_release(usbvision->vdev);
}
@@ -1799,11 +1644,7 @@ static struct usb_usbvision *usbvision_alloc(struct usb_device *dev)
mutex_init(&usbvision->lock); /* available */
// prepare control urb for control messages during interrupts
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
- usbvision->ctrlUrb = usb_alloc_urb(USBVISION_URB_FRAMES);
-#else
usbvision->ctrlUrb = usb_alloc_urb(USBVISION_URB_FRAMES, GFP_KERNEL);
-#endif
if (usbvision->ctrlUrb == NULL) {
goto err_exit;
}
@@ -2006,12 +1847,7 @@ static int __devinit usbvision_probe(struct usb_interface *intf,
usbvision_create_sysfs(usbvision->vdev);
PDEBUG(DBG_PROBE, "success");
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
- MOD_DEC_USE_COUNT;
- return usbvision;
-#else
return 0;
-#endif
}
@@ -2023,15 +1859,9 @@ static int __devinit usbvision_probe(struct usb_interface *intf,
* with no ill consequences.
*
*/
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
-static void usbvision_disconnect(struct usb_device *dev, void *ptr)
-{
- struct usb_usbvision *usbvision = (struct usb_usbvision *) ptr;
-#else
static void __devexit usbvision_disconnect(struct usb_interface *intf)
{
struct usb_usbvision *usbvision = usb_get_intfdata(intf);
-#endif
PDEBUG(DBG_PROBE, "");
@@ -2039,11 +1869,7 @@ static void __devexit usbvision_disconnect(struct usb_interface *intf)
err("%s: usb_get_intfdata() failed", __func__);
return;
}
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
- MOD_INC_USE_COUNT;
-#else
usb_set_intfdata (intf, NULL);
-#endif
mutex_lock(&usbvision->lock);
@@ -2056,9 +1882,7 @@ static void __devexit usbvision_disconnect(struct usb_interface *intf)
}
usbvision->remove_pending = 1; // Now all ISO data will be ignored
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
usb_put_dev(usbvision->dev);
-#endif
usbvision->dev = NULL; // USB device is no more
mutex_unlock(&usbvision->lock);
@@ -2073,15 +1897,10 @@ static void __devexit usbvision_disconnect(struct usb_interface *intf)
}
PDEBUG(DBG_PROBE, "success");
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
- MOD_DEC_USE_COUNT;
-#endif
}
static struct usb_driver usbvision_driver = {
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,31)) && \
- (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16))
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)
.owner = THIS_MODULE,
#endif
.name = "usbvision",
diff --git a/linux/drivers/media/video/usbvision/usbvision.h b/linux/drivers/media/video/usbvision/usbvision.h
index 9f4c40dbf..371c6987f 100644
--- a/linux/drivers/media/video/usbvision/usbvision.h
+++ b/linux/drivers/media/video/usbvision/usbvision.h
@@ -401,11 +401,7 @@ struct usb_usbvision {
struct semaphore lock;
#endif
struct timer_list powerOffTimer;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
- struct tq_struct powerOffTask;
-#else
struct work_struct powerOffWork;
-#endif
int power; /* is the device powered on? */
int user; /* user count for exclusive use */
int initialized; /* Had we already sent init sequence? */
diff --git a/linux/drivers/media/video/uvc/Kconfig b/linux/drivers/media/video/uvc/Kconfig
new file mode 100644
index 000000000..c2d9760de
--- /dev/null
+++ b/linux/drivers/media/video/uvc/Kconfig
@@ -0,0 +1,17 @@
+config USB_VIDEO_CLASS
+ tristate "USB Video Class (UVC)"
+ ---help---
+ Support for the USB Video Class (UVC). Currently only video
+ input devices, such as webcams, are supported.
+
+ For more information see: <http://linux-uvc.berlios.de/>
+
+config USB_VIDEO_CLASS_INPUT_EVDEV
+ bool "UVC input events device support"
+ default y
+ depends on USB_VIDEO_CLASS && INPUT
+ ---help---
+ This option makes USB Video Class devices register an input device
+ to report button events.
+
+ If you are in doubt, say Y.
diff --git a/linux/drivers/media/video/uvc/Makefile b/linux/drivers/media/video/uvc/Makefile
new file mode 100644
index 000000000..968c1994e
--- /dev/null
+++ b/linux/drivers/media/video/uvc/Makefile
@@ -0,0 +1,3 @@
+uvcvideo-objs := uvc_driver.o uvc_queue.o uvc_v4l2.o uvc_video.o uvc_ctrl.o \
+ uvc_status.o uvc_isight.o
+obj-$(CONFIG_USB_VIDEO_CLASS) += uvcvideo.o
diff --git a/linux/drivers/media/video/uvc/uvc_ctrl.c b/linux/drivers/media/video/uvc/uvc_ctrl.c
new file mode 100644
index 000000000..3ae955126
--- /dev/null
+++ b/linux/drivers/media/video/uvc/uvc_ctrl.c
@@ -0,0 +1,1257 @@
+/*
+ * uvc_ctrl.c -- USB Video Class driver - Controls
+ *
+ * Copyright (C) 2005-2008
+ * Laurent Pinchart (laurent.pinchart@skynet.be)
+ *
+ * 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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/usb.h>
+#include <linux/videodev2.h>
+#include <linux/vmalloc.h>
+#include <linux/wait.h>
+#include <asm/atomic.h>
+
+#include "uvcvideo.h"
+
+#define UVC_CTRL_NDATA 2
+#define UVC_CTRL_DATA_CURRENT 0
+#define UVC_CTRL_DATA_BACKUP 1
+
+/* ------------------------------------------------------------------------
+ * Control, formats, ...
+ */
+
+static struct uvc_control_info uvc_ctrls[] = {
+ {
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = PU_BRIGHTNESS_CONTROL,
+ .index = 0,
+ .size = 2,
+ .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+ | UVC_CONTROL_RESTORE,
+ },
+ {
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = PU_CONTRAST_CONTROL,
+ .index = 1,
+ .size = 2,
+ .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+ | UVC_CONTROL_RESTORE,
+ },
+ {
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = PU_HUE_CONTROL,
+ .index = 2,
+ .size = 2,
+ .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+ | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE,
+ },
+ {
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = PU_SATURATION_CONTROL,
+ .index = 3,
+ .size = 2,
+ .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+ | UVC_CONTROL_RESTORE,
+ },
+ {
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = PU_SHARPNESS_CONTROL,
+ .index = 4,
+ .size = 2,
+ .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+ | UVC_CONTROL_RESTORE,
+ },
+ {
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = PU_GAMMA_CONTROL,
+ .index = 5,
+ .size = 2,
+ .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+ | UVC_CONTROL_RESTORE,
+ },
+ {
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = PU_BACKLIGHT_COMPENSATION_CONTROL,
+ .index = 8,
+ .size = 2,
+ .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+ | UVC_CONTROL_RESTORE,
+ },
+ {
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = PU_GAIN_CONTROL,
+ .index = 9,
+ .size = 2,
+ .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+ | UVC_CONTROL_RESTORE,
+ },
+ {
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = PU_POWER_LINE_FREQUENCY_CONTROL,
+ .index = 10,
+ .size = 1,
+ .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+ | UVC_CONTROL_RESTORE,
+ },
+ {
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = PU_HUE_AUTO_CONTROL,
+ .index = 11,
+ .size = 1,
+ .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
+ | UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE,
+ },
+ {
+ .entity = UVC_GUID_UVC_CAMERA,
+ .selector = CT_AE_MODE_CONTROL,
+ .index = 1,
+ .size = 1,
+ .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
+ | UVC_CONTROL_GET_DEF | UVC_CONTROL_GET_RES
+ | UVC_CONTROL_RESTORE,
+ },
+ {
+ .entity = UVC_GUID_UVC_CAMERA,
+ .selector = CT_AE_PRIORITY_CONTROL,
+ .index = 2,
+ .size = 1,
+ .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
+ | UVC_CONTROL_RESTORE,
+ },
+ {
+ .entity = UVC_GUID_UVC_CAMERA,
+ .selector = CT_EXPOSURE_TIME_ABSOLUTE_CONTROL,
+ .index = 3,
+ .size = 4,
+ .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+ | UVC_CONTROL_RESTORE,
+ },
+ {
+ .entity = UVC_GUID_UVC_CAMERA,
+ .selector = CT_FOCUS_ABSOLUTE_CONTROL,
+ .index = 5,
+ .size = 2,
+ .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+ | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE,
+ },
+ {
+ .entity = UVC_GUID_UVC_CAMERA,
+ .selector = CT_FOCUS_AUTO_CONTROL,
+ .index = 17,
+ .size = 1,
+ .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
+ | UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE,
+ },
+ {
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL,
+ .index = 12,
+ .size = 1,
+ .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
+ | UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE,
+ },
+ {
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = PU_WHITE_BALANCE_TEMPERATURE_CONTROL,
+ .index = 6,
+ .size = 2,
+ .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+ | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE,
+ },
+ {
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL,
+ .index = 13,
+ .size = 1,
+ .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
+ | UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE,
+ },
+ {
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = PU_WHITE_BALANCE_COMPONENT_CONTROL,
+ .index = 7,
+ .size = 4,
+ .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+ | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE,
+ },
+};
+
+static struct uvc_menu_info power_line_frequency_controls[] = {
+ { 0, "Disabled" },
+ { 1, "50 Hz" },
+ { 2, "60 Hz" },
+};
+
+static struct uvc_menu_info exposure_auto_controls[] = {
+ { 1, "Manual Mode" },
+ { 2, "Auto Mode" },
+ { 4, "Shutter Priority Mode" },
+ { 8, "Aperture Priority Mode" },
+};
+
+static struct uvc_control_mapping uvc_ctrl_mappings[] = {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .name = "Brightness",
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = PU_BRIGHTNESS_CONTROL,
+ .size = 16,
+ .offset = 0,
+ .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
+ .data_type = UVC_CTRL_DATA_TYPE_SIGNED,
+ },
+ {
+ .id = V4L2_CID_CONTRAST,
+ .name = "Contrast",
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = PU_CONTRAST_CONTROL,
+ .size = 16,
+ .offset = 0,
+ .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
+ .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED,
+ },
+ {
+ .id = V4L2_CID_HUE,
+ .name = "Hue",
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = PU_HUE_CONTROL,
+ .size = 16,
+ .offset = 0,
+ .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
+ .data_type = UVC_CTRL_DATA_TYPE_SIGNED,
+ },
+ {
+ .id = V4L2_CID_SATURATION,
+ .name = "Saturation",
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = PU_SATURATION_CONTROL,
+ .size = 16,
+ .offset = 0,
+ .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
+ .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED,
+ },
+ {
+ .id = V4L2_CID_SHARPNESS,
+ .name = "Sharpness",
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = PU_SHARPNESS_CONTROL,
+ .size = 16,
+ .offset = 0,
+ .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
+ .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED,
+ },
+ {
+ .id = V4L2_CID_GAMMA,
+ .name = "Gamma",
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = PU_GAMMA_CONTROL,
+ .size = 16,
+ .offset = 0,
+ .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
+ .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED,
+ },
+ {
+ .id = V4L2_CID_BACKLIGHT_COMPENSATION,
+ .name = "Backlight Compensation",
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = PU_BACKLIGHT_COMPENSATION_CONTROL,
+ .size = 16,
+ .offset = 0,
+ .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
+ .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED,
+ },
+ {
+ .id = V4L2_CID_GAIN,
+ .name = "Gain",
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = PU_GAIN_CONTROL,
+ .size = 16,
+ .offset = 0,
+ .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
+ .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED,
+ },
+ {
+ .id = V4L2_CID_POWER_LINE_FREQUENCY,
+ .name = "Power Line Frequency",
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = PU_POWER_LINE_FREQUENCY_CONTROL,
+ .size = 2,
+ .offset = 0,
+ .v4l2_type = V4L2_CTRL_TYPE_MENU,
+ .data_type = UVC_CTRL_DATA_TYPE_ENUM,
+ .menu_info = power_line_frequency_controls,
+ .menu_count = ARRAY_SIZE(power_line_frequency_controls),
+ },
+ {
+ .id = V4L2_CID_HUE_AUTO,
+ .name = "Hue, Auto",
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = PU_HUE_AUTO_CONTROL,
+ .size = 1,
+ .offset = 0,
+ .v4l2_type = V4L2_CTRL_TYPE_BOOLEAN,
+ .data_type = UVC_CTRL_DATA_TYPE_BOOLEAN,
+ },
+ {
+ .id = V4L2_CID_EXPOSURE_AUTO,
+ .name = "Exposure, Auto",
+ .entity = UVC_GUID_UVC_CAMERA,
+ .selector = CT_AE_MODE_CONTROL,
+ .size = 4,
+ .offset = 0,
+ .v4l2_type = V4L2_CTRL_TYPE_MENU,
+ .data_type = UVC_CTRL_DATA_TYPE_BITMASK,
+ .menu_info = exposure_auto_controls,
+ .menu_count = ARRAY_SIZE(exposure_auto_controls),
+ },
+ {
+ .id = V4L2_CID_EXPOSURE_AUTO_PRIORITY,
+ .name = "Exposure, Auto Priority",
+ .entity = UVC_GUID_UVC_CAMERA,
+ .selector = CT_AE_PRIORITY_CONTROL,
+ .size = 1,
+ .offset = 0,
+ .v4l2_type = V4L2_CTRL_TYPE_BOOLEAN,
+ .data_type = UVC_CTRL_DATA_TYPE_BOOLEAN,
+ },
+ {
+ .id = V4L2_CID_EXPOSURE_ABSOLUTE,
+ .name = "Exposure (Absolute)",
+ .entity = UVC_GUID_UVC_CAMERA,
+ .selector = CT_EXPOSURE_TIME_ABSOLUTE_CONTROL,
+ .size = 32,
+ .offset = 0,
+ .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
+ .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED,
+ },
+ {
+ .id = V4L2_CID_AUTO_WHITE_BALANCE,
+ .name = "White Balance Temperature, Auto",
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL,
+ .size = 1,
+ .offset = 0,
+ .v4l2_type = V4L2_CTRL_TYPE_BOOLEAN,
+ .data_type = UVC_CTRL_DATA_TYPE_BOOLEAN,
+ },
+ {
+ .id = V4L2_CID_WHITE_BALANCE_TEMPERATURE,
+ .name = "White Balance Temperature",
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = PU_WHITE_BALANCE_TEMPERATURE_CONTROL,
+ .size = 16,
+ .offset = 0,
+ .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
+ .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED,
+ },
+ {
+ .id = V4L2_CID_AUTO_WHITE_BALANCE,
+ .name = "White Balance Component, Auto",
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL,
+ .size = 1,
+ .offset = 0,
+ .v4l2_type = V4L2_CTRL_TYPE_BOOLEAN,
+ .data_type = UVC_CTRL_DATA_TYPE_BOOLEAN,
+ },
+ {
+ .id = V4L2_CID_BLUE_BALANCE,
+ .name = "White Balance Blue Component",
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = PU_WHITE_BALANCE_COMPONENT_CONTROL,
+ .size = 16,
+ .offset = 0,
+ .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
+ .data_type = UVC_CTRL_DATA_TYPE_SIGNED,
+ },
+ {
+ .id = V4L2_CID_RED_BALANCE,
+ .name = "White Balance Red Component",
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = PU_WHITE_BALANCE_COMPONENT_CONTROL,
+ .size = 16,
+ .offset = 16,
+ .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
+ .data_type = UVC_CTRL_DATA_TYPE_SIGNED,
+ },
+ {
+ .id = V4L2_CID_FOCUS_ABSOLUTE,
+ .name = "Focus (absolute)",
+ .entity = UVC_GUID_UVC_CAMERA,
+ .selector = CT_FOCUS_ABSOLUTE_CONTROL,
+ .size = 16,
+ .offset = 0,
+ .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
+ .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED,
+ },
+ {
+ .id = V4L2_CID_FOCUS_AUTO,
+ .name = "Focus, Auto",
+ .entity = UVC_GUID_UVC_CAMERA,
+ .selector = CT_FOCUS_AUTO_CONTROL,
+ .size = 1,
+ .offset = 0,
+ .v4l2_type = V4L2_CTRL_TYPE_BOOLEAN,
+ .data_type = UVC_CTRL_DATA_TYPE_BOOLEAN,
+ },
+};
+
+/* ------------------------------------------------------------------------
+ * Utility functions
+ */
+
+static inline __u8 *uvc_ctrl_data(struct uvc_control *ctrl, int id)
+{
+ return ctrl->data + id * ctrl->info->size;
+}
+
+static inline int uvc_get_bit(const __u8 *data, int bit)
+{
+ return (data[bit >> 3] >> (bit & 7)) & 1;
+}
+
+/* Extract the bit string specified by mapping->offset and mapping->size
+ * from the little-endian data stored at 'data' and return the result as
+ * a signed 32bit integer. Sign extension will be performed if the mapping
+ * references a signed data type.
+ */
+static __s32 uvc_get_le_value(const __u8 *data,
+ struct uvc_control_mapping *mapping)
+{
+ int bits = mapping->size;
+ int offset = mapping->offset;
+ __s32 value = 0;
+ __u8 mask;
+
+ data += offset / 8;
+ offset &= 7;
+ mask = ((1LL << bits) - 1) << offset;
+
+ for (; bits > 0; data++) {
+ __u8 byte = *data & mask;
+ value |= offset > 0 ? (byte >> offset) : (byte << (-offset));
+ bits -= 8 - (offset > 0 ? offset : 0);
+ offset -= 8;
+ mask = (1 << bits) - 1;
+ }
+
+ /* Sign-extend the value if needed */
+ if (mapping->data_type == UVC_CTRL_DATA_TYPE_SIGNED)
+ value |= -(value & (1 << (mapping->size - 1)));
+
+ return value;
+}
+
+/* Set the bit string specified by mapping->offset and mapping->size
+ * in the little-endian data stored at 'data' to the value 'value'.
+ */
+static void uvc_set_le_value(__s32 value, __u8 *data,
+ struct uvc_control_mapping *mapping)
+{
+ int bits = mapping->size;
+ int offset = mapping->offset;
+ __u8 mask;
+
+ data += offset / 8;
+ offset &= 7;
+
+ for (; bits > 0; data++) {
+ mask = ((1LL << bits) - 1) << offset;
+ *data = (*data & ~mask) | ((value << offset) & mask);
+ value >>= offset ? offset : 8;
+ bits -= 8 - offset;
+ offset = 0;
+ }
+}
+
+/* ------------------------------------------------------------------------
+ * Terminal and unit management
+ */
+
+static const __u8 uvc_processing_guid[16] = UVC_GUID_UVC_PROCESSING;
+static const __u8 uvc_camera_guid[16] = UVC_GUID_UVC_CAMERA;
+static const __u8 uvc_media_transport_input_guid[16] =
+ UVC_GUID_UVC_MEDIA_TRANSPORT_INPUT;
+
+static int uvc_entity_match_guid(struct uvc_entity *entity, __u8 guid[16])
+{
+ switch (UVC_ENTITY_TYPE(entity)) {
+ case ITT_CAMERA:
+ return memcmp(uvc_camera_guid, guid, 16) == 0;
+
+ case ITT_MEDIA_TRANSPORT_INPUT:
+ return memcmp(uvc_media_transport_input_guid, guid, 16) == 0;
+
+ case VC_PROCESSING_UNIT:
+ return memcmp(uvc_processing_guid, guid, 16) == 0;
+
+ case VC_EXTENSION_UNIT:
+ return memcmp(entity->extension.guidExtensionCode,
+ guid, 16) == 0;
+
+ default:
+ return 0;
+ }
+}
+
+/* ------------------------------------------------------------------------
+ * UVC Controls
+ */
+
+static void __uvc_find_control(struct uvc_entity *entity, __u32 v4l2_id,
+ struct uvc_control_mapping **mapping, struct uvc_control **control,
+ int next)
+{
+ struct uvc_control *ctrl;
+ struct uvc_control_mapping *map;
+ unsigned int i;
+
+ if (entity == NULL)
+ return;
+
+ for (i = 0; i < entity->ncontrols; ++i) {
+ ctrl = &entity->controls[i];
+ if (ctrl->info == NULL)
+ continue;
+
+ list_for_each_entry(map, &ctrl->info->mappings, list) {
+ if ((map->id == v4l2_id) && !next) {
+ *control = ctrl;
+ *mapping = map;
+ return;
+ }
+
+ if ((*mapping == NULL || (*mapping)->id > map->id) &&
+ (map->id > v4l2_id) && next) {
+ *control = ctrl;
+ *mapping = map;
+ }
+ }
+ }
+}
+
+struct uvc_control *uvc_find_control(struct uvc_video_device *video,
+ __u32 v4l2_id, struct uvc_control_mapping **mapping)
+{
+ struct uvc_control *ctrl = NULL;
+ struct uvc_entity *entity;
+ int next = v4l2_id & V4L2_CTRL_FLAG_NEXT_CTRL;
+
+ *mapping = NULL;
+
+ /* Mask the query flags. */
+ v4l2_id &= V4L2_CTRL_ID_MASK;
+
+ /* Find the control. */
+ __uvc_find_control(video->processing, v4l2_id, mapping, &ctrl, next);
+ if (ctrl && !next)
+ return ctrl;
+
+ list_for_each_entry(entity, &video->iterms, chain) {
+ __uvc_find_control(entity, v4l2_id, mapping, &ctrl, next);
+ if (ctrl && !next)
+ return ctrl;
+ }
+
+ list_for_each_entry(entity, &video->extensions, chain) {
+ __uvc_find_control(entity, v4l2_id, mapping, &ctrl, next);
+ if (ctrl && !next)
+ return ctrl;
+ }
+
+ if (ctrl == NULL && !next)
+ uvc_trace(UVC_TRACE_CONTROL, "Control 0x%08x not found.\n",
+ v4l2_id);
+
+ return ctrl;
+}
+
+int uvc_query_v4l2_ctrl(struct uvc_video_device *video,
+ struct v4l2_queryctrl *v4l2_ctrl)
+{
+ struct uvc_control *ctrl;
+ struct uvc_control_mapping *mapping;
+ struct uvc_menu_info *menu;
+ unsigned int i;
+ __u8 data[8];
+ int ret;
+
+ ctrl = uvc_find_control(video, v4l2_ctrl->id, &mapping);
+ if (ctrl == NULL)
+ return -EINVAL;
+
+ v4l2_ctrl->id = mapping->id;
+ v4l2_ctrl->type = mapping->v4l2_type;
+ strncpy(v4l2_ctrl->name, mapping->name, sizeof v4l2_ctrl->name);
+ v4l2_ctrl->flags = 0;
+
+ if (!(ctrl->info->flags & UVC_CONTROL_SET_CUR))
+ v4l2_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ if (ctrl->info->flags & UVC_CONTROL_GET_DEF) {
+ if ((ret = uvc_query_ctrl(video->dev, GET_DEF, ctrl->entity->id,
+ video->dev->intfnum, ctrl->info->selector,
+ &data, ctrl->info->size)) < 0)
+ return ret;
+ v4l2_ctrl->default_value = uvc_get_le_value(data, mapping);
+ }
+
+ if (mapping->v4l2_type == V4L2_CTRL_TYPE_MENU) {
+ v4l2_ctrl->minimum = 0;
+ v4l2_ctrl->maximum = mapping->menu_count - 1;
+ v4l2_ctrl->step = 1;
+
+ menu = mapping->menu_info;
+ for (i = 0; i < mapping->menu_count; ++i, ++menu) {
+ if (menu->value == v4l2_ctrl->default_value) {
+ v4l2_ctrl->default_value = i;
+ break;
+ }
+ }
+
+ return 0;
+ }
+
+ if (ctrl->info->flags & UVC_CONTROL_GET_MIN) {
+ if ((ret = uvc_query_ctrl(video->dev, GET_MIN, ctrl->entity->id,
+ video->dev->intfnum, ctrl->info->selector,
+ &data, ctrl->info->size)) < 0)
+ return ret;
+ v4l2_ctrl->minimum = uvc_get_le_value(data, mapping);
+ }
+ if (ctrl->info->flags & UVC_CONTROL_GET_MAX) {
+ if ((ret = uvc_query_ctrl(video->dev, GET_MAX, ctrl->entity->id,
+ video->dev->intfnum, ctrl->info->selector,
+ &data, ctrl->info->size)) < 0)
+ return ret;
+ v4l2_ctrl->maximum = uvc_get_le_value(data, mapping);
+ }
+ if (ctrl->info->flags & UVC_CONTROL_GET_RES) {
+ if ((ret = uvc_query_ctrl(video->dev, GET_RES, ctrl->entity->id,
+ video->dev->intfnum, ctrl->info->selector,
+ &data, ctrl->info->size)) < 0)
+ return ret;
+ v4l2_ctrl->step = uvc_get_le_value(data, mapping);
+ }
+
+ return 0;
+}
+
+
+/* --------------------------------------------------------------------------
+ * Control transactions
+ *
+ * To make extended set operations as atomic as the hardware allows, controls
+ * are handled using begin/commit/rollback operations.
+ *
+ * At the beginning of a set request, uvc_ctrl_begin should be called to
+ * initialize the request. This function acquires the control lock.
+ *
+ * When setting a control, the new value is stored in the control data field
+ * at position UVC_CTRL_DATA_CURRENT. The control is then marked as dirty for
+ * later processing. If the UVC and V4L2 control sizes differ, the current
+ * value is loaded from the hardware before storing the new value in the data
+ * field.
+ *
+ * After processing all controls in the transaction, uvc_ctrl_commit or
+ * uvc_ctrl_rollback must be called to apply the pending changes to the
+ * hardware or revert them. When applying changes, all controls marked as
+ * dirty will be modified in the UVC device, and the dirty flag will be
+ * cleared. When reverting controls, the control data field
+ * UVC_CTRL_DATA_CURRENT is reverted to its previous value
+ * (UVC_CTRL_DATA_BACKUP) for all dirty controls. Both functions release the
+ * control lock.
+ */
+int uvc_ctrl_begin(struct uvc_video_device *video)
+{
+ return mutex_lock_interruptible(&video->ctrl_mutex) ? -ERESTARTSYS : 0;
+}
+
+static int uvc_ctrl_commit_entity(struct uvc_device *dev,
+ struct uvc_entity *entity, int rollback)
+{
+ struct uvc_control *ctrl;
+ unsigned int i;
+ int ret;
+
+ if (entity == NULL)
+ return 0;
+
+ for (i = 0; i < entity->ncontrols; ++i) {
+ ctrl = &entity->controls[i];
+ if (ctrl->info == NULL || !ctrl->dirty)
+ continue;
+
+ if (!rollback)
+ ret = uvc_query_ctrl(dev, SET_CUR, ctrl->entity->id,
+ dev->intfnum, ctrl->info->selector,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
+ ctrl->info->size);
+ else
+ ret = 0;
+
+ if (rollback || ret < 0)
+ memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP),
+ ctrl->info->size);
+
+ if ((ctrl->info->flags & UVC_CONTROL_GET_CUR) == 0)
+ ctrl->loaded = 0;
+
+ ctrl->dirty = 0;
+
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+int __uvc_ctrl_commit(struct uvc_video_device *video, int rollback)
+{
+ struct uvc_entity *entity;
+ int ret = 0;
+
+ /* Find the control. */
+ ret = uvc_ctrl_commit_entity(video->dev, video->processing, rollback);
+ if (ret < 0)
+ goto done;
+
+ list_for_each_entry(entity, &video->iterms, chain) {
+ ret = uvc_ctrl_commit_entity(video->dev, entity, rollback);
+ if (ret < 0)
+ goto done;
+ }
+
+ list_for_each_entry(entity, &video->extensions, chain) {
+ ret = uvc_ctrl_commit_entity(video->dev, entity, rollback);
+ if (ret < 0)
+ goto done;
+ }
+
+done:
+ mutex_unlock(&video->ctrl_mutex);
+ return ret;
+}
+
+int uvc_ctrl_get(struct uvc_video_device *video,
+ struct v4l2_ext_control *xctrl)
+{
+ struct uvc_control *ctrl;
+ struct uvc_control_mapping *mapping;
+ struct uvc_menu_info *menu;
+ unsigned int i;
+ int ret;
+
+ ctrl = uvc_find_control(video, xctrl->id, &mapping);
+ if (ctrl == NULL || (ctrl->info->flags & UVC_CONTROL_GET_CUR) == 0)
+ return -EINVAL;
+
+ if (!ctrl->loaded) {
+ ret = uvc_query_ctrl(video->dev, GET_CUR, ctrl->entity->id,
+ video->dev->intfnum, ctrl->info->selector,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
+ ctrl->info->size);
+ if (ret < 0)
+ return ret;
+
+ if ((ctrl->info->flags & UVC_CONTROL_AUTO_UPDATE) == 0)
+ ctrl->loaded = 1;
+ }
+
+ xctrl->value = uvc_get_le_value(
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), mapping);
+
+ if (mapping->v4l2_type == V4L2_CTRL_TYPE_MENU) {
+ menu = mapping->menu_info;
+ for (i = 0; i < mapping->menu_count; ++i, ++menu) {
+ if (menu->value == xctrl->value) {
+ xctrl->value = i;
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+int uvc_ctrl_set(struct uvc_video_device *video,
+ struct v4l2_ext_control *xctrl)
+{
+ struct uvc_control *ctrl;
+ struct uvc_control_mapping *mapping;
+ s32 value = xctrl->value;
+ int ret;
+
+ ctrl = uvc_find_control(video, xctrl->id, &mapping);
+ if (ctrl == NULL || (ctrl->info->flags & UVC_CONTROL_SET_CUR) == 0)
+ return -EINVAL;
+
+ if (mapping->v4l2_type == V4L2_CTRL_TYPE_MENU) {
+ if (value < 0 || value >= mapping->menu_count)
+ return -EINVAL;
+ value = mapping->menu_info[value].value;
+ }
+
+ if (!ctrl->loaded && (ctrl->info->size * 8) != mapping->size) {
+ if ((ctrl->info->flags & UVC_CONTROL_GET_CUR) == 0) {
+ memset(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
+ 0, ctrl->info->size);
+ } else {
+ ret = uvc_query_ctrl(video->dev, GET_CUR,
+ ctrl->entity->id, video->dev->intfnum,
+ ctrl->info->selector,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
+ ctrl->info->size);
+ if (ret < 0)
+ return ret;
+ }
+
+ if ((ctrl->info->flags & UVC_CONTROL_AUTO_UPDATE) == 0)
+ ctrl->loaded = 1;
+ }
+
+ if (!ctrl->dirty) {
+ memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP),
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
+ ctrl->info->size);
+ }
+
+ uvc_set_le_value(value,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), mapping);
+
+ ctrl->dirty = 1;
+ ctrl->modified = 1;
+ return 0;
+}
+
+/* --------------------------------------------------------------------------
+ * Dynamic controls
+ */
+
+int uvc_xu_ctrl_query(struct uvc_video_device *video,
+ struct uvc_xu_control *xctrl, int set)
+{
+ struct uvc_entity *entity;
+ struct uvc_control *ctrl = NULL;
+ unsigned int i, found = 0;
+ __u8 *data;
+ int ret;
+
+ /* Find the extension unit. */
+ list_for_each_entry(entity, &video->extensions, chain) {
+ if (entity->id == xctrl->unit)
+ break;
+ }
+
+ if (entity->id != xctrl->unit) {
+ uvc_trace(UVC_TRACE_CONTROL, "Extension unit %u not found.\n",
+ xctrl->unit);
+ return -EINVAL;
+ }
+
+ /* Find the control. */
+ for (i = 0; i < entity->ncontrols; ++i) {
+ ctrl = &entity->controls[i];
+ if (ctrl->info == NULL)
+ continue;
+
+ if (ctrl->info->selector == xctrl->selector) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ uvc_trace(UVC_TRACE_CONTROL,
+ "Control " UVC_GUID_FORMAT "/%u not found.\n",
+ UVC_GUID_ARGS(entity->extension.guidExtensionCode),
+ xctrl->selector);
+ return -EINVAL;
+ }
+
+ /* Validate control data size. */
+ if (ctrl->info->size != xctrl->size)
+ return -EINVAL;
+
+ if ((set && !(ctrl->info->flags & UVC_CONTROL_SET_CUR)) ||
+ (!set && !(ctrl->info->flags & UVC_CONTROL_GET_CUR)))
+ return -EINVAL;
+
+ if (mutex_lock_interruptible(&video->ctrl_mutex))
+ return -ERESTARTSYS;
+
+ memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP),
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
+ xctrl->size);
+ data = uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT);
+
+ if (set && copy_from_user(data, xctrl->data, xctrl->size)) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ ret = uvc_query_ctrl(video->dev, set ? SET_CUR : GET_CUR, xctrl->unit,
+ video->dev->intfnum, xctrl->selector, data,
+ xctrl->size);
+ if (ret < 0)
+ goto out;
+
+ if (!set && copy_to_user(xctrl->data, data, xctrl->size)) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+out:
+ if (ret)
+ memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP),
+ xctrl->size);
+
+ mutex_unlock(&video->ctrl_mutex);
+ return ret;
+}
+
+/* --------------------------------------------------------------------------
+ * Suspend/resume
+ */
+
+/*
+ * Restore control values after resume, skipping controls that haven't been
+ * changed.
+ *
+ * TODO
+ * - Don't restore modified controls that are back to their default value.
+ * - Handle restore order (Auto-Exposure Mode should be restored before
+ * Exposure Time).
+ */
+int uvc_ctrl_resume_device(struct uvc_device *dev)
+{
+ struct uvc_control *ctrl;
+ struct uvc_entity *entity;
+ unsigned int i;
+ int ret;
+
+ /* Walk the entities list and restore controls when possible. */
+ list_for_each_entry(entity, &dev->entities, list) {
+
+ for (i = 0; i < entity->ncontrols; ++i) {
+ ctrl = &entity->controls[i];
+
+ if (ctrl->info == NULL || !ctrl->modified ||
+ (ctrl->info->flags & UVC_CONTROL_RESTORE) == 0)
+ continue;
+
+ printk(KERN_INFO "restoring control " UVC_GUID_FORMAT
+ "/%u/%u\n", UVC_GUID_ARGS(ctrl->info->entity),
+ ctrl->info->index, ctrl->info->selector);
+ ctrl->dirty = 1;
+ }
+
+ ret = uvc_ctrl_commit_entity(dev, entity, 0);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+/* --------------------------------------------------------------------------
+ * Control and mapping handling
+ */
+
+static void uvc_ctrl_add_ctrl(struct uvc_device *dev,
+ struct uvc_control_info *info)
+{
+ struct uvc_entity *entity;
+ struct uvc_control *ctrl = NULL;
+ int ret, found = 0;
+ unsigned int i;
+
+ list_for_each_entry(entity, &dev->entities, list) {
+ if (!uvc_entity_match_guid(entity, info->entity))
+ continue;
+
+ for (i = 0; i < entity->ncontrols; ++i) {
+ ctrl = &entity->controls[i];
+ if (ctrl->index == info->index) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (found)
+ break;
+ }
+
+ if (!found)
+ return;
+
+ if (UVC_ENTITY_TYPE(entity) == VC_EXTENSION_UNIT) {
+ /* Check if the device control information and length match
+ * the user supplied information.
+ */
+ __u32 flags;
+ __le16 size;
+ __u8 inf;
+
+ if ((ret = uvc_query_ctrl(dev, GET_LEN, ctrl->entity->id,
+ dev->intfnum, info->selector, (__u8 *)&size, 2)) < 0) {
+ uvc_trace(UVC_TRACE_CONTROL, "GET_LEN failed on "
+ "control " UVC_GUID_FORMAT "/%u (%d).\n",
+ UVC_GUID_ARGS(info->entity), info->selector,
+ ret);
+ return;
+ }
+
+ if (info->size != le16_to_cpu(size)) {
+ uvc_trace(UVC_TRACE_CONTROL, "Control " UVC_GUID_FORMAT
+ "/%u size doesn't match user supplied "
+ "value.\n", UVC_GUID_ARGS(info->entity),
+ info->selector);
+ return;
+ }
+
+ if ((ret = uvc_query_ctrl(dev, GET_INFO, ctrl->entity->id,
+ dev->intfnum, info->selector, &inf, 1)) < 0) {
+ uvc_trace(UVC_TRACE_CONTROL, "GET_INFO failed on "
+ "control " UVC_GUID_FORMAT "/%u (%d).\n",
+ UVC_GUID_ARGS(info->entity), info->selector,
+ ret);
+ return;
+ }
+
+ flags = info->flags;
+ if (((flags & UVC_CONTROL_GET_CUR) && !(inf & (1 << 0))) ||
+ ((flags & UVC_CONTROL_SET_CUR) && !(inf & (1 << 1)))) {
+ uvc_trace(UVC_TRACE_CONTROL, "Control "
+ UVC_GUID_FORMAT "/%u flags don't match "
+ "supported operations.\n",
+ UVC_GUID_ARGS(info->entity), info->selector);
+ return;
+ }
+ }
+
+ ctrl->info = info;
+ ctrl->data = kmalloc(ctrl->info->size * UVC_CTRL_NDATA, GFP_KERNEL);
+ uvc_trace(UVC_TRACE_CONTROL, "Added control " UVC_GUID_FORMAT "/%u "
+ "to device %s entity %u\n", UVC_GUID_ARGS(ctrl->info->entity),
+ ctrl->info->selector, dev->udev->devpath, entity->id);
+}
+
+/*
+ * Add an item to the UVC control information list, and instantiate a control
+ * structure for each device that supports the control.
+ */
+int uvc_ctrl_add_info(struct uvc_control_info *info)
+{
+ struct uvc_control_info *ctrl;
+ struct uvc_device *dev;
+ int ret = 0;
+
+ /* Find matching controls by walking the devices, entities and
+ * controls list.
+ */
+ mutex_lock(&uvc_driver.ctrl_mutex);
+
+ /* First check if the list contains a control matching the new one.
+ * Bail out if it does.
+ */
+ list_for_each_entry(ctrl, &uvc_driver.controls, list) {
+ if (memcmp(ctrl->entity, info->entity, 16))
+ continue;
+
+ if (ctrl->selector == info->selector) {
+ uvc_trace(UVC_TRACE_CONTROL, "Control "
+ UVC_GUID_FORMAT "/%u is already defined.\n",
+ UVC_GUID_ARGS(info->entity), info->selector);
+ ret = -EEXIST;
+ goto end;
+ }
+ if (ctrl->index == info->index) {
+ uvc_trace(UVC_TRACE_CONTROL, "Control "
+ UVC_GUID_FORMAT "/%u would overwrite index "
+ "%d.\n", UVC_GUID_ARGS(info->entity),
+ info->selector, info->index);
+ ret = -EEXIST;
+ goto end;
+ }
+ }
+
+ list_for_each_entry(dev, &uvc_driver.devices, list)
+ uvc_ctrl_add_ctrl(dev, info);
+
+ INIT_LIST_HEAD(&info->mappings);
+ list_add_tail(&info->list, &uvc_driver.controls);
+end:
+ mutex_unlock(&uvc_driver.ctrl_mutex);
+ return ret;
+}
+
+int uvc_ctrl_add_mapping(struct uvc_control_mapping *mapping)
+{
+ struct uvc_control_info *info;
+ struct uvc_control_mapping *map;
+ int ret = -EINVAL;
+
+ if (mapping->id & ~V4L2_CTRL_ID_MASK) {
+ uvc_trace(UVC_TRACE_CONTROL, "Can't add mapping '%s' with "
+ "invalid control id 0x%08x\n", mapping->name,
+ mapping->id);
+ return -EINVAL;
+ }
+
+ mutex_lock(&uvc_driver.ctrl_mutex);
+ list_for_each_entry(info, &uvc_driver.controls, list) {
+ if (memcmp(info->entity, mapping->entity, 16) ||
+ info->selector != mapping->selector)
+ continue;
+
+ if (info->size * 8 < mapping->size + mapping->offset) {
+ uvc_trace(UVC_TRACE_CONTROL, "Mapping '%s' would "
+ "overflow control " UVC_GUID_FORMAT "/%u\n",
+ mapping->name, UVC_GUID_ARGS(info->entity),
+ info->selector);
+ ret = -EOVERFLOW;
+ goto end;
+ }
+
+ /* Check if the list contains a mapping matching the new one.
+ * Bail out if it does.
+ */
+ list_for_each_entry(map, &info->mappings, list) {
+ if (map->id == mapping->id) {
+ uvc_trace(UVC_TRACE_CONTROL, "Mapping '%s' is "
+ "already defined.\n", mapping->name);
+ ret = -EEXIST;
+ goto end;
+ }
+ }
+
+ mapping->ctrl = info;
+ list_add_tail(&mapping->list, &info->mappings);
+ uvc_trace(UVC_TRACE_CONTROL, "Adding mapping %s to control "
+ UVC_GUID_FORMAT "/%u.\n", mapping->name,
+ UVC_GUID_ARGS(info->entity), info->selector);
+
+ ret = 0;
+ break;
+ }
+end:
+ mutex_unlock(&uvc_driver.ctrl_mutex);
+ return ret;
+}
+
+/*
+ * Initialize device controls.
+ */
+int uvc_ctrl_init_device(struct uvc_device *dev)
+{
+ struct uvc_control_info *info;
+ struct uvc_control *ctrl;
+ struct uvc_entity *entity;
+ unsigned int i;
+
+ /* Walk the entities list and instantiate controls */
+ list_for_each_entry(entity, &dev->entities, list) {
+ unsigned int bControlSize = 0, ncontrols = 0;
+ __u8 *bmControls = NULL;
+
+ if (UVC_ENTITY_TYPE(entity) == VC_EXTENSION_UNIT) {
+ bmControls = entity->extension.bmControls;
+ bControlSize = entity->extension.bControlSize;
+ } else if (UVC_ENTITY_TYPE(entity) == VC_PROCESSING_UNIT) {
+ bmControls = entity->processing.bmControls;
+ bControlSize = entity->processing.bControlSize;
+ } else if (UVC_ENTITY_TYPE(entity) == ITT_CAMERA) {
+ bmControls = entity->camera.bmControls;
+ bControlSize = entity->camera.bControlSize;
+ }
+
+ for (i = 0; i < bControlSize; ++i)
+ ncontrols += hweight8(bmControls[i]);
+
+ if (ncontrols == 0)
+ continue;
+
+ entity->controls = kzalloc(ncontrols*sizeof *ctrl, GFP_KERNEL);
+ if (entity->controls == NULL)
+ return -ENOMEM;
+
+ entity->ncontrols = ncontrols;
+
+ ctrl = entity->controls;
+ for (i = 0; i < bControlSize * 8; ++i) {
+ if (uvc_get_bit(bmControls, i) == 0)
+ continue;
+
+ ctrl->entity = entity;
+ ctrl->index = i;
+ ctrl++;
+ }
+ }
+
+ /* Walk the controls info list and associate them with the device
+ * controls, then add the device to the global device list. This has
+ * to be done while holding the controls lock, to make sure
+ * uvc_ctrl_add_info() will not get called in-between.
+ */
+ mutex_lock(&uvc_driver.ctrl_mutex);
+ list_for_each_entry(info, &uvc_driver.controls, list)
+ uvc_ctrl_add_ctrl(dev, info);
+
+ list_add_tail(&dev->list, &uvc_driver.devices);
+ mutex_unlock(&uvc_driver.ctrl_mutex);
+
+ return 0;
+}
+
+/*
+ * Cleanup device controls.
+ */
+void uvc_ctrl_cleanup_device(struct uvc_device *dev)
+{
+ struct uvc_entity *entity;
+ unsigned int i;
+
+ /* Remove the device from the global devices list */
+ mutex_lock(&uvc_driver.ctrl_mutex);
+ if (dev->list.next != NULL)
+ list_del(&dev->list);
+ mutex_unlock(&uvc_driver.ctrl_mutex);
+
+ list_for_each_entry(entity, &dev->entities, list) {
+ for (i = 0; i < entity->ncontrols; ++i)
+ kfree(entity->controls[i].data);
+
+ kfree(entity->controls);
+ }
+}
+
+void uvc_ctrl_init(void)
+{
+ struct uvc_control_info *ctrl = uvc_ctrls;
+ struct uvc_control_info *cend = ctrl + ARRAY_SIZE(uvc_ctrls);
+ struct uvc_control_mapping *mapping = uvc_ctrl_mappings;
+ struct uvc_control_mapping *mend =
+ mapping + ARRAY_SIZE(uvc_ctrl_mappings);
+
+ for (; ctrl < cend; ++ctrl)
+ uvc_ctrl_add_info(ctrl);
+
+ for (; mapping < mend; ++mapping)
+ uvc_ctrl_add_mapping(mapping);
+}
+
diff --git a/linux/drivers/media/video/uvc/uvc_driver.c b/linux/drivers/media/video/uvc/uvc_driver.c
new file mode 100644
index 000000000..2c0b16960
--- /dev/null
+++ b/linux/drivers/media/video/uvc/uvc_driver.c
@@ -0,0 +1,1966 @@
+/*
+ * uvc_driver.c -- USB Video Class driver
+ *
+ * Copyright (C) 2005-2008
+ * Laurent Pinchart (laurent.pinchart@skynet.be)
+ *
+ * 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 driver aims to support video input devices compliant with the 'USB
+ * Video Class' specification.
+ *
+ * The driver doesn't support the deprecated v4l1 interface. It implements the
+ * mmap capture method only, and doesn't do any image format conversion in
+ * software. If your user-space application doesn't support YUYV or MJPEG, fix
+ * it :-). Please note that the MJPEG data have been stripped from their
+ * Huffman tables (DHT marker), you will need to add it back if your JPEG
+ * codec can't handle MJPEG data.
+ */
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/videodev2.h>
+#include <linux/vmalloc.h>
+#include <linux/wait.h>
+#include <asm/atomic.h>
+
+#include <media/v4l2-common.h>
+
+#include "uvcvideo.h"
+
+#define DRIVER_AUTHOR "Laurent Pinchart <laurent.pinchart@skynet.be>"
+#define DRIVER_DESC "USB Video Class driver"
+#ifndef DRIVER_VERSION
+#define DRIVER_VERSION "v0.1.0"
+#endif
+
+static unsigned int uvc_quirks_param;
+unsigned int uvc_trace_param;
+
+/* ------------------------------------------------------------------------
+ * Control, formats, ...
+ */
+
+static struct uvc_format_desc uvc_fmts[] = {
+ {
+ .name = "YUV 4:2:2 (YUYV)",
+ .guid = UVC_GUID_FORMAT_YUY2,
+ .fcc = V4L2_PIX_FMT_YUYV,
+ },
+ {
+ .name = "YUV 4:2:0 (NV12)",
+ .guid = UVC_GUID_FORMAT_NV12,
+ .fcc = V4L2_PIX_FMT_NV12,
+ },
+ {
+ .name = "MJPEG",
+ .guid = UVC_GUID_FORMAT_MJPEG,
+ .fcc = V4L2_PIX_FMT_MJPEG,
+ },
+ {
+ .name = "YVU 4:2:0 (YV12)",
+ .guid = UVC_GUID_FORMAT_YV12,
+ .fcc = V4L2_PIX_FMT_YVU420,
+ },
+ {
+ .name = "YUV 4:2:0 (I420)",
+ .guid = UVC_GUID_FORMAT_I420,
+ .fcc = V4L2_PIX_FMT_YUV420,
+ },
+ {
+ .name = "YUV 4:2:2 (UYVY)",
+ .guid = UVC_GUID_FORMAT_UYVY,
+ .fcc = V4L2_PIX_FMT_UYVY,
+ },
+ {
+ .name = "Greyscale",
+ .guid = UVC_GUID_FORMAT_Y800,
+ .fcc = V4L2_PIX_FMT_GREY,
+ },
+ {
+ .name = "RGB Bayer",
+ .guid = UVC_GUID_FORMAT_BY8,
+ .fcc = V4L2_PIX_FMT_SBGGR8,
+ },
+};
+
+/* ------------------------------------------------------------------------
+ * Utility functions
+ */
+
+struct usb_host_endpoint *uvc_find_endpoint(struct usb_host_interface *alts,
+ __u8 epaddr)
+{
+ struct usb_host_endpoint *ep;
+ unsigned int i;
+
+ for (i = 0; i < alts->desc.bNumEndpoints; ++i) {
+ ep = &alts->endpoint[i];
+ if (ep->desc.bEndpointAddress == epaddr)
+ return ep;
+ }
+
+ return NULL;
+}
+
+static struct uvc_format_desc *uvc_format_by_guid(const __u8 guid[16])
+{
+ unsigned int len = ARRAY_SIZE(uvc_fmts);
+ unsigned int i;
+
+ for (i = 0; i < len; ++i) {
+ if (memcmp(guid, uvc_fmts[i].guid, 16) == 0)
+ return &uvc_fmts[i];
+ }
+
+ return NULL;
+}
+
+static __u32 uvc_colorspace(const __u8 primaries)
+{
+ static const __u8 colorprimaries[] = {
+ 0,
+ V4L2_COLORSPACE_SRGB,
+ V4L2_COLORSPACE_470_SYSTEM_M,
+ V4L2_COLORSPACE_470_SYSTEM_BG,
+ V4L2_COLORSPACE_SMPTE170M,
+ V4L2_COLORSPACE_SMPTE240M,
+ };
+
+ if (primaries < ARRAY_SIZE(colorprimaries))
+ return colorprimaries[primaries];
+
+ return 0;
+}
+
+/* Simplify a fraction using a simple continued fraction decomposition. The
+ * idea here is to convert fractions such as 333333/10000000 to 1/30 using
+ * 32 bit arithmetic only. The algorithm is not perfect and relies upon two
+ * arbitrary parameters to remove non-significative terms from the simple
+ * continued fraction decomposition. Using 8 and 333 for n_terms and threshold
+ * respectively seems to give nice results.
+ */
+void uvc_simplify_fraction(uint32_t *numerator, uint32_t *denominator,
+ unsigned int n_terms, unsigned int threshold)
+{
+ uint32_t *an;
+ uint32_t x, y, r;
+ unsigned int i, n;
+
+ an = kmalloc(n_terms * sizeof *an, GFP_KERNEL);
+ if (an == NULL)
+ return;
+
+ /* Convert the fraction to a simple continued fraction. See
+ * http://mathforum.org/dr.math/faq/faq.fractions.html
+ * Stop if the current term is bigger than or equal to the given
+ * threshold.
+ */
+ x = *numerator;
+ y = *denominator;
+
+ for (n = 0; n < n_terms && y != 0; ++n) {
+ an[n] = x / y;
+ if (an[n] >= threshold) {
+ if (n < 2)
+ n++;
+ break;
+ }
+
+ r = x - an[n] * y;
+ x = y;
+ y = r;
+ }
+
+ /* Expand the simple continued fraction back to an integer fraction. */
+ x = 0;
+ y = 1;
+
+ for (i = n; i > 0; --i) {
+ r = y;
+ y = an[i-1] * y + x;
+ x = r;
+ }
+
+ *numerator = y;
+ *denominator = x;
+ kfree(an);
+}
+
+/* Convert a fraction to a frame interval in 100ns multiples. The idea here is
+ * to compute numerator / denominator * 10000000 using 32 bit fixed point
+ * arithmetic only.
+ */
+uint32_t uvc_fraction_to_interval(uint32_t numerator, uint32_t denominator)
+{
+ uint32_t multiplier;
+
+ /* Saturate the result if the operation would overflow. */
+ if (denominator == 0 ||
+ numerator/denominator >= ((uint32_t)-1)/10000000)
+ return (uint32_t)-1;
+
+ /* Divide both the denominator and the multiplier by two until
+ * numerator * multiplier doesn't overflow. If anyone knows a better
+ * algorithm please let me know.
+ */
+ multiplier = 10000000;
+ while (numerator > ((uint32_t)-1)/multiplier) {
+ multiplier /= 2;
+ denominator /= 2;
+ }
+
+ return denominator ? numerator * multiplier / denominator : 0;
+}
+
+/* ------------------------------------------------------------------------
+ * Terminal and unit management
+ */
+
+static struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id)
+{
+ struct uvc_entity *entity;
+
+ list_for_each_entry(entity, &dev->entities, list) {
+ if (entity->id == id)
+ return entity;
+ }
+
+ return NULL;
+}
+
+static struct uvc_entity *uvc_entity_by_reference(struct uvc_device *dev,
+ int id, struct uvc_entity *entity)
+{
+ unsigned int i;
+
+ if (entity == NULL)
+ entity = list_entry(&dev->entities, struct uvc_entity, list);
+
+ list_for_each_entry_continue(entity, &dev->entities, list) {
+ switch (UVC_ENTITY_TYPE(entity)) {
+ case TT_STREAMING:
+ if (entity->output.bSourceID == id)
+ return entity;
+ break;
+
+ case VC_PROCESSING_UNIT:
+ if (entity->processing.bSourceID == id)
+ return entity;
+ break;
+
+ case VC_SELECTOR_UNIT:
+ for (i = 0; i < entity->selector.bNrInPins; ++i)
+ if (entity->selector.baSourceID[i] == id)
+ return entity;
+ break;
+
+ case VC_EXTENSION_UNIT:
+ for (i = 0; i < entity->extension.bNrInPins; ++i)
+ if (entity->extension.baSourceID[i] == id)
+ return entity;
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+/* ------------------------------------------------------------------------
+ * Descriptors handling
+ */
+
+static int uvc_parse_format(struct uvc_device *dev,
+ struct uvc_streaming *streaming, struct uvc_format *format,
+ __u32 **intervals, unsigned char *buffer, int buflen)
+{
+ struct usb_interface *intf = streaming->intf;
+ struct usb_host_interface *alts = intf->cur_altsetting;
+ struct uvc_format_desc *fmtdesc;
+ struct uvc_frame *frame;
+ const unsigned char *start = buffer;
+ unsigned int interval;
+ unsigned int i, n;
+ __u8 ftype;
+
+ format->type = buffer[2];
+ format->index = buffer[3];
+
+ switch (buffer[2]) {
+ case VS_FORMAT_UNCOMPRESSED:
+ case VS_FORMAT_FRAME_BASED:
+ n = buffer[2] == VS_FORMAT_UNCOMPRESSED ? 27 : 28;
+ if (buflen < n) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+ "interface %d FORMAT error\n",
+ dev->udev->devnum,
+ alts->desc.bInterfaceNumber);
+ return -EINVAL;
+ }
+
+ /* Find the format descriptor from its GUID. */
+ fmtdesc = uvc_format_by_guid(&buffer[5]);
+
+ if (fmtdesc != NULL) {
+ strncpy(format->name, fmtdesc->name,
+ sizeof format->name);
+ format->fcc = fmtdesc->fcc;
+ } else {
+ uvc_printk(KERN_INFO, "Unknown video format "
+ UVC_GUID_FORMAT "\n",
+ UVC_GUID_ARGS(&buffer[5]));
+ snprintf(format->name, sizeof format->name,
+ UVC_GUID_FORMAT, UVC_GUID_ARGS(&buffer[5]));
+ format->fcc = 0;
+ }
+
+ format->bpp = buffer[21];
+ if (buffer[2] == VS_FORMAT_UNCOMPRESSED) {
+ ftype = VS_FRAME_UNCOMPRESSED;
+ } else {
+ ftype = VS_FRAME_FRAME_BASED;
+ if (buffer[27])
+ format->flags = UVC_FMT_FLAG_COMPRESSED;
+ }
+ break;
+
+ case VS_FORMAT_MJPEG:
+ if (buflen < 11) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+ "interface %d FORMAT error\n",
+ dev->udev->devnum,
+ alts->desc.bInterfaceNumber);
+ return -EINVAL;
+ }
+
+ strncpy(format->name, "MJPEG", sizeof format->name);
+ format->fcc = V4L2_PIX_FMT_MJPEG;
+ format->flags = UVC_FMT_FLAG_COMPRESSED;
+ format->bpp = 0;
+ ftype = VS_FRAME_MJPEG;
+ break;
+
+ case VS_FORMAT_DV:
+ if (buflen < 9) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+ "interface %d FORMAT error\n",
+ dev->udev->devnum,
+ alts->desc.bInterfaceNumber);
+ return -EINVAL;
+ }
+
+ switch (buffer[8] & 0x7f) {
+ case 0:
+ strncpy(format->name, "SD-DV", sizeof format->name);
+ break;
+ case 1:
+ strncpy(format->name, "SDL-DV", sizeof format->name);
+ break;
+ case 2:
+ strncpy(format->name, "HD-DV", sizeof format->name);
+ break;
+ default:
+ uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+ "interface %d: unknown DV format %u\n",
+ dev->udev->devnum,
+ alts->desc.bInterfaceNumber, buffer[8]);
+ return -EINVAL;
+ }
+
+ strncat(format->name, buffer[8] & (1 << 7) ? " 60Hz" : " 50Hz",
+ sizeof format->name);
+
+ format->fcc = V4L2_PIX_FMT_DV;
+ format->flags = UVC_FMT_FLAG_COMPRESSED | UVC_FMT_FLAG_STREAM;
+ format->bpp = 0;
+ ftype = 0;
+
+ /* Create a dummy frame descriptor. */
+ frame = &format->frame[0];
+ memset(&format->frame[0], 0, sizeof format->frame[0]);
+ frame->bFrameIntervalType = 1;
+ frame->dwDefaultFrameInterval = 1;
+ frame->dwFrameInterval = *intervals;
+ *(*intervals)++ = 1;
+ format->nframes = 1;
+ break;
+
+ case VS_FORMAT_MPEG2TS:
+ case VS_FORMAT_STREAM_BASED:
+ /* Not supported yet. */
+ default:
+ uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+ "interface %d unsupported format %u\n",
+ dev->udev->devnum, alts->desc.bInterfaceNumber,
+ buffer[2]);
+ return -EINVAL;
+ }
+
+ uvc_trace(UVC_TRACE_DESCR, "Found format %s.\n", format->name);
+
+ buflen -= buffer[0];
+ buffer += buffer[0];
+
+ /* Parse the frame descriptors. Only uncompressed, MJPEG and frame
+ * based formats have frame descriptors.
+ */
+ while (buflen > 2 && buffer[2] == ftype) {
+ frame = &format->frame[format->nframes];
+
+ if (ftype != VS_FRAME_FRAME_BASED)
+ n = buflen > 25 ? buffer[25] : 0;
+ else
+ n = buflen > 21 ? buffer[21] : 0;
+
+ n = n ? n : 3;
+
+ if (buflen < 26 + 4*n) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+ "interface %d FRAME error\n", dev->udev->devnum,
+ alts->desc.bInterfaceNumber);
+ return -EINVAL;
+ }
+
+ frame->bFrameIndex = buffer[3];
+ frame->bmCapabilities = buffer[4];
+ frame->wWidth = le16_to_cpup((__le16 *)&buffer[5]);
+ frame->wHeight = le16_to_cpup((__le16 *)&buffer[7]);
+ frame->dwMinBitRate = le32_to_cpup((__le32 *)&buffer[9]);
+ frame->dwMaxBitRate = le32_to_cpup((__le32 *)&buffer[13]);
+ if (ftype != VS_FRAME_FRAME_BASED) {
+ frame->dwMaxVideoFrameBufferSize =
+ le32_to_cpup((__le32 *)&buffer[17]);
+ frame->dwDefaultFrameInterval =
+ le32_to_cpup((__le32 *)&buffer[21]);
+ frame->bFrameIntervalType = buffer[25];
+ } else {
+ frame->dwMaxVideoFrameBufferSize = 0;
+ frame->dwDefaultFrameInterval =
+ le32_to_cpup((__le32 *)&buffer[17]);
+ frame->bFrameIntervalType = buffer[21];
+ }
+ frame->dwFrameInterval = *intervals;
+
+ /* Several UVC chipsets screw up dwMaxVideoFrameBufferSize
+ * completely. Observed behaviours range from setting the
+ * value to 1.1x the actual frame size of hardwiring the
+ * 16 low bits to 0. This results in a higher than necessary
+ * memory usage as well as a wrong image size information. For
+ * uncompressed formats this can be fixed by computing the
+ * value from the frame size.
+ */
+ if (!(format->flags & UVC_FMT_FLAG_COMPRESSED))
+ frame->dwMaxVideoFrameBufferSize = format->bpp
+ * frame->wWidth * frame->wHeight / 8;
+
+ /* Some bogus devices report dwMinFrameInterval equal to
+ * dwMaxFrameInterval and have dwFrameIntervalStep set to
+ * zero. Setting all null intervals to 1 fixes the problem and
+ * some other divisions by zero which could happen.
+ */
+ for (i = 0; i < n; ++i) {
+ interval = le32_to_cpup((__le32 *)&buffer[26+4*i]);
+ *(*intervals)++ = interval ? interval : 1;
+ }
+
+ /* Make sure that the default frame interval stays between
+ * the boundaries.
+ */
+ n -= frame->bFrameIntervalType ? 1 : 2;
+ frame->dwDefaultFrameInterval =
+ min(frame->dwFrameInterval[n],
+ max(frame->dwFrameInterval[0],
+ frame->dwDefaultFrameInterval));
+
+ uvc_trace(UVC_TRACE_DESCR, "- %ux%u (%u.%u fps)\n",
+ frame->wWidth, frame->wHeight,
+ 10000000/frame->dwDefaultFrameInterval,
+ (100000000/frame->dwDefaultFrameInterval)%10);
+
+ format->nframes++;
+ buflen -= buffer[0];
+ buffer += buffer[0];
+ }
+
+ if (buflen > 2 && buffer[2] == VS_STILL_IMAGE_FRAME) {
+ buflen -= buffer[0];
+ buffer += buffer[0];
+ }
+
+ if (buflen > 2 && buffer[2] == VS_COLORFORMAT) {
+ if (buflen < 6) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+ "interface %d COLORFORMAT error\n",
+ dev->udev->devnum,
+ alts->desc.bInterfaceNumber);
+ return -EINVAL;
+ }
+
+ format->colorspace = uvc_colorspace(buffer[3]);
+
+ buflen -= buffer[0];
+ buffer += buffer[0];
+ }
+
+ return buffer - start;
+}
+
+static int uvc_parse_streaming(struct uvc_device *dev,
+ struct usb_interface *intf)
+{
+ struct uvc_streaming *streaming = NULL;
+ struct uvc_format *format;
+ struct uvc_frame *frame;
+ struct usb_host_interface *alts = &intf->altsetting[0];
+ unsigned char *_buffer, *buffer = alts->extra;
+ int _buflen, buflen = alts->extralen;
+ unsigned int nformats = 0, nframes = 0, nintervals = 0;
+ unsigned int size, i, n, p;
+ __u32 *interval;
+ __u16 psize;
+ int ret = -EINVAL;
+
+ if (intf->cur_altsetting->desc.bInterfaceSubClass
+ != SC_VIDEOSTREAMING) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d interface %d isn't a "
+ "video streaming interface\n", dev->udev->devnum,
+ intf->altsetting[0].desc.bInterfaceNumber);
+ return -EINVAL;
+ }
+
+ if (usb_driver_claim_interface(&uvc_driver.driver, intf, dev)) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d interface %d is already "
+ "claimed\n", dev->udev->devnum,
+ intf->altsetting[0].desc.bInterfaceNumber);
+ return -EINVAL;
+ }
+
+ streaming = kzalloc(sizeof *streaming, GFP_KERNEL);
+ if (streaming == NULL) {
+ usb_driver_release_interface(&uvc_driver.driver, intf);
+ return -EINVAL;
+ }
+
+ mutex_init(&streaming->mutex);
+ streaming->intf = usb_get_intf(intf);
+ streaming->intfnum = intf->cur_altsetting->desc.bInterfaceNumber;
+
+ /* The Pico iMage webcam has its class-specific interface descriptors
+ * after the endpoint descriptors.
+ */
+ if (buflen == 0) {
+ for (i = 0; i < alts->desc.bNumEndpoints; ++i) {
+ struct usb_host_endpoint *ep = &alts->endpoint[i];
+
+ if (ep->extralen == 0)
+ continue;
+
+ if (ep->extralen > 2 &&
+ ep->extra[1] == USB_DT_CS_INTERFACE) {
+ uvc_trace(UVC_TRACE_DESCR, "trying extra data "
+ "from endpoint %u.\n", i);
+ buffer = alts->endpoint[i].extra;
+ buflen = alts->endpoint[i].extralen;
+ break;
+ }
+ }
+ }
+
+ /* Skip the standard interface descriptors. */
+ while (buflen > 2 && buffer[1] != USB_DT_CS_INTERFACE) {
+ buflen -= buffer[0];
+ buffer += buffer[0];
+ }
+
+ if (buflen <= 2) {
+ uvc_trace(UVC_TRACE_DESCR, "no class-specific streaming "
+ "interface descriptors found.\n");
+ goto error;
+ }
+
+ /* Parse the header descriptor. */
+ if (buffer[2] == VS_OUTPUT_HEADER) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface "
+ "%d OUTPUT HEADER descriptor is not supported.\n",
+ dev->udev->devnum, alts->desc.bInterfaceNumber);
+ goto error;
+ } else if (buffer[2] == VS_INPUT_HEADER) {
+ p = buflen >= 5 ? buffer[3] : 0;
+ n = buflen >= 12 ? buffer[12] : 0;
+
+ if (buflen < 13 + p*n || buffer[2] != VS_INPUT_HEADER) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
+ "interface %d INPUT HEADER descriptor is "
+ "invalid.\n", dev->udev->devnum,
+ alts->desc.bInterfaceNumber);
+ goto error;
+ }
+
+ streaming->header.bNumFormats = p;
+ streaming->header.bEndpointAddress = buffer[6];
+ streaming->header.bmInfo = buffer[7];
+ streaming->header.bTerminalLink = buffer[8];
+ streaming->header.bStillCaptureMethod = buffer[9];
+ streaming->header.bTriggerSupport = buffer[10];
+ streaming->header.bTriggerUsage = buffer[11];
+ streaming->header.bControlSize = n;
+
+ streaming->header.bmaControls = kmalloc(p*n, GFP_KERNEL);
+ if (streaming->header.bmaControls == NULL) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ memcpy(streaming->header.bmaControls, &buffer[13], p*n);
+ } else {
+ uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface "
+ "%d HEADER descriptor not found.\n", dev->udev->devnum,
+ alts->desc.bInterfaceNumber);
+ goto error;
+ }
+
+ buflen -= buffer[0];
+ buffer += buffer[0];
+
+ _buffer = buffer;
+ _buflen = buflen;
+
+ /* Count the format and frame descriptors. */
+ while (_buflen > 2) {
+ switch (_buffer[2]) {
+ case VS_FORMAT_UNCOMPRESSED:
+ case VS_FORMAT_MJPEG:
+ case VS_FORMAT_FRAME_BASED:
+ nformats++;
+ break;
+
+ case VS_FORMAT_DV:
+ /* DV format has no frame descriptor. We will create a
+ * dummy frame descriptor with a dummy frame interval.
+ */
+ nformats++;
+ nframes++;
+ nintervals++;
+ break;
+
+ case VS_FORMAT_MPEG2TS:
+ case VS_FORMAT_STREAM_BASED:
+ uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
+ "interface %d FORMAT %u is not supported.\n",
+ dev->udev->devnum,
+ alts->desc.bInterfaceNumber, _buffer[2]);
+ break;
+
+ case VS_FRAME_UNCOMPRESSED:
+ case VS_FRAME_MJPEG:
+ nframes++;
+ if (_buflen > 25)
+ nintervals += _buffer[25] ? _buffer[25] : 3;
+ break;
+
+ case VS_FRAME_FRAME_BASED:
+ nframes++;
+ if (_buflen > 21)
+ nintervals += _buffer[21] ? _buffer[21] : 3;
+ break;
+ }
+
+ _buflen -= _buffer[0];
+ _buffer += _buffer[0];
+ }
+
+ if (nformats == 0) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface "
+ "%d has no supported formats defined.\n",
+ dev->udev->devnum, alts->desc.bInterfaceNumber);
+ goto error;
+ }
+
+ size = nformats * sizeof *format + nframes * sizeof *frame
+ + nintervals * sizeof *interval;
+ format = kzalloc(size, GFP_KERNEL);
+ if (format == NULL) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ frame = (struct uvc_frame *)&format[nformats];
+ interval = (__u32 *)&frame[nframes];
+
+ streaming->format = format;
+ streaming->nformats = nformats;
+
+ /* Parse the format descriptors. */
+ while (buflen > 2) {
+ switch (buffer[2]) {
+ case VS_FORMAT_UNCOMPRESSED:
+ case VS_FORMAT_MJPEG:
+ case VS_FORMAT_DV:
+ case VS_FORMAT_FRAME_BASED:
+ format->frame = frame;
+ ret = uvc_parse_format(dev, streaming, format,
+ &interval, buffer, buflen);
+ if (ret < 0)
+ goto error;
+
+ frame += format->nframes;
+ format++;
+
+ buflen -= ret;
+ buffer += ret;
+ continue;
+
+ default:
+ break;
+ }
+
+ buflen -= buffer[0];
+ buffer += buffer[0];
+ }
+
+ /* Parse the alternate settings to find the maximum bandwidth. */
+ for (i = 0; i < intf->num_altsetting; ++i) {
+ struct usb_host_endpoint *ep;
+ alts = &intf->altsetting[i];
+ ep = uvc_find_endpoint(alts,
+ streaming->header.bEndpointAddress);
+ if (ep == NULL)
+ continue;
+
+ psize = le16_to_cpu(ep->desc.wMaxPacketSize);
+ psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
+ if (psize > streaming->maxpsize)
+ streaming->maxpsize = psize;
+ }
+
+ list_add_tail(&streaming->list, &dev->streaming);
+ return 0;
+
+error:
+ usb_driver_release_interface(&uvc_driver.driver, intf);
+ usb_put_intf(intf);
+ kfree(streaming->format);
+ kfree(streaming->header.bmaControls);
+ kfree(streaming);
+ return ret;
+}
+
+/* Parse vendor-specific extensions. */
+static int uvc_parse_vendor_control(struct uvc_device *dev,
+ const unsigned char *buffer, int buflen)
+{
+ struct usb_device *udev = dev->udev;
+ struct usb_host_interface *alts = dev->intf->cur_altsetting;
+ struct uvc_entity *unit;
+ unsigned int n, p;
+ int handled = 0;
+
+ switch (le16_to_cpu(dev->udev->descriptor.idVendor)) {
+ case 0x046d: /* Logitech */
+ if (buffer[1] != 0x41 || buffer[2] != 0x01)
+ break;
+
+ /* Logitech implements several vendor specific functions
+ * through vendor specific extension units (LXU).
+ *
+ * The LXU descriptors are similar to XU descriptors
+ * (see "USB Device Video Class for Video Devices", section
+ * 3.7.2.6 "Extension Unit Descriptor") with the following
+ * differences:
+ *
+ * ----------------------------------------------------------
+ * 0 bLength 1 Number
+ * Size of this descriptor, in bytes: 24+p+n*2
+ * ----------------------------------------------------------
+ * 23+p+n bmControlsType N Bitmap
+ * Individual bits in the set are defined:
+ * 0: Absolute
+ * 1: Relative
+ *
+ * This bitset is mapped exactly the same as bmControls.
+ * ----------------------------------------------------------
+ * 23+p+n*2 bReserved 1 Boolean
+ * ----------------------------------------------------------
+ * 24+p+n*2 iExtension 1 Index
+ * Index of a string descriptor that describes this
+ * extension unit.
+ * ----------------------------------------------------------
+ */
+ p = buflen >= 22 ? buffer[21] : 0;
+ n = buflen >= 25 + p ? buffer[22+p] : 0;
+
+ if (buflen < 25 + p + 2*n) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
+ "interface %d EXTENSION_UNIT error\n",
+ udev->devnum, alts->desc.bInterfaceNumber);
+ break;
+ }
+
+ unit = kzalloc(sizeof *unit + p + 2*n, GFP_KERNEL);
+ if (unit == NULL)
+ return -ENOMEM;
+
+ unit->id = buffer[3];
+ unit->type = VC_EXTENSION_UNIT;
+ memcpy(unit->extension.guidExtensionCode, &buffer[4], 16);
+ unit->extension.bNumControls = buffer[20];
+ unit->extension.bNrInPins =
+ le16_to_cpup((__le16 *)&buffer[21]);
+ unit->extension.baSourceID = (__u8 *)unit + sizeof *unit;
+ memcpy(unit->extension.baSourceID, &buffer[22], p);
+ unit->extension.bControlSize = buffer[22+p];
+ unit->extension.bmControls = (__u8 *)unit + sizeof *unit + p;
+ unit->extension.bmControlsType = (__u8 *)unit + sizeof *unit
+ + p + n;
+ memcpy(unit->extension.bmControls, &buffer[23+p], 2*n);
+
+ if (buffer[24+p+2*n] != 0)
+ usb_string(udev, buffer[24+p+2*n], unit->name,
+ sizeof unit->name);
+ else
+ sprintf(unit->name, "Extension %u", buffer[3]);
+
+ list_add_tail(&unit->list, &dev->entities);
+ handled = 1;
+ break;
+ }
+
+ return handled;
+}
+
+static int uvc_parse_standard_control(struct uvc_device *dev,
+ const unsigned char *buffer, int buflen)
+{
+ struct usb_device *udev = dev->udev;
+ struct uvc_entity *unit, *term;
+ struct usb_interface *intf;
+ struct usb_host_interface *alts = dev->intf->cur_altsetting;
+ unsigned int i, n, p, len;
+ __u16 type;
+
+ switch (buffer[2]) {
+ case VC_HEADER:
+ n = buflen >= 12 ? buffer[11] : 0;
+
+ if (buflen < 12 || buflen < 12 + n) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
+ "interface %d HEADER error\n", udev->devnum,
+ alts->desc.bInterfaceNumber);
+ return -EINVAL;
+ }
+
+ dev->uvc_version = le16_to_cpup((__le16 *)&buffer[3]);
+ dev->clock_frequency = le32_to_cpup((__le32 *)&buffer[7]);
+
+ /* Parse all USB Video Streaming interfaces. */
+ for (i = 0; i < n; ++i) {
+ intf = usb_ifnum_to_if(udev, buffer[12+i]);
+ if (intf == NULL) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d "
+ "interface %d doesn't exists\n",
+ udev->devnum, i);
+ continue;
+ }
+
+ uvc_parse_streaming(dev, intf);
+ }
+ break;
+
+ case VC_INPUT_TERMINAL:
+ if (buflen < 8) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
+ "interface %d INPUT_TERMINAL error\n",
+ udev->devnum, alts->desc.bInterfaceNumber);
+ return -EINVAL;
+ }
+
+ /* Make sure the terminal type MSB is not null, otherwise it
+ * could be confused with a unit.
+ */
+ type = le16_to_cpup((__le16 *)&buffer[4]);
+ if ((type & 0xff00) == 0) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
+ "interface %d INPUT_TERMINAL %d has invalid "
+ "type 0x%04x, skipping\n", udev->devnum,
+ alts->desc.bInterfaceNumber,
+ buffer[3], type);
+ return 0;
+ }
+
+ n = 0;
+ p = 0;
+ len = 8;
+
+ if (type == ITT_CAMERA) {
+ n = buflen >= 15 ? buffer[14] : 0;
+ len = 15;
+
+ } else if (type == ITT_MEDIA_TRANSPORT_INPUT) {
+ n = buflen >= 9 ? buffer[8] : 0;
+ p = buflen >= 10 + n ? buffer[9+n] : 0;
+ len = 10;
+ }
+
+ if (buflen < len + n + p) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
+ "interface %d INPUT_TERMINAL error\n",
+ udev->devnum, alts->desc.bInterfaceNumber);
+ return -EINVAL;
+ }
+
+ term = kzalloc(sizeof *term + n + p, GFP_KERNEL);
+ if (term == NULL)
+ return -ENOMEM;
+
+ term->id = buffer[3];
+ term->type = type | UVC_TERM_INPUT;
+
+ if (UVC_ENTITY_TYPE(term) == ITT_CAMERA) {
+ term->camera.bControlSize = n;
+ term->camera.bmControls = (__u8 *)term + sizeof *term;
+ term->camera.wObjectiveFocalLengthMin =
+ le16_to_cpup((__le16 *)&buffer[8]);
+ term->camera.wObjectiveFocalLengthMax =
+ le16_to_cpup((__le16 *)&buffer[10]);
+ term->camera.wOcularFocalLength =
+ le16_to_cpup((__le16 *)&buffer[12]);
+ memcpy(term->camera.bmControls, &buffer[15], n);
+ } else if (UVC_ENTITY_TYPE(term) == ITT_MEDIA_TRANSPORT_INPUT) {
+ term->media.bControlSize = n;
+ term->media.bmControls = (__u8 *)term + sizeof *term;
+ term->media.bTransportModeSize = p;
+ term->media.bmTransportModes = (__u8 *)term
+ + sizeof *term + n;
+ memcpy(term->media.bmControls, &buffer[9], n);
+ memcpy(term->media.bmTransportModes, &buffer[10+n], p);
+ }
+
+ if (buffer[7] != 0)
+ usb_string(udev, buffer[7], term->name,
+ sizeof term->name);
+ else if (UVC_ENTITY_TYPE(term) == ITT_CAMERA)
+ sprintf(term->name, "Camera %u", buffer[3]);
+ else if (UVC_ENTITY_TYPE(term) == ITT_MEDIA_TRANSPORT_INPUT)
+ sprintf(term->name, "Media %u", buffer[3]);
+ else
+ sprintf(term->name, "Input %u", buffer[3]);
+
+ list_add_tail(&term->list, &dev->entities);
+ break;
+
+ case VC_OUTPUT_TERMINAL:
+ if (buflen < 9) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
+ "interface %d OUTPUT_TERMINAL error\n",
+ udev->devnum, alts->desc.bInterfaceNumber);
+ return -EINVAL;
+ }
+
+ /* Make sure the terminal type MSB is not null, otherwise it
+ * could be confused with a unit.
+ */
+ type = le16_to_cpup((__le16 *)&buffer[4]);
+ if ((type & 0xff00) == 0) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
+ "interface %d OUTPUT_TERMINAL %d has invalid "
+ "type 0x%04x, skipping\n", udev->devnum,
+ alts->desc.bInterfaceNumber, buffer[3], type);
+ return 0;
+ }
+
+ term = kzalloc(sizeof *term, GFP_KERNEL);
+ if (term == NULL)
+ return -ENOMEM;
+
+ term->id = buffer[3];
+ term->type = type | UVC_TERM_OUTPUT;
+ term->output.bSourceID = buffer[7];
+
+ if (buffer[8] != 0)
+ usb_string(udev, buffer[8], term->name,
+ sizeof term->name);
+ else
+ sprintf(term->name, "Output %u", buffer[3]);
+
+ list_add_tail(&term->list, &dev->entities);
+ break;
+
+ case VC_SELECTOR_UNIT:
+ p = buflen >= 5 ? buffer[4] : 0;
+
+ if (buflen < 5 || buflen < 6 + p) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
+ "interface %d SELECTOR_UNIT error\n",
+ udev->devnum, alts->desc.bInterfaceNumber);
+ return -EINVAL;
+ }
+
+ unit = kzalloc(sizeof *unit + p, GFP_KERNEL);
+ if (unit == NULL)
+ return -ENOMEM;
+
+ unit->id = buffer[3];
+ unit->type = buffer[2];
+ unit->selector.bNrInPins = buffer[4];
+ unit->selector.baSourceID = (__u8 *)unit + sizeof *unit;
+ memcpy(unit->selector.baSourceID, &buffer[5], p);
+
+ if (buffer[5+p] != 0)
+ usb_string(udev, buffer[5+p], unit->name,
+ sizeof unit->name);
+ else
+ sprintf(unit->name, "Selector %u", buffer[3]);
+
+ list_add_tail(&unit->list, &dev->entities);
+ break;
+
+ case VC_PROCESSING_UNIT:
+ n = buflen >= 8 ? buffer[7] : 0;
+ p = dev->uvc_version >= 0x0110 ? 10 : 9;
+
+ if (buflen < p + n) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
+ "interface %d PROCESSING_UNIT error\n",
+ udev->devnum, alts->desc.bInterfaceNumber);
+ return -EINVAL;
+ }
+
+ unit = kzalloc(sizeof *unit + n, GFP_KERNEL);
+ if (unit == NULL)
+ return -ENOMEM;
+
+ unit->id = buffer[3];
+ unit->type = buffer[2];
+ unit->processing.bSourceID = buffer[4];
+ unit->processing.wMaxMultiplier =
+ le16_to_cpup((__le16 *)&buffer[5]);
+ unit->processing.bControlSize = buffer[7];
+ unit->processing.bmControls = (__u8 *)unit + sizeof *unit;
+ memcpy(unit->processing.bmControls, &buffer[8], n);
+ if (dev->uvc_version >= 0x0110)
+ unit->processing.bmVideoStandards = buffer[9+n];
+
+ if (buffer[8+n] != 0)
+ usb_string(udev, buffer[8+n], unit->name,
+ sizeof unit->name);
+ else
+ sprintf(unit->name, "Processing %u", buffer[3]);
+
+ list_add_tail(&unit->list, &dev->entities);
+ break;
+
+ case VC_EXTENSION_UNIT:
+ p = buflen >= 22 ? buffer[21] : 0;
+ n = buflen >= 24 + p ? buffer[22+p] : 0;
+
+ if (buflen < 24 + p + n) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
+ "interface %d EXTENSION_UNIT error\n",
+ udev->devnum, alts->desc.bInterfaceNumber);
+ return -EINVAL;
+ }
+
+ unit = kzalloc(sizeof *unit + p + n, GFP_KERNEL);
+ if (unit == NULL)
+ return -ENOMEM;
+
+ unit->id = buffer[3];
+ unit->type = buffer[2];
+ memcpy(unit->extension.guidExtensionCode, &buffer[4], 16);
+ unit->extension.bNumControls = buffer[20];
+ unit->extension.bNrInPins =
+ le16_to_cpup((__le16 *)&buffer[21]);
+ unit->extension.baSourceID = (__u8 *)unit + sizeof *unit;
+ memcpy(unit->extension.baSourceID, &buffer[22], p);
+ unit->extension.bControlSize = buffer[22+p];
+ unit->extension.bmControls = (__u8 *)unit + sizeof *unit + p;
+ memcpy(unit->extension.bmControls, &buffer[23+p], n);
+
+ if (buffer[23+p+n] != 0)
+ usb_string(udev, buffer[23+p+n], unit->name,
+ sizeof unit->name);
+ else
+ sprintf(unit->name, "Extension %u", buffer[3]);
+
+ list_add_tail(&unit->list, &dev->entities);
+ break;
+
+ default:
+ uvc_trace(UVC_TRACE_DESCR, "Found an unknown CS_INTERFACE "
+ "descriptor (%u)\n", buffer[2]);
+ break;
+ }
+
+ return 0;
+}
+
+static int uvc_parse_control(struct uvc_device *dev)
+{
+ struct usb_host_interface *alts = dev->intf->cur_altsetting;
+ unsigned char *buffer = alts->extra;
+ int buflen = alts->extralen;
+ int ret;
+
+ /* Parse the default alternate setting only, as the UVC specification
+ * defines a single alternate setting, the default alternate setting
+ * zero.
+ */
+
+ while (buflen > 2) {
+ if (uvc_parse_vendor_control(dev, buffer, buflen) ||
+ buffer[1] != USB_DT_CS_INTERFACE)
+ goto next_descriptor;
+
+ if ((ret = uvc_parse_standard_control(dev, buffer, buflen)) < 0)
+ return ret;
+
+next_descriptor:
+ buflen -= buffer[0];
+ buffer += buffer[0];
+ }
+
+ /* Check if the optional status endpoint is present. */
+ if (alts->desc.bNumEndpoints == 1) {
+ struct usb_host_endpoint *ep = &alts->endpoint[0];
+ struct usb_endpoint_descriptor *desc = &ep->desc;
+
+ if (usb_endpoint_is_int_in(desc) &&
+ le16_to_cpu(desc->wMaxPacketSize) >= 8 &&
+ desc->bInterval != 0) {
+ uvc_trace(UVC_TRACE_DESCR, "Found a Status endpoint "
+ "(addr %02x).\n", desc->bEndpointAddress);
+ dev->int_ep = ep;
+ }
+ }
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------------
+ * USB probe and disconnect
+ */
+
+/*
+ * Unregister the video devices.
+ */
+static void uvc_unregister_video(struct uvc_device *dev)
+{
+ if (dev->video.vdev) {
+ if (dev->video.vdev->minor == -1)
+ video_device_release(dev->video.vdev);
+ else
+ video_unregister_device(dev->video.vdev);
+ dev->video.vdev = NULL;
+ }
+}
+
+/*
+ * Scan the UVC descriptors to locate a chain starting at an Output Terminal
+ * and containing the following units:
+ *
+ * - a USB Streaming Output Terminal
+ * - zero or one Processing Unit
+ * - zero, one or mode single-input Selector Units
+ * - zero or one multiple-input Selector Units, provided all inputs are
+ * connected to input terminals
+ * - zero, one or mode single-input Extension Units
+ * - one Camera Input Terminal, or one or more External terminals.
+ *
+ * A side forward scan is made on each detected entity to check for additional
+ * extension units.
+ */
+static int uvc_scan_chain_entity(struct uvc_video_device *video,
+ struct uvc_entity *entity)
+{
+ switch (UVC_ENTITY_TYPE(entity)) {
+ case VC_EXTENSION_UNIT:
+ if (uvc_trace_param & UVC_TRACE_PROBE)
+ printk(" <- XU %d", entity->id);
+
+ if (entity->extension.bNrInPins != 1) {
+ uvc_trace(UVC_TRACE_DESCR, "Extension unit %d has more "
+ "than 1 input pin.\n", entity->id);
+ return -1;
+ }
+
+ list_add_tail(&entity->chain, &video->extensions);
+ break;
+
+ case VC_PROCESSING_UNIT:
+ if (uvc_trace_param & UVC_TRACE_PROBE)
+ printk(" <- PU %d", entity->id);
+
+ if (video->processing != NULL) {
+ uvc_trace(UVC_TRACE_DESCR, "Found multiple "
+ "Processing Units in chain.\n");
+ return -1;
+ }
+
+ video->processing = entity;
+ break;
+
+ case VC_SELECTOR_UNIT:
+ if (uvc_trace_param & UVC_TRACE_PROBE)
+ printk(" <- SU %d", entity->id);
+
+ /* Single-input selector units are ignored. */
+ if (entity->selector.bNrInPins == 1)
+ break;
+
+ if (video->selector != NULL) {
+ uvc_trace(UVC_TRACE_DESCR, "Found multiple Selector "
+ "Units in chain.\n");
+ return -1;
+ }
+
+ video->selector = entity;
+ break;
+
+ case ITT_VENDOR_SPECIFIC:
+ case ITT_CAMERA:
+ case ITT_MEDIA_TRANSPORT_INPUT:
+ if (uvc_trace_param & UVC_TRACE_PROBE)
+ printk(" <- IT %d\n", entity->id);
+
+ list_add_tail(&entity->chain, &video->iterms);
+ break;
+
+ default:
+ uvc_trace(UVC_TRACE_DESCR, "Unsupported entity type "
+ "0x%04x found in chain.\n", UVC_ENTITY_TYPE(entity));
+ return -1;
+ }
+
+ return 0;
+}
+
+static int uvc_scan_chain_forward(struct uvc_video_device *video,
+ struct uvc_entity *entity, struct uvc_entity *prev)
+{
+ struct uvc_entity *forward;
+ int found;
+
+ /* Forward scan */
+ forward = NULL;
+ found = 0;
+
+ while (1) {
+ forward = uvc_entity_by_reference(video->dev, entity->id,
+ forward);
+ if (forward == NULL)
+ break;
+
+ if (UVC_ENTITY_TYPE(forward) != VC_EXTENSION_UNIT ||
+ forward == prev)
+ continue;
+
+ if (forward->extension.bNrInPins != 1) {
+ uvc_trace(UVC_TRACE_DESCR, "Extension unit %d has"
+ "more than 1 input pin.\n", entity->id);
+ return -1;
+ }
+
+ list_add_tail(&forward->chain, &video->extensions);
+ if (uvc_trace_param & UVC_TRACE_PROBE) {
+ if (!found)
+ printk(" (-> XU");
+
+ printk(" %d", forward->id);
+ found = 1;
+ }
+ }
+ if (found)
+ printk(")");
+
+ return 0;
+}
+
+static int uvc_scan_chain_backward(struct uvc_video_device *video,
+ struct uvc_entity *entity)
+{
+ struct uvc_entity *term;
+ int id = -1, i;
+
+ switch (UVC_ENTITY_TYPE(entity)) {
+ case VC_EXTENSION_UNIT:
+ id = entity->extension.baSourceID[0];
+ break;
+
+ case VC_PROCESSING_UNIT:
+ id = entity->processing.bSourceID;
+ break;
+
+ case VC_SELECTOR_UNIT:
+ /* Single-input selector units are ignored. */
+ if (entity->selector.bNrInPins == 1) {
+ id = entity->selector.baSourceID[0];
+ break;
+ }
+
+ if (uvc_trace_param & UVC_TRACE_PROBE)
+ printk(" <- IT");
+
+ video->selector = entity;
+ for (i = 0; i < entity->selector.bNrInPins; ++i) {
+ id = entity->selector.baSourceID[i];
+ term = uvc_entity_by_id(video->dev, id);
+ if (term == NULL || !UVC_ENTITY_IS_ITERM(term)) {
+ uvc_trace(UVC_TRACE_DESCR, "Selector unit %d "
+ "input %d isn't connected to an "
+ "input terminal\n", entity->id, i);
+ return -1;
+ }
+
+ if (uvc_trace_param & UVC_TRACE_PROBE)
+ printk(" %d", term->id);
+
+ list_add_tail(&term->chain, &video->iterms);
+ uvc_scan_chain_forward(video, term, entity);
+ }
+
+ if (uvc_trace_param & UVC_TRACE_PROBE)
+ printk("\n");
+
+ id = 0;
+ break;
+ }
+
+ return id;
+}
+
+static int uvc_scan_chain(struct uvc_video_device *video)
+{
+ struct uvc_entity *entity, *prev;
+ int id;
+
+ entity = video->oterm;
+ uvc_trace(UVC_TRACE_PROBE, "Scanning UVC chain: OT %d", entity->id);
+ id = entity->output.bSourceID;
+ while (id != 0) {
+ prev = entity;
+ entity = uvc_entity_by_id(video->dev, id);
+ if (entity == NULL) {
+ uvc_trace(UVC_TRACE_DESCR, "Found reference to "
+ "unknown entity %d.\n", id);
+ return -1;
+ }
+
+ /* Process entity */
+ if (uvc_scan_chain_entity(video, entity) < 0)
+ return -1;
+
+ /* Forward scan */
+ if (uvc_scan_chain_forward(video, entity, prev) < 0)
+ return -1;
+
+ /* Stop when a terminal is found. */
+ if (!UVC_ENTITY_IS_UNIT(entity))
+ break;
+
+ /* Backward scan */
+ id = uvc_scan_chain_backward(video, entity);
+ if (id < 0)
+ return id;
+ }
+
+ /* Initialize the video buffers queue. */
+ uvc_queue_init(&video->queue);
+
+ return 0;
+}
+
+/*
+ * Register the video devices.
+ *
+ * The driver currently supports a single video device per control interface
+ * only. The terminal and units must match the following structure:
+ *
+ * ITT_CAMERA -> VC_PROCESSING_UNIT -> VC_EXTENSION_UNIT{0,n} -> TT_STREAMING
+ *
+ * The Extension Units, if present, must have a single input pin. The
+ * Processing Unit and Extension Units can be in any order. Additional
+ * Extension Units connected to the main chain as single-unit branches are
+ * also supported.
+ */
+static int uvc_register_video(struct uvc_device *dev)
+{
+ struct video_device *vdev;
+ struct uvc_entity *term;
+ int found = 0, ret;
+
+ /* Check if the control interface matches the structure we expect. */
+ list_for_each_entry(term, &dev->entities, list) {
+ struct uvc_streaming *streaming;
+
+ if (UVC_ENTITY_TYPE(term) != TT_STREAMING)
+ continue;
+
+ memset(&dev->video, 0, sizeof dev->video);
+ mutex_init(&dev->video.ctrl_mutex);
+ INIT_LIST_HEAD(&dev->video.iterms);
+ INIT_LIST_HEAD(&dev->video.extensions);
+ dev->video.oterm = term;
+ dev->video.dev = dev;
+ if (uvc_scan_chain(&dev->video) < 0)
+ continue;
+
+ list_for_each_entry(streaming, &dev->streaming, list) {
+ if (streaming->header.bTerminalLink == term->id) {
+ dev->video.streaming = streaming;
+ found = 1;
+ break;
+ }
+ }
+
+ if (found)
+ break;
+ }
+
+ if (!found) {
+ uvc_printk(KERN_INFO, "No valid video chain found.\n");
+ return -1;
+ }
+
+ if (uvc_trace_param & UVC_TRACE_PROBE) {
+ uvc_printk(KERN_INFO, "Found a valid video chain (");
+ list_for_each_entry(term, &dev->video.iterms, chain) {
+ printk("%d", term->id);
+ if (term->chain.next != &dev->video.iterms)
+ printk(",");
+ }
+ printk(" -> %d).\n", dev->video.oterm->id);
+ }
+
+ /* Initialize the streaming interface with default streaming
+ * parameters.
+ */
+ if ((ret = uvc_video_init(&dev->video)) < 0) {
+ uvc_printk(KERN_ERR, "Failed to initialize the device "
+ "(%d).\n", ret);
+ return ret;
+ }
+
+ /* Register the device with V4L. */
+ vdev = video_device_alloc();
+ if (vdev == NULL)
+ return -1;
+
+ /* We already hold a reference to dev->udev. The video device will be
+ * unregistered before the reference is released, so we don't need to
+ * get another one.
+ */
+ vdev->dev = &dev->intf->dev;
+ vdev->type = 0;
+ vdev->type2 = 0;
+ vdev->minor = -1;
+ vdev->fops = &uvc_fops;
+ vdev->release = video_device_release;
+ strncpy(vdev->name, dev->name, sizeof vdev->name);
+
+ /* Set the driver data before calling video_register_device, otherwise
+ * uvc_v4l2_open might race us.
+ *
+ * FIXME: usb_set_intfdata hasn't been called so far. Is that a
+ * problem ? Does any function which could be called here get
+ * a pointer to the usb_interface ?
+ */
+ dev->video.vdev = vdev;
+ video_set_drvdata(vdev, &dev->video);
+
+ if (video_register_device(vdev, VFL_TYPE_GRABBER, -1) < 0) {
+ dev->video.vdev = NULL;
+ video_device_release(vdev);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Delete the UVC device.
+ *
+ * Called by the kernel when the last reference to the uvc_device structure
+ * is released.
+ *
+ * Unregistering the video devices is done here because every opened instance
+ * must be closed before the device can be unregistered. An alternative would
+ * have been to use another reference count for uvc_v4l2_open/uvc_release, and
+ * unregister the video devices on disconnect when that reference count drops
+ * to zero.
+ *
+ * As this function is called after or during disconnect(), all URBs have
+ * already been canceled by the USB core. There is no need to kill the
+ * interrupt URB manually.
+ */
+void uvc_delete(struct kref *kref)
+{
+ struct uvc_device *dev = container_of(kref, struct uvc_device, kref);
+ struct list_head *p, *n;
+
+ /* Unregister the video device */
+ uvc_unregister_video(dev);
+ usb_put_intf(dev->intf);
+ usb_put_dev(dev->udev);
+
+ uvc_status_cleanup(dev);
+ uvc_ctrl_cleanup_device(dev);
+
+ list_for_each_safe(p, n, &dev->entities) {
+ struct uvc_entity *entity;
+ entity = list_entry(p, struct uvc_entity, list);
+ kfree(entity);
+ }
+
+ list_for_each_safe(p, n, &dev->streaming) {
+ struct uvc_streaming *streaming;
+ streaming = list_entry(p, struct uvc_streaming, list);
+ usb_driver_release_interface(&uvc_driver.driver,
+ streaming->intf);
+ usb_put_intf(streaming->intf);
+ kfree(streaming->format);
+ kfree(streaming->header.bmaControls);
+ kfree(streaming);
+ }
+
+ kfree(dev);
+}
+
+static int uvc_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct usb_device *udev = interface_to_usbdev(intf);
+ struct uvc_device *dev;
+ int ret;
+
+ if (id->idVendor && id->idProduct)
+ uvc_trace(UVC_TRACE_PROBE, "Probing known UVC device %s "
+ "(%04x:%04x)\n", udev->devpath, id->idVendor,
+ id->idProduct);
+ else
+ uvc_trace(UVC_TRACE_PROBE, "Probing generic UVC device %s\n",
+ udev->devpath);
+
+ /* Allocate memory for the device and initialize it */
+ if ((dev = kzalloc(sizeof *dev, GFP_KERNEL)) == NULL)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&dev->entities);
+ INIT_LIST_HEAD(&dev->streaming);
+ kref_init(&dev->kref);
+
+ dev->udev = usb_get_dev(udev);
+ dev->intf = usb_get_intf(intf);
+ dev->intfnum = intf->cur_altsetting->desc.bInterfaceNumber;
+ dev->quirks = id->driver_info | uvc_quirks_param;
+
+ if (udev->product != NULL)
+ strncpy(dev->name, udev->product, sizeof dev->name);
+ else
+ snprintf(dev->name, sizeof dev->name,
+ "UVC Camera (%04x:%04x)",
+ le16_to_cpu(udev->descriptor.idVendor),
+ le16_to_cpu(udev->descriptor.idProduct));
+
+ /* Parse the Video Class control descriptor */
+ if (uvc_parse_control(dev) < 0) {
+ uvc_trace(UVC_TRACE_PROBE, "Unable to parse UVC "
+ "descriptors.\n");
+ goto error;
+ }
+
+ uvc_printk(KERN_INFO, "Found UVC %u.%02u device %s (%04x:%04x)\n",
+ dev->uvc_version >> 8, dev->uvc_version & 0xff,
+ udev->product ? udev->product : "<unnamed>",
+ le16_to_cpu(udev->descriptor.idVendor),
+ le16_to_cpu(udev->descriptor.idProduct));
+
+ if (uvc_quirks_param != 0) {
+ uvc_printk(KERN_INFO, "Forcing device quirks 0x%x by module "
+ "parameter for testing purpose.\n", uvc_quirks_param);
+ uvc_printk(KERN_INFO, "Please report required quirks to the "
+ "linux-uvc-devel mailing list.\n");
+ }
+
+ /* Initialize controls */
+ if (uvc_ctrl_init_device(dev) < 0)
+ goto error;
+
+ /* Register the video devices */
+ if (uvc_register_video(dev) < 0)
+ goto error;
+
+ /* Save our data pointer in the interface data */
+ usb_set_intfdata(intf, dev);
+
+ /* Initialize the interrupt URB */
+ if ((ret = uvc_status_init(dev)) < 0) {
+ uvc_printk(KERN_INFO, "Unable to initialize the status "
+ "endpoint (%d), status interrupt will not be "
+ "supported.\n", ret);
+ }
+
+ uvc_trace(UVC_TRACE_PROBE, "UVC device initialized.\n");
+ return 0;
+
+error:
+ kref_put(&dev->kref, uvc_delete);
+ return -ENODEV;
+}
+
+static void uvc_disconnect(struct usb_interface *intf)
+{
+ struct uvc_device *dev = usb_get_intfdata(intf);
+
+ /* Set the USB interface data to NULL. This can be done outside the
+ * lock, as there's no other reader.
+ */
+ usb_set_intfdata(intf, NULL);
+
+ if (intf->cur_altsetting->desc.bInterfaceSubClass == SC_VIDEOSTREAMING)
+ return;
+
+ /* uvc_v4l2_open() might race uvc_disconnect(). A static driver-wide
+ * lock is needed to prevent uvc_disconnect from releasing its
+ * reference to the uvc_device instance after uvc_v4l2_open() received
+ * the pointer to the device (video_devdata) but before it got the
+ * chance to increase the reference count (kref_get).
+ */
+ mutex_lock(&uvc_driver.open_mutex);
+
+ dev->state |= UVC_DEV_DISCONNECTED;
+ kref_put(&dev->kref, uvc_delete);
+
+ mutex_unlock(&uvc_driver.open_mutex);
+}
+
+static int uvc_suspend(struct usb_interface *intf, pm_message_t message)
+{
+ struct uvc_device *dev = usb_get_intfdata(intf);
+
+ uvc_trace(UVC_TRACE_SUSPEND, "Suspending interface %u\n",
+ intf->cur_altsetting->desc.bInterfaceNumber);
+
+ /* Controls are cached on the fly so they don't need to be saved. */
+ if (intf->cur_altsetting->desc.bInterfaceSubClass == SC_VIDEOCONTROL)
+ return uvc_status_suspend(dev);
+
+ if (dev->video.streaming->intf != intf) {
+ uvc_trace(UVC_TRACE_SUSPEND, "Suspend: video streaming USB "
+ "interface mismatch.\n");
+ return -EINVAL;
+ }
+
+ return uvc_video_suspend(&dev->video);
+}
+
+static int uvc_resume(struct usb_interface *intf)
+{
+ struct uvc_device *dev = usb_get_intfdata(intf);
+ int ret;
+
+ uvc_trace(UVC_TRACE_SUSPEND, "Resuming interface %u\n",
+ intf->cur_altsetting->desc.bInterfaceNumber);
+
+ if (intf->cur_altsetting->desc.bInterfaceSubClass == SC_VIDEOCONTROL) {
+ if ((ret = uvc_ctrl_resume_device(dev)) < 0)
+ return ret;
+
+ return uvc_status_resume(dev);
+ }
+
+ if (dev->video.streaming->intf != intf) {
+ uvc_trace(UVC_TRACE_SUSPEND, "Resume: video streaming USB "
+ "interface mismatch.\n");
+ return -EINVAL;
+ }
+
+ return uvc_video_resume(&dev->video);
+}
+
+/* ------------------------------------------------------------------------
+ * Driver initialization and cleanup
+ */
+
+/*
+ * The Logitech cameras listed below have their interface class set to
+ * VENDOR_SPEC because they don't announce themselves as UVC devices, even
+ * though they are compliant.
+ */
+static struct usb_device_id uvc_ids[] = {
+ /* ALi M5606 (Clevo M540SR) */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x0402,
+ .idProduct = 0x5606,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_PROBE_MINMAX },
+ /* Creative Live! Optia */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x041e,
+ .idProduct = 0x4057,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_PROBE_MINMAX },
+ /* Microsoft Lifecam NX-6000 */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x045e,
+ .idProduct = 0x00f8,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_PROBE_MINMAX },
+ /* Microsoft Lifecam VX-7000 */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x045e,
+ .idProduct = 0x0723,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_PROBE_MINMAX },
+ /* Logitech Quickcam Fusion */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x046d,
+ .idProduct = 0x08c1,
+ .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0 },
+ /* Logitech Quickcam Orbit MP */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x046d,
+ .idProduct = 0x08c2,
+ .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0 },
+ /* Logitech Quickcam Pro for Notebook */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x046d,
+ .idProduct = 0x08c3,
+ .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0 },
+ /* Logitech Quickcam Pro 5000 */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x046d,
+ .idProduct = 0x08c5,
+ .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0 },
+ /* Logitech Quickcam OEM Dell Notebook */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x046d,
+ .idProduct = 0x08c6,
+ .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0 },
+ /* Logitech Quickcam OEM Cisco VT Camera II */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x046d,
+ .idProduct = 0x08c7,
+ .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0 },
+ /* Apple Built-In iSight */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x05ac,
+ .idProduct = 0x8501,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_PROBE_MINMAX
+ | UVC_QUIRK_BUILTIN_ISIGHT },
+ /* Genesys Logic USB 2.0 PC Camera */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x05e3,
+ .idProduct = 0x0505,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_STREAM_NO_FID },
+ /* Silicon Motion SM371 */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x090c,
+ .idProduct = 0xb371,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_PROBE_MINMAX },
+ /* MT6227 */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x0e8d,
+ .idProduct = 0x0004,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_PROBE_MINMAX },
+ /* Syntek (HP Spartan) */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x174f,
+ .idProduct = 0x5212,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_STREAM_NO_FID },
+ /* Syntek (Asus U3S) */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x174f,
+ .idProduct = 0x8a33,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_STREAM_NO_FID },
+ /* Ecamm Pico iMage */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x18cd,
+ .idProduct = 0xcafe,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_PROBE_EXTRAFIELDS },
+ /* Bodelin ProScopeHR */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_DEV_HI
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x19ab,
+ .idProduct = 0x1000,
+ .bcdDevice_hi = 0x0126,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_STATUS_INTERVAL },
+ /* SiGma Micro USB Web Camera */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x1c4f,
+ .idProduct = 0x3000,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_PROBE_MINMAX
+ | UVC_QUIRK_IGNORE_SELECTOR_UNIT},
+ /* Acer OEM Webcam - Unknown vendor */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x5986,
+ .idProduct = 0x0100,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_PROBE_MINMAX },
+ /* Packard Bell OEM Webcam */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x5986,
+ .idProduct = 0x0101,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_PROBE_MINMAX },
+ /* Acer Crystal Eye webcam */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x5986,
+ .idProduct = 0x0102,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_PROBE_MINMAX },
+ /* Medion Akoya Mini E1210 */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x5986,
+ .idProduct = 0x0141,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_PROBE_MINMAX },
+ /* Acer OrbiCam - Unknown vendor */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x5986,
+ .idProduct = 0x0200,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_PROBE_MINMAX },
+ /* Generic USB Video Class */
+ { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, 0) },
+ {}
+};
+
+MODULE_DEVICE_TABLE(usb, uvc_ids);
+
+struct uvc_driver uvc_driver = {
+ .driver = {
+ .name = "uvcvideo",
+ .probe = uvc_probe,
+ .disconnect = uvc_disconnect,
+ .suspend = uvc_suspend,
+ .resume = uvc_resume,
+ .id_table = uvc_ids,
+ .supports_autosuspend = 1,
+ },
+};
+
+static int __init uvc_init(void)
+{
+ int result;
+
+ INIT_LIST_HEAD(&uvc_driver.devices);
+ INIT_LIST_HEAD(&uvc_driver.controls);
+ mutex_init(&uvc_driver.open_mutex);
+ mutex_init(&uvc_driver.ctrl_mutex);
+
+ uvc_ctrl_init();
+
+ result = usb_register(&uvc_driver.driver);
+ if (result == 0)
+ printk(KERN_INFO DRIVER_DESC " (" DRIVER_VERSION ")\n");
+ return result;
+}
+
+static void __exit uvc_cleanup(void)
+{
+ usb_deregister(&uvc_driver.driver);
+}
+
+module_init(uvc_init);
+module_exit(uvc_cleanup);
+
+module_param_named(quirks, uvc_quirks_param, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(quirks, "Forced device quirks");
+module_param_named(trace, uvc_trace_param, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(trace, "Trace level bitmask");
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRIVER_VERSION);
+
diff --git a/linux/drivers/media/video/uvc/uvc_isight.c b/linux/drivers/media/video/uvc/uvc_isight.c
new file mode 100644
index 000000000..37bdefdbe
--- /dev/null
+++ b/linux/drivers/media/video/uvc/uvc_isight.c
@@ -0,0 +1,134 @@
+/*
+ * uvc_isight.c -- USB Video Class driver - iSight support
+ *
+ * Copyright (C) 2006-2007
+ * Ivan N. Zlatev <contact@i-nz.net>
+ *
+ * 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.
+ *
+ */
+
+#include <linux/usb.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+
+#include "uvcvideo.h"
+
+/* Built-in iSight webcams implements most of UVC 1.0 except a
+ * different packet format. Instead of sending a header at the
+ * beginning of each isochronous transfer payload, the webcam sends a
+ * single header per image (on its own in a packet), followed by
+ * packets containing data only.
+ *
+ * Offset Size (bytes) Description
+ * ------------------------------------------------------------------
+ * 0x00 1 Header length
+ * 0x01 1 Flags (UVC-compliant)
+ * 0x02 4 Always equal to '11223344'
+ * 0x06 8 Always equal to 'deadbeefdeadface'
+ * 0x0e 16 Unknown
+ *
+ * The header can be prefixed by an optional, unknown-purpose byte.
+ */
+
+static int isight_decode(struct uvc_video_queue *queue, struct uvc_buffer *buf,
+ const __u8 *data, unsigned int len)
+{
+ static const __u8 hdr[] = {
+ 0x11, 0x22, 0x33, 0x44,
+ 0xde, 0xad, 0xbe, 0xef,
+ 0xde, 0xad, 0xfa, 0xce
+ };
+
+ unsigned int maxlen, nbytes;
+ __u8 *mem;
+ int is_header = 0;
+
+ if (buf == NULL)
+ return 0;
+
+ if ((len >= 14 && memcmp(&data[2], hdr, 12) == 0) ||
+ (len >= 15 && memcmp(&data[3], hdr, 12) == 0)) {
+ uvc_trace(UVC_TRACE_FRAME, "iSight header found\n");
+ is_header = 1;
+ }
+
+ /* Synchronize to the input stream by waiting for a header packet. */
+ if (buf->state != UVC_BUF_STATE_ACTIVE) {
+ if (!is_header) {
+ uvc_trace(UVC_TRACE_FRAME, "Dropping packet (out of "
+ "sync).\n");
+ return 0;
+ }
+
+ buf->state = UVC_BUF_STATE_ACTIVE;
+ }
+
+ /* Mark the buffer as done if we're at the beginning of a new frame.
+ *
+ * Empty buffers (bytesused == 0) don't trigger end of frame detection
+ * as it doesn't make sense to return an empty buffer.
+ */
+ if (is_header && buf->buf.bytesused != 0) {
+ buf->state = UVC_BUF_STATE_DONE;
+ return -EAGAIN;
+ }
+
+ /* Copy the video data to the buffer. Skip header packets, as they
+ * contain no data.
+ */
+ if (!is_header) {
+ maxlen = buf->buf.length - buf->buf.bytesused;
+ mem = queue->mem + buf->buf.m.offset + buf->buf.bytesused;
+ nbytes = min(len, maxlen);
+ memcpy(mem, data, nbytes);
+ buf->buf.bytesused += nbytes;
+
+ if (len > maxlen || buf->buf.bytesused == buf->buf.length) {
+ uvc_trace(UVC_TRACE_FRAME, "Frame complete "
+ "(overflow).\n");
+ buf->state = UVC_BUF_STATE_DONE;
+ }
+ }
+
+ return 0;
+}
+
+void uvc_video_decode_isight(struct urb *urb, struct uvc_video_device *video,
+ struct uvc_buffer *buf)
+{
+ int ret, i;
+
+ for (i = 0; i < urb->number_of_packets; ++i) {
+ if (urb->iso_frame_desc[i].status < 0) {
+ uvc_trace(UVC_TRACE_FRAME, "USB isochronous frame "
+ "lost (%d).\n",
+ urb->iso_frame_desc[i].status);
+ }
+
+ /* Decode the payload packet.
+ * uvc_video_decode is entered twice when a frame transition
+ * has been detected because the end of frame can only be
+ * reliably detected when the first packet of the new frame
+ * is processed. The first pass detects the transition and
+ * closes the previous frame's buffer, the second pass
+ * processes the data of the first payload of the new frame.
+ */
+ do {
+ ret = isight_decode(&video->queue, buf,
+ urb->transfer_buffer +
+ urb->iso_frame_desc[i].offset,
+ urb->iso_frame_desc[i].actual_length);
+
+ if (buf == NULL)
+ break;
+
+ if (buf->state == UVC_BUF_STATE_DONE ||
+ buf->state == UVC_BUF_STATE_ERROR)
+ buf = uvc_queue_next_buffer(&video->queue, buf);
+ } while (ret == -EAGAIN);
+ }
+}
diff --git a/linux/drivers/media/video/uvc/uvc_queue.c b/linux/drivers/media/video/uvc/uvc_queue.c
new file mode 100644
index 000000000..7388d0cee
--- /dev/null
+++ b/linux/drivers/media/video/uvc/uvc_queue.c
@@ -0,0 +1,478 @@
+/*
+ * uvc_queue.c -- USB Video Class driver - Buffers management
+ *
+ * Copyright (C) 2005-2008
+ * Laurent Pinchart (laurent.pinchart@skynet.be)
+ *
+ * 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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/videodev2.h>
+#include <linux/vmalloc.h>
+#include <linux/wait.h>
+#include <asm/atomic.h>
+
+#include "uvcvideo.h"
+
+/* ------------------------------------------------------------------------
+ * Video buffers queue management.
+ *
+ * Video queues is initialized by uvc_queue_init(). The function performs
+ * basic initialization of the uvc_video_queue struct and never fails.
+ *
+ * Video buffer allocation and freeing are performed by uvc_alloc_buffers and
+ * uvc_free_buffers respectively. The former acquires the video queue lock,
+ * while the later must be called with the lock held (so that allocation can
+ * free previously allocated buffers). Trying to free buffers that are mapped
+ * to user space will return -EBUSY.
+ *
+ * Video buffers are managed using two queues. However, unlike most USB video
+ * drivers which use an in queue and an out queue, we use a main queue which
+ * holds all queued buffers (both 'empty' and 'done' buffers), and an irq
+ * queue which holds empty buffers. This design (copied from video-buf)
+ * minimizes locking in interrupt, as only one queue is shared between
+ * interrupt and user contexts.
+ *
+ * Use cases
+ * ---------
+ *
+ * Unless stated otherwise, all operations which modify the irq buffers queue
+ * are protected by the irq spinlock.
+ *
+ * 1. The user queues the buffers, starts streaming and dequeues a buffer.
+ *
+ * The buffers are added to the main and irq queues. Both operations are
+ * protected by the queue lock, and the latert is protected by the irq
+ * spinlock as well.
+ *
+ * The completion handler fetches a buffer from the irq queue and fills it
+ * with video data. If no buffer is available (irq queue empty), the handler
+ * returns immediately.
+ *
+ * When the buffer is full, the completion handler removes it from the irq
+ * queue, marks it as ready (UVC_BUF_STATE_DONE) and wake its wait queue.
+ * At that point, any process waiting on the buffer will be woken up. If a
+ * process tries to dequeue a buffer after it has been marked ready, the
+ * dequeing will succeed immediately.
+ *
+ * 2. Buffers are queued, user is waiting on a buffer and the device gets
+ * disconnected.
+ *
+ * When the device is disconnected, the kernel calls the completion handler
+ * with an appropriate status code. The handler marks all buffers in the
+ * irq queue as being erroneous (UVC_BUF_STATE_ERROR) and wakes them up so
+ * that any process waiting on a buffer gets woken up.
+ *
+ * Waking up up the first buffer on the irq list is not enough, as the
+ * process waiting on the buffer might restart the dequeue operation
+ * immediately.
+ *
+ */
+
+void uvc_queue_init(struct uvc_video_queue *queue)
+{
+ mutex_init(&queue->mutex);
+ spin_lock_init(&queue->irqlock);
+ INIT_LIST_HEAD(&queue->mainqueue);
+ INIT_LIST_HEAD(&queue->irqqueue);
+}
+
+/*
+ * Allocate the video buffers.
+ *
+ * Pages are reserved to make sure they will not be swaped, as they will be
+ * filled in URB completion handler.
+ *
+ * Buffers will be individually mapped, so they must all be page aligned.
+ */
+int uvc_alloc_buffers(struct uvc_video_queue *queue, unsigned int nbuffers,
+ unsigned int buflength)
+{
+ unsigned int bufsize = PAGE_ALIGN(buflength);
+ unsigned int i;
+ void *mem = NULL;
+ int ret;
+
+ if (nbuffers > UVC_MAX_VIDEO_BUFFERS)
+ nbuffers = UVC_MAX_VIDEO_BUFFERS;
+
+ mutex_lock(&queue->mutex);
+
+ if ((ret = uvc_free_buffers(queue)) < 0)
+ goto done;
+
+ /* Bail out if no buffers should be allocated. */
+ if (nbuffers == 0)
+ goto done;
+
+ /* Decrement the number of buffers until allocation succeeds. */
+ for (; nbuffers > 0; --nbuffers) {
+ mem = vmalloc_32(nbuffers * bufsize);
+ if (mem != NULL)
+ break;
+ }
+
+ if (mem == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ for (i = 0; i < nbuffers; ++i) {
+ memset(&queue->buffer[i], 0, sizeof queue->buffer[i]);
+ queue->buffer[i].buf.index = i;
+ queue->buffer[i].buf.m.offset = i * bufsize;
+ queue->buffer[i].buf.length = buflength;
+ queue->buffer[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ queue->buffer[i].buf.sequence = 0;
+ queue->buffer[i].buf.field = V4L2_FIELD_NONE;
+ queue->buffer[i].buf.memory = V4L2_MEMORY_MMAP;
+ queue->buffer[i].buf.flags = 0;
+ init_waitqueue_head(&queue->buffer[i].wait);
+ }
+
+ queue->mem = mem;
+ queue->count = nbuffers;
+ queue->buf_size = bufsize;
+ ret = nbuffers;
+
+done:
+ mutex_unlock(&queue->mutex);
+ return ret;
+}
+
+/*
+ * Free the video buffers.
+ *
+ * This function must be called with the queue lock held.
+ */
+int uvc_free_buffers(struct uvc_video_queue *queue)
+{
+ unsigned int i;
+
+ for (i = 0; i < queue->count; ++i) {
+ if (queue->buffer[i].vma_use_count != 0)
+ return -EBUSY;
+ }
+
+ if (queue->count) {
+ vfree(queue->mem);
+ queue->count = 0;
+ }
+
+ return 0;
+}
+
+static void __uvc_query_buffer(struct uvc_buffer *buf,
+ struct v4l2_buffer *v4l2_buf)
+{
+ memcpy(v4l2_buf, &buf->buf, sizeof *v4l2_buf);
+
+ if (buf->vma_use_count)
+ v4l2_buf->flags |= V4L2_BUF_FLAG_MAPPED;
+
+ switch (buf->state) {
+ case UVC_BUF_STATE_ERROR:
+ case UVC_BUF_STATE_DONE:
+ v4l2_buf->flags |= V4L2_BUF_FLAG_DONE;
+ break;
+ case UVC_BUF_STATE_QUEUED:
+ case UVC_BUF_STATE_ACTIVE:
+ v4l2_buf->flags |= V4L2_BUF_FLAG_QUEUED;
+ break;
+ case UVC_BUF_STATE_IDLE:
+ default:
+ break;
+ }
+}
+
+int uvc_query_buffer(struct uvc_video_queue *queue,
+ struct v4l2_buffer *v4l2_buf)
+{
+ int ret = 0;
+
+ mutex_lock(&queue->mutex);
+ if (v4l2_buf->index >= queue->count) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ __uvc_query_buffer(&queue->buffer[v4l2_buf->index], v4l2_buf);
+
+done:
+ mutex_unlock(&queue->mutex);
+ return ret;
+}
+
+/*
+ * Queue a video buffer. Attempting to queue a buffer that has already been
+ * queued will return -EINVAL.
+ */
+int uvc_queue_buffer(struct uvc_video_queue *queue,
+ struct v4l2_buffer *v4l2_buf)
+{
+ struct uvc_buffer *buf;
+ unsigned long flags;
+ int ret = 0;
+
+ uvc_trace(UVC_TRACE_CAPTURE, "Queuing buffer %u.\n", v4l2_buf->index);
+
+ if (v4l2_buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+ v4l2_buf->memory != V4L2_MEMORY_MMAP) {
+ uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer type (%u) "
+ "and/or memory (%u).\n", v4l2_buf->type,
+ v4l2_buf->memory);
+ return -EINVAL;
+ }
+
+ mutex_lock(&queue->mutex);
+ if (v4l2_buf->index >= queue->count) {
+ uvc_trace(UVC_TRACE_CAPTURE, "[E] Out of range index.\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ buf = &queue->buffer[v4l2_buf->index];
+ if (buf->state != UVC_BUF_STATE_IDLE) {
+ uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer state "
+ "(%u).\n", buf->state);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ spin_lock_irqsave(&queue->irqlock, flags);
+ if (queue->flags & UVC_QUEUE_DISCONNECTED) {
+ spin_unlock_irqrestore(&queue->irqlock, flags);
+ ret = -ENODEV;
+ goto done;
+ }
+ buf->state = UVC_BUF_STATE_QUEUED;
+ buf->buf.bytesused = 0;
+ list_add_tail(&buf->stream, &queue->mainqueue);
+ list_add_tail(&buf->queue, &queue->irqqueue);
+ spin_unlock_irqrestore(&queue->irqlock, flags);
+
+done:
+ mutex_unlock(&queue->mutex);
+ return ret;
+}
+
+static int uvc_queue_waiton(struct uvc_buffer *buf, int nonblocking)
+{
+ if (nonblocking) {
+ return (buf->state != UVC_BUF_STATE_QUEUED &&
+ buf->state != UVC_BUF_STATE_ACTIVE)
+ ? 0 : -EAGAIN;
+ }
+
+ return wait_event_interruptible(buf->wait,
+ buf->state != UVC_BUF_STATE_QUEUED &&
+ buf->state != UVC_BUF_STATE_ACTIVE);
+}
+
+/*
+ * Dequeue a video buffer. If nonblocking is false, block until a buffer is
+ * available.
+ */
+int uvc_dequeue_buffer(struct uvc_video_queue *queue,
+ struct v4l2_buffer *v4l2_buf, int nonblocking)
+{
+ struct uvc_buffer *buf;
+ int ret = 0;
+
+ if (v4l2_buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+ v4l2_buf->memory != V4L2_MEMORY_MMAP) {
+ uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer type (%u) "
+ "and/or memory (%u).\n", v4l2_buf->type,
+ v4l2_buf->memory);
+ return -EINVAL;
+ }
+
+ mutex_lock(&queue->mutex);
+ if (list_empty(&queue->mainqueue)) {
+ uvc_trace(UVC_TRACE_CAPTURE, "[E] Empty buffer queue.\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ buf = list_first_entry(&queue->mainqueue, struct uvc_buffer, stream);
+ if ((ret = uvc_queue_waiton(buf, nonblocking)) < 0)
+ goto done;
+
+ uvc_trace(UVC_TRACE_CAPTURE, "Dequeuing buffer %u (%u, %u bytes).\n",
+ buf->buf.index, buf->state, buf->buf.bytesused);
+
+ switch (buf->state) {
+ case UVC_BUF_STATE_ERROR:
+ uvc_trace(UVC_TRACE_CAPTURE, "[W] Corrupted data "
+ "(transmission error).\n");
+ ret = -EIO;
+ case UVC_BUF_STATE_DONE:
+ buf->state = UVC_BUF_STATE_IDLE;
+ break;
+
+ case UVC_BUF_STATE_IDLE:
+ case UVC_BUF_STATE_QUEUED:
+ case UVC_BUF_STATE_ACTIVE:
+ default:
+ uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer state %u "
+ "(driver bug?).\n", buf->state);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ list_del(&buf->stream);
+ __uvc_query_buffer(buf, v4l2_buf);
+
+done:
+ mutex_unlock(&queue->mutex);
+ return ret;
+}
+
+/*
+ * Poll the video queue.
+ *
+ * This function implements video queue polling and is intended to be used by
+ * the device poll handler.
+ */
+unsigned int uvc_queue_poll(struct uvc_video_queue *queue, struct file *file,
+ poll_table *wait)
+{
+ struct uvc_buffer *buf;
+ unsigned int mask = 0;
+
+ mutex_lock(&queue->mutex);
+ if (list_empty(&queue->mainqueue)) {
+ mask |= POLLERR;
+ goto done;
+ }
+ buf = list_first_entry(&queue->mainqueue, struct uvc_buffer, stream);
+
+ poll_wait(file, &buf->wait, wait);
+ if (buf->state == UVC_BUF_STATE_DONE ||
+ buf->state == UVC_BUF_STATE_ERROR)
+ mask |= POLLIN | POLLRDNORM;
+
+done:
+ mutex_unlock(&queue->mutex);
+ return mask;
+}
+
+/*
+ * Enable or disable the video buffers queue.
+ *
+ * The queue must be enabled before starting video acquisition and must be
+ * disabled after stopping it. This ensures that the video buffers queue
+ * state can be properly initialized before buffers are accessed from the
+ * interrupt handler.
+ *
+ * Enabling the video queue initializes parameters (such as sequence number,
+ * sync pattern, ...). If the queue is already enabled, return -EBUSY.
+ *
+ * Disabling the video queue cancels the queue and removes all buffers from
+ * the main queue.
+ *
+ * This function can't be called from interrupt context. Use
+ * uvc_queue_cancel() instead.
+ */
+int uvc_queue_enable(struct uvc_video_queue *queue, int enable)
+{
+ unsigned int i;
+ int ret = 0;
+
+ mutex_lock(&queue->mutex);
+ if (enable) {
+ if (uvc_queue_streaming(queue)) {
+ ret = -EBUSY;
+ goto done;
+ }
+ queue->sequence = 0;
+ queue->flags |= UVC_QUEUE_STREAMING;
+ } else {
+ uvc_queue_cancel(queue, 0);
+ INIT_LIST_HEAD(&queue->mainqueue);
+
+ for (i = 0; i < queue->count; ++i)
+ queue->buffer[i].state = UVC_BUF_STATE_IDLE;
+
+ queue->flags &= ~UVC_QUEUE_STREAMING;
+ }
+
+done:
+ mutex_unlock(&queue->mutex);
+ return ret;
+}
+
+/*
+ * Cancel the video buffers queue.
+ *
+ * Cancelling the queue marks all buffers on the irq queue as erroneous,
+ * wakes them up and remove them from the queue.
+ *
+ * If the disconnect parameter is set, further calls to uvc_queue_buffer will
+ * fail with -ENODEV.
+ *
+ * This function acquires the irq spinlock and can be called from interrupt
+ * context.
+ */
+void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect)
+{
+ struct uvc_buffer *buf;
+ unsigned long flags;
+
+ spin_lock_irqsave(&queue->irqlock, flags);
+ while (!list_empty(&queue->irqqueue)) {
+ buf = list_first_entry(&queue->irqqueue, struct uvc_buffer,
+ queue);
+ list_del(&buf->queue);
+ buf->state = UVC_BUF_STATE_ERROR;
+ wake_up(&buf->wait);
+ }
+ /* This must be protected by the irqlock spinlock to avoid race
+ * conditions between uvc_queue_buffer and the disconnection event that
+ * could result in an interruptible wait in uvc_dequeue_buffer. Do not
+ * blindly replace this logic by checking for the UVC_DEV_DISCONNECTED
+ * state outside the queue code.
+ */
+ if (disconnect)
+ queue->flags |= UVC_QUEUE_DISCONNECTED;
+ spin_unlock_irqrestore(&queue->irqlock, flags);
+}
+
+struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
+ struct uvc_buffer *buf)
+{
+ struct uvc_buffer *nextbuf;
+ unsigned long flags;
+
+ if ((queue->flags & UVC_QUEUE_DROP_INCOMPLETE) &&
+ buf->buf.length != buf->buf.bytesused) {
+ buf->state = UVC_BUF_STATE_QUEUED;
+ buf->buf.bytesused = 0;
+ return buf;
+ }
+
+ spin_lock_irqsave(&queue->irqlock, flags);
+ list_del(&buf->queue);
+ if (!list_empty(&queue->irqqueue))
+ nextbuf = list_first_entry(&queue->irqqueue, struct uvc_buffer,
+ queue);
+ else
+ nextbuf = NULL;
+ spin_unlock_irqrestore(&queue->irqlock, flags);
+
+ buf->buf.sequence = queue->sequence++;
+ do_gettimeofday(&buf->buf.timestamp);
+
+ wake_up(&buf->wait);
+ return nextbuf;
+}
+
diff --git a/linux/drivers/media/video/uvc/uvc_status.c b/linux/drivers/media/video/uvc/uvc_status.c
new file mode 100644
index 000000000..75e678ac5
--- /dev/null
+++ b/linux/drivers/media/video/uvc/uvc_status.c
@@ -0,0 +1,221 @@
+/*
+ * uvc_status.c -- USB Video Class driver - Status endpoint
+ *
+ * Copyright (C) 2007-2008
+ * Laurent Pinchart (laurent.pinchart@skynet.be)
+ *
+ * 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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/input.h>
+#include <linux/usb.h>
+#include <linux/usb/input.h>
+
+#include "uvcvideo.h"
+
+/* --------------------------------------------------------------------------
+ * Input device
+ */
+#ifdef CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV
+static int uvc_input_init(struct uvc_device *dev)
+{
+ struct usb_device *udev = dev->udev;
+ struct input_dev *input;
+ char *phys = NULL;
+ int ret;
+
+ input = input_allocate_device();
+ if (input == NULL)
+ return -ENOMEM;
+
+ phys = kmalloc(6 + strlen(udev->bus->bus_name) + strlen(udev->devpath),
+ GFP_KERNEL);
+ if (phys == NULL) {
+ ret = -ENOMEM;
+ goto error;
+ }
+ sprintf(phys, "usb-%s-%s", udev->bus->bus_name, udev->devpath);
+
+ input->name = dev->name;
+ input->phys = phys;
+ usb_to_input_id(udev, &input->id);
+ input->dev.parent = &dev->intf->dev;
+
+ set_bit(EV_KEY, input->evbit);
+ set_bit(BTN_0, input->keybit);
+
+ if ((ret = input_register_device(input)) < 0)
+ goto error;
+
+ dev->input = input;
+ return 0;
+
+error:
+ input_free_device(input);
+ kfree(phys);
+ return ret;
+}
+
+static void uvc_input_cleanup(struct uvc_device *dev)
+{
+ if (dev->input)
+ input_unregister_device(dev->input);
+}
+
+static void uvc_input_report_key(struct uvc_device *dev, unsigned int code,
+ int value)
+{
+ if (dev->input)
+ input_report_key(dev->input, code, value);
+}
+
+#else
+#define uvc_input_init(dev)
+#define uvc_input_cleanup(dev)
+#define uvc_input_report_key(dev, code, value)
+#endif /* CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV */
+
+/* --------------------------------------------------------------------------
+ * Status interrupt endpoint
+ */
+static void uvc_event_streaming(struct uvc_device *dev, __u8 *data, int len)
+{
+ if (len < 3) {
+ uvc_trace(UVC_TRACE_STATUS, "Invalid streaming status event "
+ "received.\n");
+ return;
+ }
+
+ if (data[2] == 0) {
+ if (len < 4)
+ return;
+ uvc_trace(UVC_TRACE_STATUS, "Button (intf %u) %s len %d\n",
+ data[1], data[3] ? "pressed" : "released", len);
+ uvc_input_report_key(dev, BTN_0, data[3]);
+ } else {
+ uvc_trace(UVC_TRACE_STATUS, "Stream %u error event %02x %02x "
+ "len %d.\n", data[1], data[2], data[3], len);
+ }
+}
+
+static void uvc_event_control(struct uvc_device *dev, __u8 *data, int len)
+{
+ char *attrs[3] = { "value", "info", "failure" };
+
+ if (len < 6 || data[2] != 0 || data[4] > 2) {
+ uvc_trace(UVC_TRACE_STATUS, "Invalid control status event "
+ "received.\n");
+ return;
+ }
+
+ uvc_trace(UVC_TRACE_STATUS, "Control %u/%u %s change len %d.\n",
+ data[1], data[3], attrs[data[4]], len);
+}
+
+static void uvc_status_complete(struct urb *urb)
+{
+ struct uvc_device *dev = urb->context;
+ int len, ret;
+
+ switch (urb->status) {
+ case 0:
+ break;
+
+ case -ENOENT: /* usb_kill_urb() called. */
+ case -ECONNRESET: /* usb_unlink_urb() called. */
+ case -ESHUTDOWN: /* The endpoint is being disabled. */
+ case -EPROTO: /* Device is disconnected (reported by some
+ * host controller). */
+ return;
+
+ default:
+ uvc_printk(KERN_WARNING, "Non-zero status (%d) in status "
+ "completion handler.\n", urb->status);
+ return;
+ }
+
+ len = urb->actual_length;
+ if (len > 0) {
+ switch (dev->status[0] & 0x0f) {
+ case UVC_STATUS_TYPE_CONTROL:
+ uvc_event_control(dev, dev->status, len);
+ break;
+
+ case UVC_STATUS_TYPE_STREAMING:
+ uvc_event_streaming(dev, dev->status, len);
+ break;
+
+ default:
+ uvc_printk(KERN_INFO, "unknown event type %u.\n",
+ dev->status[0]);
+ break;
+ }
+ }
+
+ /* Resubmit the URB. */
+ urb->interval = dev->int_ep->desc.bInterval;
+ if ((ret = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
+ uvc_printk(KERN_ERR, "Failed to resubmit status URB (%d).\n",
+ ret);
+ }
+}
+
+int uvc_status_init(struct uvc_device *dev)
+{
+ struct usb_host_endpoint *ep = dev->int_ep;
+ unsigned int pipe;
+ int interval;
+
+ if (ep == NULL)
+ return 0;
+
+ uvc_input_init(dev);
+
+ dev->int_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (dev->int_urb == NULL)
+ return -ENOMEM;
+
+ pipe = usb_rcvintpipe(dev->udev, ep->desc.bEndpointAddress);
+
+ /* For high-speed interrupt endpoints, the bInterval value is used as
+ * an exponent of two. Some developers forgot about it.
+ */
+ interval = ep->desc.bInterval;
+ if (interval > 16 && dev->udev->speed == USB_SPEED_HIGH &&
+ (dev->quirks & UVC_QUIRK_STATUS_INTERVAL))
+ interval = fls(interval) - 1;
+
+ usb_fill_int_urb(dev->int_urb, dev->udev, pipe,
+ dev->status, sizeof dev->status, uvc_status_complete,
+ dev, interval);
+
+ return usb_submit_urb(dev->int_urb, GFP_KERNEL);
+}
+
+void uvc_status_cleanup(struct uvc_device *dev)
+{
+ usb_kill_urb(dev->int_urb);
+ usb_free_urb(dev->int_urb);
+ uvc_input_cleanup(dev);
+}
+
+int uvc_status_suspend(struct uvc_device *dev)
+{
+ usb_kill_urb(dev->int_urb);
+ return 0;
+}
+
+int uvc_status_resume(struct uvc_device *dev)
+{
+ if (dev->int_urb == NULL)
+ return 0;
+
+ return usb_submit_urb(dev->int_urb, GFP_NOIO);
+}
+
diff --git a/linux/drivers/media/video/uvc/uvc_v4l2.c b/linux/drivers/media/video/uvc/uvc_v4l2.c
new file mode 100644
index 000000000..0456bbdcd
--- /dev/null
+++ b/linux/drivers/media/video/uvc/uvc_v4l2.c
@@ -0,0 +1,1106 @@
+/*
+ * uvc_v4l2.c -- USB Video Class driver - V4L2 API
+ *
+ * Copyright (C) 2005-2008
+ * Laurent Pinchart (laurent.pinchart@skynet.be)
+ *
+ * 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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/videodev2.h>
+#include <linux/vmalloc.h>
+#include <linux/mm.h>
+#include <linux/wait.h>
+#include <asm/atomic.h>
+
+#include <media/v4l2-common.h>
+
+#include "uvcvideo.h"
+
+/* ------------------------------------------------------------------------
+ * V4L2 interface
+ */
+
+/*
+ * Mapping V4L2 controls to UVC controls can be straighforward if done well.
+ * Most of the UVC controls exist in V4L2, and can be mapped directly. Some
+ * must be grouped (for instance the Red Balance, Blue Balance and Do White
+ * Balance V4L2 controls use the White Balance Component UVC control) or
+ * otherwise translated. The approach we take here is to use a translation
+ * table for the controls which can be mapped directly, and handle the others
+ * manually.
+ */
+static int uvc_v4l2_query_menu(struct uvc_video_device *video,
+ struct v4l2_querymenu *query_menu)
+{
+ struct uvc_menu_info *menu_info;
+ struct uvc_control_mapping *mapping;
+ struct uvc_control *ctrl;
+
+ ctrl = uvc_find_control(video, query_menu->id, &mapping);
+ if (ctrl == NULL || mapping->v4l2_type != V4L2_CTRL_TYPE_MENU)
+ return -EINVAL;
+
+ if (query_menu->index >= mapping->menu_count)
+ return -EINVAL;
+
+ menu_info = &mapping->menu_info[query_menu->index];
+ strncpy(query_menu->name, menu_info->name, 32);
+ return 0;
+}
+
+/*
+ * Find the frame interval closest to the requested frame interval for the
+ * given frame format and size. This should be done by the device as part of
+ * the Video Probe and Commit negotiation, but some hardware don't implement
+ * that feature.
+ */
+static __u32 uvc_try_frame_interval(struct uvc_frame *frame, __u32 interval)
+{
+ unsigned int i;
+
+ if (frame->bFrameIntervalType) {
+ __u32 best = -1, dist;
+
+ for (i = 0; i < frame->bFrameIntervalType; ++i) {
+ dist = interval > frame->dwFrameInterval[i]
+ ? interval - frame->dwFrameInterval[i]
+ : frame->dwFrameInterval[i] - interval;
+
+ if (dist > best)
+ break;
+
+ best = dist;
+ }
+
+ interval = frame->dwFrameInterval[i-1];
+ } else {
+ const __u32 min = frame->dwFrameInterval[0];
+ const __u32 max = frame->dwFrameInterval[1];
+ const __u32 step = frame->dwFrameInterval[2];
+
+ interval = min + (interval - min + step/2) / step * step;
+ if (interval > max)
+ interval = max;
+ }
+
+ return interval;
+}
+
+static int uvc_v4l2_try_format(struct uvc_video_device *video,
+ struct v4l2_format *fmt, struct uvc_streaming_control *probe,
+ struct uvc_format **uvc_format, struct uvc_frame **uvc_frame)
+{
+ struct uvc_format *format = NULL;
+ struct uvc_frame *frame = NULL;
+ __u16 rw, rh;
+ unsigned int d, maxd;
+ unsigned int i;
+ __u32 interval;
+ int ret = 0;
+ __u8 *fcc;
+
+ if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ fcc = (__u8 *)&fmt->fmt.pix.pixelformat;
+ uvc_trace(UVC_TRACE_FORMAT, "Trying format 0x%08x (%c%c%c%c): %ux%u.\n",
+ fmt->fmt.pix.pixelformat,
+ fcc[0], fcc[1], fcc[2], fcc[3],
+ fmt->fmt.pix.width, fmt->fmt.pix.height);
+
+ /* Check if the hardware supports the requested format. */
+ for (i = 0; i < video->streaming->nformats; ++i) {
+ format = &video->streaming->format[i];
+ if (format->fcc == fmt->fmt.pix.pixelformat)
+ break;
+ }
+
+ if (format == NULL || format->fcc != fmt->fmt.pix.pixelformat) {
+ uvc_trace(UVC_TRACE_FORMAT, "Unsupported format 0x%08x.\n",
+ fmt->fmt.pix.pixelformat);
+ return -EINVAL;
+ }
+
+ /* Find the closest image size. The distance between image sizes is
+ * the size in pixels of the non-overlapping regions between the
+ * requested size and the frame-specified size.
+ */
+ rw = fmt->fmt.pix.width;
+ rh = fmt->fmt.pix.height;
+ maxd = (unsigned int)-1;
+
+ for (i = 0; i < format->nframes; ++i) {
+ __u16 w = format->frame[i].wWidth;
+ __u16 h = format->frame[i].wHeight;
+
+ d = min(w, rw) * min(h, rh);
+ d = w*h + rw*rh - 2*d;
+ if (d < maxd) {
+ maxd = d;
+ frame = &format->frame[i];
+ }
+
+ if (maxd == 0)
+ break;
+ }
+
+ if (frame == NULL) {
+ uvc_trace(UVC_TRACE_FORMAT, "Unsupported size %ux%u.\n",
+ fmt->fmt.pix.width, fmt->fmt.pix.height);
+ return -EINVAL;
+ }
+
+ /* Use the default frame interval. */
+ interval = frame->dwDefaultFrameInterval;
+ uvc_trace(UVC_TRACE_FORMAT, "Using default frame interval %u.%u us "
+ "(%u.%u fps).\n", interval/10, interval%10, 10000000/interval,
+ (100000000/interval)%10);
+
+ /* Set the format index, frame index and frame interval. */
+ memset(probe, 0, sizeof *probe);
+ probe->bmHint = 1; /* dwFrameInterval */
+ probe->bFormatIndex = format->index;
+ probe->bFrameIndex = frame->bFrameIndex;
+ probe->dwFrameInterval = uvc_try_frame_interval(frame, interval);
+ /* Some webcams stall the probe control set request when the
+ * dwMaxVideoFrameSize field is set to zero. The UVC specification
+ * clearly states that the field is read-only from the host, so this
+ * is a webcam bug. Set dwMaxVideoFrameSize to the value reported by
+ * the webcam to work around the problem.
+ *
+ * The workaround could probably be enabled for all webcams, so the
+ * quirk can be removed if needed. It's currently useful to detect
+ * webcam bugs and fix them before they hit the market (providing
+ * developers test their webcams with the Linux driver as well as with
+ * the Windows driver).
+ */
+ if (video->dev->quirks & UVC_QUIRK_PROBE_EXTRAFIELDS)
+ probe->dwMaxVideoFrameSize =
+ video->streaming->ctrl.dwMaxVideoFrameSize;
+
+ /* Probe the device */
+ if ((ret = uvc_probe_video(video, probe)) < 0)
+ goto done;
+
+ fmt->fmt.pix.width = frame->wWidth;
+ fmt->fmt.pix.height = frame->wHeight;
+ fmt->fmt.pix.field = V4L2_FIELD_NONE;
+ fmt->fmt.pix.bytesperline = format->bpp * frame->wWidth / 8;
+ fmt->fmt.pix.sizeimage = probe->dwMaxVideoFrameSize;
+ fmt->fmt.pix.colorspace = format->colorspace;
+ fmt->fmt.pix.priv = 0;
+
+ if (uvc_format != NULL)
+ *uvc_format = format;
+ if (uvc_frame != NULL)
+ *uvc_frame = frame;
+
+done:
+ return ret;
+}
+
+static int uvc_v4l2_get_format(struct uvc_video_device *video,
+ struct v4l2_format *fmt)
+{
+ struct uvc_format *format = video->streaming->cur_format;
+ struct uvc_frame *frame = video->streaming->cur_frame;
+
+ if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ if (format == NULL || frame == NULL)
+ return -EINVAL;
+
+ fmt->fmt.pix.pixelformat = format->fcc;
+ fmt->fmt.pix.width = frame->wWidth;
+ fmt->fmt.pix.height = frame->wHeight;
+ fmt->fmt.pix.field = V4L2_FIELD_NONE;
+ fmt->fmt.pix.bytesperline = format->bpp * frame->wWidth / 8;
+ fmt->fmt.pix.sizeimage = video->streaming->ctrl.dwMaxVideoFrameSize;
+ fmt->fmt.pix.colorspace = format->colorspace;
+ fmt->fmt.pix.priv = 0;
+
+ return 0;
+}
+
+static int uvc_v4l2_set_format(struct uvc_video_device *video,
+ struct v4l2_format *fmt)
+{
+ struct uvc_streaming_control probe;
+ struct uvc_format *format;
+ struct uvc_frame *frame;
+ int ret;
+
+ if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ if (uvc_queue_streaming(&video->queue))
+ return -EBUSY;
+
+ ret = uvc_v4l2_try_format(video, fmt, &probe, &format, &frame);
+ if (ret < 0)
+ return ret;
+
+ if ((ret = uvc_set_video_ctrl(video, &probe, 0)) < 0)
+ return ret;
+
+ memcpy(&video->streaming->ctrl, &probe, sizeof probe);
+ video->streaming->cur_format = format;
+ video->streaming->cur_frame = frame;
+
+ return 0;
+}
+
+static int uvc_v4l2_get_streamparm(struct uvc_video_device *video,
+ struct v4l2_streamparm *parm)
+{
+ uint32_t numerator, denominator;
+
+ if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ numerator = video->streaming->ctrl.dwFrameInterval;
+ denominator = 10000000;
+ uvc_simplify_fraction(&numerator, &denominator, 8, 333);
+
+ memset(parm, 0, sizeof *parm);
+ parm->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
+ parm->parm.capture.capturemode = 0;
+ parm->parm.capture.timeperframe.numerator = numerator;
+ parm->parm.capture.timeperframe.denominator = denominator;
+ parm->parm.capture.extendedmode = 0;
+ parm->parm.capture.readbuffers = 0;
+
+ return 0;
+}
+
+static int uvc_v4l2_set_streamparm(struct uvc_video_device *video,
+ struct v4l2_streamparm *parm)
+{
+ struct uvc_frame *frame = video->streaming->cur_frame;
+ struct uvc_streaming_control probe;
+ uint32_t interval;
+ int ret;
+
+ if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ if (uvc_queue_streaming(&video->queue))
+ return -EBUSY;
+
+ memcpy(&probe, &video->streaming->ctrl, sizeof probe);
+ interval = uvc_fraction_to_interval(
+ parm->parm.capture.timeperframe.numerator,
+ parm->parm.capture.timeperframe.denominator);
+
+ uvc_trace(UVC_TRACE_FORMAT, "Setting frame interval to %u/%u (%u).\n",
+ parm->parm.capture.timeperframe.numerator,
+ parm->parm.capture.timeperframe.denominator,
+ interval);
+ probe.dwFrameInterval = uvc_try_frame_interval(frame, interval);
+
+ /* Probe the device with the new settings. */
+ if ((ret = uvc_probe_video(video, &probe)) < 0)
+ return ret;
+
+ /* Commit the new settings. */
+ if ((ret = uvc_set_video_ctrl(video, &probe, 0)) < 0)
+ return ret;
+
+ memcpy(&video->streaming->ctrl, &probe, sizeof probe);
+
+ /* Return the actual frame period. */
+ parm->parm.capture.timeperframe.numerator = probe.dwFrameInterval;
+ parm->parm.capture.timeperframe.denominator = 10000000;
+ uvc_simplify_fraction(&parm->parm.capture.timeperframe.numerator,
+ &parm->parm.capture.timeperframe.denominator,
+ 8, 333);
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------------
+ * Privilege management
+ */
+
+/*
+ * Privilege management is the multiple-open implementation basis. The current
+ * implementation is completely transparent for the end-user and doesn't
+ * require explicit use of the VIDIOC_G_PRIORITY and VIDIOC_S_PRIORITY ioctls.
+ * Those ioctls enable finer control on the device (by making possible for a
+ * user to request exclusive access to a device), but are not mature yet.
+ * Switching to the V4L2 priority mechanism might be considered in the future
+ * if this situation changes.
+ *
+ * Each open instance of a UVC device can either be in a privileged or
+ * unprivileged state. Only a single instance can be in a privileged state at
+ * a given time. Trying to perform an operation which requires privileges will
+ * automatically acquire the required privileges if possible, or return -EBUSY
+ * otherwise. Privileges are dismissed when closing the instance.
+ *
+ * Operations which require privileges are:
+ *
+ * - VIDIOC_S_INPUT
+ * - VIDIOC_S_PARM
+ * - VIDIOC_S_FMT
+ * - VIDIOC_TRY_FMT
+ * - VIDIOC_REQBUFS
+ */
+static int uvc_acquire_privileges(struct uvc_fh *handle)
+{
+ int ret = 0;
+
+ /* Always succeed if the handle is already privileged. */
+ if (handle->state == UVC_HANDLE_ACTIVE)
+ return 0;
+
+ /* Check if the device already has a privileged handle. */
+ mutex_lock(&uvc_driver.open_mutex);
+ if (atomic_inc_return(&handle->device->active) != 1) {
+ atomic_dec(&handle->device->active);
+ ret = -EBUSY;
+ goto done;
+ }
+
+ handle->state = UVC_HANDLE_ACTIVE;
+
+done:
+ mutex_unlock(&uvc_driver.open_mutex);
+ return ret;
+}
+
+static void uvc_dismiss_privileges(struct uvc_fh *handle)
+{
+ if (handle->state == UVC_HANDLE_ACTIVE)
+ atomic_dec(&handle->device->active);
+
+ handle->state = UVC_HANDLE_PASSIVE;
+}
+
+static int uvc_has_privileges(struct uvc_fh *handle)
+{
+ return handle->state == UVC_HANDLE_ACTIVE;
+}
+
+/* ------------------------------------------------------------------------
+ * V4L2 file operations
+ */
+
+static int uvc_v4l2_open(struct inode *inode, struct file *file)
+{
+ struct video_device *vdev;
+ struct uvc_video_device *video;
+ struct uvc_fh *handle;
+ int ret = 0;
+
+ uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_open\n");
+ mutex_lock(&uvc_driver.open_mutex);
+ vdev = video_devdata(file);
+ video = video_get_drvdata(vdev);
+
+ if (video->dev->state & UVC_DEV_DISCONNECTED) {
+ ret = -ENODEV;
+ goto done;
+ }
+
+ ret = usb_autopm_get_interface(video->dev->intf);
+ if (ret < 0)
+ goto done;
+
+ /* Create the device handle. */
+ handle = kzalloc(sizeof *handle, GFP_KERNEL);
+ if (handle == NULL) {
+ usb_autopm_put_interface(video->dev->intf);
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ handle->device = video;
+ handle->state = UVC_HANDLE_PASSIVE;
+ file->private_data = handle;
+
+ kref_get(&video->dev->kref);
+
+done:
+ mutex_unlock(&uvc_driver.open_mutex);
+ return ret;
+}
+
+static int uvc_v4l2_release(struct inode *inode, struct file *file)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct uvc_video_device *video = video_get_drvdata(vdev);
+ struct uvc_fh *handle = (struct uvc_fh *)file->private_data;
+
+ uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_release\n");
+
+ /* Only free resources if this is a privileged handle. */
+ if (uvc_has_privileges(handle)) {
+ uvc_video_enable(video, 0);
+
+ mutex_lock(&video->queue.mutex);
+ if (uvc_free_buffers(&video->queue) < 0)
+ uvc_printk(KERN_ERR, "uvc_v4l2_release: Unable to "
+ "free buffers.\n");
+ mutex_unlock(&video->queue.mutex);
+ }
+
+ /* Release the file handle. */
+ uvc_dismiss_privileges(handle);
+ kfree(handle);
+ file->private_data = NULL;
+
+ usb_autopm_put_interface(video->dev->intf);
+ kref_put(&video->dev->kref, uvc_delete);
+ return 0;
+}
+
+static int uvc_v4l2_do_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, void *arg)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct uvc_video_device *video = video_get_drvdata(vdev);
+ struct uvc_fh *handle = (struct uvc_fh *)file->private_data;
+ int ret = 0;
+
+ if (uvc_trace_param & UVC_TRACE_IOCTL)
+ v4l_printk_ioctl(cmd);
+
+ switch (cmd) {
+ /* Query capabilities */
+ case VIDIOC_QUERYCAP:
+ {
+ struct v4l2_capability *cap = arg;
+
+ memset(cap, 0, sizeof *cap);
+ strncpy(cap->driver, "uvcvideo", sizeof cap->driver);
+ strncpy(cap->card, vdev->name, 32);
+ strncpy(cap->bus_info, video->dev->udev->bus->bus_name,
+ sizeof cap->bus_info);
+ cap->version = DRIVER_VERSION_NUMBER;
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE
+ | V4L2_CAP_STREAMING;
+ break;
+ }
+
+ /* Get, Set & Query control */
+ case VIDIOC_QUERYCTRL:
+ return uvc_query_v4l2_ctrl(video, arg);
+
+ case VIDIOC_G_CTRL:
+ {
+ struct v4l2_control *ctrl = arg;
+ struct v4l2_ext_control xctrl;
+
+ memset(&xctrl, 0, sizeof xctrl);
+ xctrl.id = ctrl->id;
+
+ uvc_ctrl_begin(video);
+ ret = uvc_ctrl_get(video, &xctrl);
+ uvc_ctrl_rollback(video);
+ if (ret >= 0)
+ ctrl->value = xctrl.value;
+ break;
+ }
+
+ case VIDIOC_S_CTRL:
+ {
+ struct v4l2_control *ctrl = arg;
+ struct v4l2_ext_control xctrl;
+
+ memset(&xctrl, 0, sizeof xctrl);
+ xctrl.id = ctrl->id;
+ xctrl.value = ctrl->value;
+
+ uvc_ctrl_begin(video);
+ ret = uvc_ctrl_set(video, &xctrl);
+ if (ret < 0) {
+ uvc_ctrl_rollback(video);
+ return ret;
+ }
+ ret = uvc_ctrl_commit(video);
+ break;
+ }
+
+ case VIDIOC_QUERYMENU:
+ return uvc_v4l2_query_menu(video, arg);
+
+ case VIDIOC_G_EXT_CTRLS:
+ {
+ struct v4l2_ext_controls *ctrls = arg;
+ struct v4l2_ext_control *ctrl = ctrls->controls;
+ unsigned int i;
+
+ uvc_ctrl_begin(video);
+ for (i = 0; i < ctrls->count; ++ctrl, ++i) {
+ ret = uvc_ctrl_get(video, ctrl);
+ if (ret < 0) {
+ uvc_ctrl_rollback(video);
+ ctrls->error_idx = i;
+ return ret;
+ }
+ }
+ ctrls->error_idx = 0;
+ ret = uvc_ctrl_rollback(video);
+ break;
+ }
+
+ case VIDIOC_S_EXT_CTRLS:
+ case VIDIOC_TRY_EXT_CTRLS:
+ {
+ struct v4l2_ext_controls *ctrls = arg;
+ struct v4l2_ext_control *ctrl = ctrls->controls;
+ unsigned int i;
+
+ ret = uvc_ctrl_begin(video);
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < ctrls->count; ++ctrl, ++i) {
+ ret = uvc_ctrl_set(video, ctrl);
+ if (ret < 0) {
+ uvc_ctrl_rollback(video);
+ ctrls->error_idx = i;
+ return ret;
+ }
+ }
+
+ ctrls->error_idx = 0;
+
+ if (cmd == VIDIOC_S_EXT_CTRLS)
+ ret = uvc_ctrl_commit(video);
+ else
+ ret = uvc_ctrl_rollback(video);
+ break;
+ }
+
+ /* Get, Set & Enum input */
+ case VIDIOC_ENUMINPUT:
+ {
+ const struct uvc_entity *selector = video->selector;
+ struct v4l2_input *input = arg;
+ struct uvc_entity *iterm = NULL;
+ u32 index = input->index;
+ int pin = 0;
+
+ if (selector == NULL ||
+ (video->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) {
+ if (index != 0)
+ return -EINVAL;
+ iterm = list_first_entry(&video->iterms,
+ struct uvc_entity, chain);
+ pin = iterm->id;
+ } else if (pin < selector->selector.bNrInPins) {
+ pin = selector->selector.baSourceID[index];
+ list_for_each_entry(iterm, video->iterms.next, chain) {
+ if (iterm->id == pin)
+ break;
+ }
+ }
+
+ if (iterm == NULL || iterm->id != pin)
+ return -EINVAL;
+
+ memset(input, 0, sizeof *input);
+ input->index = index;
+ strncpy(input->name, iterm->name, sizeof input->name);
+ if (UVC_ENTITY_TYPE(iterm) == ITT_CAMERA)
+ input->type = V4L2_INPUT_TYPE_CAMERA;
+ break;
+ }
+
+ case VIDIOC_G_INPUT:
+ {
+ u8 input;
+
+ if (video->selector == NULL ||
+ (video->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) {
+ *(int *)arg = 0;
+ break;
+ }
+
+ ret = uvc_query_ctrl(video->dev, GET_CUR, video->selector->id,
+ video->dev->intfnum, SU_INPUT_SELECT_CONTROL,
+ &input, 1);
+ if (ret < 0)
+ return ret;
+
+ *(int *)arg = input - 1;
+ break;
+ }
+
+ case VIDIOC_S_INPUT:
+ {
+ u8 input = *(u32 *)arg + 1;
+
+ if ((ret = uvc_acquire_privileges(handle)) < 0)
+ return ret;
+
+ if (video->selector == NULL ||
+ (video->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) {
+ if (input != 1)
+ return -EINVAL;
+ break;
+ }
+
+ if (input > video->selector->selector.bNrInPins)
+ return -EINVAL;
+
+ return uvc_query_ctrl(video->dev, SET_CUR, video->selector->id,
+ video->dev->intfnum, SU_INPUT_SELECT_CONTROL,
+ &input, 1);
+ }
+
+ /* Try, Get, Set & Enum format */
+ case VIDIOC_ENUM_FMT:
+ {
+ struct v4l2_fmtdesc *fmt = arg;
+ struct uvc_format *format;
+
+ if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+ fmt->index >= video->streaming->nformats)
+ return -EINVAL;
+
+ format = &video->streaming->format[fmt->index];
+ fmt->flags = 0;
+ if (format->flags & UVC_FMT_FLAG_COMPRESSED)
+ fmt->flags |= V4L2_FMT_FLAG_COMPRESSED;
+ strncpy(fmt->description, format->name,
+ sizeof fmt->description);
+ fmt->description[sizeof fmt->description - 1] = 0;
+ fmt->pixelformat = format->fcc;
+ break;
+ }
+
+ case VIDIOC_TRY_FMT:
+ {
+ struct uvc_streaming_control probe;
+
+ if ((ret = uvc_acquire_privileges(handle)) < 0)
+ return ret;
+
+ return uvc_v4l2_try_format(video, arg, &probe, NULL, NULL);
+ }
+
+ case VIDIOC_S_FMT:
+ if ((ret = uvc_acquire_privileges(handle)) < 0)
+ return ret;
+
+ return uvc_v4l2_set_format(video, arg);
+
+ case VIDIOC_G_FMT:
+ return uvc_v4l2_get_format(video, arg);
+
+ /* Frame size enumeration */
+ case VIDIOC_ENUM_FRAMESIZES:
+ {
+ struct v4l2_frmsizeenum *fsize = arg;
+ struct uvc_format *format = NULL;
+ struct uvc_frame *frame;
+ int i;
+
+ /* Look for the given pixel format */
+ for (i = 0; i < video->streaming->nformats; i++) {
+ if (video->streaming->format[i].fcc ==
+ fsize->pixel_format) {
+ format = &video->streaming->format[i];
+ break;
+ }
+ }
+ if (format == NULL)
+ return -EINVAL;
+
+ if (fsize->index >= format->nframes)
+ return -EINVAL;
+
+ frame = &format->frame[fsize->index];
+ fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+ fsize->discrete.width = frame->wWidth;
+ fsize->discrete.height = frame->wHeight;
+ break;
+ }
+
+ /* Frame interval enumeration */
+ case VIDIOC_ENUM_FRAMEINTERVALS:
+ {
+ struct v4l2_frmivalenum *fival = arg;
+ struct uvc_format *format = NULL;
+ struct uvc_frame *frame = NULL;
+ int i;
+
+ /* Look for the given pixel format and frame size */
+ for (i = 0; i < video->streaming->nformats; i++) {
+ if (video->streaming->format[i].fcc ==
+ fival->pixel_format) {
+ format = &video->streaming->format[i];
+ break;
+ }
+ }
+ if (format == NULL)
+ return -EINVAL;
+
+ for (i = 0; i < format->nframes; i++) {
+ if (format->frame[i].wWidth == fival->width &&
+ format->frame[i].wHeight == fival->height) {
+ frame = &format->frame[i];
+ break;
+ }
+ }
+ if (frame == NULL)
+ return -EINVAL;
+
+ if (frame->bFrameIntervalType) {
+ if (fival->index >= frame->bFrameIntervalType)
+ return -EINVAL;
+
+ fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
+ fival->discrete.numerator =
+ frame->dwFrameInterval[fival->index];
+ fival->discrete.denominator = 10000000;
+ uvc_simplify_fraction(&fival->discrete.numerator,
+ &fival->discrete.denominator, 8, 333);
+ } else {
+ fival->type = V4L2_FRMIVAL_TYPE_STEPWISE;
+ fival->stepwise.min.numerator =
+ frame->dwFrameInterval[0];
+ fival->stepwise.min.denominator = 10000000;
+ fival->stepwise.max.numerator =
+ frame->dwFrameInterval[1];
+ fival->stepwise.max.denominator = 10000000;
+ fival->stepwise.step.numerator =
+ frame->dwFrameInterval[2];
+ fival->stepwise.step.denominator = 10000000;
+ uvc_simplify_fraction(&fival->stepwise.min.numerator,
+ &fival->stepwise.min.denominator, 8, 333);
+ uvc_simplify_fraction(&fival->stepwise.max.numerator,
+ &fival->stepwise.max.denominator, 8, 333);
+ uvc_simplify_fraction(&fival->stepwise.step.numerator,
+ &fival->stepwise.step.denominator, 8, 333);
+ }
+ break;
+ }
+
+ /* Get & Set streaming parameters */
+ case VIDIOC_G_PARM:
+ return uvc_v4l2_get_streamparm(video, arg);
+
+ case VIDIOC_S_PARM:
+ if ((ret = uvc_acquire_privileges(handle)) < 0)
+ return ret;
+
+ return uvc_v4l2_set_streamparm(video, arg);
+
+ /* Cropping and scaling */
+ case VIDIOC_CROPCAP:
+ {
+ struct v4l2_cropcap *ccap = arg;
+ struct uvc_frame *frame = video->streaming->cur_frame;
+
+ if (ccap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ ccap->bounds.left = 0;
+ ccap->bounds.top = 0;
+ ccap->bounds.width = frame->wWidth;
+ ccap->bounds.height = frame->wHeight;
+
+ ccap->defrect = ccap->bounds;
+
+ ccap->pixelaspect.numerator = 1;
+ ccap->pixelaspect.denominator = 1;
+ break;
+ }
+
+ case VIDIOC_G_CROP:
+ case VIDIOC_S_CROP:
+ return -EINVAL;
+
+ /* Buffers & streaming */
+ case VIDIOC_REQBUFS:
+ {
+ struct v4l2_requestbuffers *rb = arg;
+ unsigned int bufsize =
+ video->streaming->ctrl.dwMaxVideoFrameSize;
+
+ if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+ rb->memory != V4L2_MEMORY_MMAP)
+ return -EINVAL;
+
+ if ((ret = uvc_acquire_privileges(handle)) < 0)
+ return ret;
+
+ ret = uvc_alloc_buffers(&video->queue, rb->count, bufsize);
+ if (ret < 0)
+ return ret;
+
+ if (!(video->streaming->cur_format->flags &
+ UVC_FMT_FLAG_COMPRESSED))
+ video->queue.flags |= UVC_QUEUE_DROP_INCOMPLETE;
+
+ rb->count = ret;
+ ret = 0;
+ break;
+ }
+
+ case VIDIOC_QUERYBUF:
+ {
+ struct v4l2_buffer *buf = arg;
+
+ if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ if (!uvc_has_privileges(handle))
+ return -EBUSY;
+
+ return uvc_query_buffer(&video->queue, buf);
+ }
+
+ case VIDIOC_QBUF:
+ if (!uvc_has_privileges(handle))
+ return -EBUSY;
+
+ return uvc_queue_buffer(&video->queue, arg);
+
+ case VIDIOC_DQBUF:
+ if (!uvc_has_privileges(handle))
+ return -EBUSY;
+
+ return uvc_dequeue_buffer(&video->queue, arg,
+ file->f_flags & O_NONBLOCK);
+
+ case VIDIOC_STREAMON:
+ {
+ int *type = arg;
+
+ if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ if (!uvc_has_privileges(handle))
+ return -EBUSY;
+
+ if ((ret = uvc_video_enable(video, 1)) < 0)
+ return ret;
+ break;
+ }
+
+ case VIDIOC_STREAMOFF:
+ {
+ int *type = arg;
+
+ if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ if (!uvc_has_privileges(handle))
+ return -EBUSY;
+
+ return uvc_video_enable(video, 0);
+ }
+
+ /* Analog video standards make no sense for digital cameras. */
+ case VIDIOC_ENUMSTD:
+ case VIDIOC_QUERYSTD:
+ case VIDIOC_G_STD:
+ case VIDIOC_S_STD:
+
+ case VIDIOC_OVERLAY:
+
+ case VIDIOC_ENUMAUDIO:
+ case VIDIOC_ENUMAUDOUT:
+
+ case VIDIOC_ENUMOUTPUT:
+ uvc_trace(UVC_TRACE_IOCTL, "Unsupported ioctl 0x%08x\n", cmd);
+ return -EINVAL;
+
+ /* Dynamic controls. */
+ case UVCIOC_CTRL_ADD:
+ {
+ struct uvc_xu_control_info *xinfo = arg;
+ struct uvc_control_info *info;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ info = kmalloc(sizeof *info, GFP_KERNEL);
+ if (info == NULL)
+ return -ENOMEM;
+
+ memcpy(info->entity, xinfo->entity, sizeof info->entity);
+ info->index = xinfo->index;
+ info->selector = xinfo->selector;
+ info->size = xinfo->size;
+ info->flags = xinfo->flags;
+
+ info->flags |= UVC_CONTROL_GET_MIN | UVC_CONTROL_GET_MAX |
+ UVC_CONTROL_GET_RES | UVC_CONTROL_GET_DEF;
+
+ ret = uvc_ctrl_add_info(info);
+ if (ret < 0)
+ kfree(info);
+ break;
+ }
+
+ case UVCIOC_CTRL_MAP:
+ {
+ struct uvc_xu_control_mapping *xmap = arg;
+ struct uvc_control_mapping *map;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ map = kmalloc(sizeof *map, GFP_KERNEL);
+ if (map == NULL)
+ return -ENOMEM;
+
+ map->id = xmap->id;
+ memcpy(map->name, xmap->name, sizeof map->name);
+ memcpy(map->entity, xmap->entity, sizeof map->entity);
+ map->selector = xmap->selector;
+ map->size = xmap->size;
+ map->offset = xmap->offset;
+ map->v4l2_type = xmap->v4l2_type;
+ map->data_type = xmap->data_type;
+
+ ret = uvc_ctrl_add_mapping(map);
+ if (ret < 0)
+ kfree(map);
+ break;
+ }
+
+ case UVCIOC_CTRL_GET:
+ return uvc_xu_ctrl_query(video, arg, 0);
+
+ case UVCIOC_CTRL_SET:
+ return uvc_xu_ctrl_query(video, arg, 1);
+
+ default:
+ if ((ret = v4l_compat_translate_ioctl(inode, file, cmd, arg,
+ uvc_v4l2_do_ioctl)) == -ENOIOCTLCMD)
+ uvc_trace(UVC_TRACE_IOCTL, "Unknown ioctl 0x%08x\n",
+ cmd);
+ return ret;
+ }
+
+ return ret;
+}
+
+static int uvc_v4l2_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_ioctl\n");
+ return video_usercopy(inode, file, cmd, arg, uvc_v4l2_do_ioctl);
+}
+
+static ssize_t uvc_v4l2_read(struct file *file, char __user *data,
+ size_t count, loff_t *ppos)
+{
+ uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_read: not implemented.\n");
+ return -ENODEV;
+}
+
+/*
+ * VMA operations.
+ */
+static void uvc_vm_open(struct vm_area_struct *vma)
+{
+ struct uvc_buffer *buffer = vma->vm_private_data;
+ buffer->vma_use_count++;
+}
+
+static void uvc_vm_close(struct vm_area_struct *vma)
+{
+ struct uvc_buffer *buffer = vma->vm_private_data;
+ buffer->vma_use_count--;
+}
+
+static struct vm_operations_struct uvc_vm_ops = {
+ .open = uvc_vm_open,
+ .close = uvc_vm_close,
+};
+
+static int uvc_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct uvc_video_device *video = video_get_drvdata(vdev);
+ struct uvc_buffer *buffer;
+ struct page *page;
+ unsigned long addr, start, size;
+ unsigned int i;
+ int ret = 0;
+
+ uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_mmap\n");
+
+ start = vma->vm_start;
+ size = vma->vm_end - vma->vm_start;
+
+ mutex_lock(&video->queue.mutex);
+
+ for (i = 0; i < video->queue.count; ++i) {
+ buffer = &video->queue.buffer[i];
+ if ((buffer->buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff)
+ break;
+ }
+
+ if (i == video->queue.count || size != video->queue.buf_size) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ /*
+ * VM_IO marks the area as being an mmaped region for I/O to a
+ * device. It also prevents the region from being core dumped.
+ */
+ vma->vm_flags |= VM_IO;
+
+ addr = (unsigned long)video->queue.mem + buffer->buf.m.offset;
+ while (size > 0) {
+ page = vmalloc_to_page((void *)addr);
+ if ((ret = vm_insert_page(vma, start, page)) < 0)
+ goto done;
+
+ start += PAGE_SIZE;
+ addr += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
+
+ vma->vm_ops = &uvc_vm_ops;
+ vma->vm_private_data = buffer;
+ uvc_vm_open(vma);
+
+done:
+ mutex_unlock(&video->queue.mutex);
+ return ret;
+}
+
+static unsigned int uvc_v4l2_poll(struct file *file, poll_table *wait)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct uvc_video_device *video = video_get_drvdata(vdev);
+
+ uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_poll\n");
+
+ return uvc_queue_poll(&video->queue, file, wait);
+}
+
+struct file_operations uvc_fops = {
+ .owner = THIS_MODULE,
+ .open = uvc_v4l2_open,
+ .release = uvc_v4l2_release,
+ .ioctl = uvc_v4l2_ioctl,
+ .compat_ioctl = v4l_compat_ioctl32,
+ .llseek = no_llseek,
+ .read = uvc_v4l2_read,
+ .mmap = uvc_v4l2_mmap,
+ .poll = uvc_v4l2_poll,
+};
+
diff --git a/linux/drivers/media/video/uvc/uvc_video.c b/linux/drivers/media/video/uvc/uvc_video.c
new file mode 100644
index 000000000..ad63794fd
--- /dev/null
+++ b/linux/drivers/media/video/uvc/uvc_video.c
@@ -0,0 +1,967 @@
+/*
+ * uvc_video.c -- USB Video Class driver - Video handling
+ *
+ * Copyright (C) 2005-2008
+ * Laurent Pinchart (laurent.pinchart@skynet.be)
+ *
+ * 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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/videodev2.h>
+#include <linux/vmalloc.h>
+#include <linux/wait.h>
+#include <asm/atomic.h>
+#include <asm/unaligned.h>
+
+#include <media/v4l2-common.h>
+
+#include "uvcvideo.h"
+
+/* ------------------------------------------------------------------------
+ * UVC Controls
+ */
+
+static int __uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
+ __u8 intfnum, __u8 cs, void *data, __u16 size,
+ int timeout)
+{
+ __u8 type = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+ unsigned int pipe;
+ int ret;
+
+ pipe = (query & 0x80) ? usb_rcvctrlpipe(dev->udev, 0)
+ : usb_sndctrlpipe(dev->udev, 0);
+ type |= (query & 0x80) ? USB_DIR_IN : USB_DIR_OUT;
+
+ ret = usb_control_msg(dev->udev, pipe, query, type, cs << 8,
+ unit << 8 | intfnum, data, size, timeout);
+
+ if (ret != size) {
+ uvc_printk(KERN_ERR, "Failed to query (%u) UVC control %u "
+ "(unit %u) : %d (exp. %u).\n", query, cs, unit, ret,
+ size);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
+ __u8 intfnum, __u8 cs, void *data, __u16 size)
+{
+ return __uvc_query_ctrl(dev, query, unit, intfnum, cs, data, size,
+ UVC_CTRL_CONTROL_TIMEOUT);
+}
+
+static void uvc_fixup_buffer_size(struct uvc_video_device *video,
+ struct uvc_streaming_control *ctrl)
+{
+ struct uvc_format *format;
+ struct uvc_frame *frame;
+
+ if (ctrl->bFormatIndex <= 0 ||
+ ctrl->bFormatIndex > video->streaming->nformats)
+ return;
+
+ format = &video->streaming->format[ctrl->bFormatIndex - 1];
+
+ if (ctrl->bFrameIndex <= 0 ||
+ ctrl->bFrameIndex > format->nframes)
+ return;
+
+ frame = &format->frame[ctrl->bFrameIndex - 1];
+
+ if (!(format->flags & UVC_FMT_FLAG_COMPRESSED) ||
+ (ctrl->dwMaxVideoFrameSize == 0 &&
+ video->dev->uvc_version < 0x0110))
+ ctrl->dwMaxVideoFrameSize =
+ frame->dwMaxVideoFrameBufferSize;
+}
+
+static int uvc_get_video_ctrl(struct uvc_video_device *video,
+ struct uvc_streaming_control *ctrl, int probe, __u8 query)
+{
+ __u8 data[34];
+ __u8 size;
+ int ret;
+
+ size = video->dev->uvc_version >= 0x0110 ? 34 : 26;
+ ret = __uvc_query_ctrl(video->dev, query, 0, video->streaming->intfnum,
+ probe ? VS_PROBE_CONTROL : VS_COMMIT_CONTROL, &data, size,
+ UVC_CTRL_STREAMING_TIMEOUT);
+
+ if (ret < 0)
+ return ret;
+
+ ctrl->bmHint = le16_to_cpup((__le16 *)&data[0]);
+ ctrl->bFormatIndex = data[2];
+ ctrl->bFrameIndex = data[3];
+ ctrl->dwFrameInterval = le32_to_cpup((__le32 *)&data[4]);
+ ctrl->wKeyFrameRate = le16_to_cpup((__le16 *)&data[8]);
+ ctrl->wPFrameRate = le16_to_cpup((__le16 *)&data[10]);
+ ctrl->wCompQuality = le16_to_cpup((__le16 *)&data[12]);
+ ctrl->wCompWindowSize = le16_to_cpup((__le16 *)&data[14]);
+ ctrl->wDelay = le16_to_cpup((__le16 *)&data[16]);
+ ctrl->dwMaxVideoFrameSize =
+ le32_to_cpu(get_unaligned((__le32 *)&data[18]));
+ ctrl->dwMaxPayloadTransferSize =
+ le32_to_cpu(get_unaligned((__le32 *)&data[22]));
+
+ if (size == 34) {
+ ctrl->dwClockFrequency =
+ le32_to_cpu(get_unaligned((__le32 *)&data[26]));
+ ctrl->bmFramingInfo = data[30];
+ ctrl->bPreferedVersion = data[31];
+ ctrl->bMinVersion = data[32];
+ ctrl->bMaxVersion = data[33];
+ } else {
+ ctrl->dwClockFrequency = video->dev->clock_frequency;
+ ctrl->bmFramingInfo = 0;
+ ctrl->bPreferedVersion = 0;
+ ctrl->bMinVersion = 0;
+ ctrl->bMaxVersion = 0;
+ }
+
+ /* Some broken devices return a null or wrong dwMaxVideoFrameSize.
+ * Try to get the value from the format and frame descriptor.
+ */
+ uvc_fixup_buffer_size(video, ctrl);
+
+ return 0;
+}
+
+int uvc_set_video_ctrl(struct uvc_video_device *video,
+ struct uvc_streaming_control *ctrl, int probe)
+{
+ __u8 data[34];
+ __u8 size;
+
+ size = video->dev->uvc_version >= 0x0110 ? 34 : 26;
+ memset(data, 0, sizeof data);
+
+ *(__le16 *)&data[0] = cpu_to_le16(ctrl->bmHint);
+ data[2] = ctrl->bFormatIndex;
+ data[3] = ctrl->bFrameIndex;
+ *(__le32 *)&data[4] = cpu_to_le32(ctrl->dwFrameInterval);
+ *(__le16 *)&data[8] = cpu_to_le16(ctrl->wKeyFrameRate);
+ *(__le16 *)&data[10] = cpu_to_le16(ctrl->wPFrameRate);
+ *(__le16 *)&data[12] = cpu_to_le16(ctrl->wCompQuality);
+ *(__le16 *)&data[14] = cpu_to_le16(ctrl->wCompWindowSize);
+ *(__le16 *)&data[16] = cpu_to_le16(ctrl->wDelay);
+ /* Note: Some of the fields below are not required for IN devices (see
+ * UVC spec, 4.3.1.1), but we still copy them in case support for OUT
+ * devices is added in the future. */
+ put_unaligned(cpu_to_le32(ctrl->dwMaxVideoFrameSize),
+ (__le32 *)&data[18]);
+ put_unaligned(cpu_to_le32(ctrl->dwMaxPayloadTransferSize),
+ (__le32 *)&data[22]);
+
+ if (size == 34) {
+ put_unaligned(cpu_to_le32(ctrl->dwClockFrequency),
+ (__le32 *)&data[26]);
+ data[30] = ctrl->bmFramingInfo;
+ data[31] = ctrl->bPreferedVersion;
+ data[32] = ctrl->bMinVersion;
+ data[33] = ctrl->bMaxVersion;
+ }
+
+ return __uvc_query_ctrl(video->dev, SET_CUR, 0,
+ video->streaming->intfnum,
+ probe ? VS_PROBE_CONTROL : VS_COMMIT_CONTROL, &data, size,
+ UVC_CTRL_STREAMING_TIMEOUT);
+}
+
+int uvc_probe_video(struct uvc_video_device *video,
+ struct uvc_streaming_control *probe)
+{
+ struct uvc_streaming_control probe_min, probe_max;
+ __u16 bandwidth;
+ unsigned int i;
+ int ret;
+
+ mutex_lock(&video->streaming->mutex);
+
+ /* Perform probing. The device should adjust the requested values
+ * according to its capabilities. However, some devices, namely the
+ * first generation UVC Logitech webcams, don't implement the Video
+ * Probe control properly, and just return the needed bandwidth. For
+ * that reason, if the needed bandwidth exceeds the maximum available
+ * bandwidth, try to lower the quality.
+ */
+ if ((ret = uvc_set_video_ctrl(video, probe, 1)) < 0)
+ goto done;
+
+ /* Get the minimum and maximum values for compression settings. */
+ if (!(video->dev->quirks & UVC_QUIRK_PROBE_MINMAX)) {
+ ret = uvc_get_video_ctrl(video, &probe_min, 1, GET_MIN);
+ if (ret < 0)
+ goto done;
+ ret = uvc_get_video_ctrl(video, &probe_max, 1, GET_MAX);
+ if (ret < 0)
+ goto done;
+
+ probe->wCompQuality = probe_max.wCompQuality;
+ }
+
+ for (i = 0; i < 2; ++i) {
+ if ((ret = uvc_set_video_ctrl(video, probe, 1)) < 0 ||
+ (ret = uvc_get_video_ctrl(video, probe, 1, GET_CUR)) < 0)
+ goto done;
+
+ if (video->streaming->intf->num_altsetting == 1)
+ break;
+
+ bandwidth = probe->dwMaxPayloadTransferSize;
+ if (bandwidth <= video->streaming->maxpsize)
+ break;
+
+ if (video->dev->quirks & UVC_QUIRK_PROBE_MINMAX) {
+ ret = -ENOSPC;
+ goto done;
+ }
+
+ /* TODO: negotiate compression parameters */
+ probe->wKeyFrameRate = probe_min.wKeyFrameRate;
+ probe->wPFrameRate = probe_min.wPFrameRate;
+ probe->wCompQuality = probe_max.wCompQuality;
+ probe->wCompWindowSize = probe_min.wCompWindowSize;
+ }
+
+done:
+ mutex_unlock(&video->streaming->mutex);
+ return ret;
+}
+
+/* ------------------------------------------------------------------------
+ * Video codecs
+ */
+
+/* Values for bmHeaderInfo (Video and Still Image Payload Headers, 2.4.3.3) */
+#define UVC_STREAM_EOH (1 << 7)
+#define UVC_STREAM_ERR (1 << 6)
+#define UVC_STREAM_STI (1 << 5)
+#define UVC_STREAM_RES (1 << 4)
+#define UVC_STREAM_SCR (1 << 3)
+#define UVC_STREAM_PTS (1 << 2)
+#define UVC_STREAM_EOF (1 << 1)
+#define UVC_STREAM_FID (1 << 0)
+
+/* Video payload decoding is handled by uvc_video_decode_start(),
+ * uvc_video_decode_data() and uvc_video_decode_end().
+ *
+ * uvc_video_decode_start is called with URB data at the start of a bulk or
+ * isochronous payload. It processes header data and returns the header size
+ * in bytes if successful. If an error occurs, it returns a negative error
+ * code. The following error codes have special meanings.
+ *
+ * - EAGAIN informs the caller that the current video buffer should be marked
+ * as done, and that the function should be called again with the same data
+ * and a new video buffer. This is used when end of frame conditions can be
+ * reliably detected at the beginning of the next frame only.
+ *
+ * If an error other than -EAGAIN is returned, the caller will drop the current
+ * payload. No call to uvc_video_decode_data and uvc_video_decode_end will be
+ * made until the next payload. -ENODATA can be used to drop the current
+ * payload if no other error code is appropriate.
+ *
+ * uvc_video_decode_data is called for every URB with URB data. It copies the
+ * data to the video buffer.
+ *
+ * uvc_video_decode_end is called with header data at the end of a bulk or
+ * isochronous payload. It performs any additional header data processing and
+ * returns 0 or a negative error code if an error occured. As header data have
+ * already been processed by uvc_video_decode_start, this functions isn't
+ * required to perform sanity checks a second time.
+ *
+ * For isochronous transfers where a payload is always transfered in a single
+ * URB, the three functions will be called in a row.
+ *
+ * To let the decoder process header data and update its internal state even
+ * when no video buffer is available, uvc_video_decode_start must be prepared
+ * to be called with a NULL buf parameter. uvc_video_decode_data and
+ * uvc_video_decode_end will never be called with a NULL buffer.
+ */
+static int uvc_video_decode_start(struct uvc_video_device *video,
+ struct uvc_buffer *buf, const __u8 *data, int len)
+{
+ __u8 fid;
+
+ /* Sanity checks:
+ * - packet must be at least 2 bytes long
+ * - bHeaderLength value must be at least 2 bytes (see above)
+ * - bHeaderLength value can't be larger than the packet size.
+ */
+ if (len < 2 || data[0] < 2 || data[0] > len)
+ return -EINVAL;
+
+ /* Skip payloads marked with the error bit ("error frames"). */
+ if (data[1] & UVC_STREAM_ERR) {
+ uvc_trace(UVC_TRACE_FRAME, "Dropping payload (error bit "
+ "set).\n");
+ return -ENODATA;
+ }
+
+ fid = data[1] & UVC_STREAM_FID;
+
+ /* Store the payload FID bit and return immediately when the buffer is
+ * NULL.
+ */
+ if (buf == NULL) {
+ video->last_fid = fid;
+ return -ENODATA;
+ }
+
+ /* Synchronize to the input stream by waiting for the FID bit to be
+ * toggled when the the buffer state is not UVC_BUF_STATE_ACTIVE.
+ * queue->last_fid is initialized to -1, so the first isochronous
+ * frame will always be in sync.
+ *
+ * If the device doesn't toggle the FID bit, invert video->last_fid
+ * when the EOF bit is set to force synchronisation on the next packet.
+ */
+ if (buf->state != UVC_BUF_STATE_ACTIVE) {
+ if (fid == video->last_fid) {
+ uvc_trace(UVC_TRACE_FRAME, "Dropping payload (out of "
+ "sync).\n");
+ if ((video->dev->quirks & UVC_QUIRK_STREAM_NO_FID) &&
+ (data[1] & UVC_STREAM_EOF))
+ video->last_fid ^= UVC_STREAM_FID;
+ return -ENODATA;
+ }
+
+ /* TODO: Handle PTS and SCR. */
+ buf->state = UVC_BUF_STATE_ACTIVE;
+ }
+
+ /* Mark the buffer as done if we're at the beginning of a new frame.
+ * End of frame detection is better implemented by checking the EOF
+ * bit (FID bit toggling is delayed by one frame compared to the EOF
+ * bit), but some devices don't set the bit at end of frame (and the
+ * last payload can be lost anyway). We thus must check if the FID has
+ * been toggled.
+ *
+ * queue->last_fid is initialized to -1, so the first isochronous
+ * frame will never trigger an end of frame detection.
+ *
+ * Empty buffers (bytesused == 0) don't trigger end of frame detection
+ * as it doesn't make sense to return an empty buffer. This also
+ * avoids detecting and of frame conditions at FID toggling if the
+ * previous payload had the EOF bit set.
+ */
+ if (fid != video->last_fid && buf->buf.bytesused != 0) {
+ uvc_trace(UVC_TRACE_FRAME, "Frame complete (FID bit "
+ "toggled).\n");
+ buf->state = UVC_BUF_STATE_DONE;
+ return -EAGAIN;
+ }
+
+ video->last_fid = fid;
+
+ return data[0];
+}
+
+static void uvc_video_decode_data(struct uvc_video_device *video,
+ struct uvc_buffer *buf, const __u8 *data, int len)
+{
+ struct uvc_video_queue *queue = &video->queue;
+ unsigned int maxlen, nbytes;
+ void *mem;
+
+ if (len <= 0)
+ return;
+
+ /* Copy the video data to the buffer. */
+ maxlen = buf->buf.length - buf->buf.bytesused;
+ mem = queue->mem + buf->buf.m.offset + buf->buf.bytesused;
+ nbytes = min((unsigned int)len, maxlen);
+ memcpy(mem, data, nbytes);
+ buf->buf.bytesused += nbytes;
+
+ /* Complete the current frame if the buffer size was exceeded. */
+ if (len > maxlen) {
+ uvc_trace(UVC_TRACE_FRAME, "Frame complete (overflow).\n");
+ buf->state = UVC_BUF_STATE_DONE;
+ }
+}
+
+static void uvc_video_decode_end(struct uvc_video_device *video,
+ struct uvc_buffer *buf, const __u8 *data, int len)
+{
+ /* Mark the buffer as done if the EOF marker is set. */
+ if (data[1] & UVC_STREAM_EOF && buf->buf.bytesused != 0) {
+ uvc_trace(UVC_TRACE_FRAME, "Frame complete (EOF found).\n");
+ if (data[0] == len)
+ uvc_trace(UVC_TRACE_FRAME, "EOF in empty payload.\n");
+ buf->state = UVC_BUF_STATE_DONE;
+ if (video->dev->quirks & UVC_QUIRK_STREAM_NO_FID)
+ video->last_fid ^= UVC_STREAM_FID;
+ }
+}
+
+/* ------------------------------------------------------------------------
+ * URB handling
+ */
+
+/*
+ * Completion handler for video URBs.
+ */
+static void uvc_video_decode_isoc(struct urb *urb,
+ struct uvc_video_device *video, struct uvc_buffer *buf)
+{
+ u8 *mem;
+ int ret, i;
+
+ for (i = 0; i < urb->number_of_packets; ++i) {
+ if (urb->iso_frame_desc[i].status < 0) {
+ uvc_trace(UVC_TRACE_FRAME, "USB isochronous frame "
+ "lost (%d).\n", urb->iso_frame_desc[i].status);
+ continue;
+ }
+
+ /* Decode the payload header. */
+ mem = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+ do {
+ ret = uvc_video_decode_start(video, buf, mem,
+ urb->iso_frame_desc[i].actual_length);
+ if (ret == -EAGAIN)
+ buf = uvc_queue_next_buffer(&video->queue, buf);
+ } while (ret == -EAGAIN);
+
+ if (ret < 0)
+ continue;
+
+ /* Decode the payload data. */
+ uvc_video_decode_data(video, buf, mem + ret,
+ urb->iso_frame_desc[i].actual_length - ret);
+
+ /* Process the header again. */
+ uvc_video_decode_end(video, buf, mem, ret);
+
+ if (buf->state == UVC_BUF_STATE_DONE ||
+ buf->state == UVC_BUF_STATE_ERROR)
+ buf = uvc_queue_next_buffer(&video->queue, buf);
+ }
+}
+
+static void uvc_video_decode_bulk(struct urb *urb,
+ struct uvc_video_device *video, struct uvc_buffer *buf)
+{
+ u8 *mem;
+ int len, ret;
+
+ mem = urb->transfer_buffer;
+ len = urb->actual_length;
+ video->bulk.payload_size += len;
+
+ /* If the URB is the first of its payload, decode and save the
+ * header.
+ */
+ if (video->bulk.header_size == 0) {
+ do {
+ ret = uvc_video_decode_start(video, buf, mem, len);
+ if (ret == -EAGAIN)
+ buf = uvc_queue_next_buffer(&video->queue, buf);
+ } while (ret == -EAGAIN);
+
+ /* If an error occured skip the rest of the payload. */
+ if (ret < 0 || buf == NULL) {
+ video->bulk.skip_payload = 1;
+ return;
+ }
+
+ video->bulk.header_size = ret;
+ memcpy(video->bulk.header, mem, video->bulk.header_size);
+
+ mem += ret;
+ len -= ret;
+ }
+
+ /* The buffer queue might have been cancelled while a bulk transfer
+ * was in progress, so we can reach here with buf equal to NULL. Make
+ * sure buf is never dereferenced if NULL.
+ */
+
+ /* Process video data. */
+ if (!video->bulk.skip_payload && buf != NULL)
+ uvc_video_decode_data(video, buf, mem, len);
+
+ /* Detect the payload end by a URB smaller than the maximum size (or
+ * a payload size equal to the maximum) and process the header again.
+ */
+ if (urb->actual_length < urb->transfer_buffer_length ||
+ video->bulk.payload_size >= video->bulk.max_payload_size) {
+ if (!video->bulk.skip_payload && buf != NULL) {
+ uvc_video_decode_end(video, buf, video->bulk.header,
+ video->bulk.header_size);
+ if (buf->state == UVC_BUF_STATE_DONE ||
+ buf->state == UVC_BUF_STATE_ERROR)
+ buf = uvc_queue_next_buffer(&video->queue, buf);
+ }
+
+ video->bulk.header_size = 0;
+ video->bulk.skip_payload = 0;
+ video->bulk.payload_size = 0;
+ }
+}
+
+static void uvc_video_complete(struct urb *urb)
+{
+ struct uvc_video_device *video = urb->context;
+ struct uvc_video_queue *queue = &video->queue;
+ struct uvc_buffer *buf = NULL;
+ unsigned long flags;
+ int ret;
+
+ switch (urb->status) {
+ case 0:
+ break;
+
+ default:
+ uvc_printk(KERN_WARNING, "Non-zero status (%d) in video "
+ "completion handler.\n", urb->status);
+
+ case -ENOENT: /* usb_kill_urb() called. */
+ if (video->frozen)
+ return;
+
+ case -ECONNRESET: /* usb_unlink_urb() called. */
+ case -ESHUTDOWN: /* The endpoint is being disabled. */
+ uvc_queue_cancel(queue, urb->status == -ESHUTDOWN);
+ return;
+ }
+
+ spin_lock_irqsave(&queue->irqlock, flags);
+ if (!list_empty(&queue->irqqueue))
+ buf = list_first_entry(&queue->irqqueue, struct uvc_buffer,
+ queue);
+ spin_unlock_irqrestore(&queue->irqlock, flags);
+
+ video->decode(urb, video, buf);
+
+ if ((ret = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
+ uvc_printk(KERN_ERR, "Failed to resubmit video URB (%d).\n",
+ ret);
+ }
+}
+
+/*
+ * Free transfer buffers.
+ */
+static void uvc_free_urb_buffers(struct uvc_video_device *video)
+{
+ unsigned int i;
+
+ for (i = 0; i < UVC_URBS; ++i) {
+ if (video->urb_buffer[i]) {
+ usb_buffer_free(video->dev->udev, video->urb_size,
+ video->urb_buffer[i], video->urb_dma[i]);
+ video->urb_buffer[i] = NULL;
+ }
+ }
+
+ video->urb_size = 0;
+}
+
+/*
+ * Allocate transfer buffers. This function can be called with buffers
+ * already allocated when resuming from suspend, in which case it will
+ * return without touching the buffers.
+ *
+ * Return 0 on success or -ENOMEM when out of memory.
+ */
+static int uvc_alloc_urb_buffers(struct uvc_video_device *video,
+ unsigned int size)
+{
+ unsigned int i;
+
+ /* Buffers are already allocated, bail out. */
+ if (video->urb_size)
+ return 0;
+
+ for (i = 0; i < UVC_URBS; ++i) {
+ video->urb_buffer[i] = usb_buffer_alloc(video->dev->udev,
+ size, GFP_KERNEL, &video->urb_dma[i]);
+ if (video->urb_buffer[i] == NULL) {
+ uvc_free_urb_buffers(video);
+ return -ENOMEM;
+ }
+ }
+
+ video->urb_size = size;
+ return 0;
+}
+
+/*
+ * Uninitialize isochronous/bulk URBs and free transfer buffers.
+ */
+static void uvc_uninit_video(struct uvc_video_device *video, int free_buffers)
+{
+ struct urb *urb;
+ unsigned int i;
+
+ for (i = 0; i < UVC_URBS; ++i) {
+ if ((urb = video->urb[i]) == NULL)
+ continue;
+
+ usb_kill_urb(urb);
+ usb_free_urb(urb);
+ video->urb[i] = NULL;
+ }
+
+ if (free_buffers)
+ uvc_free_urb_buffers(video);
+}
+
+/*
+ * Initialize isochronous URBs and allocate transfer buffers. The packet size
+ * is given by the endpoint.
+ */
+static int uvc_init_video_isoc(struct uvc_video_device *video,
+ struct usb_host_endpoint *ep, gfp_t gfp_flags)
+{
+ struct urb *urb;
+ unsigned int npackets, i, j;
+ __u16 psize;
+ __u32 size;
+
+ /* Compute the number of isochronous packets to allocate by dividing
+ * the maximum video frame size by the packet size. Limit the result
+ * to UVC_MAX_ISO_PACKETS.
+ */
+ psize = le16_to_cpu(ep->desc.wMaxPacketSize);
+ psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
+
+ size = video->streaming->ctrl.dwMaxVideoFrameSize;
+ if (size > UVC_MAX_FRAME_SIZE)
+ return -EINVAL;
+
+ npackets = (size + psize - 1) / psize;
+ if (npackets > UVC_MAX_ISO_PACKETS)
+ npackets = UVC_MAX_ISO_PACKETS;
+
+ size = npackets * psize;
+
+ if (uvc_alloc_urb_buffers(video, size) < 0)
+ return -ENOMEM;
+
+ for (i = 0; i < UVC_URBS; ++i) {
+ urb = usb_alloc_urb(npackets, gfp_flags);
+ if (urb == NULL) {
+ uvc_uninit_video(video, 1);
+ return -ENOMEM;
+ }
+
+ urb->dev = video->dev->udev;
+ urb->context = video;
+ urb->pipe = usb_rcvisocpipe(video->dev->udev,
+ ep->desc.bEndpointAddress);
+ urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
+ urb->interval = ep->desc.bInterval;
+ urb->transfer_buffer = video->urb_buffer[i];
+ urb->transfer_dma = video->urb_dma[i];
+ urb->complete = uvc_video_complete;
+ urb->number_of_packets = npackets;
+ urb->transfer_buffer_length = size;
+
+ for (j = 0; j < npackets; ++j) {
+ urb->iso_frame_desc[j].offset = j * psize;
+ urb->iso_frame_desc[j].length = psize;
+ }
+
+ video->urb[i] = urb;
+ }
+
+ return 0;
+}
+
+/*
+ * Initialize bulk URBs and allocate transfer buffers. The packet size is
+ * given by the endpoint.
+ */
+static int uvc_init_video_bulk(struct uvc_video_device *video,
+ struct usb_host_endpoint *ep, gfp_t gfp_flags)
+{
+ struct urb *urb;
+ unsigned int pipe, i;
+ __u16 psize;
+ __u32 size;
+
+ /* Compute the bulk URB size. Some devices set the maximum payload
+ * size to a value too high for memory-constrained devices. We must
+ * then transfer the payload accross multiple URBs. To be consistant
+ * with isochronous mode, allocate maximum UVC_MAX_ISO_PACKETS per bulk
+ * URB.
+ */
+ psize = le16_to_cpu(ep->desc.wMaxPacketSize) & 0x07ff;
+ size = video->streaming->ctrl.dwMaxPayloadTransferSize;
+ video->bulk.max_payload_size = size;
+ if (size > psize * UVC_MAX_ISO_PACKETS)
+ size = psize * UVC_MAX_ISO_PACKETS;
+
+ if (uvc_alloc_urb_buffers(video, size) < 0)
+ return -ENOMEM;
+
+ pipe = usb_rcvbulkpipe(video->dev->udev, ep->desc.bEndpointAddress);
+
+ for (i = 0; i < UVC_URBS; ++i) {
+ urb = usb_alloc_urb(0, gfp_flags);
+ if (urb == NULL) {
+ uvc_uninit_video(video, 1);
+ return -ENOMEM;
+ }
+
+ usb_fill_bulk_urb(urb, video->dev->udev, pipe,
+ video->urb_buffer[i], size, uvc_video_complete,
+ video);
+ urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
+ urb->transfer_dma = video->urb_dma[i];
+
+ video->urb[i] = urb;
+ }
+
+ return 0;
+}
+
+/*
+ * Initialize isochronous/bulk URBs and allocate transfer buffers.
+ */
+static int uvc_init_video(struct uvc_video_device *video, gfp_t gfp_flags)
+{
+ struct usb_interface *intf = video->streaming->intf;
+ struct usb_host_interface *alts;
+ struct usb_host_endpoint *ep = NULL;
+ int intfnum = video->streaming->intfnum;
+ unsigned int bandwidth, psize, i;
+ int ret;
+
+ video->last_fid = -1;
+ video->bulk.header_size = 0;
+ video->bulk.skip_payload = 0;
+ video->bulk.payload_size = 0;
+
+ if (intf->num_altsetting > 1) {
+ /* Isochronous endpoint, select the alternate setting. */
+ bandwidth = video->streaming->ctrl.dwMaxPayloadTransferSize;
+
+ if (bandwidth == 0) {
+ uvc_printk(KERN_WARNING, "device %s requested null "
+ "bandwidth, defaulting to lowest.\n",
+ video->vdev->name);
+ bandwidth = 1;
+ }
+
+ for (i = 0; i < intf->num_altsetting; ++i) {
+ alts = &intf->altsetting[i];
+ ep = uvc_find_endpoint(alts,
+ video->streaming->header.bEndpointAddress);
+ if (ep == NULL)
+ continue;
+
+ /* Check if the bandwidth is high enough. */
+ psize = le16_to_cpu(ep->desc.wMaxPacketSize);
+ psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
+ if (psize >= bandwidth)
+ break;
+ }
+
+ if (i >= intf->num_altsetting)
+ return -EIO;
+
+ if ((ret = usb_set_interface(video->dev->udev, intfnum, i)) < 0)
+ return ret;
+
+ ret = uvc_init_video_isoc(video, ep, gfp_flags);
+ } else {
+ /* Bulk endpoint, proceed to URB initialization. */
+ ep = uvc_find_endpoint(&intf->altsetting[0],
+ video->streaming->header.bEndpointAddress);
+ if (ep == NULL)
+ return -EIO;
+
+ ret = uvc_init_video_bulk(video, ep, gfp_flags);
+ }
+
+ if (ret < 0)
+ return ret;
+
+ /* Submit the URBs. */
+ for (i = 0; i < UVC_URBS; ++i) {
+ if ((ret = usb_submit_urb(video->urb[i], gfp_flags)) < 0) {
+ uvc_printk(KERN_ERR, "Failed to submit URB %u "
+ "(%d).\n", i, ret);
+ uvc_uninit_video(video, 1);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+/* --------------------------------------------------------------------------
+ * Suspend/resume
+ */
+
+/*
+ * Stop streaming without disabling the video queue.
+ *
+ * To let userspace applications resume without trouble, we must not touch the
+ * video buffers in any way. We mark the device as frozen to make sure the URB
+ * completion handler won't try to cancel the queue when we kill the URBs.
+ */
+int uvc_video_suspend(struct uvc_video_device *video)
+{
+ if (!uvc_queue_streaming(&video->queue))
+ return 0;
+
+ video->frozen = 1;
+ uvc_uninit_video(video, 0);
+ usb_set_interface(video->dev->udev, video->streaming->intfnum, 0);
+ return 0;
+}
+
+/*
+ * Reconfigure the video interface and restart streaming if it was enable
+ * before suspend.
+ *
+ * If an error occurs, disable the video queue. This will wake all pending
+ * buffers, making sure userspace applications are notified of the problem
+ * instead of waiting forever.
+ */
+int uvc_video_resume(struct uvc_video_device *video)
+{
+ int ret;
+
+ video->frozen = 0;
+
+ if ((ret = uvc_set_video_ctrl(video, &video->streaming->ctrl, 0)) < 0) {
+ uvc_queue_enable(&video->queue, 0);
+ return ret;
+ }
+
+ if (!uvc_queue_streaming(&video->queue))
+ return 0;
+
+ if ((ret = uvc_init_video(video, GFP_NOIO)) < 0)
+ uvc_queue_enable(&video->queue, 0);
+
+ return ret;
+}
+
+/* ------------------------------------------------------------------------
+ * Video device
+ */
+
+/*
+ * Initialize the UVC video device by retrieving the default format and
+ * committing it.
+ *
+ * Some cameras (namely the Fuji Finepix) set the format and frame
+ * indexes to zero. The UVC standard doesn't clearly make this a spec
+ * violation, so try to silently fix the values if possible.
+ *
+ * This function is called before registering the device with V4L.
+ */
+int uvc_video_init(struct uvc_video_device *video)
+{
+ struct uvc_streaming_control *probe = &video->streaming->ctrl;
+ struct uvc_format *format = NULL;
+ struct uvc_frame *frame = NULL;
+ unsigned int i;
+ int ret;
+
+ if (video->streaming->nformats == 0) {
+ uvc_printk(KERN_INFO, "No supported video formats found.\n");
+ return -EINVAL;
+ }
+
+ /* Alternate setting 0 should be the default, yet the XBox Live Vision
+ * Cam (and possibly other devices) crash or otherwise misbehave if
+ * they don't receive a SET_INTERFACE request before any other video
+ * control request.
+ */
+ usb_set_interface(video->dev->udev, video->streaming->intfnum, 0);
+
+ /* Some webcams don't suport GET_DEF request on the probe control. We
+ * fall back to GET_CUR if GET_DEF fails.
+ */
+ if ((ret = uvc_get_video_ctrl(video, probe, 1, GET_DEF)) < 0 &&
+ (ret = uvc_get_video_ctrl(video, probe, 1, GET_CUR)) < 0)
+ return ret;
+
+ /* Check if the default format descriptor exists. Use the first
+ * available format otherwise.
+ */
+ for (i = video->streaming->nformats; i > 0; --i) {
+ format = &video->streaming->format[i-1];
+ if (format->index == probe->bFormatIndex)
+ break;
+ }
+
+ if (format->nframes == 0) {
+ uvc_printk(KERN_INFO, "No frame descriptor found for the "
+ "default format.\n");
+ return -EINVAL;
+ }
+
+ /* Zero bFrameIndex might be correct. Stream-based formats (including
+ * MPEG-2 TS and DV) do not support frames but have a dummy frame
+ * descriptor with bFrameIndex set to zero. If the default frame
+ * descriptor is not found, use the first avalable frame.
+ */
+ for (i = format->nframes; i > 0; --i) {
+ frame = &format->frame[i-1];
+ if (frame->bFrameIndex == probe->bFrameIndex)
+ break;
+ }
+
+ /* Commit the default settings. */
+ probe->bFormatIndex = format->index;
+ probe->bFrameIndex = frame->bFrameIndex;
+ if ((ret = uvc_set_video_ctrl(video, probe, 0)) < 0)
+ return ret;
+
+ video->streaming->cur_format = format;
+ video->streaming->cur_frame = frame;
+ atomic_set(&video->active, 0);
+
+ /* Select the video decoding function */
+ if (video->dev->quirks & UVC_QUIRK_BUILTIN_ISIGHT)
+ video->decode = uvc_video_decode_isight;
+ else if (video->streaming->intf->num_altsetting > 1)
+ video->decode = uvc_video_decode_isoc;
+ else
+ video->decode = uvc_video_decode_bulk;
+
+ return 0;
+}
+
+/*
+ * Enable or disable the video stream.
+ */
+int uvc_video_enable(struct uvc_video_device *video, int enable)
+{
+ int ret;
+
+ if (!enable) {
+ uvc_uninit_video(video, 1);
+ usb_set_interface(video->dev->udev,
+ video->streaming->intfnum, 0);
+ uvc_queue_enable(&video->queue, 0);
+ return 0;
+ }
+
+ if ((ret = uvc_queue_enable(&video->queue, 1)) < 0)
+ return ret;
+
+ return uvc_init_video(video, GFP_KERNEL);
+}
+
diff --git a/linux/drivers/media/video/uvc/uvcvideo.h b/linux/drivers/media/video/uvc/uvcvideo.h
new file mode 100644
index 000000000..bafe3406e
--- /dev/null
+++ b/linux/drivers/media/video/uvc/uvcvideo.h
@@ -0,0 +1,799 @@
+#ifndef _USB_VIDEO_H_
+#define _USB_VIDEO_H_
+
+#include <linux/kernel.h>
+#include <linux/videodev2.h>
+
+
+/*
+ * Dynamic controls
+ */
+
+/* Data types for UVC control data */
+#define UVC_CTRL_DATA_TYPE_RAW 0
+#define UVC_CTRL_DATA_TYPE_SIGNED 1
+#define UVC_CTRL_DATA_TYPE_UNSIGNED 2
+#define UVC_CTRL_DATA_TYPE_BOOLEAN 3
+#define UVC_CTRL_DATA_TYPE_ENUM 4
+#define UVC_CTRL_DATA_TYPE_BITMASK 5
+
+/* Control flags */
+#define UVC_CONTROL_SET_CUR (1 << 0)
+#define UVC_CONTROL_GET_CUR (1 << 1)
+#define UVC_CONTROL_GET_MIN (1 << 2)
+#define UVC_CONTROL_GET_MAX (1 << 3)
+#define UVC_CONTROL_GET_RES (1 << 4)
+#define UVC_CONTROL_GET_DEF (1 << 5)
+/* Control should be saved at suspend and restored at resume. */
+#define UVC_CONTROL_RESTORE (1 << 6)
+/* Control can be updated by the camera. */
+#define UVC_CONTROL_AUTO_UPDATE (1 << 7)
+
+#define UVC_CONTROL_GET_RANGE (UVC_CONTROL_GET_CUR | UVC_CONTROL_GET_MIN | \
+ UVC_CONTROL_GET_MAX | UVC_CONTROL_GET_RES | \
+ UVC_CONTROL_GET_DEF)
+
+struct uvc_xu_control_info {
+ __u8 entity[16];
+ __u8 index;
+ __u8 selector;
+ __u16 size;
+ __u32 flags;
+};
+
+struct uvc_xu_control_mapping {
+ __u32 id;
+ __u8 name[32];
+ __u8 entity[16];
+ __u8 selector;
+
+ __u8 size;
+ __u8 offset;
+ enum v4l2_ctrl_type v4l2_type;
+ __u32 data_type;
+};
+
+struct uvc_xu_control {
+ __u8 unit;
+ __u8 selector;
+ __u16 size;
+ __u8 __user *data;
+};
+
+#define UVCIOC_CTRL_ADD _IOW('U', 1, struct uvc_xu_control_info)
+#define UVCIOC_CTRL_MAP _IOWR('U', 2, struct uvc_xu_control_mapping)
+#define UVCIOC_CTRL_GET _IOWR('U', 3, struct uvc_xu_control)
+#define UVCIOC_CTRL_SET _IOW('U', 4, struct uvc_xu_control)
+
+#ifdef __KERNEL__
+
+#include <linux/poll.h>
+
+/* --------------------------------------------------------------------------
+ * UVC constants
+ */
+
+#define SC_UNDEFINED 0x00
+#define SC_VIDEOCONTROL 0x01
+#define SC_VIDEOSTREAMING 0x02
+#define SC_VIDEO_INTERFACE_COLLECTION 0x03
+
+#define PC_PROTOCOL_UNDEFINED 0x00
+
+#define CS_UNDEFINED 0x20
+#define CS_DEVICE 0x21
+#define CS_CONFIGURATION 0x22
+#define CS_STRING 0x23
+#define CS_INTERFACE 0x24
+#define CS_ENDPOINT 0x25
+
+/* VideoControl class specific interface descriptor */
+#define VC_DESCRIPTOR_UNDEFINED 0x00
+#define VC_HEADER 0x01
+#define VC_INPUT_TERMINAL 0x02
+#define VC_OUTPUT_TERMINAL 0x03
+#define VC_SELECTOR_UNIT 0x04
+#define VC_PROCESSING_UNIT 0x05
+#define VC_EXTENSION_UNIT 0x06
+
+/* VideoStreaming class specific interface descriptor */
+#define VS_UNDEFINED 0x00
+#define VS_INPUT_HEADER 0x01
+#define VS_OUTPUT_HEADER 0x02
+#define VS_STILL_IMAGE_FRAME 0x03
+#define VS_FORMAT_UNCOMPRESSED 0x04
+#define VS_FRAME_UNCOMPRESSED 0x05
+#define VS_FORMAT_MJPEG 0x06
+#define VS_FRAME_MJPEG 0x07
+#define VS_FORMAT_MPEG2TS 0x0a
+#define VS_FORMAT_DV 0x0c
+#define VS_COLORFORMAT 0x0d
+#define VS_FORMAT_FRAME_BASED 0x10
+#define VS_FRAME_FRAME_BASED 0x11
+#define VS_FORMAT_STREAM_BASED 0x12
+
+/* Endpoint type */
+#define EP_UNDEFINED 0x00
+#define EP_GENERAL 0x01
+#define EP_ENDPOINT 0x02
+#define EP_INTERRUPT 0x03
+
+/* Request codes */
+#define RC_UNDEFINED 0x00
+#define SET_CUR 0x01
+#define GET_CUR 0x81
+#define GET_MIN 0x82
+#define GET_MAX 0x83
+#define GET_RES 0x84
+#define GET_LEN 0x85
+#define GET_INFO 0x86
+#define GET_DEF 0x87
+
+/* VideoControl interface controls */
+#define VC_CONTROL_UNDEFINED 0x00
+#define VC_VIDEO_POWER_MODE_CONTROL 0x01
+#define VC_REQUEST_ERROR_CODE_CONTROL 0x02
+
+/* Terminal controls */
+#define TE_CONTROL_UNDEFINED 0x00
+
+/* Selector Unit controls */
+#define SU_CONTROL_UNDEFINED 0x00
+#define SU_INPUT_SELECT_CONTROL 0x01
+
+/* Camera Terminal controls */
+#define CT_CONTROL_UNDEFINED 0x00
+#define CT_SCANNING_MODE_CONTROL 0x01
+#define CT_AE_MODE_CONTROL 0x02
+#define CT_AE_PRIORITY_CONTROL 0x03
+#define CT_EXPOSURE_TIME_ABSOLUTE_CONTROL 0x04
+#define CT_EXPOSURE_TIME_RELATIVE_CONTROL 0x05
+#define CT_FOCUS_ABSOLUTE_CONTROL 0x06
+#define CT_FOCUS_RELATIVE_CONTROL 0x07
+#define CT_FOCUS_AUTO_CONTROL 0x08
+#define CT_IRIS_ABSOLUTE_CONTROL 0x09
+#define CT_IRIS_RELATIVE_CONTROL 0x0a
+#define CT_ZOOM_ABSOLUTE_CONTROL 0x0b
+#define CT_ZOOM_RELATIVE_CONTROL 0x0c
+#define CT_PANTILT_ABSOLUTE_CONTROL 0x0d
+#define CT_PANTILT_RELATIVE_CONTROL 0x0e
+#define CT_ROLL_ABSOLUTE_CONTROL 0x0f
+#define CT_ROLL_RELATIVE_CONTROL 0x10
+#define CT_PRIVACY_CONTROL 0x11
+
+/* Processing Unit controls */
+#define PU_CONTROL_UNDEFINED 0x00
+#define PU_BACKLIGHT_COMPENSATION_CONTROL 0x01
+#define PU_BRIGHTNESS_CONTROL 0x02
+#define PU_CONTRAST_CONTROL 0x03
+#define PU_GAIN_CONTROL 0x04
+#define PU_POWER_LINE_FREQUENCY_CONTROL 0x05
+#define PU_HUE_CONTROL 0x06
+#define PU_SATURATION_CONTROL 0x07
+#define PU_SHARPNESS_CONTROL 0x08
+#define PU_GAMMA_CONTROL 0x09
+#define PU_WHITE_BALANCE_TEMPERATURE_CONTROL 0x0a
+#define PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL 0x0b
+#define PU_WHITE_BALANCE_COMPONENT_CONTROL 0x0c
+#define PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL 0x0d
+#define PU_DIGITAL_MULTIPLIER_CONTROL 0x0e
+#define PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL 0x0f
+#define PU_HUE_AUTO_CONTROL 0x10
+#define PU_ANALOG_VIDEO_STANDARD_CONTROL 0x11
+#define PU_ANALOG_LOCK_STATUS_CONTROL 0x12
+
+#define LXU_MOTOR_PANTILT_RELATIVE_CONTROL 0x01
+#define LXU_MOTOR_PANTILT_RESET_CONTROL 0x02
+#define LXU_MOTOR_FOCUS_MOTOR_CONTROL 0x03
+
+/* VideoStreaming interface controls */
+#define VS_CONTROL_UNDEFINED 0x00
+#define VS_PROBE_CONTROL 0x01
+#define VS_COMMIT_CONTROL 0x02
+#define VS_STILL_PROBE_CONTROL 0x03
+#define VS_STILL_COMMIT_CONTROL 0x04
+#define VS_STILL_IMAGE_TRIGGER_CONTROL 0x05
+#define VS_STREAM_ERROR_CODE_CONTROL 0x06
+#define VS_GENERATE_KEY_FRAME_CONTROL 0x07
+#define VS_UPDATE_FRAME_SEGMENT_CONTROL 0x08
+#define VS_SYNC_DELAY_CONTROL 0x09
+
+#define TT_VENDOR_SPECIFIC 0x0100
+#define TT_STREAMING 0x0101
+
+/* Input Terminal types */
+#define ITT_VENDOR_SPECIFIC 0x0200
+#define ITT_CAMERA 0x0201
+#define ITT_MEDIA_TRANSPORT_INPUT 0x0202
+
+/* Output Terminal types */
+#define OTT_VENDOR_SPECIFIC 0x0300
+#define OTT_DISPLAY 0x0301
+#define OTT_MEDIA_TRANSPORT_OUTPUT 0x0302
+
+/* External Terminal types */
+#define EXTERNAL_VENDOR_SPECIFIC 0x0400
+#define COMPOSITE_CONNECTOR 0x0401
+#define SVIDEO_CONNECTOR 0x0402
+#define COMPONENT_CONNECTOR 0x0403
+
+#define UVC_TERM_INPUT 0x0000
+#define UVC_TERM_OUTPUT 0x8000
+
+#define UVC_ENTITY_TYPE(entity) ((entity)->type & 0x7fff)
+#define UVC_ENTITY_IS_UNIT(entity) (((entity)->type & 0xff00) == 0)
+#define UVC_ENTITY_IS_TERM(entity) (((entity)->type & 0xff00) != 0)
+#define UVC_ENTITY_IS_ITERM(entity) \
+ (((entity)->type & 0x8000) == UVC_TERM_INPUT)
+#define UVC_ENTITY_IS_OTERM(entity) \
+ (((entity)->type & 0x8000) == UVC_TERM_OUTPUT)
+
+#define UVC_STATUS_TYPE_CONTROL 1
+#define UVC_STATUS_TYPE_STREAMING 2
+
+/* ------------------------------------------------------------------------
+ * GUIDs
+ */
+#define UVC_GUID_UVC_CAMERA \
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}
+#define UVC_GUID_UVC_OUTPUT \
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}
+#define UVC_GUID_UVC_MEDIA_TRANSPORT_INPUT \
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}
+#define UVC_GUID_UVC_PROCESSING \
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01}
+#define UVC_GUID_UVC_SELECTOR \
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02}
+
+#define UVC_GUID_LOGITECH_DEV_INFO \
+ {0x82, 0x06, 0x61, 0x63, 0x70, 0x50, 0xab, 0x49, \
+ 0xb8, 0xcc, 0xb3, 0x85, 0x5e, 0x8d, 0x22, 0x1e}
+#define UVC_GUID_LOGITECH_USER_HW \
+ {0x82, 0x06, 0x61, 0x63, 0x70, 0x50, 0xab, 0x49, \
+ 0xb8, 0xcc, 0xb3, 0x85, 0x5e, 0x8d, 0x22, 0x1f}
+#define UVC_GUID_LOGITECH_VIDEO \
+ {0x82, 0x06, 0x61, 0x63, 0x70, 0x50, 0xab, 0x49, \
+ 0xb8, 0xcc, 0xb3, 0x85, 0x5e, 0x8d, 0x22, 0x50}
+#define UVC_GUID_LOGITECH_MOTOR \
+ {0x82, 0x06, 0x61, 0x63, 0x70, 0x50, 0xab, 0x49, \
+ 0xb8, 0xcc, 0xb3, 0x85, 0x5e, 0x8d, 0x22, 0x56}
+
+#define UVC_GUID_FORMAT_MJPEG \
+ { 'M', 'J', 'P', 'G', 0x00, 0x00, 0x10, 0x00, \
+ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_YUY2 \
+ { 'Y', 'U', 'Y', '2', 0x00, 0x00, 0x10, 0x00, \
+ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_NV12 \
+ { 'N', 'V', '1', '2', 0x00, 0x00, 0x10, 0x00, \
+ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_YV12 \
+ { 'Y', 'V', '1', '2', 0x00, 0x00, 0x10, 0x00, \
+ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_I420 \
+ { 'I', '4', '2', '0', 0x00, 0x00, 0x10, 0x00, \
+ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_UYVY \
+ { 'U', 'Y', 'V', 'Y', 0x00, 0x00, 0x10, 0x00, \
+ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_Y800 \
+ { 'Y', '8', '0', '0', 0x00, 0x00, 0x10, 0x00, \
+ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_BY8 \
+ { 'B', 'Y', '8', ' ', 0x00, 0x00, 0x10, 0x00, \
+ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+
+
+/* ------------------------------------------------------------------------
+ * Driver specific constants.
+ */
+
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(0, 1, 0)
+
+/* Number of isochronous URBs. */
+#define UVC_URBS 5
+/* Maximum number of packets per isochronous URB. */
+#define UVC_MAX_ISO_PACKETS 40
+/* Maximum frame size in bytes, for sanity checking. */
+#define UVC_MAX_FRAME_SIZE (16*1024*1024)
+/* Maximum number of video buffers. */
+#define UVC_MAX_VIDEO_BUFFERS 32
+
+#define UVC_CTRL_CONTROL_TIMEOUT 300
+#define UVC_CTRL_STREAMING_TIMEOUT 1000
+
+/* Devices quirks */
+#define UVC_QUIRK_STATUS_INTERVAL 0x00000001
+#define UVC_QUIRK_PROBE_MINMAX 0x00000002
+#define UVC_QUIRK_PROBE_EXTRAFIELDS 0x00000004
+#define UVC_QUIRK_BUILTIN_ISIGHT 0x00000008
+#define UVC_QUIRK_STREAM_NO_FID 0x00000010
+#define UVC_QUIRK_IGNORE_SELECTOR_UNIT 0x00000020
+
+/* Format flags */
+#define UVC_FMT_FLAG_COMPRESSED 0x00000001
+#define UVC_FMT_FLAG_STREAM 0x00000002
+
+/* ------------------------------------------------------------------------
+ * Structures.
+ */
+
+struct uvc_device;
+
+/* TODO: Put the most frequently accessed fields at the beginning of
+ * structures to maximize cache efficiency.
+ */
+struct uvc_streaming_control {
+ __u16 bmHint;
+ __u8 bFormatIndex;
+ __u8 bFrameIndex;
+ __u32 dwFrameInterval;
+ __u16 wKeyFrameRate;
+ __u16 wPFrameRate;
+ __u16 wCompQuality;
+ __u16 wCompWindowSize;
+ __u16 wDelay;
+ __u32 dwMaxVideoFrameSize;
+ __u32 dwMaxPayloadTransferSize;
+ __u32 dwClockFrequency;
+ __u8 bmFramingInfo;
+ __u8 bPreferedVersion;
+ __u8 bMinVersion;
+ __u8 bMaxVersion;
+};
+
+struct uvc_menu_info {
+ __u32 value;
+ __u8 name[32];
+};
+
+struct uvc_control_info {
+ struct list_head list;
+ struct list_head mappings;
+
+ __u8 entity[16];
+ __u8 index;
+ __u8 selector;
+
+ __u16 size;
+ __u32 flags;
+};
+
+struct uvc_control_mapping {
+ struct list_head list;
+
+ struct uvc_control_info *ctrl;
+
+ __u32 id;
+ __u8 name[32];
+ __u8 entity[16];
+ __u8 selector;
+
+ __u8 size;
+ __u8 offset;
+ enum v4l2_ctrl_type v4l2_type;
+ __u32 data_type;
+
+ struct uvc_menu_info *menu_info;
+ __u32 menu_count;
+};
+
+struct uvc_control {
+ struct uvc_entity *entity;
+ struct uvc_control_info *info;
+
+ __u8 index; /* Used to match the uvc_control entry with a
+ uvc_control_info. */
+ __u8 dirty : 1,
+ loaded : 1,
+ modified : 1;
+
+ __u8 *data;
+};
+
+struct uvc_format_desc {
+ char *name;
+ __u8 guid[16];
+ __u32 fcc;
+};
+
+/* The term 'entity' refers to both UVC units and UVC terminals.
+ *
+ * The type field is either the terminal type (wTerminalType in the terminal
+ * descriptor), or the unit type (bDescriptorSubtype in the unit descriptor).
+ * As the bDescriptorSubtype field is one byte long, the type value will
+ * always have a null MSB for units. All terminal types defined by the UVC
+ * specification have a non-null MSB, so it is safe to use the MSB to
+ * differentiate between units and terminals as long as the descriptor parsing
+ * code makes sure terminal types have a non-null MSB.
+ *
+ * For terminals, the type's most significant bit stores the terminal
+ * direction (either UVC_TERM_INPUT or UVC_TERM_OUTPUT). The type field should
+ * always be accessed with the UVC_ENTITY_* macros and never directly.
+ */
+
+struct uvc_entity {
+ struct list_head list; /* Entity as part of a UVC device. */
+ struct list_head chain; /* Entity as part of a video device
+ * chain. */
+ __u8 id;
+ __u16 type;
+ char name[64];
+
+ union {
+ struct {
+ __u16 wObjectiveFocalLengthMin;
+ __u16 wObjectiveFocalLengthMax;
+ __u16 wOcularFocalLength;
+ __u8 bControlSize;
+ __u8 *bmControls;
+ } camera;
+
+ struct {
+ __u8 bControlSize;
+ __u8 *bmControls;
+ __u8 bTransportModeSize;
+ __u8 *bmTransportModes;
+ } media;
+
+ struct {
+ __u8 bSourceID;
+ } output;
+
+ struct {
+ __u8 bSourceID;
+ __u16 wMaxMultiplier;
+ __u8 bControlSize;
+ __u8 *bmControls;
+ __u8 bmVideoStandards;
+ } processing;
+
+ struct {
+ __u8 bNrInPins;
+ __u8 *baSourceID;
+ } selector;
+
+ struct {
+ __u8 guidExtensionCode[16];
+ __u8 bNumControls;
+ __u8 bNrInPins;
+ __u8 *baSourceID;
+ __u8 bControlSize;
+ __u8 *bmControls;
+ __u8 *bmControlsType;
+ } extension;
+ };
+
+ unsigned int ncontrols;
+ struct uvc_control *controls;
+};
+
+struct uvc_frame {
+ __u8 bFrameIndex;
+ __u8 bmCapabilities;
+ __u16 wWidth;
+ __u16 wHeight;
+ __u32 dwMinBitRate;
+ __u32 dwMaxBitRate;
+ __u32 dwMaxVideoFrameBufferSize;
+ __u8 bFrameIntervalType;
+ __u32 dwDefaultFrameInterval;
+ __u32 *dwFrameInterval;
+};
+
+struct uvc_format {
+ __u8 type;
+ __u8 index;
+ __u8 bpp;
+ __u8 colorspace;
+ __u32 fcc;
+ __u32 flags;
+
+ char name[32];
+
+ unsigned int nframes;
+ struct uvc_frame *frame;
+};
+
+struct uvc_streaming_header {
+ __u8 bNumFormats;
+ __u8 bEndpointAddress;
+ __u8 bTerminalLink;
+ __u8 bControlSize;
+ __u8 *bmaControls;
+ /* The following fields are used by input headers only. */
+ __u8 bmInfo;
+ __u8 bStillCaptureMethod;
+ __u8 bTriggerSupport;
+ __u8 bTriggerUsage;
+};
+
+struct uvc_streaming {
+ struct list_head list;
+
+ struct usb_interface *intf;
+ int intfnum;
+ __u16 maxpsize;
+
+ struct uvc_streaming_header header;
+
+ unsigned int nformats;
+ struct uvc_format *format;
+
+ struct uvc_streaming_control ctrl;
+ struct uvc_format *cur_format;
+ struct uvc_frame *cur_frame;
+
+ struct mutex mutex;
+};
+
+enum uvc_buffer_state {
+ UVC_BUF_STATE_IDLE = 0,
+ UVC_BUF_STATE_QUEUED = 1,
+ UVC_BUF_STATE_ACTIVE = 2,
+ UVC_BUF_STATE_DONE = 3,
+ UVC_BUF_STATE_ERROR = 4,
+};
+
+struct uvc_buffer {
+ unsigned long vma_use_count;
+ struct list_head stream;
+
+ /* Touched by interrupt handler. */
+ struct v4l2_buffer buf;
+ struct list_head queue;
+ wait_queue_head_t wait;
+ enum uvc_buffer_state state;
+};
+
+#define UVC_QUEUE_STREAMING (1 << 0)
+#define UVC_QUEUE_DISCONNECTED (1 << 1)
+#define UVC_QUEUE_DROP_INCOMPLETE (1 << 2)
+
+struct uvc_video_queue {
+ void *mem;
+ unsigned int flags;
+ __u32 sequence;
+
+ unsigned int count;
+ unsigned int buf_size;
+ struct uvc_buffer buffer[UVC_MAX_VIDEO_BUFFERS];
+ struct mutex mutex; /* protects buffers and mainqueue */
+ spinlock_t irqlock; /* protects irqqueue */
+
+ struct list_head mainqueue;
+ struct list_head irqqueue;
+};
+
+struct uvc_video_device {
+ struct uvc_device *dev;
+ struct video_device *vdev;
+ atomic_t active;
+ unsigned int frozen : 1;
+
+ struct list_head iterms;
+ struct uvc_entity *oterm;
+ struct uvc_entity *processing;
+ struct uvc_entity *selector;
+ struct list_head extensions;
+ struct mutex ctrl_mutex;
+
+ struct uvc_video_queue queue;
+
+ /* Video streaming object, must always be non-NULL. */
+ struct uvc_streaming *streaming;
+
+ void (*decode) (struct urb *urb, struct uvc_video_device *video,
+ struct uvc_buffer *buf);
+
+ /* Context data used by the bulk completion handler. */
+ struct {
+ __u8 header[256];
+ unsigned int header_size;
+ int skip_payload;
+ __u32 payload_size;
+ __u32 max_payload_size;
+ } bulk;
+
+ struct urb *urb[UVC_URBS];
+ char *urb_buffer[UVC_URBS];
+ dma_addr_t urb_dma[UVC_URBS];
+ unsigned int urb_size;
+
+ __u8 last_fid;
+};
+
+enum uvc_device_state {
+ UVC_DEV_DISCONNECTED = 1,
+};
+
+struct uvc_device {
+ struct usb_device *udev;
+ struct usb_interface *intf;
+ __u32 quirks;
+ int intfnum;
+ char name[32];
+
+ enum uvc_device_state state;
+ struct kref kref;
+ struct list_head list;
+
+ /* Video control interface */
+ __u16 uvc_version;
+ __u32 clock_frequency;
+
+ struct list_head entities;
+
+ struct uvc_video_device video;
+
+ /* Status Interrupt Endpoint */
+ struct usb_host_endpoint *int_ep;
+ struct urb *int_urb;
+ __u8 status[16];
+ struct input_dev *input;
+
+ /* Video Streaming interfaces */
+ struct list_head streaming;
+};
+
+enum uvc_handle_state {
+ UVC_HANDLE_PASSIVE = 0,
+ UVC_HANDLE_ACTIVE = 1,
+};
+
+struct uvc_fh {
+ struct uvc_video_device *device;
+ enum uvc_handle_state state;
+};
+
+struct uvc_driver {
+ struct usb_driver driver;
+
+ struct mutex open_mutex; /* protects from open/disconnect race */
+
+ struct list_head devices; /* struct uvc_device list */
+ struct list_head controls; /* struct uvc_control_info list */
+ struct mutex ctrl_mutex; /* protects controls and devices
+ lists */
+};
+
+/* ------------------------------------------------------------------------
+ * Debugging, printing and logging
+ */
+
+#define UVC_TRACE_PROBE (1 << 0)
+#define UVC_TRACE_DESCR (1 << 1)
+#define UVC_TRACE_CONTROL (1 << 2)
+#define UVC_TRACE_FORMAT (1 << 3)
+#define UVC_TRACE_CAPTURE (1 << 4)
+#define UVC_TRACE_CALLS (1 << 5)
+#define UVC_TRACE_IOCTL (1 << 6)
+#define UVC_TRACE_FRAME (1 << 7)
+#define UVC_TRACE_SUSPEND (1 << 8)
+#define UVC_TRACE_STATUS (1 << 9)
+
+extern unsigned int uvc_trace_param;
+
+#define uvc_trace(flag, msg...) \
+ do { \
+ if (uvc_trace_param & flag) \
+ printk(KERN_DEBUG "uvcvideo: " msg); \
+ } while (0)
+
+#define uvc_printk(level, msg...) \
+ printk(level "uvcvideo: " msg)
+
+#define UVC_GUID_FORMAT "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-" \
+ "%02x%02x%02x%02x%02x%02x"
+#define UVC_GUID_ARGS(guid) \
+ (guid)[3], (guid)[2], (guid)[1], (guid)[0], \
+ (guid)[5], (guid)[4], \
+ (guid)[7], (guid)[6], \
+ (guid)[8], (guid)[9], \
+ (guid)[10], (guid)[11], (guid)[12], \
+ (guid)[13], (guid)[14], (guid)[15]
+
+/* --------------------------------------------------------------------------
+ * Internal functions.
+ */
+
+/* Core driver */
+extern struct uvc_driver uvc_driver;
+extern void uvc_delete(struct kref *kref);
+
+/* Video buffers queue management. */
+extern void uvc_queue_init(struct uvc_video_queue *queue);
+extern int uvc_alloc_buffers(struct uvc_video_queue *queue,
+ unsigned int nbuffers, unsigned int buflength);
+extern int 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_queue_buffer(struct uvc_video_queue *queue,
+ struct v4l2_buffer *v4l2_buf);
+extern int uvc_dequeue_buffer(struct uvc_video_queue *queue,
+ struct v4l2_buffer *v4l2_buf, int nonblocking);
+extern int uvc_queue_enable(struct uvc_video_queue *queue, int enable);
+extern void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect);
+extern struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
+ struct uvc_buffer *buf);
+extern unsigned int uvc_queue_poll(struct uvc_video_queue *queue,
+ struct file *file, poll_table *wait);
+static inline int uvc_queue_streaming(struct uvc_video_queue *queue)
+{
+ return queue->flags & UVC_QUEUE_STREAMING;
+}
+
+/* V4L2 interface */
+extern struct file_operations uvc_fops;
+
+/* Video */
+extern int uvc_video_init(struct uvc_video_device *video);
+extern int uvc_video_suspend(struct uvc_video_device *video);
+extern int uvc_video_resume(struct uvc_video_device *video);
+extern int uvc_video_enable(struct uvc_video_device *video, int enable);
+extern int uvc_probe_video(struct uvc_video_device *video,
+ struct uvc_streaming_control *probe);
+extern int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
+ __u8 intfnum, __u8 cs, void *data, __u16 size);
+extern int uvc_set_video_ctrl(struct uvc_video_device *video,
+ struct uvc_streaming_control *ctrl, int probe);
+
+/* Status */
+extern int uvc_status_init(struct uvc_device *dev);
+extern void uvc_status_cleanup(struct uvc_device *dev);
+extern int uvc_status_suspend(struct uvc_device *dev);
+extern int uvc_status_resume(struct uvc_device *dev);
+
+/* Controls */
+extern struct uvc_control *uvc_find_control(struct uvc_video_device *video,
+ __u32 v4l2_id, struct uvc_control_mapping **mapping);
+extern int uvc_query_v4l2_ctrl(struct uvc_video_device *video,
+ struct v4l2_queryctrl *v4l2_ctrl);
+
+extern int uvc_ctrl_add_info(struct uvc_control_info *info);
+extern int uvc_ctrl_add_mapping(struct uvc_control_mapping *mapping);
+extern int uvc_ctrl_init_device(struct uvc_device *dev);
+extern void uvc_ctrl_cleanup_device(struct uvc_device *dev);
+extern int uvc_ctrl_resume_device(struct uvc_device *dev);
+extern void uvc_ctrl_init(void);
+
+extern int uvc_ctrl_begin(struct uvc_video_device *video);
+extern int __uvc_ctrl_commit(struct uvc_video_device *video, int rollback);
+static inline int uvc_ctrl_commit(struct uvc_video_device *video)
+{
+ return __uvc_ctrl_commit(video, 0);
+}
+static inline int uvc_ctrl_rollback(struct uvc_video_device *video)
+{
+ return __uvc_ctrl_commit(video, 1);
+}
+
+extern int uvc_ctrl_get(struct uvc_video_device *video,
+ struct v4l2_ext_control *xctrl);
+extern int uvc_ctrl_set(struct uvc_video_device *video,
+ struct v4l2_ext_control *xctrl);
+
+extern int uvc_xu_ctrl_query(struct uvc_video_device *video,
+ struct uvc_xu_control *ctrl, int set);
+
+/* Utility functions */
+extern void uvc_simplify_fraction(uint32_t *numerator, uint32_t *denominator,
+ unsigned int n_terms, unsigned int threshold);
+extern uint32_t uvc_fraction_to_interval(uint32_t numerator,
+ uint32_t denominator);
+extern struct usb_host_endpoint *uvc_find_endpoint(
+ struct usb_host_interface *alts, __u8 epaddr);
+
+/* Quirks support */
+void uvc_video_decode_isight(struct urb *urb, struct uvc_video_device *video,
+ struct uvc_buffer *buf);
+
+#endif /* __KERNEL__ */
+
+#endif
+
diff --git a/linux/drivers/media/video/v4l2-common.c b/linux/drivers/media/video/v4l2-common.c
index b721aca4e..c8b3da9f6 100644
--- a/linux/drivers/media/video/v4l2-common.c
+++ b/linux/drivers/media/video/v4l2-common.c
@@ -732,9 +732,6 @@ int v4l2_i2c_attach(struct i2c_adapter *adapter, int address, struct i2c_driver
err = probe(client, NULL);
if (err == 0) {
i2c_attach_client(client);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
- MOD_INC_USE_COUNT;
-#endif
} else {
kfree(client);
}
diff --git a/linux/drivers/media/video/videobuf-dma-sg.c b/linux/drivers/media/video/videobuf-dma-sg.c
index 7d459ed6b..39ae44bda 100644
--- a/linux/drivers/media/video/videobuf-dma-sg.c
+++ b/linux/drivers/media/video/videobuf-dma-sg.c
@@ -265,11 +265,7 @@ int videobuf_dma_sync(struct videobuf_queue *q, struct videobuf_dmabuf *dma)
MAGIC_CHECK(dma->magic, MAGIC_DMABUF);
BUG_ON(!dma->sglen);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,5)
- dma_sync_sg(q->dev, dma->sglist, dma->nr_pages, dma->direction);
-#else
dma_sync_sg_for_cpu(q->dev, dma->sglist, dma->nr_pages, dma->direction);
-#endif
return 0;
}
@@ -392,13 +388,8 @@ videobuf_vm_close(struct vm_area_struct *vma)
*/
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
static struct page*
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,1)
-videobuf_vm_nopage(struct vm_area_struct *vma, unsigned long vaddr,
- int write_access)
-#else
videobuf_vm_nopage(struct vm_area_struct *vma, unsigned long vaddr,
int *type)
-#endif
{
struct page *page;
@@ -409,15 +400,9 @@ videobuf_vm_nopage(struct vm_area_struct *vma, unsigned long vaddr,
page = alloc_page(GFP_USER | __GFP_DMA32);
if (!page)
return NOPAGE_OOM;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,20)
- clear_user_page(page_address(page), vaddr);
-#else
clear_user_page(page_address(page), vaddr, page);
-#endif
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,1)
if (type)
*type = VM_FAULT_MINOR;
-#endif
return page;
}
#else
diff --git a/linux/drivers/media/video/videobuf-dvb.c b/linux/drivers/media/video/videobuf-dvb.c
index 9a821371a..d9979ab26 100644
--- a/linux/drivers/media/video/videobuf-dvb.c
+++ b/linux/drivers/media/video/videobuf-dvb.c
@@ -13,8 +13,6 @@
* (at your option) any later version.
*/
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)
-
#include <linux/module.h>
#include <linux/init.h>
#include <linux/device.h>
@@ -161,17 +159,10 @@ int videobuf_dvb_register(struct videobuf_dvb *dvb,
dvb->name, result);
goto fail_adapter;
}
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12))
dvb->adapter.priv = adapter_priv;
/* register frontend */
result = dvb_register_frontend(&dvb->adapter, dvb->frontend);
-#else
- dvb->adapter->priv = adapter_priv;
-
- /* register frontend */
- result = dvb_register_frontend(dvb->adapter, dvb->frontend);
-#endif
if (result < 0) {
printk(KERN_WARNING "%s: dvb_register_frontend failed (errno = %d)\n",
dvb->name, result);
@@ -197,11 +188,7 @@ int videobuf_dvb_register(struct videobuf_dvb *dvb,
dvb->dmxdev.filternum = 256;
dvb->dmxdev.demux = &dvb->demux.dmx;
dvb->dmxdev.capabilities = 0;
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12))
result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter);
-#else
- result = dvb_dmxdev_init(&dvb->dmxdev, dvb->adapter);
-#endif
if (result < 0) {
printk(KERN_WARNING "%s: dvb_dmxdev_init failed (errno = %d)\n",
dvb->name, result);
@@ -232,11 +219,7 @@ int videobuf_dvb_register(struct videobuf_dvb *dvb,
}
/* register network adapter */
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12))
dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx);
-#else
- dvb_net_init(dvb->adapter, &dvb->net, &dvb->demux.dmx);
-#endif
return 0;
fail_fe_conn:
@@ -251,11 +234,7 @@ fail_dmx:
dvb_unregister_frontend(dvb->frontend);
fail_frontend:
dvb_frontend_detach(dvb->frontend);
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12))
dvb_unregister_adapter(&dvb->adapter);
-#else
- dvb_unregister_adapter(dvb->adapter);
-#endif
fail_adapter:
return result;
}
@@ -269,11 +248,7 @@ void videobuf_dvb_unregister(struct videobuf_dvb *dvb)
dvb_dmx_release(&dvb->demux);
dvb_unregister_frontend(dvb->frontend);
dvb_frontend_detach(dvb->frontend);
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12))
dvb_unregister_adapter(&dvb->adapter);
-#else
- dvb_unregister_adapter(dvb->adapter);
-#endif
}
EXPORT_SYMBOL(videobuf_dvb_register);
@@ -286,5 +261,3 @@ EXPORT_SYMBOL(videobuf_dvb_unregister);
* compile-command: "make DVB=1"
* End:
*/
-#endif /* LINUX_VERSION_CODE */
-
diff --git a/linux/drivers/media/video/videodev.c b/linux/drivers/media/video/videodev.c
index d7059944b..91fcf1695 100644
--- a/linux/drivers/media/video/videodev.c
+++ b/linux/drivers/media/video/videodev.c
@@ -17,15 +17,19 @@
*/
#define dbgarg(cmd, fmt, arg...) \
- if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) { \
+ do { \
+ if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) { \
printk(KERN_DEBUG "%s: ", vfd->name); \
v4l_printk_ioctl(cmd); \
printk(" " fmt, ## arg); \
- }
+ } \
+ } while (0)
#define dbgarg2(fmt, arg...) \
- if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) \
- printk(KERN_DEBUG "%s: " fmt, vfd->name, ## arg);
+ do { \
+ if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) \
+ printk(KERN_DEBUG "%s: " fmt, vfd->name, ## arg);\
+ } while (0)
#include <linux/module.h>
#include <linux/types.h>
@@ -55,12 +59,51 @@
#define VIDEO_NUM_DEVICES 256
#define VIDEO_NAME "video4linux"
+struct std_descr {
+ v4l2_std_id std;
+ const char *descr;
+};
+
+static const struct std_descr standards[] = {
+ { V4L2_STD_NTSC, "NTSC" },
+ { V4L2_STD_NTSC_M, "NTSC-M" },
+ { V4L2_STD_NTSC_M_JP, "NTSC-M-JP" },
+ { V4L2_STD_NTSC_M_KR, "NTSC-M-KR" },
+ { V4L2_STD_NTSC_443, "NTSC-443" },
+ { V4L2_STD_PAL, "PAL" },
+ { V4L2_STD_PAL_BG, "PAL-BG" },
+ { V4L2_STD_PAL_B, "PAL-B" },
+ { V4L2_STD_PAL_B1, "PAL-B1" },
+ { V4L2_STD_PAL_G, "PAL-G" },
+ { V4L2_STD_PAL_H, "PAL-H" },
+ { V4L2_STD_PAL_I, "PAL-I" },
+ { V4L2_STD_PAL_DK, "PAL-DK" },
+ { V4L2_STD_PAL_D, "PAL-D" },
+ { V4L2_STD_PAL_D1, "PAL-D1" },
+ { V4L2_STD_PAL_K, "PAL-K" },
+ { V4L2_STD_PAL_M, "PAL-M" },
+ { V4L2_STD_PAL_N, "PAL-N" },
+ { V4L2_STD_PAL_Nc, "PAL-Nc" },
+ { V4L2_STD_PAL_60, "PAL-60" },
+ { V4L2_STD_SECAM, "SECAM" },
+ { V4L2_STD_SECAM_B, "SECAM-B" },
+ { V4L2_STD_SECAM_G, "SECAM-G" },
+ { V4L2_STD_SECAM_H, "SECAM-H" },
+ { V4L2_STD_SECAM_DK, "SECAM-DK" },
+ { V4L2_STD_SECAM_D, "SECAM-D" },
+ { V4L2_STD_SECAM_K, "SECAM-K" },
+ { V4L2_STD_SECAM_K1, "SECAM-K1" },
+ { V4L2_STD_SECAM_L, "SECAM-L" },
+ { V4L2_STD_SECAM_LC, "SECAM-Lc" },
+ { 0, "Unknown" }
+};
+
/* video4linux standard ID conversion to standard name
*/
-char *v4l2_norm_to_name(v4l2_std_id id)
+const char *v4l2_norm_to_name(v4l2_std_id id)
{
- char *name;
u32 myid = id;
+ int i;
/* HACK: ppc32 architecture doesn't have __ucmpdi2 function to handle
64 bit comparations. So, on that architecture, with some gcc
@@ -68,110 +111,17 @@ char *v4l2_norm_to_name(v4l2_std_id id)
*/
BUG_ON(myid != id);
- switch (myid) {
- case V4L2_STD_PAL:
- name = "PAL";
- break;
- case V4L2_STD_PAL_BG:
- name = "PAL-BG";
- break;
- case V4L2_STD_PAL_DK:
- name = "PAL-DK";
- break;
- case V4L2_STD_PAL_B:
- name = "PAL-B";
- break;
- case V4L2_STD_PAL_B1:
- name = "PAL-B1";
- break;
- case V4L2_STD_PAL_G:
- name = "PAL-G";
- break;
- case V4L2_STD_PAL_H:
- name = "PAL-H";
- break;
- case V4L2_STD_PAL_I:
- name = "PAL-I";
- break;
- case V4L2_STD_PAL_D:
- name = "PAL-D";
- break;
- case V4L2_STD_PAL_D1:
- name = "PAL-D1";
- break;
- case V4L2_STD_PAL_K:
- name = "PAL-K";
- break;
- case V4L2_STD_PAL_M:
- name = "PAL-M";
- break;
- case V4L2_STD_PAL_N:
- name = "PAL-N";
- break;
- case V4L2_STD_PAL_Nc:
- name = "PAL-Nc";
- break;
- case V4L2_STD_PAL_60:
- name = "PAL-60";
- break;
- case V4L2_STD_NTSC:
- name = "NTSC";
- break;
- case V4L2_STD_NTSC_M:
- name = "NTSC-M";
- break;
- case V4L2_STD_NTSC_M_JP:
- name = "NTSC-M-JP";
- break;
- case V4L2_STD_NTSC_443:
- name = "NTSC-443";
- break;
- case V4L2_STD_NTSC_M_KR:
- name = "NTSC-M-KR";
- break;
- case V4L2_STD_SECAM:
- name = "SECAM";
- break;
- case V4L2_STD_SECAM_DK:
- name = "SECAM-DK";
- break;
- case V4L2_STD_SECAM_B:
- name = "SECAM-B";
- break;
- case V4L2_STD_SECAM_D:
- name = "SECAM-D";
- break;
- case V4L2_STD_SECAM_G:
- name = "SECAM-G";
- break;
- case V4L2_STD_SECAM_H:
- name = "SECAM-H";
- break;
- case V4L2_STD_SECAM_K:
- name = "SECAM-K";
- break;
- case V4L2_STD_SECAM_K1:
- name = "SECAM-K1";
- break;
- case V4L2_STD_SECAM_L:
- name = "SECAM-L";
- break;
- case V4L2_STD_SECAM_LC:
- name = "SECAM-LC";
- break;
- default:
- name = "Unknown";
- break;
- }
-
- return name;
+ for (i = 0; standards[i].std; i++)
+ if (myid == standards[i].std)
+ break;
+ return standards[i].descr;
}
EXPORT_SYMBOL(v4l2_norm_to_name);
/* Fill in the fields of a v4l2_standard structure according to the
'id' and 'transmission' parameters. Returns negative on error. */
int v4l2_video_std_construct(struct v4l2_standard *vs,
- int id, char *name)
+ int id, const char *name)
{
u32 index = vs->index;
@@ -195,7 +145,7 @@ EXPORT_SYMBOL(v4l2_video_std_construct);
/* ----------------------------------------------------------------- */
/* some arrays for pretty-printing debug messages of enum types */
-char *v4l2_field_names[] = {
+const char *v4l2_field_names[] = {
[V4L2_FIELD_ANY] = "any",
[V4L2_FIELD_NONE] = "none",
[V4L2_FIELD_TOP] = "top",
@@ -209,19 +159,19 @@ char *v4l2_field_names[] = {
};
EXPORT_SYMBOL(v4l2_field_names);
-char *v4l2_type_names[] = {
- [V4L2_BUF_TYPE_VIDEO_CAPTURE] = "video-cap",
- [V4L2_BUF_TYPE_VIDEO_OVERLAY] = "video-over",
- [V4L2_BUF_TYPE_VIDEO_OUTPUT] = "video-out",
+const char *v4l2_type_names[] = {
+ [V4L2_BUF_TYPE_VIDEO_CAPTURE] = "vid-cap",
+ [V4L2_BUF_TYPE_VIDEO_OVERLAY] = "vid-overlay",
+ [V4L2_BUF_TYPE_VIDEO_OUTPUT] = "vid-out",
[V4L2_BUF_TYPE_VBI_CAPTURE] = "vbi-cap",
[V4L2_BUF_TYPE_VBI_OUTPUT] = "vbi-out",
[V4L2_BUF_TYPE_SLICED_VBI_CAPTURE] = "sliced-vbi-cap",
[V4L2_BUF_TYPE_SLICED_VBI_OUTPUT] = "sliced-vbi-out",
- [V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY] = "video-out-over",
+ [V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY] = "vid-out-overlay",
};
EXPORT_SYMBOL(v4l2_type_names);
-static char *v4l2_memory_names[] = {
+static const char *v4l2_memory_names[] = {
[V4L2_MEMORY_MMAP] = "mmap",
[V4L2_MEMORY_USERPTR] = "userptr",
[V4L2_MEMORY_OVERLAY] = "overlay",
@@ -429,29 +379,22 @@ EXPORT_SYMBOL(v4l_printk_ioctl);
* sysfs stuff
*/
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13)
-static ssize_t show_name(struct class_device *cd, char *buf)
-#else
-static ssize_t show_name(struct device *cd,
+static ssize_t show_index(struct device *cd,
struct device_attribute *attr, char *buf)
-#endif
{
struct video_device *vfd = container_of(cd, struct video_device,
class_dev);
- return sprintf(buf, "%.*s\n", (int)sizeof(vfd->name), vfd->name);
+ return sprintf(buf, "%i\n", vfd->index);
}
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12)
-static ssize_t show_dev(struct class_device *cd, char *buf)
+
+static ssize_t show_name(struct device *cd,
+ struct device_attribute *attr, char *buf)
{
struct video_device *vfd = container_of(cd, struct video_device,
- class_dev);
- dev_t dev = MKDEV(VIDEO_MAJOR, vfd->minor);
- return print_dev_t(buf,dev);
+ class_dev);
+ return sprintf(buf, "%.*s\n", (int)sizeof(vfd->name), vfd->name);
}
-static DEVICE_ATTR(dev, S_IRUGO, show_dev, NULL);
-#endif
-
struct video_device *video_device_alloc(void)
{
struct video_device *vfd;
@@ -467,11 +410,7 @@ void video_device_release(struct video_device *vfd)
}
EXPORT_SYMBOL(video_device_release);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13)
-static void video_release(struct class_device *cd)
-#else
static void video_release(struct device *cd)
-#endif
{
struct video_device *vfd = container_of(cd, struct video_device,
class_dev);
@@ -484,21 +423,16 @@ static void video_release(struct device *cd)
vfd->release(vfd);
}
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13)
static struct device_attribute video_device_attrs[] = {
__ATTR(name, S_IRUGO, show_name, NULL),
+ __ATTR(index, S_IRUGO, show_index, NULL),
__ATTR_NULL
};
-#endif
static struct class video_class = {
.name = VIDEO_NAME,
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13)
- .release = video_release,
-#else
.dev_attrs = video_device_attrs,
.dev_release = video_release,
-#endif
};
/*
@@ -738,7 +672,7 @@ static void dbgbuf(unsigned int cmd, struct video_device *vfd,
p->field, p->sequence,
prt_names(p->memory, v4l2_memory_names),
p->m.userptr, p->length);
- dbgarg2 ("timecode= %02d:%02d:%02d type=%d, "
+ dbgarg2("timecode=%02d:%02d:%02d type=%d, "
"flags=0x%08d, frames=%d, userbits=0x%08x\n",
tc->hours,tc->minutes,tc->seconds,
tc->type, tc->flags, tc->frames, *(__u32 *) tc->userbits);
@@ -747,7 +681,7 @@ static void dbgbuf(unsigned int cmd, struct video_device *vfd,
static inline void dbgrect(struct video_device *vfd, char *s,
struct v4l2_rect *r)
{
- dbgarg2 ("%sRect start at %dx%d, size= %dx%d\n", s, r->left, r->top,
+ dbgarg2("%sRect start at %dx%d, size=%dx%d\n", s, r->left, r->top,
r->width, r->height);
};
@@ -765,6 +699,51 @@ static inline void v4l_print_pix_fmt (struct video_device *vfd,
fmt->bytesperline, fmt->sizeimage, fmt->colorspace);
};
+static inline void v4l_print_ext_ctrls(unsigned int cmd,
+ struct video_device *vfd, struct v4l2_ext_controls *c, int show_vals)
+{
+ __u32 i;
+
+ if (!(vfd->debug & V4L2_DEBUG_IOCTL_ARG))
+ return;
+ dbgarg(cmd, "");
+ printk(KERN_CONT "class=0x%x", c->ctrl_class);
+ for (i = 0; i < c->count; i++) {
+ if (show_vals)
+ printk(KERN_CONT " id/val=0x%x/0x%x",
+ c->controls[i].id, c->controls[i].value);
+ else
+ printk(KERN_CONT " id=0x%x", c->controls[i].id);
+ }
+ printk(KERN_CONT "\n");
+};
+
+static inline int check_ext_ctrls(struct v4l2_ext_controls *c, int allow_priv)
+{
+ __u32 i;
+
+ /* zero the reserved fields */
+ c->reserved[0] = c->reserved[1] = 0;
+ for (i = 0; i < c->count; i++) {
+ c->controls[i].reserved2[0] = 0;
+ c->controls[i].reserved2[1] = 0;
+ }
+ /* V4L2_CID_PRIVATE_BASE cannot be used as control class
+ when using extended controls.
+ Only when passed in through VIDIOC_G_CTRL and VIDIOC_S_CTRL
+ is it allowed for backwards compatibility.
+ */
+ if (!allow_priv && c->ctrl_class == V4L2_CID_PRIVATE_BASE)
+ return 0;
+ /* Check that all controls are from the same control class. */
+ for (i = 0; i < c->count; i++) {
+ if (V4L2_CTRL_ID2CLASS(c->controls[i].id) != c->ctrl_class) {
+ c->error_idx = i;
+ return 0;
+ }
+ }
+ return 1;
+}
static int check_fmt (struct video_device *vfd, enum v4l2_buf_type type)
{
@@ -972,7 +951,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
if (vfd->vidioc_g_fmt_vid_cap)
ret = vfd->vidioc_g_fmt_vid_cap(file, fh, f);
if (!ret)
- v4l_print_pix_fmt(vfd,&f->fmt.pix);
+ v4l_print_pix_fmt(vfd, &f->fmt.pix);
break;
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
if (vfd->vidioc_g_fmt_vid_overlay)
@@ -982,6 +961,8 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
if (vfd->vidioc_g_fmt_vid_out)
ret = vfd->vidioc_g_fmt_vid_out(file, fh, f);
+ if (!ret)
+ v4l_print_pix_fmt(vfd, &f->fmt.pix);
break;
case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
if (vfd->vidioc_g_fmt_vid_out_overlay)
@@ -1020,12 +1001,11 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
struct v4l2_format *f = (struct v4l2_format *)arg;
/* FIXME: Should be one dump per type */
- dbgarg (cmd, "type=%s\n", prt_names(f->type,
- v4l2_type_names));
+ dbgarg(cmd, "type=%s\n", prt_names(f->type, v4l2_type_names));
switch (f->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- v4l_print_pix_fmt(vfd,&f->fmt.pix);
+ v4l_print_pix_fmt(vfd, &f->fmt.pix);
if (vfd->vidioc_s_fmt_vid_cap)
ret = vfd->vidioc_s_fmt_vid_cap(file, fh, f);
break;
@@ -1035,6 +1015,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
fh, f);
break;
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ v4l_print_pix_fmt(vfd, &f->fmt.pix);
if (vfd->vidioc_s_fmt_vid_out)
ret = vfd->vidioc_s_fmt_vid_out(file, fh, f);
break;
@@ -1081,7 +1062,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
if (vfd->vidioc_try_fmt_vid_cap)
ret = vfd->vidioc_try_fmt_vid_cap(file, fh, f);
if (!ret)
- v4l_print_pix_fmt(vfd,&f->fmt.pix);
+ v4l_print_pix_fmt(vfd, &f->fmt.pix);
break;
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
if (vfd->vidioc_try_fmt_vid_overlay)
@@ -1091,6 +1072,8 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
if (vfd->vidioc_try_fmt_vid_out)
ret = vfd->vidioc_try_fmt_vid_out(file, fh, f);
+ if (!ret)
+ v4l_print_pix_fmt(vfd, &f->fmt.pix);
break;
case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
if (vfd->vidioc_try_fmt_vid_out_overlay)
@@ -1201,29 +1184,29 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
}
case VIDIOC_G_FBUF:
{
- struct v4l2_framebuffer *p=arg;
+ struct v4l2_framebuffer *p = arg;
+
if (!vfd->vidioc_g_fbuf)
break;
- ret=vfd->vidioc_g_fbuf(file, fh, arg);
+ ret = vfd->vidioc_g_fbuf(file, fh, arg);
if (!ret) {
- dbgarg (cmd, "capability=%d, flags=%d, base=0x%08lx\n",
- p->capability,p->flags,
+ dbgarg(cmd, "capability=0x%x, flags=%d, base=0x%08lx\n",
+ p->capability, p->flags,
(unsigned long)p->base);
- v4l_print_pix_fmt (vfd, &p->fmt);
+ v4l_print_pix_fmt(vfd, &p->fmt);
}
break;
}
case VIDIOC_S_FBUF:
{
- struct v4l2_framebuffer *p=arg;
+ struct v4l2_framebuffer *p = arg;
+
if (!vfd->vidioc_s_fbuf)
break;
-
- dbgarg (cmd, "capability=%d, flags=%d, base=0x%08lx\n",
- p->capability,p->flags,(unsigned long)p->base);
- v4l_print_pix_fmt (vfd, &p->fmt);
- ret=vfd->vidioc_s_fbuf(file, fh, arg);
-
+ dbgarg(cmd, "capability=0x%x, flags=%d, base=0x%08lx\n",
+ p->capability, p->flags, (unsigned long)p->base);
+ v4l_print_pix_fmt(vfd, &p->fmt);
+ ret = vfd->vidioc_s_fbuf(file, fh, arg);
break;
}
case VIDIOC_STREAMON:
@@ -1249,95 +1232,40 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
case VIDIOC_ENUMSTD:
{
struct v4l2_standard *p = arg;
- v4l2_std_id id = vfd->tvnorms,curr_id=0;
- unsigned int index = p->index,i;
-
- if (index<0) {
- ret=-EINVAL;
- break;
- }
-
- /* Return norm array on a canonical way */
- for (i=0;i<= index && id; i++) {
- if ( (id & V4L2_STD_PAL) == V4L2_STD_PAL) {
- curr_id = V4L2_STD_PAL;
- } else if ( (id & V4L2_STD_PAL_BG) == V4L2_STD_PAL_BG) {
- curr_id = V4L2_STD_PAL_BG;
- } else if ( (id & V4L2_STD_PAL_DK) == V4L2_STD_PAL_DK) {
- curr_id = V4L2_STD_PAL_DK;
- } else if ( (id & V4L2_STD_PAL_B) == V4L2_STD_PAL_B) {
- curr_id = V4L2_STD_PAL_B;
- } else if ( (id & V4L2_STD_PAL_B1) == V4L2_STD_PAL_B1) {
- curr_id = V4L2_STD_PAL_B1;
- } else if ( (id & V4L2_STD_PAL_G) == V4L2_STD_PAL_G) {
- curr_id = V4L2_STD_PAL_G;
- } else if ( (id & V4L2_STD_PAL_H) == V4L2_STD_PAL_H) {
- curr_id = V4L2_STD_PAL_H;
- } else if ( (id & V4L2_STD_PAL_I) == V4L2_STD_PAL_I) {
- curr_id = V4L2_STD_PAL_I;
- } else if ( (id & V4L2_STD_PAL_D) == V4L2_STD_PAL_D) {
- curr_id = V4L2_STD_PAL_D;
- } else if ( (id & V4L2_STD_PAL_D1) == V4L2_STD_PAL_D1) {
- curr_id = V4L2_STD_PAL_D1;
- } else if ( (id & V4L2_STD_PAL_K) == V4L2_STD_PAL_K) {
- curr_id = V4L2_STD_PAL_K;
- } else if ( (id & V4L2_STD_PAL_M) == V4L2_STD_PAL_M) {
- curr_id = V4L2_STD_PAL_M;
- } else if ( (id & V4L2_STD_PAL_N) == V4L2_STD_PAL_N) {
- curr_id = V4L2_STD_PAL_N;
- } else if ( (id & V4L2_STD_PAL_Nc) == V4L2_STD_PAL_Nc) {
- curr_id = V4L2_STD_PAL_Nc;
- } else if ( (id & V4L2_STD_PAL_60) == V4L2_STD_PAL_60) {
- curr_id = V4L2_STD_PAL_60;
- } else if ( (id & V4L2_STD_NTSC) == V4L2_STD_NTSC) {
- curr_id = V4L2_STD_NTSC;
- } else if ( (id & V4L2_STD_NTSC_M) == V4L2_STD_NTSC_M) {
- curr_id = V4L2_STD_NTSC_M;
- } else if ( (id & V4L2_STD_NTSC_M_JP) == V4L2_STD_NTSC_M_JP) {
- curr_id = V4L2_STD_NTSC_M_JP;
- } else if ( (id & V4L2_STD_NTSC_443) == V4L2_STD_NTSC_443) {
- curr_id = V4L2_STD_NTSC_443;
- } else if ( (id & V4L2_STD_NTSC_M_KR) == V4L2_STD_NTSC_M_KR) {
- curr_id = V4L2_STD_NTSC_M_KR;
- } else if ( (id & V4L2_STD_SECAM) == V4L2_STD_SECAM) {
- curr_id = V4L2_STD_SECAM;
- } else if ( (id & V4L2_STD_SECAM_DK) == V4L2_STD_SECAM_DK) {
- curr_id = V4L2_STD_SECAM_DK;
- } else if ( (id & V4L2_STD_SECAM_B) == V4L2_STD_SECAM_B) {
- curr_id = V4L2_STD_SECAM_B;
- } else if ( (id & V4L2_STD_SECAM_D) == V4L2_STD_SECAM_D) {
- curr_id = V4L2_STD_SECAM_D;
- } else if ( (id & V4L2_STD_SECAM_G) == V4L2_STD_SECAM_G) {
- curr_id = V4L2_STD_SECAM_G;
- } else if ( (id & V4L2_STD_SECAM_H) == V4L2_STD_SECAM_H) {
- curr_id = V4L2_STD_SECAM_H;
- } else if ( (id & V4L2_STD_SECAM_K) == V4L2_STD_SECAM_K) {
- curr_id = V4L2_STD_SECAM_K;
- } else if ( (id & V4L2_STD_SECAM_K1) == V4L2_STD_SECAM_K1) {
- curr_id = V4L2_STD_SECAM_K1;
- } else if ( (id & V4L2_STD_SECAM_L) == V4L2_STD_SECAM_L) {
- curr_id = V4L2_STD_SECAM_L;
- } else if ( (id & V4L2_STD_SECAM_LC) == V4L2_STD_SECAM_LC) {
- curr_id = V4L2_STD_SECAM_LC;
- } else {
+ v4l2_std_id id = vfd->tvnorms, curr_id = 0;
+ unsigned int index = p->index, i, j = 0;
+ const char *descr = "";
+
+ /* Return norm array in a canonical way */
+ for (i = 0; i <= index && id; i++) {
+ /* last std value in the standards array is 0, so this
+ while always ends there since (id & 0) == 0. */
+ while ((id & standards[j].std) != standards[j].std)
+ j++;
+ curr_id = standards[j].std;
+ descr = standards[j].descr;
+ j++;
+ if (curr_id == 0)
break;
- }
- id &= ~curr_id;
+ if (curr_id != V4L2_STD_PAL &&
+ curr_id != V4L2_STD_SECAM &&
+ curr_id != V4L2_STD_NTSC)
+ id &= ~curr_id;
}
- if (i<=index)
+ if (i <= index)
return -EINVAL;
- v4l2_video_std_construct(p, curr_id,v4l2_norm_to_name(curr_id));
+ v4l2_video_std_construct(p, curr_id, descr);
p->index = index;
- dbgarg (cmd, "index=%d, id=%Ld, name=%s, fps=%d/%d, "
+ dbgarg(cmd, "index=%d, id=0x%Lx, name=%s, fps=%d/%d, "
"framelines=%d\n", p->index,
(unsigned long long)p->id, p->name,
p->frameperiod.numerator,
p->frameperiod.denominator,
p->framelines);
- ret=0;
+ ret = 0;
break;
}
case VIDIOC_G_STD:
@@ -1352,14 +1280,14 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
*id = vfd->current_norm;
if (!ret)
- dbgarg(cmd, "value=%08Lx\n", (long long unsigned)*id);
+ dbgarg(cmd, "std=0x%08Lx\n", (long long unsigned)*id);
break;
}
case VIDIOC_S_STD:
{
v4l2_std_id *id = arg,norm;
- dbgarg (cmd, "value=%08Lx\n", (long long unsigned) *id);
+ dbgarg(cmd, "std=%08Lx\n", (long long unsigned)*id);
norm = (*id) & vfd->tvnorms;
if ( vfd->tvnorms && !norm) /* Check if std is supported */
@@ -1448,8 +1376,8 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
ret = vfd->vidioc_enum_output(file, fh, p);
if (!ret)
dbgarg(cmd, "index=%d, name=%s, type=%d, "
- "audioset=%d, "
- "modulator=%d, std=%08Lx\n",
+ "audioset=0x%x, "
+ "modulator=%d, std=0x%08Lx\n",
p->index, p->name, p->type, p->audioset,
p->modulator, (unsigned long long)p->std);
break;
@@ -1479,132 +1407,172 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
/* --- controls ---------------------------------------------- */
case VIDIOC_QUERYCTRL:
{
- struct v4l2_queryctrl *p=arg;
+ struct v4l2_queryctrl *p = arg;
if (!vfd->vidioc_queryctrl)
break;
- ret=vfd->vidioc_queryctrl(file, fh, p);
-
+ ret = vfd->vidioc_queryctrl(file, fh, p);
if (!ret)
- dbgarg (cmd, "id=%d, type=%d, name=%s, "
- "min/max=%d/%d,"
- " step=%d, default=%d, flags=0x%08x\n",
- p->id,p->type,p->name,p->minimum,
- p->maximum,p->step,p->default_value,
- p->flags);
+ dbgarg(cmd, "id=0x%x, type=%d, name=%s, min/max=%d/%d, "
+ "step=%d, default=%d, flags=0x%08x\n",
+ p->id, p->type, p->name,
+ p->minimum, p->maximum,
+ p->step, p->default_value, p->flags);
+ else
+ dbgarg(cmd, "id=0x%x\n", p->id);
break;
}
case VIDIOC_G_CTRL:
{
struct v4l2_control *p = arg;
- if (!vfd->vidioc_g_ctrl)
+ if (vfd->vidioc_g_ctrl)
+ ret = vfd->vidioc_g_ctrl(file, fh, p);
+ else if (vfd->vidioc_g_ext_ctrls) {
+ struct v4l2_ext_controls ctrls;
+ struct v4l2_ext_control ctrl;
+
+ ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(p->id);
+ ctrls.count = 1;
+ ctrls.controls = &ctrl;
+ ctrl.id = p->id;
+ ctrl.value = p->value;
+ if (check_ext_ctrls(&ctrls, 1)) {
+ ret = vfd->vidioc_g_ext_ctrls(file, fh, &ctrls);
+ if (ret == 0)
+ p->value = ctrl.value;
+ }
+ } else
break;
- dbgarg(cmd, "Enum for index=%d\n", p->id);
-
- ret=vfd->vidioc_g_ctrl(file, fh, p);
if (!ret)
- dbgarg2 ( "id=%d, value=%d\n", p->id, p->value);
+ dbgarg(cmd, "id=0x%x, value=%d\n", p->id, p->value);
+ else
+ dbgarg(cmd, "id=0x%x\n", p->id);
break;
}
case VIDIOC_S_CTRL:
{
struct v4l2_control *p = arg;
+ struct v4l2_ext_controls ctrls;
+ struct v4l2_ext_control ctrl;
+
+ if (!vfd->vidioc_s_ctrl && !vfd->vidioc_s_ext_ctrls)
+ break;
- if (!vfd->vidioc_s_ctrl)
+ dbgarg(cmd, "id=0x%x, value=%d\n", p->id, p->value);
+
+ if (vfd->vidioc_s_ctrl) {
+ ret = vfd->vidioc_s_ctrl(file, fh, p);
+ break;
+ }
+ if (!vfd->vidioc_s_ext_ctrls)
break;
- dbgarg (cmd, "id=%d, value=%d\n", p->id, p->value);
- ret=vfd->vidioc_s_ctrl(file, fh, p);
+ ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(p->id);
+ ctrls.count = 1;
+ ctrls.controls = &ctrl;
+ ctrl.id = p->id;
+ ctrl.value = p->value;
+ if (check_ext_ctrls(&ctrls, 1))
+ ret = vfd->vidioc_s_ext_ctrls(file, fh, &ctrls);
break;
}
case VIDIOC_G_EXT_CTRLS:
{
struct v4l2_ext_controls *p = arg;
- if (vfd->vidioc_g_ext_ctrls) {
- dbgarg(cmd, "count=%d\n", p->count);
-
- ret=vfd->vidioc_g_ext_ctrls(file, fh, p);
- }
+ p->error_idx = p->count;
+ if (!vfd->vidioc_g_ext_ctrls)
+ break;
+ if (check_ext_ctrls(p, 0))
+ ret = vfd->vidioc_g_ext_ctrls(file, fh, p);
+ v4l_print_ext_ctrls(cmd, vfd, p, !ret);
break;
}
case VIDIOC_S_EXT_CTRLS:
{
struct v4l2_ext_controls *p = arg;
- if (vfd->vidioc_s_ext_ctrls) {
- dbgarg(cmd, "count=%d\n", p->count);
-
- ret=vfd->vidioc_s_ext_ctrls(file, fh, p);
- }
+ p->error_idx = p->count;
+ if (!vfd->vidioc_s_ext_ctrls)
+ break;
+ v4l_print_ext_ctrls(cmd, vfd, p, 1);
+ if (check_ext_ctrls(p, 0))
+ ret = vfd->vidioc_s_ext_ctrls(file, fh, p);
break;
}
case VIDIOC_TRY_EXT_CTRLS:
{
struct v4l2_ext_controls *p = arg;
- if (vfd->vidioc_try_ext_ctrls) {
- dbgarg(cmd, "count=%d\n", p->count);
-
- ret=vfd->vidioc_try_ext_ctrls(file, fh, p);
- }
+ p->error_idx = p->count;
+ if (!vfd->vidioc_try_ext_ctrls)
+ break;
+ v4l_print_ext_ctrls(cmd, vfd, p, 1);
+ if (check_ext_ctrls(p, 0))
+ ret = vfd->vidioc_try_ext_ctrls(file, fh, p);
break;
}
case VIDIOC_QUERYMENU:
{
- struct v4l2_querymenu *p=arg;
+ struct v4l2_querymenu *p = arg;
+
if (!vfd->vidioc_querymenu)
break;
- ret=vfd->vidioc_querymenu(file, fh, p);
+ ret = vfd->vidioc_querymenu(file, fh, p);
if (!ret)
- dbgarg (cmd, "id=%d, index=%d, name=%s\n",
- p->id,p->index,p->name);
+ dbgarg(cmd, "id=0x%x, index=%d, name=%s\n",
+ p->id, p->index, p->name);
+ else
+ dbgarg(cmd, "id=0x%x, index=%d\n",
+ p->id, p->index);
break;
}
/* --- audio ---------------------------------------------- */
case VIDIOC_ENUMAUDIO:
{
- struct v4l2_audio *p=arg;
+ struct v4l2_audio *p = arg;
if (!vfd->vidioc_enumaudio)
break;
- dbgarg(cmd, "Enum for index=%d\n", p->index);
- ret=vfd->vidioc_enumaudio(file, fh, p);
+ ret = vfd->vidioc_enumaudio(file, fh, p);
if (!ret)
- dbgarg2("index=%d, name=%s, capability=%d, "
- "mode=%d\n",p->index,p->name,
+ dbgarg(cmd, "index=%d, name=%s, capability=0x%x, "
+ "mode=0x%x\n", p->index, p->name,
p->capability, p->mode);
+ else
+ dbgarg(cmd, "index=%d\n", p->index);
break;
}
case VIDIOC_G_AUDIO:
{
- struct v4l2_audio *p=arg;
- __u32 index=p->index;
+ struct v4l2_audio *p = arg;
+ __u32 index = p->index;
if (!vfd->vidioc_g_audio)
break;
- memset(p,0,sizeof(*p));
- p->index=index;
- dbgarg(cmd, "Get for index=%d\n", p->index);
- ret=vfd->vidioc_g_audio(file, fh, p);
+ memset(p, 0, sizeof(*p));
+ p->index = index;
+ ret = vfd->vidioc_g_audio(file, fh, p);
if (!ret)
- dbgarg2("index=%d, name=%s, capability=%d, "
- "mode=%d\n",p->index,
- p->name,p->capability, p->mode);
+ dbgarg(cmd, "index=%d, name=%s, capability=0x%x, "
+ "mode=0x%x\n", p->index,
+ p->name, p->capability, p->mode);
+ else
+ dbgarg(cmd, "index=%d\n", p->index);
break;
}
case VIDIOC_S_AUDIO:
{
- struct v4l2_audio *p=arg;
+ struct v4l2_audio *p = arg;
if (!vfd->vidioc_s_audio)
break;
- dbgarg(cmd, "index=%d, name=%s, capability=%d, "
- "mode=%d\n", p->index, p->name,
+ dbgarg(cmd, "index=%d, name=%s, capability=0x%x, "
+ "mode=0x%x\n", p->index, p->name,
p->capability, p->mode);
- ret=vfd->vidioc_s_audio(file, fh, p);
+ ret = vfd->vidioc_s_audio(file, fh, p);
break;
}
case VIDIOC_ENUMAUDOUT:
@@ -1680,9 +1648,9 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
struct v4l2_crop *p=arg;
if (!vfd->vidioc_g_crop)
break;
+ dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
ret=vfd->vidioc_g_crop(file, fh, p);
if (!ret) {
- dbgarg(cmd, "type=%d\n", p->type);
dbgrect(vfd, "", &p->c);
}
break;
@@ -1692,21 +1660,24 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
struct v4l2_crop *p=arg;
if (!vfd->vidioc_s_crop)
break;
- dbgarg(cmd, "type=%d\n", p->type);
+ dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
dbgrect(vfd, "", &p->c);
ret=vfd->vidioc_s_crop(file, fh, p);
break;
}
case VIDIOC_CROPCAP:
{
- struct v4l2_cropcap *p=arg;
+ struct v4l2_cropcap *p = arg;
+
/*FIXME: Should also show v4l2_fract pixelaspect */
if (!vfd->vidioc_cropcap)
break;
- dbgarg(cmd, "type=%d\n", p->type);
- dbgrect(vfd, "bounds ", &p->bounds);
- dbgrect(vfd, "defrect ", &p->defrect);
- ret=vfd->vidioc_cropcap(file, fh, p);
+ dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
+ ret = vfd->vidioc_cropcap(file, fh, p);
+ if (!ret) {
+ dbgrect(vfd, "bounds ", &p->bounds);
+ dbgrect(vfd, "defrect ", &p->defrect);
+ }
break;
}
case VIDIOC_G_JPEGCOMP:
@@ -1749,26 +1720,26 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
}
case VIDIOC_ENCODER_CMD:
{
- struct v4l2_encoder_cmd *p=arg;
+ struct v4l2_encoder_cmd *p = arg;
if (!vfd->vidioc_encoder_cmd)
break;
- ret=vfd->vidioc_encoder_cmd(file, fh, p);
+ memset(&p->raw, 0, sizeof(p->raw));
+ ret = vfd->vidioc_encoder_cmd(file, fh, p);
if (!ret)
- dbgarg (cmd, "cmd=%d, flags=%d\n",
- p->cmd,p->flags);
+ dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags);
break;
}
case VIDIOC_TRY_ENCODER_CMD:
{
- struct v4l2_encoder_cmd *p=arg;
+ struct v4l2_encoder_cmd *p = arg;
if (!vfd->vidioc_try_encoder_cmd)
break;
- ret=vfd->vidioc_try_encoder_cmd(file, fh, p);
+ memset(&p->raw, 0, sizeof(p->raw));
+ ret = vfd->vidioc_try_encoder_cmd(file, fh, p);
if (!ret)
- dbgarg (cmd, "cmd=%d, flags=%d\n",
- p->cmd,p->flags);
+ dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags);
break;
}
case VIDIOC_G_PARM:
@@ -1808,40 +1779,42 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
}
case VIDIOC_G_TUNER:
{
- struct v4l2_tuner *p=arg;
- __u32 index=p->index;
+ struct v4l2_tuner *p = arg;
+ __u32 index = p->index;
if (!vfd->vidioc_g_tuner)
break;
- memset(p,0,sizeof(*p));
- p->index=index;
+ memset(p, 0, sizeof(*p));
+ p->index = index;
- ret=vfd->vidioc_g_tuner(file, fh, p);
+ ret = vfd->vidioc_g_tuner(file, fh, p);
if (!ret)
- dbgarg (cmd, "index=%d, name=%s, type=%d, "
- "capability=%d, rangelow=%d, "
+ dbgarg(cmd, "index=%d, name=%s, type=%d, "
+ "capability=0x%x, rangelow=%d, "
"rangehigh=%d, signal=%d, afc=%d, "
- "rxsubchans=%d, audmode=%d\n",
+ "rxsubchans=0x%x, audmode=%d\n",
p->index, p->name, p->type,
p->capability, p->rangelow,
- p->rangehigh, p->rxsubchans,
- p->audmode, p->signal, p->afc);
+ p->rangehigh, p->signal, p->afc,
+ p->rxsubchans, p->audmode);
break;
}
case VIDIOC_S_TUNER:
{
- struct v4l2_tuner *p=arg;
+ struct v4l2_tuner *p = arg;
+
if (!vfd->vidioc_s_tuner)
break;
- dbgarg (cmd, "index=%d, name=%s, type=%d, "
- "capability=%d, rangelow=%d, rangehigh=%d, "
- "signal=%d, afc=%d, rxsubchans=%d, "
- "audmode=%d\n",p->index, p->name, p->type,
- p->capability, p->rangelow,p->rangehigh,
- p->rxsubchans, p->audmode, p->signal,
- p->afc);
- ret=vfd->vidioc_s_tuner(file, fh, p);
+ dbgarg(cmd, "index=%d, name=%s, type=%d, "
+ "capability=0x%x, rangelow=%d, "
+ "rangehigh=%d, signal=%d, afc=%d, "
+ "rxsubchans=0x%x, audmode=%d\n",
+ p->index, p->name, p->type,
+ p->capability, p->rangelow,
+ p->rangehigh, p->signal, p->afc,
+ p->rxsubchans, p->audmode);
+ ret = vfd->vidioc_s_tuner(file, fh, p);
break;
}
case VIDIOC_G_FREQUENCY:
@@ -1871,12 +1844,17 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
}
case VIDIOC_G_SLICED_VBI_CAP:
{
- struct v4l2_sliced_vbi_cap *p=arg;
+ struct v4l2_sliced_vbi_cap *p = arg;
+ __u32 type = p->type;
+
if (!vfd->vidioc_g_sliced_vbi_cap)
break;
- ret=vfd->vidioc_g_sliced_vbi_cap(file, fh, p);
+ memset(p, 0, sizeof(*p));
+ p->type = type;
+ dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
+ ret = vfd->vidioc_g_sliced_vbi_cap(file, fh, p);
if (!ret)
- dbgarg (cmd, "service_set=%d\n", p->service_set);
+ dbgarg2("service_set=%d\n", p->service_set);
break;
}
case VIDIOC_LOG_STATUS:
@@ -1937,10 +1915,9 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
} /* switch */
if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) {
- if (ret<0) {
- printk("%s: err: on ", vfd->name);
+ if (ret < 0) {
v4l_print_ioctl(vfd->name, cmd);
- printk("\n");
+ printk(KERN_CONT " error %d\n", ret);
}
}
@@ -2042,8 +2019,84 @@ out:
}
EXPORT_SYMBOL(video_ioctl2);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25)
+struct index_info {
+ struct device *dev;
+ unsigned int used[VIDEO_NUM_DEVICES];
+};
+
+static int __fill_index_info(struct device *cd, void *data)
+{
+ struct index_info *info = data;
+ struct video_device *vfd = container_of(cd, struct video_device,
+ class_dev);
+
+ if (info->dev == vfd->dev)
+ info->used[vfd->index] = 1;
+
+ return 0;
+}
+
+/**
+ * assign_index - assign stream number based on parent device
+ * @vdev: video_device to assign index number to, vdev->dev should be assigned
+ * @num: -1 if auto assign, requested number otherwise
+ *
+ *
+ * returns -ENFILE if num is already in use, a free index number if
+ * successful.
+ */
+static int get_index(struct video_device *vdev, int num)
+{
+ struct index_info *info;
+ int i;
+ int ret = 0;
+
+ if (num >= VIDEO_NUM_DEVICES)
+ return -EINVAL;
+
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ info->dev = vdev->dev;
+
+ ret = class_for_each_device(&video_class, info,
+ __fill_index_info);
+
+ if (ret < 0)
+ goto out;
+
+ if (num >= 0) {
+ if (!info->used[num])
+ ret = num;
+ else
+ ret = -ENFILE;
+
+ goto out;
+ }
+
+ for (i = 0; i < VIDEO_NUM_DEVICES; i++) {
+ if (info->used[i])
+ continue;
+ ret = i;
+ goto out;
+ }
+
+out:
+ kfree(info);
+ return ret;
+}
+#endif
+
static const struct file_operations video_fops;
+int video_register_device(struct video_device *vfd, int type, int nr)
+{
+ return video_register_device_index(vfd, type, nr, -1);
+}
+EXPORT_SYMBOL(video_register_device);
+
/**
* video_register_device - register video4linux devices
* @vfd: video device structure we want to register
@@ -2069,7 +2122,8 @@ static const struct file_operations video_fops;
* %VFL_TYPE_RADIO - A radio card
*/
-int video_register_device(struct video_device *vfd, int type, int nr)
+int video_register_device_index(struct video_device *vfd, int type, int nr,
+ int index)
{
int i=0;
int base;
@@ -2126,51 +2180,36 @@ int video_register_device(struct video_device *vfd, int type, int nr)
}
video_device[i]=vfd;
vfd->minor=i;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25)
+ ret = get_index(vfd, index);
+#else
+ ret = 0;
+#endif
+ if (ret < 0) {
+ printk(KERN_ERR "%s: get_index failed\n",
+ __func__);
+ goto fail_minor;
+ }
+
+ vfd->index = ret;
+
mutex_unlock(&videodev_lock);
mutex_init(&vfd->lock);
/* sysfs class */
memset(&vfd->class_dev, 0x00, sizeof(vfd->class_dev));
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13)
- if (vfd->dev)
- vfd->class_dev.dev = vfd->dev;
-#else
if (vfd->dev)
vfd->class_dev.parent = vfd->dev;
-#endif
vfd->class_dev.class = &video_class;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12)
vfd->class_dev.devt = MKDEV(VIDEO_MAJOR, vfd->minor);
-#endif
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13)
- sprintf(vfd->class_dev.class_id, "%s%d", name_base, i - base);
-#else
sprintf(vfd->class_dev.bus_id, "%s%d", name_base, i - base);
-#endif
ret = device_register(&vfd->class_dev);
if (ret < 0) {
printk(KERN_ERR "%s: device_register failed\n",
__func__);
goto fail_minor;
}
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13)
- ret = class_device_create_file(&vfd->class_dev, &class_device_attr_name);
- if (ret < 0) {
- printk(KERN_ERR "%s: class_device_create_file 'name' failed\n",
- __FUNCTION__);
- class_device_unregister(&vfd->class_dev);
- goto fail_minor;
- }
-#endif
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12)
- ret = class_device_create_file(&vfd->class_dev, &class_device_attr_dev);
- if (ret < 0) {
- printk(KERN_ERR "%s: class_device_create_file 'dev' failed\n",
- __FUNCTION__);
- class_device_unregister(&vfd->class_dev);
- goto fail_minor;
- }
-#endif
#if 1 /* keep */
/* needed until all drivers are fixed */
@@ -2188,7 +2227,7 @@ fail_minor:
mutex_unlock(&videodev_lock);
return ret;
}
-EXPORT_SYMBOL(video_register_device);
+EXPORT_SYMBOL(video_register_device_index);
/**
* video_unregister_device - unregister a video4linux device
diff --git a/linux/drivers/media/video/vivi.c b/linux/drivers/media/video/vivi.c
index 028040dd8..98ee2225c 100644
--- a/linux/drivers/media/video/vivi.c
+++ b/linux/drivers/media/video/vivi.c
@@ -40,14 +40,14 @@
#include <linux/interrupt.h>
#include <media/videobuf-vmalloc.h>
#include <media/v4l2-common.h>
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
#include <linux/kthread.h>
-#endif
#include <linux/highmem.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
#include <linux/freezer.h>
#endif
+#define VIVI_MODULE_NAME "vivi"
+
/* Wake up at about 30 fps */
#define WAKE_NUMERATOR 30
#define WAKE_DENOMINATOR 1001
@@ -56,7 +56,7 @@
#include "font.h"
#define VIVI_MAJOR_VERSION 0
-#define VIVI_MINOR_VERSION 4
+#define VIVI_MINOR_VERSION 5
#define VIVI_RELEASE 0
#define VIVI_VERSION \
KERNEL_VERSION(VIVI_MAJOR_VERSION, VIVI_MINOR_VERSION, VIVI_RELEASE)
@@ -159,10 +159,6 @@ struct vivi_dmaqueue {
/* thread for generating video stream*/
struct task_struct *kthread;
wait_queue_head_t wq;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
- struct semaphore *notify;
- int rmmod:1;
-#endif
/* Counters to control fps rate */
int frame;
int ini_jiffies;
@@ -340,13 +336,14 @@ static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
int hmax = buf->vb.height;
int wmax = buf->vb.width;
struct timeval ts;
- char *tmpbuf = kmalloc(wmax * 2, GFP_ATOMIC);
+ char *tmpbuf;
void *vbuf = videobuf_to_vmalloc(&buf->vb);
- if (!tmpbuf)
+ if (!vbuf)
return;
- if (!vbuf)
+ tmpbuf = kmalloc(wmax * 2, GFP_ATOMIC);
+ if (!tmpbuf)
return;
for (h = 0; h < hmax; h++) {
@@ -443,13 +440,8 @@ static void vivi_sleep(struct vivi_fh *fh)
(unsigned long)dma_q);
add_wait_queue(&dma_q->wq, &wait);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
- if ((q->rmmod || signal_pending(current)))
- goto stop_task;
-#else
if (kthread_should_stop())
goto stop_task;
-#endif
/* Calculate time to wake up */
timeout = msecs_to_jiffies(frames_to_ms(1));
@@ -468,20 +460,6 @@ static int vivi_thread(void *data)
struct vivi_fh *fh = data;
struct vivi_dev *dev = fh->dev;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
- daemonize();
- exit_files(current);
- reparent_to_init();
-
- spin_lock_irq(SIGMASK_LOCK(current));
- sigfillset(&current->blocked);
- spin_unlock_irq(SIGMASK_LOCK(current));
- strcpy(current->comm, "vivi");
-
- dma_q->kthread = current;
- if (dma_q->notify != NULL)
- up(dma_q->notify);
-#endif
dprintk(dev, 1, "thread started\n");
set_freezable();
@@ -489,20 +467,10 @@ static int vivi_thread(void *data)
for (;;) {
vivi_sleep(fh);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
- if (dma_q->rmmod || signal_pending(current))
-#else
if (kthread_should_stop())
-#endif
break;
}
dprintk(dev, 1, "thread: exit\n");
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
- dma_q->kthread = NULL;
-
- if (dma_q->notify != NULL)
- up(dma_q->notify);
-#endif
return 0;
}
@@ -516,28 +484,12 @@ static int vivi_start_thread(struct vivi_fh *fh)
dprintk(dev, 1, "%s\n", __func__);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
dma_q->kthread = kthread_run(vivi_thread, fh, "vivi");
if (IS_ERR(dma_q->kthread)) {
printk(KERN_ERR "vivi: kernel_thread() failed\n");
return PTR_ERR(dma_q->kthread);
}
-#else
- DECLARE_MUTEX_LOCKED(sem);
-
- dma_q->kthread = NULL;
- dma_q->notify = &sem;
- dma_q->rmmod = 0;
-
- if (kernel_thread(vivi_thread, fh, 0) < 0) {
- printk(KERN_ERR "sdim: kernel_thread() failed\n");
- return -EINVAL;
- }
-
- down(&sem);
- dma_q->notify = NULL;
-#endif
/* Wakes thread */
wake_up_interruptible(&dma_q->wq);
@@ -552,19 +504,7 @@ static void vivi_stop_thread(struct vivi_dmaqueue *dma_q)
dprintk(dev, 1, "%s\n", __func__);
/* shutdown control thread */
if (dma_q->kthread) {
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
- DECLARE_MUTEX_LOCKED(sem);
-
- /* shutdown control thread */
- dma_q->notify = &sem;
- dma_q->rmmod = 1;
- if (waitqueue_active(&dma_q->wq))
- wake_up_interruptible(&dma_q->wq);
- down(&sem);
- dma_q->notify = NULL;
-#else
kthread_stop(dma_q->kthread);
-#endif
dma_q->kthread = NULL;
}
}
@@ -1086,10 +1026,15 @@ static int vivi_release(void)
list_del(list);
dev = list_entry(list, struct vivi_dev, vivi_devlist);
- if (-1 != dev->vfd->minor)
+ if (-1 != dev->vfd->minor) {
video_unregister_device(dev->vfd);
- else
+ printk(KERN_INFO "%s: /dev/video%d unregistered.\n",
+ VIVI_MODULE_NAME, dev->vfd->minor);
+ } else {
video_device_release(dev->vfd);
+ printk(KERN_INFO "%s: /dev/video%d released.\n",
+ VIVI_MODULE_NAME, dev->vfd->minor);
+ }
kfree(dev);
}
@@ -1122,9 +1067,7 @@ static const struct file_operations vivi_fops = {
.read = vivi_read,
.poll = vivi_poll,
.ioctl = video_ioctl2, /* V4L2 ioctl handler */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11)
.compat_ioctl = v4l_compat_ioctl32,
-#endif
.mmap = vivi_mmap,
.llseek = no_llseek,
};
@@ -1202,6 +1145,8 @@ static int __init vivi_init(void)
video_nr++;
dev->vfd = vfd;
+ printk(KERN_INFO "%s: V4L2 device registered as /dev/video%d\n",
+ VIVI_MODULE_NAME, vfd->minor);
}
if (ret < 0) {
@@ -1209,7 +1154,9 @@ static int __init vivi_init(void)
printk(KERN_INFO "Error %d while loading vivi driver\n", ret);
} else
printk(KERN_INFO "Video Technology Magazine Virtual Video "
- "Capture Board successfully loaded.\n");
+ "Capture Board ver %u.%u.%u successfully loaded.\n",
+ (VIVI_VERSION >> 16) & 0xFF, (VIVI_VERSION >> 8) & 0xFF,
+ VIVI_VERSION & 0xFF);
return ret;
}
diff --git a/linux/drivers/media/video/vp27smpx.c b/linux/drivers/media/video/vp27smpx.c
index 28f0cd162..6c47c5e5a 100644
--- a/linux/drivers/media/video/vp27smpx.c
+++ b/linux/drivers/media/video/vp27smpx.c
@@ -31,10 +31,6 @@
#include <media/v4l2-common.h>
#include <media/v4l2-chip-ident.h>
#include <media/v4l2-i2c-drv.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
-#include "i2c-compat.h"
-#include <linux/slab.h>
-#endif
#include "compat.h"
MODULE_DESCRIPTION("vp27smpx driver");
@@ -44,10 +40,6 @@ MODULE_LICENSE("GPL");
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
static unsigned short normal_i2c[] = { 0xb6 >> 1, I2C_CLIENT_END };
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 13)
-static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
-#endif
-
I2C_CLIENT_INSMOD;
#endif
@@ -144,8 +136,9 @@ static int vp27smpx_probe(struct i2c_client *client,
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -EIO;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
snprintf(client->name, sizeof(client->name) - 1, "vp27smpx");
-
+#endif
v4l_info(client, "chip found @ 0x%x (%s)\n",
client->addr << 1, client->adapter->name);
@@ -168,17 +161,21 @@ static int vp27smpx_remove(struct i2c_client *client)
/* ----------------------------------------------------------------------- */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+static const struct i2c_device_id vp27smpx_id[] = {
+ { "vp27smpx", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, vp27smpx_id);
+#endif
+
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.name = "vp27smpx",
.driverid = I2C_DRIVERID_VP27SMPX,
.command = vp27smpx_command,
.probe = vp27smpx_probe,
.remove = vp27smpx_remove,
-#ifndef I2C_CLASS_TV_ANALOG
- .legacy_id = I2C_HW_B_CX2341X,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ .id_table = vp27smpx_id,
#endif
};
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
-EXPORT_NO_SYMBOLS;
-#endif
diff --git a/linux/drivers/media/video/wm8739.c b/linux/drivers/media/video/wm8739.c
index 838444ece..b361d0d42 100644
--- a/linux/drivers/media/video/wm8739.c
+++ b/linux/drivers/media/video/wm8739.c
@@ -31,10 +31,6 @@
#include <media/v4l2-common.h>
#include <media/v4l2-chip-ident.h>
#include <media/v4l2-i2c-drv.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
-#include "i2c-compat.h"
-#include <linux/slab.h>
-#endif
#include "compat.h"
MODULE_DESCRIPTION("wm8739 driver");
@@ -43,21 +39,13 @@ MODULE_LICENSE("GPL");
static int debug;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
module_param(debug, int, 0644);
-#else
-MODULE_PARM(debug, "i");
-#endif
MODULE_PARM_DESC(debug, "Debug level (0-1)");
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
static unsigned short normal_i2c[] = { 0x34 >> 1, 0x36 >> 1, I2C_CLIENT_END };
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 13)
-static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
-#endif
-
I2C_CLIENT_INSMOD;
#endif
@@ -331,17 +319,21 @@ static int wm8739_remove(struct i2c_client *client)
return 0;
}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+static const struct i2c_device_id wm8739_id[] = {
+ { "wm8739", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8739_id);
+#endif
+
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.name = "wm8739",
.driverid = I2C_DRIVERID_WM8739,
.command = wm8739_command,
.probe = wm8739_probe,
.remove = wm8739_remove,
-#ifndef I2C_CLASS_TV_ANALOG
- .legacy_id = I2C_HW_B_CX2341X,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ .id_table = wm8739_id,
#endif
};
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
-EXPORT_NO_SYMBOLS;
-#endif
diff --git a/linux/drivers/media/video/wm8775.c b/linux/drivers/media/video/wm8775.c
index d0e47fb22..e7a2e0449 100644
--- a/linux/drivers/media/video/wm8775.c
+++ b/linux/drivers/media/video/wm8775.c
@@ -35,10 +35,6 @@
#include <media/v4l2-common.h>
#include <media/v4l2-chip-ident.h>
#include <media/v4l2-i2c-drv-legacy.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
-#include "i2c-compat.h"
-#include <linux/slab.h>
-#endif
#include "compat.h"
MODULE_DESCRIPTION("wm8775 driver");
@@ -47,10 +43,6 @@ MODULE_LICENSE("GPL");
static unsigned short normal_i2c[] = { 0x36 >> 1, I2C_CLIENT_END };
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 13)
-static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
-#endif
-
I2C_CLIENT_INSMOD;
@@ -224,14 +216,21 @@ static int wm8775_remove(struct i2c_client *client)
return 0;
}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+static const struct i2c_device_id wm8775_id[] = {
+ { "wm8775", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8775_id);
+
+#endif
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.name = "wm8775",
.driverid = I2C_DRIVERID_WM8775,
.command = wm8775_command,
.probe = wm8775_probe,
.remove = wm8775_remove,
-};
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
-EXPORT_NO_SYMBOLS;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ .id_table = wm8775_id,
#endif
+};
diff --git a/linux/drivers/media/video/zc0301/zc0301_core.c b/linux/drivers/media/video/zc0301/zc0301_core.c
index 261964c6a..e167fa560 100644
--- a/linux/drivers/media/video/zc0301/zc0301_core.c
+++ b/linux/drivers/media/video/zc0301/zc0301_core.c
@@ -38,7 +38,7 @@
#include <linux/mm.h>
#include <linux/vmalloc.h>
#include <linux/page-flags.h>
-#include <linux/byteorder/generic.h>
+#include <asm/byteorder.h>
#include <asm/page.h>
#include <asm/uaccess.h>
diff --git a/linux/drivers/media/video/zoran.h b/linux/drivers/media/video/zoran.h
index 5f74688c1..baa5f423d 100644
--- a/linux/drivers/media/video/zoran.h
+++ b/linux/drivers/media/video/zoran.h
@@ -285,7 +285,7 @@ struct zoran_mapping {
struct zoran_jpg_buffer {
struct zoran_mapping *map;
- u32 *frag_tab; /* addresses of frag table */
+ __le32 *frag_tab; /* addresses of frag table */
u32 frag_tab_bus; /* same value cached to save time in ISR */
enum zoran_buffer_state state; /* non-zero if corresponding buffer is in use in grab queue */
struct zoran_sync bs; /* DONE: info to return to application */
@@ -454,7 +454,7 @@ struct zoran {
unsigned long jpg_queued_num; /* count of frames queued since grab/play started */
/* zr36057's code buffer table */
- u32 *stat_com; /* stat_com[i] is indexed by dma_head/tail & BUZ_MASK_STAT_COM */
+ __le32 *stat_com; /* stat_com[i] is indexed by dma_head/tail & BUZ_MASK_STAT_COM */
/* (value & BUZ_MASK_FRAME) corresponds to index in pend[] queue */
int jpg_pend[BUZ_MAX_FRAME];
diff --git a/linux/drivers/media/video/zoran_card.c b/linux/drivers/media/video/zoran_card.c
index 946dee4eb..b517ce4f1 100644
--- a/linux/drivers/media/video/zoran_card.c
+++ b/linux/drivers/media/video/zoran_card.c
@@ -62,8 +62,6 @@
#include "zoran_device.h"
#include "zoran_procfs.h"
-#define I2C_NAME(x) (x)->name
-
extern const struct zoran_format zoran_formats[];
static int card[BUZ_MAX] = { -1, -1, -1, -1 };
@@ -812,7 +810,7 @@ clientunreg_unlock_and_return:
return res;
}
-static struct i2c_algo_bit_data zoran_i2c_bit_data_template = {
+static const struct i2c_algo_bit_data zoran_i2c_bit_data_template = {
.setsda = zoran_i2c_setsda,
.setscl = zoran_i2c_setscl,
.getsda = zoran_i2c_getsda,
@@ -821,24 +819,17 @@ static struct i2c_algo_bit_data zoran_i2c_bit_data_template = {
.timeout = 100,
};
-static struct i2c_adapter zoran_i2c_adapter_template = {
- .name = "zr36057",
- .id = I2C_HW_B_ZR36067,
- .algo = NULL,
- .client_register = zoran_i2c_client_register,
- .client_unregister = zoran_i2c_client_unregister,
-};
-
static int
zoran_register_i2c (struct zoran *zr)
{
memcpy(&zr->i2c_algo, &zoran_i2c_bit_data_template,
sizeof(struct i2c_algo_bit_data));
zr->i2c_algo.data = zr;
- memcpy(&zr->i2c_adapter, &zoran_i2c_adapter_template,
- sizeof(struct i2c_adapter));
- strncpy(I2C_NAME(&zr->i2c_adapter), ZR_DEVNAME(zr),
- sizeof(I2C_NAME(&zr->i2c_adapter)) - 1);
+ zr->i2c_adapter.id = I2C_HW_B_ZR36067;
+ zr->i2c_adapter.client_register = zoran_i2c_client_register;
+ zr->i2c_adapter.client_unregister = zoran_i2c_client_unregister;
+ strlcpy(zr->i2c_adapter.name, ZR_DEVNAME(zr),
+ sizeof(zr->i2c_adapter.name));
i2c_set_adapdata(&zr->i2c_adapter, zr);
zr->i2c_adapter.algo_data = &zr->i2c_algo;
zr->i2c_adapter.dev.parent = &zr->pci_dev->dev;
@@ -1150,7 +1141,7 @@ zr36057_init (struct zoran *zr)
goto exit_free;
}
for (j = 0; j < BUZ_NUM_STAT_COM; j++) {
- zr->stat_com[j] = 1; /* mark as unavailable to zr36057 */
+ zr->stat_com[j] = cpu_to_le32(1); /* mark as unavailable to zr36057 */
}
/*
diff --git a/linux/drivers/media/video/zoran_device.c b/linux/drivers/media/video/zoran_device.c
index 575f5447c..b0a014d09 100644
--- a/linux/drivers/media/video/zoran_device.c
+++ b/linux/drivers/media/video/zoran_device.c
@@ -31,7 +31,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/vmalloc.h>
-#include <linux/byteorder/generic.h>
#include <linux/interrupt.h>
#include <linux/proc_fs.h>
@@ -48,6 +47,7 @@
#include <linux/delay.h>
#include <linux/wait.h>
+#include <asm/byteorder.h>
#include <asm/io.h>
#include "videocodec.h"
@@ -1321,7 +1321,7 @@ error_handler (struct zoran *zr,
if (i) {
/* Rotate stat_comm entries to make current entry first */
int j;
- u32 bus_addr[BUZ_NUM_STAT_COM];
+ __le32 bus_addr[BUZ_NUM_STAT_COM];
/* Here we are copying the stat_com array, which
* is already in little endian format, so
diff --git a/linux/drivers/media/video/zoran_driver.c b/linux/drivers/media/video/zoran_driver.c
index 0949c53f0..73546a20d 100644
--- a/linux/drivers/media/video/zoran_driver.c
+++ b/linux/drivers/media/video/zoran_driver.c
@@ -52,7 +52,6 @@
#include <linux/pci.h>
#include <linux/vmalloc.h>
#include <linux/wait.h>
-#include <linux/byteorder/generic.h>
#include <linux/interrupt.h>
#include <linux/i2c.h>
@@ -74,6 +73,7 @@
#include <media/v4l2-common.h>
#include "videocodec.h"
+#include <asm/byteorder.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/proc_fs.h>
@@ -97,7 +97,6 @@
V4L2_CAP_VIDEO_OVERLAY \
)
-#include <asm/byteorder.h>
#if defined(CONFIG_VIDEO_V4L1_COMPAT)
#define ZFMT(pal, fcc, cs) \
@@ -562,7 +561,7 @@ jpg_fbuffer_alloc (struct file *file)
jpg_fbuffer_free(file);
return -ENOBUFS;
}
- fh->jpg_buffers.buffer[i].frag_tab = (u32 *) mem;
+ fh->jpg_buffers.buffer[i].frag_tab = (__le32 *) mem;
fh->jpg_buffers.buffer[i].frag_tab_bus =
virt_to_bus((void *) mem);
@@ -2862,7 +2861,7 @@ zoran_do_ioctl (struct inode *inode,
{
struct v4l2_format *fmt = arg;
int i, res = 0;
- __u32 printformat;
+ __le32 printformat;
dprintk(3, KERN_DEBUG "%s: VIDIOC_S_FMT - type=%d, ",
ZR_DEVNAME(zr), fmt->type);
@@ -3107,7 +3106,7 @@ zoran_do_ioctl (struct inode *inode,
{
int i, res = 0;
struct v4l2_framebuffer *fb = arg;
- __u32 printformat = __cpu_to_le32(fb->fmt.pixelformat);
+ __le32 printformat = __cpu_to_le32(fb->fmt.pixelformat);
dprintk(3,
KERN_DEBUG
@@ -4573,7 +4572,7 @@ zoran_mmap (struct file *file,
if (todo > fraglen)
todo = fraglen;
pos =
- le32_to_cpu((unsigned long) fh->jpg_buffers.
+ le32_to_cpu(fh->jpg_buffers.
buffer[i].frag_tab[2 * j]);
/* should just be pos on i386 */
page = virt_to_phys(bus_to_virt(pos))