summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xlinux/Documentation/dvb/get_dvb_firmware2
-rw-r--r--linux/Documentation/video4linux/CARDLIST.cx238851
-rw-r--r--linux/Documentation/video4linux/CARDLIST.cx887
-rw-r--r--linux/Documentation/video4linux/CARDLIST.em28xx6
-rw-r--r--linux/Documentation/video4linux/CARDLIST.saa71344
-rw-r--r--linux/Documentation/video4linux/CARDLIST.tuner1
-rw-r--r--linux/Documentation/video4linux/cx18.txt2
-rw-r--r--linux/Documentation/video4linux/gspca.txt5
-rw-r--r--linux/arch/arm/mach-mx3/clock.c19
-rw-r--r--linux/arch/arm/mach-pxa/devices.c9
-rw-r--r--linux/arch/arm/mach-pxa/pcm990-baseboard.c2
-rw-r--r--linux/arch/arm/plat-mxc/include/mach/memory.h8
-rw-r--r--linux/arch/sh/boards/board-ap325rxa.c15
-rw-r--r--linux/arch/sh/boards/mach-migor/setup.c19
-rw-r--r--linux/drivers/media/Kconfig10
-rw-r--r--linux/drivers/media/common/ir-keymaps.c23
-rw-r--r--linux/drivers/media/common/tuners/tuner-simple.c57
-rw-r--r--linux/drivers/media/common/tuners/tuner-types.c29
-rw-r--r--linux/drivers/media/common/tuners/tuner-xc2028.c54
-rw-r--r--linux/drivers/media/common/tuners/xc5000.c273
-rw-r--r--linux/drivers/media/dvb/b2c2/flexcop-common.h8
-rw-r--r--linux/drivers/media/dvb/b2c2/flexcop-fe-tuner.c790
-rw-r--r--linux/drivers/media/dvb/b2c2/flexcop-i2c.c2
-rw-r--r--linux/drivers/media/dvb/b2c2/flexcop-misc.c20
-rw-r--r--linux/drivers/media/dvb/bt8xx/bt878.c8
-rw-r--r--linux/drivers/media/dvb/dm1105/dm1105.c121
-rw-r--r--linux/drivers/media/dvb/dvb-core/dmxdev.c14
-rw-r--r--linux/drivers/media/dvb/dvb-core/dvb_demux.c42
-rw-r--r--linux/drivers/media/dvb/dvb-core/dvb_demux.h4
-rw-r--r--linux/drivers/media/dvb/dvb-core/dvb_frontend.c2
-rw-r--r--linux/drivers/media/dvb/dvb-core/dvb_net.c65
-rw-r--r--linux/drivers/media/dvb/dvb-usb/Kconfig3
-rw-r--r--linux/drivers/media/dvb/dvb-usb/af9015.c10
-rw-r--r--linux/drivers/media/dvb/dvb-usb/dib0700_devices.c24
-rw-r--r--linux/drivers/media/dvb/dvb-usb/dibusb-common.c7
-rw-r--r--linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h4
-rw-r--r--linux/drivers/media/dvb/dvb-usb/dw2102.c328
-rw-r--r--linux/drivers/media/dvb/dvb-usb/dw2102.h1
-rw-r--r--linux/drivers/media/dvb/dvb-usb/gp8psk.c6
-rw-r--r--linux/drivers/media/dvb/frontends/au8522_dig.c98
-rw-r--r--linux/drivers/media/dvb/frontends/lgdt3305.c17
-rw-r--r--linux/drivers/media/dvb/frontends/lgs8gxx.c10
-rw-r--r--linux/drivers/media/dvb/frontends/lnbp21.c2
-rw-r--r--linux/drivers/media/dvb/frontends/mt312.c2
-rw-r--r--linux/drivers/media/dvb/frontends/stv0900.h7
-rw-r--r--linux/drivers/media/dvb/frontends/stv0900_core.c100
-rw-r--r--linux/drivers/media/dvb/frontends/stv0900_priv.h2
-rw-r--r--linux/drivers/media/dvb/siano/Makefile2
-rw-r--r--linux/drivers/media/dvb/siano/sms-cards.c188
-rw-r--r--linux/drivers/media/dvb/siano/sms-cards.h64
-rw-r--r--linux/drivers/media/dvb/siano/smscoreapi.c480
-rw-r--r--linux/drivers/media/dvb/siano/smscoreapi.h66
-rw-r--r--linux/drivers/media/dvb/siano/smsdvb.c53
-rw-r--r--linux/drivers/media/dvb/siano/smsendian.h6
-rw-r--r--linux/drivers/media/dvb/siano/smsir.c26
-rw-r--r--linux/drivers/media/dvb/siano/smssdio.c7
-rw-r--r--linux/drivers/media/dvb/siano/smsusb.c16
-rw-r--r--linux/drivers/media/radio/dsbr100.c109
-rw-r--r--linux/drivers/media/radio/radio-mr800.c1
-rw-r--r--linux/drivers/media/radio/radio-tea5764.c4
-rw-r--r--linux/drivers/media/video/Kconfig10
-rw-r--r--linux/drivers/media/video/Makefile70
-rw-r--r--linux/drivers/media/video/au0828/au0828-cards.c4
-rw-r--r--linux/drivers/media/video/au0828/au0828-core.c17
-rw-r--r--linux/drivers/media/video/au0828/au0828-video.c8
-rw-r--r--linux/drivers/media/video/bt8xx/bttv-driver.c14
-rw-r--r--linux/drivers/media/video/bt8xx/bttv-i2c.c23
-rw-r--r--linux/drivers/media/video/cx18/cx18-av-core.c140
-rw-r--r--linux/drivers/media/video/cx18/cx18-av-vbi.c4
-rw-r--r--linux/drivers/media/video/cx18/cx18-cards.c63
-rw-r--r--linux/drivers/media/video/cx18/cx18-controls.c2
-rw-r--r--linux/drivers/media/video/cx18/cx18-driver.c3
-rw-r--r--linux/drivers/media/video/cx18/cx18-driver.h5
-rw-r--r--linux/drivers/media/video/cx18/cx18-dvb.c53
-rw-r--r--linux/drivers/media/video/cx18/cx18-streams.c9
-rw-r--r--linux/drivers/media/video/cx231xx/cx231xx-avcore.c19
-rw-r--r--linux/drivers/media/video/cx231xx/cx231xx-cards.c13
-rw-r--r--linux/drivers/media/video/cx231xx/cx231xx-i2c.c34
-rw-r--r--linux/drivers/media/video/cx231xx/cx231xx-input.c2
-rw-r--r--linux/drivers/media/video/cx231xx/cx231xx-video.c26
-rw-r--r--linux/drivers/media/video/cx231xx/cx231xx.h7
-rw-r--r--linux/drivers/media/video/cx2341x.c2
-rw-r--r--linux/drivers/media/video/cx23885/cx23885-417.c1
-rw-r--r--linux/drivers/media/video/cx23885/cx23885-cards.c22
-rw-r--r--linux/drivers/media/video/cx23885/cx23885-dvb.c58
-rw-r--r--linux/drivers/media/video/cx23885/cx23885-i2c.c14
-rw-r--r--linux/drivers/media/video/cx23885/cx23885-video.c25
-rw-r--r--linux/drivers/media/video/cx23885/cx23885.h1
-rw-r--r--linux/drivers/media/video/cx88/cx88-alsa.c7
-rw-r--r--linux/drivers/media/video/cx88/cx88-cards.c189
-rw-r--r--linux/drivers/media/video/cx88/cx88-core.c1
-rw-r--r--linux/drivers/media/video/cx88/cx88-dvb.c1
-rw-r--r--linux/drivers/media/video/cx88/cx88-i2c.c15
-rw-r--r--linux/drivers/media/video/cx88/cx88-input.c2
-rw-r--r--linux/drivers/media/video/cx88/cx88-video.c27
-rw-r--r--linux/drivers/media/video/cx88/cx88.h1
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-audio.c5
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-cards.c257
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-core.c56
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-dvb.c21
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-i2c.c27
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-input.c14
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-reg.h16
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-video.c38
-rw-r--r--linux/drivers/media/video/em28xx/em28xx.h9
-rw-r--r--linux/drivers/media/video/gspca/gspca.c147
-rw-r--r--linux/drivers/media/video/gspca/m5602/m5602_ov9650.c37
-rw-r--r--linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.c6
-rw-r--r--linux/drivers/media/video/gspca/ov519.c1436
-rw-r--r--linux/drivers/media/video/gspca/ov534.c248
-rw-r--r--linux/drivers/media/video/gspca/sonixj.c183
-rw-r--r--linux/drivers/media/video/gspca/spca505.c14
-rw-r--r--linux/drivers/media/video/gspca/spca508.c1947
-rw-r--r--linux/drivers/media/video/gspca/spca561.c105
-rw-r--r--linux/drivers/media/video/gspca/stv06xx/Makefile3
-rw-r--r--linux/drivers/media/video/gspca/stv06xx/stv06xx.c55
-rw-r--r--linux/drivers/media/video/gspca/stv06xx/stv06xx.h12
-rw-r--r--linux/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c10
-rw-r--r--linux/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h3
-rw-r--r--linux/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c453
-rw-r--r--linux/drivers/media/video/gspca/stv06xx/stv06xx_st6422.h59
-rw-r--r--linux/drivers/media/video/hdpvr/hdpvr-video.c2
-rw-r--r--linux/drivers/media/video/ir-kbd-i2c.c149
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-controls.c2
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-driver.c2
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-i2c.c38
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-queue.c3
-rw-r--r--linux/drivers/media/video/mt9m001.c12
-rw-r--r--linux/drivers/media/video/mt9t031.c14
-rw-r--r--linux/drivers/media/video/mt9v022.c12
-rw-r--r--linux/drivers/media/video/mx3_camera.c6
-rw-r--r--linux/drivers/media/video/ov511.c47
-rw-r--r--linux/drivers/media/video/ov511.h3
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c4
-rw-r--r--linux/drivers/media/video/pwc/pwc-if.c6
-rw-r--r--linux/drivers/media/video/pxa_camera.c40
-rw-r--r--linux/drivers/media/video/s2255drv.c48
-rw-r--r--linux/drivers/media/video/saa7134/Kconfig1
-rw-r--r--linux/drivers/media/video/saa7134/Makefile3
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-cards.c12
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-core.c18
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-dvb.c26
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-empress.c11
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-i2c.c35
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-input.c138
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-ts.c120
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-video.c21
-rw-r--r--linux/drivers/media/video/saa7134/saa7134.h16
-rw-r--r--linux/drivers/media/video/se401.c882
-rw-r--r--linux/drivers/media/video/se401.h7
-rw-r--r--linux/drivers/media/video/sh_mobile_ceu_camera.c12
-rw-r--r--linux/drivers/media/video/soc_camera.c2
-rw-r--r--linux/drivers/media/video/tcm825x.c4
-rw-r--r--linux/drivers/media/video/tuner-core.c6
-rw-r--r--linux/drivers/media/video/tveeprom.c4
-rw-r--r--linux/drivers/media/video/tvp514x.c2
-rw-r--r--linux/drivers/media/video/usbvideo/Kconfig5
-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.c14
-rw-r--r--linux/drivers/media/video/usbvision/usbvision-video.c2
-rw-r--r--linux/drivers/media/video/uvc/uvc_ctrl.c35
-rw-r--r--linux/drivers/media/video/uvc/uvc_driver.c68
-rw-r--r--linux/drivers/media/video/uvc/uvc_queue.c14
-rw-r--r--linux/drivers/media/video/uvc/uvc_status.c21
-rw-r--r--linux/drivers/media/video/uvc/uvc_v4l2.c31
-rw-r--r--linux/drivers/media/video/uvc/uvc_video.c17
-rw-r--r--linux/drivers/media/video/uvc/uvcvideo.h5
-rw-r--r--linux/drivers/media/video/v4l2-common.c76
-rw-r--r--linux/drivers/media/video/v4l2-device.c4
-rw-r--r--linux/drivers/media/video/videobuf-core.c1
-rw-r--r--linux/drivers/media/video/videobuf-dma-sg.c19
-rw-r--r--linux/drivers/media/video/vino.c6
-rw-r--r--linux/drivers/media/video/vivi.c11
-rw-r--r--linux/drivers/media/video/w9968cf.c35
-rw-r--r--linux/drivers/media/video/zoran/zoran_card.c2
-rw-r--r--linux/drivers/media/video/zoran/zoran_driver.c14
-rw-r--r--linux/drivers/media/video/zr364xx.c6
-rw-r--r--linux/include/linux/mmc/sdio_ids.h10
-rw-r--r--linux/include/linux/videodev2.h7
-rw-r--r--linux/include/media/ir-common.h2
-rw-r--r--linux/include/media/ir-kbd-i2c.h12
-rw-r--r--linux/include/media/tuner.h1
-rw-r--r--linux/include/media/v4l2-common.h10
-rw-r--r--linux/include/media/v4l2-i2c-drv.h5
-rw-r--r--linux/sound/pci/bt87x.c8
-rwxr-xr-xmailimport6
-rw-r--r--v4l/compat.h22
-rw-r--r--[-rwxr-xr-x]v4l/scripts/gentree.pl16
-rwxr-xr-xv4l/scripts/make_config_compat.pl46
-rw-r--r--v4l/versions.txt5
-rw-r--r--v4l2-apps/libv4l/ChangeLog70
-rw-r--r--v4l2-apps/libv4l/Makefile4
-rw-r--r--v4l2-apps/libv4l/README28
-rw-r--r--v4l2-apps/libv4l/TODO5
-rw-r--r--v4l2-apps/libv4l/include/libv4l1.h2
-rw-r--r--v4l2-apps/libv4l/include/libv4l2.h24
-rw-r--r--v4l2-apps/libv4l/include/libv4lconvert.h40
-rw-r--r--v4l2-apps/libv4l/libv4l1/Makefile10
-rw-r--r--v4l2-apps/libv4l/libv4l1/libv4l1-priv.h9
-rw-r--r--v4l2-apps/libv4l/libv4l1/libv4l1.c76
-rw-r--r--v4l2-apps/libv4l/libv4l1/log.c7
-rw-r--r--v4l2-apps/libv4l/libv4l1/v4l1compat.c5
-rw-r--r--v4l2-apps/libv4l/libv4l2/Makefile12
-rw-r--r--v4l2-apps/libv4l/libv4l2/libv4l2-priv.h9
-rw-r--r--v4l2-apps/libv4l/libv4l2/libv4l2.c174
-rw-r--r--v4l2-apps/libv4l/libv4l2/log.c23
-rw-r--r--v4l2-apps/libv4l/libv4l2/v4l2convert.c20
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/Makefile28
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol-priv.h54
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c504
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.h70
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/crop.c138
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/flip.c158
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/helper-funcs.h79
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/helper.c224
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h65
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c488
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/libv4lsyscall-priv.h112
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/ov511-decomp.c666
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/ov518-decomp.c1477
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/processing/autogain.c140
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/processing/gamma.c57
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing-priv.h60
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.c181
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.h43
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/processing/whitebalance.c142
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/rgbyuv.c5
-rw-r--r--v4l2-apps/util/v4l2-ctl.cpp78
-rw-r--r--v4l2-spec/pixfmt.sgml5
-rw-r--r--v4l2-spec/vidioc-g-modulator.sgml13
231 files changed, 12990 insertions, 3885 deletions
diff --git a/linux/Documentation/dvb/get_dvb_firmware b/linux/Documentation/dvb/get_dvb_firmware
index 815a57840..a52adfc9a 100755
--- a/linux/Documentation/dvb/get_dvb_firmware
+++ b/linux/Documentation/dvb/get_dvb_firmware
@@ -317,7 +317,7 @@ sub nxt2002 {
sub nxt2004 {
my $sourcefile = "AVerTVHD_MCE_A180_Drv_v1.2.2.16.zip";
- my $url = "http://www.aver.com/support/Drivers/$sourcefile";
+ my $url = "http://www.avermedia-usa.com/support/Drivers/$sourcefile";
my $hash = "111cb885b1e009188346d72acfed024c";
my $outfile = "dvb-fe-nxt2004.fw";
my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
diff --git a/linux/Documentation/video4linux/CARDLIST.cx23885 b/linux/Documentation/video4linux/CARDLIST.cx23885
index 948e43610..450b8f8c3 100644
--- a/linux/Documentation/video4linux/CARDLIST.cx23885
+++ b/linux/Documentation/video4linux/CARDLIST.cx23885
@@ -20,3 +20,4 @@
19 -> Hauppauge WinTV-HVR1275 [0070:2215]
20 -> Hauppauge WinTV-HVR1255 [0070:2251]
21 -> Hauppauge WinTV-HVR1210 [0070:2291,0070:2295]
+ 22 -> Mygica X8506 DMB-TH [14f1:8651]
diff --git a/linux/Documentation/video4linux/CARDLIST.cx88 b/linux/Documentation/video4linux/CARDLIST.cx88
index 80527b292..0736518b2 100644
--- a/linux/Documentation/video4linux/CARDLIST.cx88
+++ b/linux/Documentation/video4linux/CARDLIST.cx88
@@ -6,8 +6,8 @@
5 -> Leadtek Winfast 2000XP Expert [107d:6611,107d:6613]
6 -> AverTV Studio 303 (M126) [1461:000b]
7 -> MSI TV-@nywhere Master [1462:8606]
- 8 -> Leadtek Winfast DV2000 [107d:6620]
- 9 -> Leadtek PVR 2000 [107d:663b,107d:663c,107d:6632]
+ 8 -> Leadtek Winfast DV2000 [107d:6620,107d:6621]
+ 9 -> Leadtek PVR 2000 [107d:663b,107d:663c,107d:6632,107d:6630,107d:6638,107d:6631,107d:6637,107d:663d]
10 -> IODATA GV-VCP3/PCI [10fc:d003]
11 -> Prolink PlayTV PVR
12 -> ASUS PVR-416 [1043:4823,1461:c111]
@@ -59,7 +59,7 @@
58 -> Pinnacle PCTV HD 800i [11bd:0051]
59 -> DViCO FusionHDTV 5 PCI nano [18ac:d530]
60 -> Pinnacle Hybrid PCTV [12ab:1788]
- 61 -> Winfast TV2000 XP Global [107d:6f18]
+ 61 -> Leadtek TV2000 XP Global [107d:6f18,107d:6618]
62 -> PowerColor RA330 [14f1:ea3d]
63 -> Geniatech X8000-MT DVBT [14f1:8852]
64 -> DViCO FusionHDTV DVB-T PRO [18ac:db30]
@@ -79,3 +79,4 @@
78 -> Prof 6200 DVB-S [b022:3022]
79 -> Terratec Cinergy HT PCI MKII [153b:1177]
80 -> Hauppauge WinTV-IR Only [0070:9290]
+ 81 -> Leadtek WinFast DTV1800 Hybrid [107d:6654]
diff --git a/linux/Documentation/video4linux/CARDLIST.em28xx b/linux/Documentation/video4linux/CARDLIST.em28xx
index bf58d957e..873630e7e 100644
--- a/linux/Documentation/video4linux/CARDLIST.em28xx
+++ b/linux/Documentation/video4linux/CARDLIST.em28xx
@@ -17,7 +17,7 @@
16 -> Hauppauge WinTV HVR 950 (em2883) [2040:6513,2040:6517,2040:651b]
17 -> Pinnacle PCTV HD Pro Stick (em2880) [2304:0227]
18 -> Hauppauge WinTV HVR 900 (R2) (em2880) [2040:6502]
- 19 -> PointNix Intra-Oral Camera (em2860)
+ 19 -> EM2860/SAA711X Reference Design (em2860)
20 -> AMD ATI TV Wonder HD 600 (em2880) [0438:b002]
21 -> eMPIA Technology, Inc. GrabBeeX+ Video Encoder (em2800) [eb1a:2801]
22 -> Unknown EM2750/EM2751 webcam grabber (em2750) [eb1a:2750,eb1a:2751]
@@ -62,3 +62,7 @@
64 -> Easy Cap Capture DC-60 (em2860)
65 -> IO-DATA GV-MVP/SZ (em2820/em2840) [04bb:0515]
66 -> Empire dual TV (em2880)
+ 67 -> Terratec Grabby (em2860) [0ccd:0096]
+ 68 -> Terratec AV350 (em2860) [0ccd:0084]
+ 69 -> KWorld ATSC 315U HDTV TV Box (em2882) [eb1a:a313]
+ 70 -> Evga inDtube (em2882)
diff --git a/linux/Documentation/video4linux/CARDLIST.saa7134 b/linux/Documentation/video4linux/CARDLIST.saa7134
index 112ff4f4f..15562427e 100644
--- a/linux/Documentation/video4linux/CARDLIST.saa7134
+++ b/linux/Documentation/video4linux/CARDLIST.saa7134
@@ -143,7 +143,7 @@
142 -> Beholder BeholdTV H6 [5ace:6290]
143 -> Beholder BeholdTV M63 [5ace:6191]
144 -> Beholder BeholdTV M6 Extra [5ace:6193]
-145 -> AVerMedia MiniPCI DVB-T Hybrid M103 [1461:f636]
+145 -> AVerMedia MiniPCI DVB-T Hybrid M103 [1461:f636,1461:f736]
146 -> ASUSTeK P7131 Analog
147 -> Asus Tiger 3in1 [1043:4878]
148 -> Encore ENLTV-FM v5.3 [1a7f:2008]
@@ -154,7 +154,7 @@
153 -> Kworld Plus TV Analog Lite PCI [17de:7128]
154 -> Avermedia AVerTV GO 007 FM Plus [1461:f31d]
155 -> Hauppauge WinTV-HVR1120 ATSC/QAM-Hybrid [0070:6706,0070:6708]
-156 -> Hauppauge WinTV-HVR1110r3 [0070:6707,0070:6709,0070:670a]
+156 -> Hauppauge WinTV-HVR1110r3 DVB-T/Hybrid [0070:6707,0070:6709,0070:670a]
157 -> Avermedia AVerTV Studio 507UA [1461:a11b]
158 -> AVerMedia Cardbus TV/Radio (E501R) [1461:b7e9]
159 -> Beholder BeholdTV 505 RDS [0000:505B]
diff --git a/linux/Documentation/video4linux/CARDLIST.tuner b/linux/Documentation/video4linux/CARDLIST.tuner
index 22c1c5597..be6784407 100644
--- a/linux/Documentation/video4linux/CARDLIST.tuner
+++ b/linux/Documentation/video4linux/CARDLIST.tuner
@@ -77,3 +77,4 @@ tuner=76 - Xceive 5000 tuner
tuner=77 - TCL tuner MF02GIP-5N-E
tuner=78 - Philips FMD1216MEX MK3 Hybrid Tuner
tuner=79 - Philips PAL/SECAM multi (FM1216 MK5)
+tuner=80 - Philips FQ1216LME MK3 PAL/SECAM w/active loopthrough
diff --git a/linux/Documentation/video4linux/cx18.txt b/linux/Documentation/video4linux/cx18.txt
index 914cb7e73..4652c0f5d 100644
--- a/linux/Documentation/video4linux/cx18.txt
+++ b/linux/Documentation/video4linux/cx18.txt
@@ -11,7 +11,7 @@ encoder chip:
2) Some people have problems getting the i2c bus to work.
The symptom is that the eeprom cannot be read and the card is
unusable. This is probably fixed, but if you have problems
- then post to the video4linux or ivtv-users mailinglist.
+ then post to the video4linux or ivtv-users mailing list.
3) VBI (raw or sliced) has not yet been implemented.
diff --git a/linux/Documentation/video4linux/gspca.txt b/linux/Documentation/video4linux/gspca.txt
index 1bb103fe9..2bcf78896 100644
--- a/linux/Documentation/video4linux/gspca.txt
+++ b/linux/Documentation/video4linux/gspca.txt
@@ -163,10 +163,11 @@ sunplus 055f:c650 Mustek MDC5500Z
zc3xx 055f:d003 Mustek WCam300A
zc3xx 055f:d004 Mustek WCam300 AN
conex 0572:0041 Creative Notebook cx11646
-ov519 05a9:0519 OmniVision
+ov519 05a9:0519 OV519 Microphone
ov519 05a9:0530 OmniVision
-ov519 05a9:4519 OmniVision
+ov519 05a9:4519 Webcam Classic
ov519 05a9:8519 OmniVision
+ov519 05a9:a518 D-Link DSB-C310 Webcam
sunplus 05da:1018 Digital Dream Enigma 1.3
stk014 05e1:0893 Syntek DV4000
spca561 060b:a001 Maxell Compact Pc PM3
diff --git a/linux/arch/arm/mach-mx3/clock.c b/linux/arch/arm/mach-mx3/clock.c
index 9957a1153..8b1423972 100644
--- a/linux/arch/arm/mach-mx3/clock.c
+++ b/linux/arch/arm/mach-mx3/clock.c
@@ -483,7 +483,7 @@ DEFINE_CLOCK(i2c3_clk, 2, MXC_CCM_CGR0, 30, NULL, NULL, &perclk_clk);
DEFINE_CLOCK(mpeg4_clk, 0, MXC_CCM_CGR1, 0, NULL, NULL, &ahb_clk);
DEFINE_CLOCK(mstick1_clk, 0, MXC_CCM_CGR1, 2, mstick1_get_rate, NULL, &usb_pll_clk);
DEFINE_CLOCK(mstick2_clk, 1, MXC_CCM_CGR1, 4, mstick2_get_rate, NULL, &usb_pll_clk);
-DEFINE_CLOCK1(csi_clk, 0, MXC_CCM_CGR1, 6, csi, NULL, &ahb_clk);
+DEFINE_CLOCK1(csi_clk, 0, MXC_CCM_CGR1, 6, csi, NULL, &serial_pll_clk);
DEFINE_CLOCK(rtc_clk, 0, MXC_CCM_CGR1, 8, NULL, NULL, &ipg_clk);
DEFINE_CLOCK(wdog_clk, 0, MXC_CCM_CGR1, 10, NULL, NULL, &ipg_clk);
DEFINE_CLOCK(pwm_clk, 0, MXC_CCM_CGR1, 12, NULL, NULL, &perclk_clk);
@@ -516,7 +516,7 @@ DEFINE_CLOCK(ipg_clk, 0, NULL, 0, ipg_get_rate, NULL, &ahb_clk);
.clk = &c, \
},
-static struct clk_lookup lookups[] __initdata = {
+static struct clk_lookup lookups[] = {
_REGISTER_CLOCK(NULL, "emi", emi_clk)
_REGISTER_CLOCK(NULL, "cspi", cspi1_clk)
_REGISTER_CLOCK(NULL, "cspi", cspi2_clk)
@@ -566,13 +566,18 @@ int __init mx31_clocks_init(unsigned long fref)
u32 reg;
int i;
- mxc_set_cpu_type(MXC_CPU_MX31);
-
ckih_rate = fref;
for (i = 0; i < ARRAY_SIZE(lookups); i++)
clkdev_add(&lookups[i]);
+ /* change the csi_clk parent if necessary */
+ reg = __raw_readl(MXC_CCM_CCMR);
+ if (!(reg & MXC_CCM_CCMR_CSCS))
+ if (clk_set_parent(&csi_clk, &usb_pll_clk))
+ pr_err("%s: error changing csi_clk parent\n", __func__);
+
+
/* Turn off all possible clocks */
__raw_writel((3 << 4), MXC_CCM_CGR0);
__raw_writel(0, MXC_CCM_CGR1);
@@ -581,6 +586,12 @@ int __init mx31_clocks_init(unsigned long fref)
MX32, but still required to be set */
MXC_CCM_CGR2);
+ /*
+ * Before turning off usb_pll make sure ipg_per_clk is generated
+ * by ipg_clk and not usb_pll.
+ */
+ __raw_writel(__raw_readl(MXC_CCM_CCMR) | (1 << 24), MXC_CCM_CCMR);
+
usb_pll_disable(&usb_pll_clk);
pr_info("Clock input source is %ld\n", clk_get_rate(&ckih_clk));
diff --git a/linux/arch/arm/mach-pxa/devices.c b/linux/arch/arm/mach-pxa/devices.c
index 5ec10735b..d19f5096a 100644
--- a/linux/arch/arm/mach-pxa/devices.c
+++ b/linux/arch/arm/mach-pxa/devices.c
@@ -39,7 +39,7 @@
#include <mach/pxafb.h>
#include <mach/mmc.h>
#include <mach/irda.h>
-#include <mach/i2c.h>
+#include <plat/i2c.h>
#include <mach/ohci.h>
#include <mach/pxa27x_keypad.h>
#include <mach/pxa2xx_spi.h>
@@ -104,7 +104,10 @@ void __init pxa_set_mci_info(struct pxamci_platform_data *info)
}
-static struct pxa2xx_udc_mach_info pxa_udc_info;
+static struct pxa2xx_udc_mach_info pxa_udc_info = {
+ .gpio_pullup = -1,
+ .gpio_vbus = -1,
+};
void __init pxa_set_udc_info(struct pxa2xx_udc_mach_info *info)
{
@@ -319,7 +322,7 @@ static struct resource pxa3xx_resources_i2c_power[] = {
};
struct platform_device pxa3xx_device_i2c_power = {
- .name = "pxa2xx-i2c",
+ .name = "pxa3xx-pwri2c",
.id = 1,
.resource = pxa3xx_resources_i2c_power,
.num_resources = ARRAY_SIZE(pxa3xx_resources_i2c_power),
diff --git a/linux/arch/arm/mach-pxa/pcm990-baseboard.c b/linux/arch/arm/mach-pxa/pcm990-baseboard.c
index 9ce1ef2e5..01791d74e 100644
--- a/linux/arch/arm/mach-pxa/pcm990-baseboard.c
+++ b/linux/arch/arm/mach-pxa/pcm990-baseboard.c
@@ -28,7 +28,7 @@
#include <media/soc_camera.h>
#include <asm/gpio.h>
-#include <mach/i2c.h>
+#include <plat/i2c.h>
#include <mach/camera.h>
#include <asm/mach/map.h>
#include <mach/pxa27x.h>
diff --git a/linux/arch/arm/plat-mxc/include/mach/memory.h b/linux/arch/arm/plat-mxc/include/mach/memory.h
index eca37d09f..6065e0017 100644
--- a/linux/arch/arm/plat-mxc/include/mach/memory.h
+++ b/linux/arch/arm/plat-mxc/include/mach/memory.h
@@ -32,4 +32,12 @@
#define CONSISTENT_DMA_SIZE SZ_4M
#endif /* CONFIG_MX1_VIDEO */
+#if defined(CONFIG_MX3_VIDEO)
+/*
+ * Increase size of DMA-consistent memory region.
+ * This is required for mx3 camera driver to capture at least two QXGA frames.
+ */
+#define CONSISTENT_DMA_SIZE SZ_8M
+#endif /* CONFIG_MX3_VIDEO */
+
#endif /* __ASM_ARCH_MXC_MEMORY_H__ */
diff --git a/linux/arch/sh/boards/board-ap325rxa.c b/linux/arch/sh/boards/board-ap325rxa.c
index 39e46919d..1c4d83ef2 100644
--- a/linux/arch/sh/boards/board-ap325rxa.c
+++ b/linux/arch/sh/boards/board-ap325rxa.c
@@ -263,6 +263,9 @@ static int camera_probe(void)
struct i2c_msg msg;
int ret;
+ if (!a)
+ return -ENODEV;
+
camera_power(1);
msg.addr = 0x6e;
msg.buf = camera_ncm03j_magic;
@@ -532,6 +535,18 @@ static int __init ap325rxa_devices_setup(void)
}
device_initcall(ap325rxa_devices_setup);
+/* Return the board specific boot mode pin configuration */
+static int ap325rxa_mode_pins(void)
+{
+ /* MD0=0, MD1=0, MD2=0: Clock Mode 0
+ * MD3=0: 16-bit Area0 Bus Width
+ * MD5=1: Little Endian
+ * TSTMD=1, MD8=1: Test Mode Disabled
+ */
+ return MODE_PIN5 | MODE_PIN8;
+}
+
static struct sh_machine_vector mv_ap325rxa __initmv = {
.mv_name = "AP-325RXA",
+ .mv_mode_pins = ap325rxa_mode_pins,
};
diff --git a/linux/arch/sh/boards/mach-migor/setup.c b/linux/arch/sh/boards/mach-migor/setup.c
index 1ee1de0bc..6ed401cd3 100644
--- a/linux/arch/sh/boards/mach-migor/setup.c
+++ b/linux/arch/sh/boards/mach-migor/setup.c
@@ -584,3 +584,22 @@ static int __init migor_devices_setup(void)
return platform_add_devices(migor_devices, ARRAY_SIZE(migor_devices));
}
__initcall(migor_devices_setup);
+
+/* Return the board specific boot mode pin configuration */
+static int migor_mode_pins(void)
+{
+ /* MD0=1, MD1=1, MD2=0: Clock Mode 3
+ * MD3=0: 16-bit Area0 Bus Width
+ * MD5=1: Little Endian
+ * TSTMD=1, MD8=0: Test Mode Disabled
+ */
+ return MODE_PIN0 | MODE_PIN1 | MODE_PIN5;
+}
+
+/*
+ * The Machine Vector
+ */
+static struct sh_machine_vector mv_migor __initmv = {
+ .mv_name = "Migo-R",
+ .mv_mode_pins = migor_mode_pins,
+};
diff --git a/linux/drivers/media/Kconfig b/linux/drivers/media/Kconfig
index 223c36ede..ba69beeb0 100644
--- a/linux/drivers/media/Kconfig
+++ b/linux/drivers/media/Kconfig
@@ -2,8 +2,14 @@
# Multimedia device configuration
#
-menu "Multimedia devices"
+menuconfig MEDIA_SUPPORT
+ tristate "Multimedia support"
depends on HAS_IOMEM
+ help
+ If you want to use Video for Linux, DVB for Linux, or DAB adapters,
+ enable this option and other options below.
+
+if MEDIA_SUPPORT
comment "Multimedia core support"
@@ -136,4 +142,4 @@ config USB_DABUSB
module will be called dabusb.
endif # DAB
-endmenu
+endif # MEDIA_SUPPORT
diff --git a/linux/drivers/media/common/ir-keymaps.c b/linux/drivers/media/common/ir-keymaps.c
index d5fd71968..56fa64b4c 100644
--- a/linux/drivers/media/common/ir-keymaps.c
+++ b/linux/drivers/media/common/ir-keymaps.c
@@ -2800,3 +2800,26 @@ IR_KEYTAB_TYPE ir_codes_dm1105_nec[IR_KEYTAB_SIZE] = {
[0x1b] = KEY_B, /*recall*/
};
EXPORT_SYMBOL_GPL(ir_codes_dm1105_nec);
+
+/* EVGA inDtube
+ Devin Heitmueller <devin.heitmueller@gmail.com>
+ */
+IR_KEYTAB_TYPE ir_codes_evga_indtube[IR_KEYTAB_SIZE] = {
+ [0x12] = KEY_POWER,
+ [0x02] = KEY_MODE, /* TV */
+ [0x14] = KEY_MUTE,
+ [0x1a] = KEY_CHANNELUP,
+ [0x16] = KEY_TV2, /* PIP */
+ [0x1d] = KEY_VOLUMEUP,
+ [0x05] = KEY_CHANNELDOWN,
+ [0x0f] = KEY_PLAYPAUSE,
+ [0x19] = KEY_VOLUMEDOWN,
+ [0x1c] = KEY_REWIND,
+ [0x0d] = KEY_RECORD,
+ [0x18] = KEY_FORWARD,
+ [0x1e] = KEY_PREVIOUS,
+ [0x1b] = KEY_STOP,
+ [0x1f] = KEY_NEXT,
+ [0x13] = KEY_CAMERA,
+};
+EXPORT_SYMBOL_GPL(ir_codes_evga_indtube);
diff --git a/linux/drivers/media/common/tuners/tuner-simple.c b/linux/drivers/media/common/tuners/tuner-simple.c
index 233476df9..2ac1c8edb 100644
--- a/linux/drivers/media/common/tuners/tuner-simple.c
+++ b/linux/drivers/media/common/tuners/tuner-simple.c
@@ -423,6 +423,24 @@ static int simple_std_setup(struct dvb_frontend *fe,
return 0;
}
+static int simple_set_aux_byte(struct dvb_frontend *fe, u8 config, u8 aux)
+{
+ struct tuner_simple_priv *priv = fe->tuner_priv;
+ int rc;
+ u8 buffer[2];
+
+ buffer[0] = (config & ~0x38) | 0x18;
+ buffer[1] = aux;
+
+ tuner_dbg("setting aux byte: 0x%02x 0x%02x\n", buffer[0], buffer[1]);
+
+ rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 2);
+ if (2 != rc)
+ tuner_warn("i2c i/o error: rc == %d (should be 2)\n", rc);
+
+ return rc == 2 ? 0 : rc;
+}
+
static int simple_post_tune(struct dvb_frontend *fe, u8 *buffer,
u16 div, u8 config, u8 cb)
{
@@ -431,30 +449,10 @@ static int simple_post_tune(struct dvb_frontend *fe, u8 *buffer,
switch (priv->type) {
case TUNER_LG_TDVS_H06XF:
- /* Set the Auxiliary Byte. */
-#if 0
- buffer[2] &= ~0x20;
- buffer[2] |= 0x18;
- buffer[3] = 0x20;
- tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n",
- buffer[0], buffer[1], buffer[2], buffer[3]);
-
- rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4);
- if (4 != rc)
- tuner_warn("i2c i/o error: rc == %d "
- "(should be 4)\n", rc);
-#else
- buffer[0] = buffer[2];
- buffer[0] &= ~0x20;
- buffer[0] |= 0x18;
- buffer[1] = 0x20;
- tuner_dbg("tv 0x%02x 0x%02x\n", buffer[0], buffer[1]);
-
- rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 2);
- if (2 != rc)
- tuner_warn("i2c i/o error: rc == %d "
- "(should be 2)\n", rc);
-#endif
+ simple_set_aux_byte(fe, config, 0x20);
+ break;
+ case TUNER_PHILIPS_FQ1216LME_MK3:
+ simple_set_aux_byte(fe, config, 0x60); /* External AGC */
break;
case TUNER_MICROTUNE_4042FI5:
{
@@ -526,6 +524,11 @@ static int simple_radio_bandswitch(struct dvb_frontend *fe, u8 *buffer)
case TUNER_THOMSON_DTT761X:
buffer[3] = 0x39;
break;
+ case TUNER_PHILIPS_FQ1216LME_MK3:
+ tuner_err("This tuner doesn't have FM\n");
+ /* Set the low band for sanity, since it covers 88-108 MHz */
+ buffer[3] = 0x01;
+ break;
case TUNER_MICROTUNE_4049FM5:
default:
buffer[3] = 0xa4;
@@ -698,12 +701,12 @@ static int simple_set_radio_freq(struct dvb_frontend *fe,
return 0;
}
- /* Bandswitch byte */
- simple_radio_bandswitch(fe, &buffer[0]);
-
buffer[2] = (t_params->ranges[0].config & ~TUNER_RATIO_MASK) |
TUNER_RATIO_SELECT_50; /* 50 kHz step */
+ /* Bandswitch byte */
+ simple_radio_bandswitch(fe, &buffer[0]);
+
/* Convert from 1/16 kHz V4L steps to 1/20 MHz (=50 kHz) PLL steps
freq * (1 Mhz / 16000 V4L steps) * (20 PLL steps / 1 MHz) =
freq * (1/800) */
diff --git a/linux/drivers/media/common/tuners/tuner-types.c b/linux/drivers/media/common/tuners/tuner-types.c
index 43afd30b0..e57d7cb2f 100644
--- a/linux/drivers/media/common/tuners/tuner-types.c
+++ b/linux/drivers/media/common/tuners/tuner-types.c
@@ -1280,6 +1280,28 @@ static struct tuner_params tuner_tcl_mf02gip_5n_params[] = {
},
};
+/* 80-89 */
+/* --------- TUNER_PHILIPS_FQ1216LME_MK3 -- active loopthrough, no FM ------- */
+
+static struct tuner_params tuner_fq1216lme_mk3_params[] = {
+ {
+ .type = TUNER_PARAM_TYPE_PAL,
+ .ranges = tuner_fm1216me_mk3_pal_ranges,
+ .count = ARRAY_SIZE(tuner_fm1216me_mk3_pal_ranges),
+ .cb_first_if_lower_freq = 1, /* not specified, but safe to do */
+ .has_tda9887 = 1, /* TDA9886 */
+ .port1_active = 1,
+ .port2_active = 1,
+ .port2_invert_for_secam_lc = 1,
+ .default_top_low = 4,
+ .default_top_mid = 4,
+ .default_top_high = 4,
+ .default_top_secam_low = 4,
+ .default_top_secam_mid = 4,
+ .default_top_secam_high = 4,
+ },
+};
+
/* --------------------------------------------------------------------- */
struct tunertype tuners[] = {
@@ -1725,6 +1747,13 @@ struct tunertype tuners[] = {
.params = tuner_fm1216mk5_params,
.count = ARRAY_SIZE(tuner_fm1216mk5_params),
},
+
+ /* 80-89 */
+ [TUNER_PHILIPS_FQ1216LME_MK3] = { /* PAL/SECAM, Loop-thru, no FM */
+ .name = "Philips FQ1216LME MK3 PAL/SECAM w/active loopthrough",
+ .params = tuner_fq1216lme_mk3_params,
+ .count = ARRAY_SIZE(tuner_fq1216lme_mk3_params),
+ },
};
EXPORT_SYMBOL(tuners);
diff --git a/linux/drivers/media/common/tuners/tuner-xc2028.c b/linux/drivers/media/common/tuners/tuner-xc2028.c
index 3f03dfa2c..a7466867c 100644
--- a/linux/drivers/media/common/tuners/tuner-xc2028.c
+++ b/linux/drivers/media/common/tuners/tuner-xc2028.c
@@ -34,7 +34,7 @@ MODULE_PARM_DESC(debug, "enable verbose debug messages");
static int no_poweroff;
module_param(no_poweroff, int, 0644);
-MODULE_PARM_DESC(debug, "0 (default) powers device off when not used.\n"
+MODULE_PARM_DESC(no_poweroff, "0 (default) powers device off when not used.\n"
"1 keep device energized and with tuner ready all the times.\n"
" Faster, but consumes more power and keeps the device hotter\n");
@@ -921,22 +921,29 @@ static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */,
* that xc2028 will be in a safe state.
* Maybe this might also be needed for DTV.
*/
- if (new_mode == T_ANALOG_TV) {
+ if (new_mode == T_ANALOG_TV)
rc = send_seq(priv, {0x00, 0x00});
- } else if (priv->cur_fw.type & ATSC) {
- offset = 1750000;
- } else {
- offset = 2750000;
+
+ /*
+ * Digital modes require an offset to adjust to the
+ * proper frequency.
+ * Analog modes require offset = 0
+ */
+ if (new_mode == T_DIGITAL_TV) {
+ /* Sets the offset according with firmware */
+ if (priv->cur_fw.type & DTV6)
+ offset = 1750000;
+ else if (priv->cur_fw.type & DTV7)
+ offset = 2250000;
+ else /* DTV8 or DTV78 */
+ offset = 2750000;
+
/*
- * We must adjust the offset by 500kHz in two cases in order
- * to correctly center the IF output:
- * 1) When the ZARLINK456 or DIBCOM52 tables were explicitly
- * selected and a 7MHz channel is tuned;
- * 2) When tuning a VHF channel with DTV78 firmware.
+ * We must adjust the offset by 500kHz when
+ * tuning a 7MHz VHF channel with DTV78 firmware
+ * (used in Australia, Italy and Germany)
*/
- if (((priv->cur_fw.type & DTV7) &&
- (priv->cur_fw.scode_table & (ZARLINK456 | DIBCOM52))) ||
- ((priv->cur_fw.type & DTV78) && freq < 470000000))
+ if ((priv->cur_fw.type & DTV78) && freq < 470000000)
offset -= 500000;
}
@@ -995,7 +1002,7 @@ static int xc2028_set_analog_freq(struct dvb_frontend *fe,
if (priv->ctrl.input1)
type |= INPUT1;
return generic_set_freq(fe, (625l * p->frequency) / 10,
- T_ANALOG_TV, type, 0, 0);
+ T_RADIO, type, 0, 0);
}
/* if std is not defined, choose one */
@@ -1026,21 +1033,20 @@ static int xc2028_set_params(struct dvb_frontend *fe,
switch(fe->ops.info.type) {
case FE_OFDM:
bw = p->u.ofdm.bandwidth;
- break;
- case FE_QAM:
- tuner_info("WARN: There are some reports that "
- "QAM 6 MHz doesn't work.\n"
- "If this works for you, please report by "
- "e-mail to: v4l-dvb-maintainer@linuxtv.org\n");
- bw = BANDWIDTH_6_MHZ;
- type |= QAM;
+ /*
+ * The only countries with 6MHz seem to be Taiwan/Uruguay.
+ * Both seem to require QAM firmware for OFDM decoding
+ * Tested in Taiwan by Terry Wu <terrywu2009@gmail.com>
+ */
+ if (bw == BANDWIDTH_6_MHZ)
+ type |= QAM;
break;
case FE_ATSC:
bw = BANDWIDTH_6_MHZ;
/* The only ATSC firmware (at least on v2.7) is D2633 */
type |= ATSC | D2633;
break;
- /* DVB-S is not supported */
+ /* DVB-S and pure QAM (FE_QAM) are not supported */
default:
return -EINVAL;
}
diff --git a/linux/drivers/media/common/tuners/xc5000.c b/linux/drivers/media/common/tuners/xc5000.c
index e38433ec6..6626d19b3 100644
--- a/linux/drivers/media/common/tuners/xc5000.c
+++ b/linux/drivers/media/common/tuners/xc5000.c
@@ -3,6 +3,7 @@
*
* Copyright (c) 2007 Xceive Corporation
* Copyright (c) 2007 Steven Toth <stoth@linuxtv.org>
+ * Copyright (c) 2009 Devin Heitmueller <dheitmueller@kernellabs.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -36,14 +37,20 @@ static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
+static int no_poweroff;
+module_param(no_poweroff, int, 0644);
+MODULE_PARM_DESC(no_poweroff, "0 (default) powers device off when not used.\n"
+ "\t\t1 keep device energized and with tuner ready all the times.\n"
+ "\t\tFaster, but consumes more power and keeps the device hotter");
+
static DEFINE_MUTEX(xc5000_list_mutex);
static LIST_HEAD(hybrid_tuner_instance_list);
#define dprintk(level, fmt, arg...) if (debug >= level) \
printk(KERN_INFO "%s: " fmt, "xc5000", ## arg)
-#define XC5000_DEFAULT_FIRMWARE "dvb-fe-xc5000-1.1.fw"
-#define XC5000_DEFAULT_FIRMWARE_SIZE 12332
+#define XC5000_DEFAULT_FIRMWARE "dvb-fe-xc5000-1.6.114.fw"
+#define XC5000_DEFAULT_FIRMWARE_SIZE 12401
struct xc5000_priv {
struct tuner_i2c_props i2c_props;
@@ -83,11 +90,11 @@ struct xc5000_priv {
#define XREG_D_CODE 0x04
#define XREG_IF_OUT 0x05
#define XREG_SEEK_MODE 0x07
-#define XREG_POWER_DOWN 0x0A
+#define XREG_POWER_DOWN 0x0A /* Obsolete */
#define XREG_SIGNALSOURCE 0x0D /* 0=Air, 1=Cable */
#define XREG_SMOOTHEDCVBS 0x0E
#define XREG_XTALFREQ 0x0F
-#define XREG_FINERFFREQ 0x10
+#define XREG_FINERFREQ 0x10
#define XREG_DDIMODE 0x11
#define XREG_ADC_ENV 0x00
@@ -100,6 +107,7 @@ struct xc5000_priv {
#define XREG_VERSION 0x07
#define XREG_PRODUCT_ID 0x08
#define XREG_BUSY 0x09
+#define XREG_BUILD 0x0D
/*
Basic firmware description. This will remain with
@@ -191,27 +199,36 @@ static struct XC_TV_STANDARD XC5000_Standard[MAX_TV_STANDARD] = {
{"FM Radio-INPUT1", 0x0208, 0x9002}
};
-static int xc5000_is_firmware_loaded(struct dvb_frontend *fe);
-static int xc5000_writeregs(struct xc5000_priv *priv, u8 *buf, u8 len);
-static int xc5000_readregs(struct xc5000_priv *priv, u8 *buf, u8 len);
-static void xc5000_TunerReset(struct dvb_frontend *fe);
+static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe);
+static int xc5000_is_firmware_loaded(struct dvb_frontend *fe);
+static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val);
+static int xc5000_TunerReset(struct dvb_frontend *fe);
static int xc_send_i2c_data(struct xc5000_priv *priv, u8 *buf, int len)
{
- return xc5000_writeregs(priv, buf, len)
- ? XC_RESULT_I2C_WRITE_FAILURE : XC_RESULT_SUCCESS;
+ struct i2c_msg msg = { .addr = priv->i2c_props.addr,
+ .flags = 0, .buf = buf, .len = len };
+
+ if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) {
+ printk(KERN_ERR "xc5000: I2C write failed (len=%i)\n", len);
+ return XC_RESULT_I2C_WRITE_FAILURE;
+ }
+ return XC_RESULT_SUCCESS;
}
+/* This routine is never used because the only time we read data from the
+ i2c bus is when we read registers, and we want that to be an atomic i2c
+ transaction in case we are on a multi-master bus */
static int xc_read_i2c_data(struct xc5000_priv *priv, u8 *buf, int len)
{
- return xc5000_readregs(priv, buf, len)
- ? XC_RESULT_I2C_READ_FAILURE : XC_RESULT_SUCCESS;
-}
+ struct i2c_msg msg = { .addr = priv->i2c_props.addr,
+ .flags = I2C_M_RD, .buf = buf, .len = len };
-static int xc_reset(struct dvb_frontend *fe)
-{
- xc5000_TunerReset(fe);
- return XC_RESULT_SUCCESS;
+ if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) {
+ printk(KERN_ERR "xc5000 I2C read failed (len=%i)\n", len);
+ return -EREMOTEIO;
+ }
+ return 0;
}
static void xc_wait(int wait_ms)
@@ -219,7 +236,7 @@ static void xc_wait(int wait_ms)
msleep(wait_ms);
}
-static void xc5000_TunerReset(struct dvb_frontend *fe)
+static int xc5000_TunerReset(struct dvb_frontend *fe)
{
struct xc5000_priv *priv = fe->tuner_priv;
int ret;
@@ -232,16 +249,21 @@ static void xc5000_TunerReset(struct dvb_frontend *fe)
priv->i2c_props.adap->algo_data,
DVB_FRONTEND_COMPONENT_TUNER,
XC5000_TUNER_RESET, 0);
- if (ret)
+ if (ret) {
printk(KERN_ERR "xc5000: reset failed\n");
- } else
+ return XC_RESULT_RESET_FAILURE;
+ }
+ } else {
printk(KERN_ERR "xc5000: no tuner reset callback function, fatal\n");
+ return XC_RESULT_RESET_FAILURE;
+ }
+ return XC_RESULT_SUCCESS;
}
static int xc_write_reg(struct xc5000_priv *priv, u16 regAddr, u16 i2cData)
{
u8 buf[4];
- int WatchDogTimer = 5;
+ int WatchDogTimer = 100;
int result;
buf[0] = (regAddr >> 8) & 0xFF;
@@ -263,7 +285,7 @@ static int xc_write_reg(struct xc5000_priv *priv, u16 regAddr, u16 i2cData)
/* busy flag cleared */
break;
} else {
- xc_wait(100); /* wait 5 ms */
+ xc_wait(5); /* wait 5 ms */
WatchDogTimer--;
}
}
@@ -276,25 +298,6 @@ static int xc_write_reg(struct xc5000_priv *priv, u16 regAddr, u16 i2cData)
return result;
}
-static int xc_read_reg(struct xc5000_priv *priv, u16 regAddr, u16 *i2cData)
-{
- u8 buf[2];
- int result;
-
- buf[0] = (regAddr >> 8) & 0xFF;
- buf[1] = regAddr & 0xFF;
- result = xc_send_i2c_data(priv, buf, 2);
- if (result != XC_RESULT_SUCCESS)
- return result;
-
- result = xc_read_i2c_data(priv, buf, 2);
- if (result != XC_RESULT_SUCCESS)
- return result;
-
- *i2cData = buf[0] * 256 + buf[1];
- return result;
-}
-
static int xc_load_i2c_sequence(struct dvb_frontend *fe, const u8 *i2c_sequence)
{
struct xc5000_priv *priv = fe->tuner_priv;
@@ -309,7 +312,7 @@ static int xc_load_i2c_sequence(struct dvb_frontend *fe, const u8 *i2c_sequence)
len = i2c_sequence[index] * 256 + i2c_sequence[index+1];
if (len == 0x0000) {
/* RESET command */
- result = xc_reset(fe);
+ result = xc5000_TunerReset(fe);
index += 2;
if (result != XC_RESULT_SUCCESS)
return result;
@@ -371,15 +374,6 @@ static int xc_SetTVStandard(struct xc5000_priv *priv,
return ret;
}
-static int xc_shutdown(struct xc5000_priv *priv)
-{
- return XC_RESULT_SUCCESS;
- /* Fixme: cannot bring tuner back alive once shutdown
- * without reloading the driver modules.
- * return xc_write_reg(priv, XREG_POWER_DOWN, 0);
- */
-}
-
static int xc_SetSignalSource(struct xc5000_priv *priv, u16 rf_mode)
{
dprintk(1, "%s(%d) Source = %s\n", __func__, rf_mode,
@@ -408,22 +402,14 @@ static int xc_set_RF_frequency(struct xc5000_priv *priv, u32 freq_hz)
freq_code = (u16)(freq_hz / 15625);
- return xc_write_reg(priv, XREG_RF_FREQ, freq_code);
+ /* Starting in firmware version 1.1.44, Xceive recommends using the
+ FINERFREQ for all normal tuning (the doc indicates reg 0x03 should
+ only be used for fast scanning for channel lock) */
+ return xc_write_reg(priv, XREG_FINERFREQ, freq_code);
}
#if 0
/* We'll probably need these for analog support */
-static int xc_FineTune_RF_frequency(struct xc5000_priv *priv, u32 freq_hz)
-{
- u16 freq_code = (u16)(freq_hz / 15625);
-
- if ((freq_hz > xc5000_tuner_ops.info.frequency_max) ||
- (freq_hz < xc5000_tuner_ops.info.frequency_min))
- return XC_RESULT_OUT_OF_RANGE;
-
- return xc_write_reg(priv, XREG_FINERFFREQ, freq_code);
-}
-
static int xc_set_Xtal_frequency(struct xc5000_priv *priv, u32 xtalFreqInKHz)
{
u16 xtalRatio = (32000 * 0x8000)/xtalFreqInKHz;
@@ -443,7 +429,7 @@ static int xc_set_IF_frequency(struct xc5000_priv *priv, u32 freq_khz)
static int xc_get_ADC_Envelope(struct xc5000_priv *priv, u16 *adc_envelope)
{
- return xc_read_reg(priv, XREG_ADC_ENV, adc_envelope);
+ return xc5000_readreg(priv, XREG_ADC_ENV, adc_envelope);
}
static int xc_get_frequency_error(struct xc5000_priv *priv, u32 *freq_error_hz)
@@ -452,8 +438,8 @@ static int xc_get_frequency_error(struct xc5000_priv *priv, u32 *freq_error_hz)
u16 regData;
u32 tmp;
- result = xc_read_reg(priv, XREG_FREQ_ERROR, &regData);
- if (result)
+ result = xc5000_readreg(priv, XREG_FREQ_ERROR, &regData);
+ if (result != XC_RESULT_SUCCESS)
return result;
tmp = (u32)regData;
@@ -463,7 +449,7 @@ static int xc_get_frequency_error(struct xc5000_priv *priv, u32 *freq_error_hz)
static int xc_get_lock_status(struct xc5000_priv *priv, u16 *lock_status)
{
- return xc_read_reg(priv, XREG_LOCK, lock_status);
+ return xc5000_readreg(priv, XREG_LOCK, lock_status);
}
static int xc_get_version(struct xc5000_priv *priv,
@@ -473,8 +459,8 @@ static int xc_get_version(struct xc5000_priv *priv,
u16 data;
int result;
- result = xc_read_reg(priv, XREG_VERSION, &data);
- if (result)
+ result = xc5000_readreg(priv, XREG_VERSION, &data);
+ if (result != XC_RESULT_SUCCESS)
return result;
(*hw_majorversion) = (data >> 12) & 0x0F;
@@ -485,13 +471,18 @@ static int xc_get_version(struct xc5000_priv *priv,
return 0;
}
+static int xc_get_buildversion(struct xc5000_priv *priv, u16 *buildrev)
+{
+ return xc5000_readreg(priv, XREG_BUILD, buildrev);
+}
+
static int xc_get_hsync_freq(struct xc5000_priv *priv, u32 *hsync_freq_hz)
{
u16 regData;
int result;
- result = xc_read_reg(priv, XREG_HSYNC_FREQ, &regData);
- if (result)
+ result = xc5000_readreg(priv, XREG_HSYNC_FREQ, &regData);
+ if (result != XC_RESULT_SUCCESS)
return result;
(*hsync_freq_hz) = ((regData & 0x0fff) * 763)/100;
@@ -500,12 +491,12 @@ static int xc_get_hsync_freq(struct xc5000_priv *priv, u32 *hsync_freq_hz)
static int xc_get_frame_lines(struct xc5000_priv *priv, u16 *frame_lines)
{
- return xc_read_reg(priv, XREG_FRAME_LINES, frame_lines);
+ return xc5000_readreg(priv, XREG_FRAME_LINES, frame_lines);
}
static int xc_get_quality(struct xc5000_priv *priv, u16 *quality)
{
- return xc_read_reg(priv, XREG_QUALITY, quality);
+ return xc5000_readreg(priv, XREG_QUALITY, quality);
}
static u16 WaitForLock(struct xc5000_priv *priv)
@@ -523,7 +514,9 @@ static u16 WaitForLock(struct xc5000_priv *priv)
return lockState;
}
-static int xc_tune_channel(struct xc5000_priv *priv, u32 freq_hz)
+#define XC_TUNE_ANALOG 0
+#define XC_TUNE_DIGITAL 1
+static int xc_tune_channel(struct xc5000_priv *priv, u32 freq_hz, int mode)
{
int found = 0;
@@ -532,8 +525,10 @@ static int xc_tune_channel(struct xc5000_priv *priv, u32 freq_hz)
if (xc_set_RF_frequency(priv, freq_hz) != XC_RESULT_SUCCESS)
return 0;
- if (WaitForLock(priv) == 1)
- found = 1;
+ if (mode == XC_TUNE_ANALOG) {
+ if (WaitForLock(priv) == 1)
+ found = 1;
+ }
return found;
}
@@ -555,32 +550,7 @@ static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val)
}
*val = (bval[0] << 8) | bval[1];
- return 0;
-}
-
-static int xc5000_writeregs(struct xc5000_priv *priv, u8 *buf, u8 len)
-{
- struct i2c_msg msg = { .addr = priv->i2c_props.addr,
- .flags = 0, .buf = buf, .len = len };
-
- if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) {
- printk(KERN_ERR "xc5000: I2C write failed (len=%i)\n",
- (int)len);
- return -EREMOTEIO;
- }
- return 0;
-}
-
-static int xc5000_readregs(struct xc5000_priv *priv, u8 *buf, u8 len)
-{
- struct i2c_msg msg = { .addr = priv->i2c_props.addr,
- .flags = I2C_M_RD, .buf = buf, .len = len };
-
- if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) {
- printk(KERN_ERR "xc5000 I2C read failed (len=%i)\n", (int)len);
- return -EREMOTEIO;
- }
- return 0;
+ return XC_RESULT_SUCCESS;
}
static int xc5000_fwupload(struct dvb_frontend *fe)
@@ -600,7 +570,7 @@ static int xc5000_fwupload(struct dvb_frontend *fe)
ret = XC_RESULT_RESET_FAILURE;
goto out;
} else {
- printk(KERN_INFO "xc5000: firmware read %Zu bytes.\n",
+ printk(KERN_DEBUG "xc5000: firmware read %Zu bytes.\n",
fw->size);
ret = XC_RESULT_SUCCESS;
}
@@ -609,8 +579,9 @@ static int xc5000_fwupload(struct dvb_frontend *fe)
printk(KERN_ERR "xc5000: firmware incorrect size\n");
ret = XC_RESULT_RESET_FAILURE;
} else {
- printk(KERN_INFO "xc5000: firmware upload\n");
+ printk(KERN_INFO "xc5000: firmware uploading...\n");
ret = xc_load_i2c_sequence(fe, fw->data);
+ printk(KERN_INFO "xc5000: firmware upload complete...\n");
}
out:
@@ -628,6 +599,7 @@ static void xc_debug_dump(struct xc5000_priv *priv)
u16 quality;
u8 hw_majorversion = 0, hw_minorversion = 0;
u8 fw_majorversion = 0, fw_minorversion = 0;
+ u16 fw_buildversion = 0;
/* Wait for stats to stabilize.
* Frame Lines needs two frame times after initial lock
@@ -647,9 +619,10 @@ static void xc_debug_dump(struct xc5000_priv *priv)
xc_get_version(priv, &hw_majorversion, &hw_minorversion,
&fw_majorversion, &fw_minorversion);
- dprintk(1, "*** HW: V%02x.%02x, FW: V%02x.%02x\n",
+ xc_get_buildversion(priv, &fw_buildversion);
+ dprintk(1, "*** HW: V%02x.%02x, FW: V%02x.%02x.%04x\n",
hw_majorversion, hw_minorversion,
- fw_majorversion, fw_minorversion);
+ fw_majorversion, fw_minorversion, fw_buildversion);
xc_get_hsync_freq(priv, &hsync_freq_hz);
dprintk(1, "*** Horizontal sync frequency = %d Hz\n", hsync_freq_hz);
@@ -667,27 +640,57 @@ static int xc5000_set_params(struct dvb_frontend *fe,
struct xc5000_priv *priv = fe->tuner_priv;
int ret;
+ if (xc5000_is_firmware_loaded(fe) != XC_RESULT_SUCCESS)
+ xc_load_fw_and_init_tuner(fe);
+
dprintk(1, "%s() frequency=%d (Hz)\n", __func__, params->frequency);
- switch (params->u.vsb.modulation) {
- case VSB_8:
- case VSB_16:
- dprintk(1, "%s() VSB modulation\n", __func__);
+ if (fe->ops.info.type == FE_ATSC) {
+ dprintk(1, "%s() ATSC\n", __func__);
+ switch (params->u.vsb.modulation) {
+ case VSB_8:
+ case VSB_16:
+ dprintk(1, "%s() VSB modulation\n", __func__);
+ priv->rf_mode = XC_RF_MODE_AIR;
+ priv->freq_hz = params->frequency - 1750000;
+ priv->bandwidth = BANDWIDTH_6_MHZ;
+ priv->video_standard = DTV6;
+ break;
+ case QAM_64:
+ case QAM_256:
+ case QAM_AUTO:
+ dprintk(1, "%s() QAM modulation\n", __func__);
+ priv->rf_mode = XC_RF_MODE_CABLE;
+ priv->freq_hz = params->frequency - 1750000;
+ priv->bandwidth = BANDWIDTH_6_MHZ;
+ priv->video_standard = DTV6;
+ break;
+ default:
+ return -EINVAL;
+ }
+ } else if (fe->ops.info.type == FE_OFDM) {
+ dprintk(1, "%s() OFDM\n", __func__);
+ switch (params->u.ofdm.bandwidth) {
+ case BANDWIDTH_6_MHZ:
+ priv->bandwidth = BANDWIDTH_6_MHZ;
+ priv->video_standard = DTV6;
+ priv->freq_hz = params->frequency - 1750000;
+ break;
+ case BANDWIDTH_7_MHZ:
+ printk(KERN_ERR "xc5000 bandwidth 7MHz not supported\n");
+ return -EINVAL;
+ case BANDWIDTH_8_MHZ:
+ priv->bandwidth = BANDWIDTH_8_MHZ;
+ priv->video_standard = DTV8;
+ priv->freq_hz = params->frequency - 2750000;
+ break;
+ default:
+ printk(KERN_ERR "xc5000 bandwidth not set!\n");
+ return -EINVAL;
+ }
priv->rf_mode = XC_RF_MODE_AIR;
- priv->freq_hz = params->frequency - 1750000;
- priv->bandwidth = BANDWIDTH_6_MHZ;
- priv->video_standard = DTV6;
- break;
- case QAM_64:
- case QAM_256:
- case QAM_AUTO:
- dprintk(1, "%s() QAM modulation\n", __func__);
- priv->rf_mode = XC_RF_MODE_CABLE;
- priv->freq_hz = params->frequency - 1750000;
- priv->bandwidth = BANDWIDTH_6_MHZ;
- priv->video_standard = DTV6;
- break;
- default:
+ } else {
+ printk(KERN_ERR "xc5000 modulation type not supported!\n");
return -EINVAL;
}
@@ -717,7 +720,7 @@ static int xc5000_set_params(struct dvb_frontend *fe,
return -EIO;
}
- xc_tune_channel(priv, priv->freq_hz);
+ xc_tune_channel(priv, priv->freq_hz, XC_TUNE_DIGITAL);
if (debug)
xc_debug_dump(priv);
@@ -744,8 +747,6 @@ static int xc5000_is_firmware_loaded(struct dvb_frontend *fe)
return ret;
}
-static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe);
-
static int xc5000_set_analog_params(struct dvb_frontend *fe,
struct analog_parameters *params)
{
@@ -826,7 +827,7 @@ tune_channel:
return -EREMOTEIO;
}
- xc_tune_channel(priv, priv->freq_hz);
+ xc_tune_channel(priv, priv->freq_hz, XC_TUNE_ANALOG);
if (debug)
xc_debug_dump(priv);
@@ -894,18 +895,18 @@ static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe)
static int xc5000_sleep(struct dvb_frontend *fe)
{
- struct xc5000_priv *priv = fe->tuner_priv;
int ret;
dprintk(1, "%s()\n", __func__);
- /* On Pinnacle PCTV HD 800i, the tuner cannot be reinitialized
- * once shutdown without reloading the driver. Maybe I am not
- * doing something right.
- *
- */
+ /* Avoid firmware reload on slow devices */
+ if (no_poweroff)
+ return 0;
- ret = xc_shutdown(priv);
+ /* According to Xceive technical support, the "powerdown" register
+ was removed in newer versions of the firmware. The "supported"
+ way to sleep the tuner is to pull the reset pin low for 10ms */
+ ret = xc5000_TunerReset(fe);
if (ret != XC_RESULT_SUCCESS) {
printk(KERN_ERR
"xc5000: %s() unable to shutdown tuner\n",
@@ -1010,7 +1011,7 @@ struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
/* Check if firmware has been loaded. It is possible that another
instance of the driver has loaded the firmware.
*/
- if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != 0)
+ if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != XC_RESULT_SUCCESS)
goto fail;
switch (id) {
diff --git a/linux/drivers/media/dvb/b2c2/flexcop-common.h b/linux/drivers/media/dvb/b2c2/flexcop-common.h
index cee2956cb..9d66105d3 100644
--- a/linux/drivers/media/dvb/b2c2/flexcop-common.h
+++ b/linux/drivers/media/dvb/b2c2/flexcop-common.h
@@ -1,9 +1,7 @@
/*
- * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
- *
- * flexcop-common.h - common header file for device-specific source files also.
- *
- * see flexcop.c for copyright information.
+ * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
+ * flexcop-common.h - common header file for device-specific source files
+ * see flexcop.c for copyright information
*/
#ifndef __FLEXCOP_COMMON_H__
#define __FLEXCOP_COMMON_H__
diff --git a/linux/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/linux/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
index f7afab594..efb4a6c2b 100644
--- a/linux/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
+++ b/linux/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
@@ -1,34 +1,27 @@
/*
- * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
- *
- * flexcop-fe-tuner.c - methods for attaching a frontend and controlling DiSEqC.
- *
- * see flexcop.c for copyright information.
+ * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
+ * flexcop-fe-tuner.c - methods for frontend attachment and DiSEqC controlling
+ * see flexcop.c for copyright information
*/
#include <media/tuner.h>
-
#include "flexcop.h"
-
-#include "stv0299.h"
-#include "mt352.h"
-#include "nxt200x.h"
-#include "bcm3510.h"
-#include "stv0297.h"
#include "mt312.h"
-#include "lgdt330x.h"
-#include "dvb-pll.h"
-#include "tuner-simple.h"
-
+#include "stv0299.h"
#include "s5h1420.h"
#include "itd1000.h"
-
-#include "cx24123.h"
#include "cx24113.h"
-
+#include "cx24123.h"
#include "isl6421.h"
+#include "mt352.h"
+#include "bcm3510.h"
+#include "nxt200x.h"
+#include "dvb-pll.h"
+#include "lgdt330x.h"
+#include "tuner-simple.h"
+#include "stv0297.h"
/* lnb control */
-
+#if defined(CONFIG_DVB_MT312_MODULE) || defined(CONFIG_DVB_STV0299_MODULE)
static int flexcop_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
{
struct flexcop_device *fc = fe->dvb->priv;
@@ -37,65 +30,62 @@ static int flexcop_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage
v = fc->read_ibi_reg(fc, misc_204);
switch (voltage) {
- case SEC_VOLTAGE_OFF:
- v.misc_204.ACPI1_sig = 1;
- break;
- case SEC_VOLTAGE_13:
- v.misc_204.ACPI1_sig = 0;
- v.misc_204.LNB_L_H_sig = 0;
- break;
- case SEC_VOLTAGE_18:
- v.misc_204.ACPI1_sig = 0;
- v.misc_204.LNB_L_H_sig = 1;
- break;
- default:
- err("unknown SEC_VOLTAGE value");
- return -EINVAL;
+ case SEC_VOLTAGE_OFF:
+ v.misc_204.ACPI1_sig = 1;
+ break;
+ case SEC_VOLTAGE_13:
+ v.misc_204.ACPI1_sig = 0;
+ v.misc_204.LNB_L_H_sig = 0;
+ break;
+ case SEC_VOLTAGE_18:
+ v.misc_204.ACPI1_sig = 0;
+ v.misc_204.LNB_L_H_sig = 1;
+ break;
+ default:
+ err("unknown SEC_VOLTAGE value");
+ return -EINVAL;
}
return fc->write_ibi_reg(fc, misc_204, v);
}
+#endif
+#if defined(CONFIG_DVB_S5H1420_MODULE) || defined(CONFIG_DVB_STV0299_MODULE) \
+ || defined(CONFIG_DVB_MT312_MODULE)
static int flexcop_sleep(struct dvb_frontend* fe)
{
struct flexcop_device *fc = fe->dvb->priv;
-/* flexcop_ibi_value v = fc->read_ibi_reg(fc,misc_204); */
-
if (fc->fe_sleep)
return fc->fe_sleep(fe);
-
-/* v.misc_204.ACPI3_sig = 1;
- fc->write_ibi_reg(fc,misc_204,v);*/
-
return 0;
}
+#endif
+/* SkyStar2 DVB-S rev 2.3 */
+#if defined(CONFIG_DVB_MT312_MODULE)
static int flexcop_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
{
- /* u16 wz_half_period_for_45_mhz[] = { 0x01ff, 0x0154, 0x00ff, 0x00cc }; */
+/* u16 wz_half_period_for_45_mhz[] = { 0x01ff, 0x0154, 0x00ff, 0x00cc }; */
struct flexcop_device *fc = fe->dvb->priv;
flexcop_ibi_value v;
u16 ax;
v.raw = 0;
-
deb_tuner("tone = %u\n",tone);
switch (tone) {
- case SEC_TONE_ON:
- ax = 0x01ff;
- break;
- case SEC_TONE_OFF:
- ax = 0;
- break;
- default:
- err("unknown SEC_TONE value");
- return -EINVAL;
+ case SEC_TONE_ON:
+ ax = 0x01ff;
+ break;
+ case SEC_TONE_OFF:
+ ax = 0;
+ break;
+ default:
+ err("unknown SEC_TONE value");
+ return -EINVAL;
}
v.lnb_switch_freq_200.LNB_CTLPrescaler_sig = 1; /* divide by 2 */
-
v.lnb_switch_freq_200.LNB_CTLHighCount_sig = ax;
v.lnb_switch_freq_200.LNB_CTLLowCount_sig = ax == 0 ? 0x1ff : ax;
-
return fc->write_ibi_reg(fc,lnb_switch_freq_200,v);
}
@@ -110,17 +100,16 @@ static void flexcop_diseqc_send_bit(struct dvb_frontend* fe, int data)
static void flexcop_diseqc_send_byte(struct dvb_frontend* fe, int data)
{
int i, par = 1, d;
-
for (i = 7; i >= 0; i--) {
d = (data >> i) & 1;
par ^= d;
flexcop_diseqc_send_bit(fe, d);
}
-
flexcop_diseqc_send_bit(fe, par);
}
-static int flexcop_send_diseqc_msg(struct dvb_frontend* fe, int len, u8 *msg, unsigned long burst)
+static int flexcop_send_diseqc_msg(struct dvb_frontend *fe,
+ int len, u8 *msg, unsigned long burst)
{
int i;
@@ -129,7 +118,6 @@ static int flexcop_send_diseqc_msg(struct dvb_frontend* fe, int len, u8 *msg, un
for (i = 0; i < len; i++)
flexcop_diseqc_send_byte(fe,msg[i]);
-
mdelay(16);
if (burst != -1) {
@@ -146,50 +134,110 @@ static int flexcop_send_diseqc_msg(struct dvb_frontend* fe, int len, u8 *msg, un
return 0;
}
-static int flexcop_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd)
+static int flexcop_diseqc_send_master_cmd(struct dvb_frontend *fe,
+ struct dvb_diseqc_master_cmd *cmd)
{
return flexcop_send_diseqc_msg(fe, cmd->msg_len, cmd->msg, 0);
}
-static int flexcop_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)
+static int flexcop_diseqc_send_burst(struct dvb_frontend *fe,
+ fe_sec_mini_cmd_t minicmd)
{
return flexcop_send_diseqc_msg(fe, 0, NULL, minicmd);
}
-/* dvb-s stv0299 */
-static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio)
+static struct mt312_config skystar23_samsung_tbdu18132_config = {
+ .demod_address = 0x0e,
+};
+
+static int skystar23_samsung_tbdu18132_tuner_set_params(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params)
+{
+ u8 buf[4];
+ u32 div;
+ struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf,
+ .len = sizeof(buf) };
+ struct flexcop_device *fc = fe->dvb->priv;
+ div = (params->frequency + (125/2)) / 125;
+
+ buf[0] = (div >> 8) & 0x7f;
+ buf[1] = (div >> 0) & 0xff;
+ buf[2] = 0x84 | ((div >> 10) & 0x60);
+ buf[3] = 0x80;
+
+ if (params->frequency < 1550000)
+ buf[3] |= 0x02;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if (i2c_transfer(&fc->fc_i2c_adap[0].i2c_adap, &msg, 1) != 1)
+ return -EIO;
+ return 0;
+}
+
+static int skystar2_rev23_attach(struct flexcop_device *fc,
+ struct i2c_adapter *i2c)
+{
+ fc->fe = dvb_attach(mt312_attach, &skystar23_samsung_tbdu18132_config, i2c);
+ if (fc->fe != NULL) {
+ struct dvb_frontend_ops *ops = &fc->fe->ops;
+ ops->tuner_ops.set_params =
+ skystar23_samsung_tbdu18132_tuner_set_params;
+ ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd;
+ ops->diseqc_send_burst = flexcop_diseqc_send_burst;
+ ops->set_tone = flexcop_set_tone;
+ ops->set_voltage = flexcop_set_voltage;
+ fc->fe_sleep = ops->sleep;
+ ops->sleep = flexcop_sleep;
+ return 1;
+ }
+ return 0;
+}
+#endif
+
+/* SkyStar2 DVB-S rev 2.6 */
+#if defined(CONFIG_DVB_STV0299_MODULE)
+static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend *fe,
+ u32 srate, u32 ratio)
{
u8 aclk = 0;
u8 bclk = 0;
- if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; }
- else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; }
- else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; }
- else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; }
- else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; }
- else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; }
-
- stv0299_writereg (fe, 0x13, aclk);
- stv0299_writereg (fe, 0x14, bclk);
- stv0299_writereg (fe, 0x1f, (ratio >> 16) & 0xff);
- stv0299_writereg (fe, 0x20, (ratio >> 8) & 0xff);
- stv0299_writereg (fe, 0x21, (ratio ) & 0xf0);
+ if (srate < 1500000) {
+ aclk = 0xb7; bclk = 0x47;
+ } else if (srate < 3000000) {
+ aclk = 0xb7; bclk = 0x4b;
+ } else if (srate < 7000000) {
+ aclk = 0xb7; bclk = 0x4f;
+ } else if (srate < 14000000) {
+ aclk = 0xb7; bclk = 0x53;
+ } else if (srate < 30000000) {
+ aclk = 0xb6; bclk = 0x53;
+ } else if (srate < 45000000) {
+ aclk = 0xb4; bclk = 0x51;
+ }
+ stv0299_writereg(fe, 0x13, aclk);
+ stv0299_writereg(fe, 0x14, bclk);
+ stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
+ stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
+ stv0299_writereg(fe, 0x21, ratio & 0xf0);
return 0;
}
-static int samsung_tbmu24112_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
+static int samsung_tbmu24112_tuner_set_params(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params)
{
u8 buf[4];
u32 div;
- struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
+ struct i2c_msg msg = {
+ .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
struct flexcop_device *fc = fe->dvb->priv;
-
div = params->frequency / 125;
buf[0] = (div >> 8) & 0x7f;
buf[1] = div & 0xff;
- buf[2] = 0x84; /* 0xC4 */
+ buf[2] = 0x84; /* 0xC4 */
buf[3] = 0x08;
if (params->frequency < 1500000)
@@ -203,48 +251,48 @@ static int samsung_tbmu24112_tuner_set_params(struct dvb_frontend* fe, struct dv
}
static u8 samsung_tbmu24112_inittab[] = {
- 0x01, 0x15,
- 0x02, 0x30,
- 0x03, 0x00,
- 0x04, 0x7D,
- 0x05, 0x35,
- 0x06, 0x02,
- 0x07, 0x00,
- 0x08, 0xC3,
- 0x0C, 0x00,
- 0x0D, 0x81,
- 0x0E, 0x23,
- 0x0F, 0x12,
- 0x10, 0x7E,
- 0x11, 0x84,
- 0x12, 0xB9,
- 0x13, 0x88,
- 0x14, 0x89,
- 0x15, 0xC9,
- 0x16, 0x00,
- 0x17, 0x5C,
- 0x18, 0x00,
- 0x19, 0x00,
- 0x1A, 0x00,
- 0x1C, 0x00,
- 0x1D, 0x00,
- 0x1E, 0x00,
- 0x1F, 0x3A,
- 0x20, 0x2E,
- 0x21, 0x80,
- 0x22, 0xFF,
- 0x23, 0xC1,
- 0x28, 0x00,
- 0x29, 0x1E,
- 0x2A, 0x14,
- 0x2B, 0x0F,
- 0x2C, 0x09,
- 0x2D, 0x05,
- 0x31, 0x1F,
- 0x32, 0x19,
- 0x33, 0xFE,
- 0x34, 0x93,
- 0xff, 0xff,
+ 0x01, 0x15,
+ 0x02, 0x30,
+ 0x03, 0x00,
+ 0x04, 0x7D,
+ 0x05, 0x35,
+ 0x06, 0x02,
+ 0x07, 0x00,
+ 0x08, 0xC3,
+ 0x0C, 0x00,
+ 0x0D, 0x81,
+ 0x0E, 0x23,
+ 0x0F, 0x12,
+ 0x10, 0x7E,
+ 0x11, 0x84,
+ 0x12, 0xB9,
+ 0x13, 0x88,
+ 0x14, 0x89,
+ 0x15, 0xC9,
+ 0x16, 0x00,
+ 0x17, 0x5C,
+ 0x18, 0x00,
+ 0x19, 0x00,
+ 0x1A, 0x00,
+ 0x1C, 0x00,
+ 0x1D, 0x00,
+ 0x1E, 0x00,
+ 0x1F, 0x3A,
+ 0x20, 0x2E,
+ 0x21, 0x80,
+ 0x22, 0xFF,
+ 0x23, 0xC1,
+ 0x28, 0x00,
+ 0x29, 0x1E,
+ 0x2A, 0x14,
+ 0x2B, 0x0F,
+ 0x2C, 0x09,
+ 0x2D, 0x05,
+ 0x31, 0x1F,
+ 0x32, 0x19,
+ 0x33, 0xFE,
+ 0x34, 0x93,
+ 0xff, 0xff,
};
static struct stv0299_config samsung_tbmu24112_config = {
@@ -259,27 +307,155 @@ static struct stv0299_config samsung_tbmu24112_config = {
.set_symbol_rate = samsung_tbmu24112_set_symbol_rate,
};
-/* dvb-t mt352 */
-static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe)
+static int skystar2_rev26_attach(struct flexcop_device *fc,
+ struct i2c_adapter *i2c)
+{
+ fc->fe = dvb_attach(stv0299_attach, &samsung_tbmu24112_config, i2c);
+ if (fc->fe != NULL) {
+ struct dvb_frontend_ops *ops = &fc->fe->ops;
+ ops->tuner_ops.set_params = samsung_tbmu24112_tuner_set_params;
+ ops->set_voltage = flexcop_set_voltage;
+ fc->fe_sleep = ops->sleep;
+ ops->sleep = flexcop_sleep;
+ return 1;
+ }
+ return 0;
+}
+#endif
+
+/* SkyStar2 DVB-S rev 2.7 */
+#if defined(CONFIG_DVB_S5H1420_MODULE)
+static struct s5h1420_config skystar2_rev2_7_s5h1420_config = {
+ .demod_address = 0x53,
+ .invert = 1,
+ .repeated_start_workaround = 1,
+ .serial_mpeg = 1,
+};
+
+static struct itd1000_config skystar2_rev2_7_itd1000_config = {
+ .i2c_address = 0x61,
+};
+
+static int skystar2_rev27_attach(struct flexcop_device *fc,
+ struct i2c_adapter *i2c)
+{
+ flexcop_ibi_value r108;
+ struct i2c_adapter *i2c_tuner;
+
+ /* enable no_base_addr - no repeated start when reading */
+ fc->fc_i2c_adap[0].no_base_addr = 1;
+ fc->fe = dvb_attach(s5h1420_attach, &skystar2_rev2_7_s5h1420_config,
+ i2c);
+ if (!fc->fe)
+ goto fail;
+
+ i2c_tuner = s5h1420_get_tuner_i2c_adapter(fc->fe);
+ if (!i2c_tuner)
+ goto fail;
+
+ fc->fe_sleep = fc->fe->ops.sleep;
+ fc->fe->ops.sleep = flexcop_sleep;
+
+ /* enable no_base_addr - no repeated start when reading */
+ fc->fc_i2c_adap[2].no_base_addr = 1;
+ if (!dvb_attach(isl6421_attach, fc->fe, &fc->fc_i2c_adap[2].i2c_adap,
+ 0x08, 1, 1)) {
+ err("ISL6421 could NOT be attached");
+ goto fail_isl;
+ }
+ info("ISL6421 successfully attached");
+
+ /* the ITD1000 requires a lower i2c clock - is it a problem ? */
+ r108.raw = 0x00000506;
+ fc->write_ibi_reg(fc, tw_sm_c_108, r108);
+ if (!dvb_attach(itd1000_attach, fc->fe, i2c_tuner,
+ &skystar2_rev2_7_itd1000_config)) {
+ err("ITD1000 could NOT be attached");
+ /* Should i2c clock be restored? */
+ goto fail_isl;
+ }
+ info("ITD1000 successfully attached");
+
+ return 1;
+
+fail_isl:
+ fc->fc_i2c_adap[2].no_base_addr = 0;
+fail:
+ /* for the next devices we need it again */
+ fc->fc_i2c_adap[0].no_base_addr = 0;
+ return 0;
+}
+#endif
+
+/* SkyStar2 rev 2.8 */
+#if defined(CONFIG_DVB_CX24123_MODULE)
+static struct cx24123_config skystar2_rev2_8_cx24123_config = {
+ .demod_address = 0x55,
+ .dont_use_pll = 1,
+ .agc_callback = cx24113_agc_callback,
+};
+
+static const struct cx24113_config skystar2_rev2_8_cx24113_config = {
+ .i2c_addr = 0x54,
+ .xtal_khz = 10111,
+};
+
+static int skystar2_rev28_attach(struct flexcop_device *fc,
+ struct i2c_adapter *i2c)
+{
+ struct i2c_adapter *i2c_tuner;
+
+ fc->fe = dvb_attach(cx24123_attach, &skystar2_rev2_8_cx24123_config,
+ i2c);
+ if (!fc->fe)
+ return 0;
+
+ i2c_tuner = cx24123_get_tuner_i2c_adapter(fc->fe);;
+ if (!i2c_tuner)
+ return 0;
+
+ if (!dvb_attach(cx24113_attach, fc->fe, &skystar2_rev2_8_cx24113_config,
+ i2c_tuner)) {
+ err("CX24113 could NOT be attached");
+ return 0;
+ }
+ info("CX24113 successfully attached");
+
+ fc->fc_i2c_adap[2].no_base_addr = 1;
+ if (!dvb_attach(isl6421_attach, fc->fe, &fc->fc_i2c_adap[2].i2c_adap,
+ 0x08, 0, 0)) {
+ err("ISL6421 could NOT be attached");
+ fc->fc_i2c_adap[2].no_base_addr = 0;
+ return 0;
+ }
+ info("ISL6421 successfully attached");
+ /* TODO on i2c_adap[1] addr 0x11 (EEPROM) there seems to be an
+ * IR-receiver (PIC16F818) - but the card has no input for that ??? */
+ return 1;
+}
+#endif
+
+/* AirStar DVB-T */
+#if defined(CONFIG_DVB_MT352_MODULE)
+static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend *fe)
{
- static u8 mt352_clock_config [] = { 0x89, 0x18, 0x2d };
- static u8 mt352_reset [] = { 0x50, 0x80 };
- static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 };
- static u8 mt352_agc_cfg [] = { 0x67, 0x28, 0xa1 };
+ static u8 mt352_clock_config[] = { 0x89, 0x18, 0x2d };
+ static u8 mt352_reset[] = { 0x50, 0x80 };
+ static u8 mt352_adc_ctl_1_cfg[] = { 0x8E, 0x40 };
+ static u8 mt352_agc_cfg[] = { 0x67, 0x28, 0xa1 };
static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 };
mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
udelay(2000);
mt352_write(fe, mt352_reset, sizeof(mt352_reset));
mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
-
mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg));
mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg));
-
return 0;
}
-static int samsung_tdtc9251dh0_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters *params, u8* pllbuf, int buf_len)
+static int samsung_tdtc9251dh0_calc_regs(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params, u8* pllbuf, int buf_len)
{
u32 div;
unsigned char bs = 0;
@@ -287,19 +463,20 @@ static int samsung_tdtc9251dh0_calc_regs(struct dvb_frontend* fe, struct dvb_fro
if (buf_len < 5)
return -EINVAL;
- #define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */
+#define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */
div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
-
- if (params->frequency >= 48000000 && params->frequency <= 154000000) bs = 0x09;
- if (params->frequency >= 161000000 && params->frequency <= 439000000) bs = 0x0a;
- if (params->frequency >= 447000000 && params->frequency <= 863000000) bs = 0x08;
+ if (params->frequency >= 48000000 && params->frequency <= 154000000) \
+ bs = 0x09;
+ if (params->frequency >= 161000000 && params->frequency <= 439000000) \
+ bs = 0x0a;
+ if (params->frequency >= 447000000 && params->frequency <= 863000000) \
+ bs = 0x08;
pllbuf[0] = 0x61;
pllbuf[1] = div >> 8;
pllbuf[2] = div & 0xff;
pllbuf[3] = 0xcc;
pllbuf[4] = bs;
-
return 5;
}
@@ -308,70 +485,95 @@ static struct mt352_config samsung_tdtc9251dh0_config = {
.demod_init = samsung_tdtc9251dh0_demod_init,
};
-static int flexcop_fe_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
+static int airstar_dvbt_attach(struct flexcop_device *fc,
+ struct i2c_adapter *i2c)
+{
+ fc->fe = dvb_attach(mt352_attach, &samsung_tdtc9251dh0_config, i2c);
+ if (fc->fe != NULL) {
+ fc->fe->ops.tuner_ops.calc_regs = samsung_tdtc9251dh0_calc_regs;
+ return 1;
+ }
+ return 0;
+}
+#endif
+
+/* AirStar ATSC 1st generation */
+#if defined(CONFIG_DVB_BCM3510_MODULE)
+static int flexcop_fe_request_firmware(struct dvb_frontend *fe,
+ const struct firmware **fw, char* name)
{
struct flexcop_device *fc = fe->dvb->priv;
return request_firmware(fw, name, fc->dev);
}
-static struct lgdt330x_config air2pc_atsc_hd5000_config = {
- .demod_address = 0x59,
- .demod_chip = LGDT3303,
- .serial_mpeg = 0x04,
- .clock_polarity_flip = 1,
-};
-
-static struct nxt200x_config samsung_tbmv_config = {
- .demod_address = 0x0a,
-};
-
static struct bcm3510_config air2pc_atsc_first_gen_config = {
.demod_address = 0x0f,
.request_firmware = flexcop_fe_request_firmware,
};
-static int skystar23_samsung_tbdu18132_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
+static int airstar_atsc1_attach(struct flexcop_device *fc,
+ struct i2c_adapter *i2c)
{
- u8 buf[4];
- u32 div;
- struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
- struct flexcop_device *fc = fe->dvb->priv;
-
- div = (params->frequency + (125/2)) / 125;
+ fc->fe = dvb_attach(bcm3510_attach, &air2pc_atsc_first_gen_config, i2c);
+ return fc->fe != NULL;
+}
+#endif
- buf[0] = (div >> 8) & 0x7f;
- buf[1] = (div >> 0) & 0xff;
- buf[2] = 0x84 | ((div >> 10) & 0x60);
- buf[3] = 0x80;
+/* AirStar ATSC 2nd generation */
+#if defined(CONFIG_DVB_NXT200X_MODULE)
+static struct nxt200x_config samsung_tbmv_config = {
+ .demod_address = 0x0a,
+};
- if (params->frequency < 1550000)
- buf[3] |= 0x02;
+static int airstar_atsc2_attach(struct flexcop_device *fc,
+ struct i2c_adapter *i2c)
+{
+ fc->fe = dvb_attach(nxt200x_attach, &samsung_tbmv_config, i2c);
+ if (!fc->fe)
+ return 0;
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
- if (i2c_transfer(&fc->fc_i2c_adap[0].i2c_adap, &msg, 1) != 1)
- return -EIO;
- return 0;
+ return !!dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL,
+ DVB_PLL_SAMSUNG_TBMV);
}
+#endif
-static struct mt312_config skystar23_samsung_tbdu18132_config = {
-
- .demod_address = 0x0e,
+/* AirStar ATSC 3rd generation */
+#if defined(CONFIG_DVB_LGDT330X_MODULE)
+static struct lgdt330x_config air2pc_atsc_hd5000_config = {
+ .demod_address = 0x59,
+ .demod_chip = LGDT3303,
+ .serial_mpeg = 0x04,
+ .clock_polarity_flip = 1,
};
+static int airstar_atsc3_attach(struct flexcop_device *fc,
+ struct i2c_adapter *i2c)
+{
+ fc->fe = dvb_attach(lgdt330x_attach, &air2pc_atsc_hd5000_config, i2c);
+ if (!fc->fe)
+ return 0;
+
+ return !!dvb_attach(simple_tuner_attach, fc->fe, i2c, 0x61,
+ TUNER_LG_TDVS_H06XF);
+}
+#endif
+
+/* CableStar2 DVB-C */
+#if defined(CONFIG_DVB_STV0297_MODULE)
static int alps_tdee4_stv0297_tuner_set_params(struct dvb_frontend* fe,
- struct dvb_frontend_parameters *fep)
+ struct dvb_frontend_parameters *fep)
{
struct flexcop_device *fc = fe->dvb->priv;
u8 buf[4];
u16 div;
int ret;
-/* 62.5 kHz * 10 */
+/* 62.5 kHz * 10 */
#define REF_FREQ 625
#define FREQ_OFFSET 36125
- div = ((fep->frequency/1000 + FREQ_OFFSET ) * 10) / REF_FREQ; // 4 MHz = 4000 KHz
+ div = ((fep->frequency/1000 + FREQ_OFFSET) * 10) / REF_FREQ;
+/* 4 MHz = 4000 KHz */
buf[0] = (u8)( div >> 8) & 0x7f;
buf[1] = (u8) div & 0xff;
@@ -384,11 +586,11 @@ static int alps_tdee4_stv0297_tuner_set_params(struct dvb_frontend* fe,
* AGD = 1, R3 R2 R1 R0 = 0 1 0 1 => byte 4 = 1**10101 = 0x95 */
buf[2] = 0x95;
-// Range(MHz) C1 * RE RTS BS4 BS3 BS2 BS1 Byte 5
-// 47 - 153 0 * 0 0 0 0 0 1 0x01
-// 153 - 430 0 * 0 0 0 0 1 0 0x02
-// 430 - 822 0 * 0 0 1 0 0 0 0x08
-// 822 - 862 1 * 0 0 1 0 0 0 0x88
+/* Range(MHz) C1 * RE RTS BS4 BS3 BS2 BS1 Byte 5
+ * 47 - 153 0 * 0 0 0 0 0 1 0x01
+ * 153 - 430 0 * 0 0 0 0 1 0 0x02
+ * 430 - 822 0 * 0 0 1 0 0 0 0x08
+ * 822 - 862 1 * 0 0 1 0 0 0 0x88 */
if (fep->frequency <= 153000000) buf[3] = 0x01;
else if (fep->frequency <= 430000000) buf[3] = 0x02;
@@ -397,11 +599,11 @@ static int alps_tdee4_stv0297_tuner_set_params(struct dvb_frontend* fe,
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0);
- deb_tuner("tuner buffer for %d Hz: %x %x %x %x\n",fep->frequency, buf[0],buf[1],buf[2],buf[3]);
+ deb_tuner("tuner buffer for %d Hz: %x %x %x %x\n", fep->frequency,
+ buf[0], buf[1], buf[2], buf[3]);
ret = fc->i2c_request(&fc->fc_i2c_adap[2],
- FC_WRITE, 0x61, buf[0], &buf[1], 3);
+ FC_WRITE, 0x61, buf[0], &buf[1], 3);
deb_tuner("tuner write returned: %d\n",ret);
-
return ret;
}
@@ -481,182 +683,73 @@ static u8 alps_tdee4_stv0297_inittab[] = {
static struct stv0297_config alps_tdee4_stv0297_config = {
.demod_address = 0x1c,
.inittab = alps_tdee4_stv0297_inittab,
-// .invert = 1,
-// .pll_set = alps_tdee4_stv0297_pll_set,
-};
-
-
-/* SkyStar2 rev2.7 (a/u) */
-static struct s5h1420_config skystar2_rev2_7_s5h1420_config = {
- .demod_address = 0x53,
- .invert = 1,
- .repeated_start_workaround = 1,
- .serial_mpeg = 1,
-};
-
-static struct itd1000_config skystar2_rev2_7_itd1000_config = {
- .i2c_address = 0x61,
};
-/* SkyStar2 rev2.8 */
-static struct cx24123_config skystar2_rev2_8_cx24123_config = {
- .demod_address = 0x55,
- .dont_use_pll = 1,
- .agc_callback = cx24113_agc_callback,
-};
-
-static const struct cx24113_config skystar2_rev2_8_cx24113_config = {
- .i2c_addr = 0x54,
- .xtal_khz = 10111,
-};
-
-/* try to figure out the frontend, each card/box can have on of the following list */
-int flexcop_frontend_init(struct flexcop_device *fc)
+static int cablestar2_attach(struct flexcop_device *fc,
+ struct i2c_adapter *i2c)
{
- struct dvb_frontend_ops *ops;
- struct i2c_adapter *i2c = &fc->fc_i2c_adap[0].i2c_adap;
- struct i2c_adapter *i2c_tuner;
-
- /* enable no_base_addr - no repeated start when reading */
- fc->fc_i2c_adap[0].no_base_addr = 1;
- fc->fe = dvb_attach(s5h1420_attach, &skystar2_rev2_7_s5h1420_config, i2c);
- if (fc->fe != NULL) {
- flexcop_ibi_value r108;
- i2c_tuner = s5h1420_get_tuner_i2c_adapter(fc->fe);
- ops = &fc->fe->ops;
-
- fc->fe_sleep = ops->sleep;
- ops->sleep = flexcop_sleep;
-
- fc->dev_type = FC_SKY_REV27;
-
- /* enable no_base_addr - no repeated start when reading */
- fc->fc_i2c_adap[2].no_base_addr = 1;
- if (dvb_attach(isl6421_attach, fc->fe, &fc->fc_i2c_adap[2].i2c_adap, 0x08, 1, 1) == NULL)
- err("ISL6421 could NOT be attached");
- else
- info("ISL6421 successfully attached");
-
- /* the ITD1000 requires a lower i2c clock - it slows down the stuff for everyone - but is it a problem ? */
- r108.raw = 0x00000506;
- fc->write_ibi_reg(fc, tw_sm_c_108, r108);
- if (i2c_tuner) {
- if (dvb_attach(itd1000_attach, fc->fe, i2c_tuner, &skystar2_rev2_7_itd1000_config) == NULL)
- err("ITD1000 could NOT be attached");
- else
- info("ITD1000 successfully attached");
- }
- goto fe_found;
- }
- fc->fc_i2c_adap[0].no_base_addr = 0; /* for the next devices we need it again */
-
- /* try the sky v2.8 (cx24123, isl6421) */
- fc->fe = dvb_attach(cx24123_attach,
- &skystar2_rev2_8_cx24123_config, i2c);
- if (fc->fe != NULL) {
- i2c_tuner = cx24123_get_tuner_i2c_adapter(fc->fe);
- if (i2c_tuner != NULL) {
- if (dvb_attach(cx24113_attach, fc->fe,
- &skystar2_rev2_8_cx24113_config,
- i2c_tuner) == NULL)
- err("CX24113 could NOT be attached");
- else
- info("CX24113 successfully attached");
- }
-
- fc->dev_type = FC_SKY_REV28;
-
- fc->fc_i2c_adap[2].no_base_addr = 1;
- if (dvb_attach(isl6421_attach, fc->fe,
- &fc->fc_i2c_adap[2].i2c_adap, 0x08, 0, 0) == NULL)
- err("ISL6421 could NOT be attached");
- else
- info("ISL6421 successfully attached");
-
- /* TODO on i2c_adap[1] addr 0x11 (EEPROM) there seems to be an
- * IR-receiver (PIC16F818) - but the card has no input for
- * that ??? */
-
- goto fe_found;
- }
-
- /* try the sky v2.6 (stv0299/Samsung tbmu24112(sl1935)) */
- fc->fe = dvb_attach(stv0299_attach, &samsung_tbmu24112_config, i2c);
- if (fc->fe != NULL) {
- ops = &fc->fe->ops;
-
- ops->tuner_ops.set_params = samsung_tbmu24112_tuner_set_params;
-
- ops->set_voltage = flexcop_set_voltage;
-
- fc->fe_sleep = ops->sleep;
- ops->sleep = flexcop_sleep;
-
- fc->dev_type = FC_SKY_REV26;
- goto fe_found;
- }
-
- /* try the air dvb-t (mt352/Samsung tdtc9251dh0(??)) */
- fc->fe = dvb_attach(mt352_attach, &samsung_tdtc9251dh0_config, i2c);
- if (fc->fe != NULL) {
- fc->dev_type = FC_AIR_DVBT;
- fc->fe->ops.tuner_ops.calc_regs = samsung_tdtc9251dh0_calc_regs;
- goto fe_found;
- }
-
- /* try the air atsc 2nd generation (nxt2002) */
- fc->fe = dvb_attach(nxt200x_attach, &samsung_tbmv_config, i2c);
- if (fc->fe != NULL) {
- fc->dev_type = FC_AIR_ATSC2;
- dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL, DVB_PLL_SAMSUNG_TBMV);
- goto fe_found;
- }
-
- fc->fe = dvb_attach(lgdt330x_attach, &air2pc_atsc_hd5000_config, i2c);
- if (fc->fe != NULL) {
- fc->dev_type = FC_AIR_ATSC3;
- dvb_attach(simple_tuner_attach, fc->fe, i2c, 0x61,
- TUNER_LG_TDVS_H06XF);
- goto fe_found;
- }
-
- /* try the air atsc 1nd generation (bcm3510)/panasonic ct10s */
- fc->fe = dvb_attach(bcm3510_attach, &air2pc_atsc_first_gen_config, i2c);
- if (fc->fe != NULL) {
- fc->dev_type = FC_AIR_ATSC1;
- goto fe_found;
- }
-
- /* try the cable dvb (stv0297) */
fc->fc_i2c_adap[0].no_base_addr = 1;
fc->fe = dvb_attach(stv0297_attach, &alps_tdee4_stv0297_config, i2c);
- if (fc->fe != NULL) {
- fc->dev_type = FC_CABLE;
- fc->fe->ops.tuner_ops.set_params = alps_tdee4_stv0297_tuner_set_params;
- goto fe_found;
+ if (!fc->fe) {
+ /* Reset for next frontend to try */
+ fc->fc_i2c_adap[0].no_base_addr = 0;
+ return 0;
}
- fc->fc_i2c_adap[0].no_base_addr = 0;
-
- /* try the sky v2.3 (vp310/Samsung tbdu18132(tsa5059)) */
- fc->fe = dvb_attach(mt312_attach,
- &skystar23_samsung_tbdu18132_config, i2c);
- if (fc->fe != NULL) {
- ops = &fc->fe->ops;
-
- ops->tuner_ops.set_params = skystar23_samsung_tbdu18132_tuner_set_params;
-
- ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd;
- ops->diseqc_send_burst = flexcop_diseqc_send_burst;
- ops->set_tone = flexcop_set_tone;
- ops->set_voltage = flexcop_set_voltage;
-
- fc->fe_sleep = ops->sleep;
- ops->sleep = flexcop_sleep;
+ fc->fe->ops.tuner_ops.set_params = alps_tdee4_stv0297_tuner_set_params;
+ return 1;
+}
+#endif
+
+static struct {
+ flexcop_device_type_t type;
+ int (*attach)(struct flexcop_device *, struct i2c_adapter *);
+} flexcop_frontends[] = {
+#if defined(CONFIG_DVB_S5H1420_MODULE)
+ { FC_SKY_REV27, skystar2_rev27_attach },
+#endif
+#if defined(CONFIG_DVB_CX24123_MODULE)
+ { FC_SKY_REV28, skystar2_rev28_attach },
+#endif
+#if defined(CONFIG_DVB_STV0299_MODULE)
+ { FC_SKY_REV26, skystar2_rev26_attach },
+#endif
+#if defined(CONFIG_DVB_MT352_MODULE)
+ { FC_AIR_DVBT, airstar_dvbt_attach },
+#endif
+#if defined(CONFIG_DVB_NXT200X_MODULE)
+ { FC_AIR_ATSC2, airstar_atsc2_attach },
+#endif
+#if defined(CONFIG_DVB_LGDT330X_MODULE)
+ { FC_AIR_ATSC3, airstar_atsc3_attach },
+#endif
+#if defined(CONFIG_DVB_BCM3510_MODULE)
+ { FC_AIR_ATSC1, airstar_atsc1_attach },
+#endif
+#if defined(CONFIG_DVB_STV0297_MODULE)
+ { FC_CABLE, cablestar2_attach },
+#endif
+#if defined(CONFIG_DVB_MT312_MODULE)
+ { FC_SKY_REV23, skystar2_rev23_attach },
+#endif
+};
- fc->dev_type = FC_SKY_REV23;
- goto fe_found;
+/* try to figure out the frontend */
+int flexcop_frontend_init(struct flexcop_device *fc)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE(flexcop_frontends); i++) {
+ /* type needs to be set before, because of some workarounds
+ * done based on the probed card type */
+ fc->dev_type = flexcop_frontends[i].type;
+ if (flexcop_frontends[i].attach(fc, &fc->fc_i2c_adap[0].i2c_adap))
+ goto fe_found;
+ /* Clean up partially attached frontend */
+ if (fc->fe) {
+ dvb_frontend_detach(fc->fe);
+ fc->fe = NULL;
+ }
}
-
+ fc->dev_type = FC_UNK;
err("no frontend driver found for this B2C2/FlexCop adapter");
return -ENODEV;
@@ -664,9 +757,7 @@ fe_found:
info("found '%s' .", fc->fe->ops.info.name);
if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) {
err("frontend registration failed!");
- ops = &fc->fe->ops;
- if (ops->release != NULL)
- ops->release(fc->fe);
+ dvb_frontend_detach(fc->fe);
fc->fe = NULL;
return -EINVAL;
}
@@ -680,6 +771,5 @@ void flexcop_frontend_exit(struct flexcop_device *fc)
dvb_unregister_frontend(fc->fe);
dvb_frontend_detach(fc->fe);
}
-
fc->init_state &= ~FC_STATE_FE_INIT;
}
diff --git a/linux/drivers/media/dvb/b2c2/flexcop-i2c.c b/linux/drivers/media/dvb/b2c2/flexcop-i2c.c
index 06a90f67e..df4d6e8d9 100644
--- a/linux/drivers/media/dvb/b2c2/flexcop-i2c.c
+++ b/linux/drivers/media/dvb/b2c2/flexcop-i2c.c
@@ -200,7 +200,7 @@ static int flexcop_master_xfer(struct i2c_adapter *i2c_adap,
msgs[i].buf[0], &msgs[i].buf[1],
msgs[i].len - 1);
if (ret < 0) {
- err("i2c master_xfer failed");
+ deb_i2c("i2c master_xfer failed");
break;
}
}
diff --git a/linux/drivers/media/dvb/b2c2/flexcop-misc.c b/linux/drivers/media/dvb/b2c2/flexcop-misc.c
index e56627d2f..f06f3a907 100644
--- a/linux/drivers/media/dvb/b2c2/flexcop-misc.c
+++ b/linux/drivers/media/dvb/b2c2/flexcop-misc.c
@@ -46,16 +46,16 @@ static const char *flexcop_revision_names[] = {
};
static const char *flexcop_device_names[] = {
- "Unknown device",
- "Air2PC/AirStar 2 DVB-T",
- "Air2PC/AirStar 2 ATSC 1st generation",
- "Air2PC/AirStar 2 ATSC 2nd generation",
- "Sky2PC/SkyStar 2 DVB-S",
- "Sky2PC/SkyStar 2 DVB-S (old version)",
- "Cable2PC/CableStar 2 DVB-C",
- "Air2PC/AirStar 2 ATSC 3rd generation (HD5000)",
- "Sky2PC/SkyStar 2 DVB-S rev 2.7a/u",
- "Sky2PC/SkyStar 2 DVB-S rev 2.8",
+ [FC_UNK] = "Unknown device",
+ [FC_CABLE] = "Cable2PC/CableStar 2 DVB-C",
+ [FC_AIR_DVBT] = "Air2PC/AirStar 2 DVB-T",
+ [FC_AIR_ATSC1] = "Air2PC/AirStar 2 ATSC 1st generation",
+ [FC_AIR_ATSC2] = "Air2PC/AirStar 2 ATSC 2nd generation",
+ [FC_AIR_ATSC3] = "Air2PC/AirStar 2 ATSC 3rd generation (HD5000)",
+ [FC_SKY_REV23] = "Sky2PC/SkyStar 2 DVB-S rev 2.3 (old version)",
+ [FC_SKY_REV26] = "Sky2PC/SkyStar 2 DVB-S rev 2.6",
+ [FC_SKY_REV27] = "Sky2PC/SkyStar 2 DVB-S rev 2.7a/u",
+ [FC_SKY_REV28] = "Sky2PC/SkyStar 2 DVB-S rev 2.8",
};
static const char *flexcop_bus_names[] = {
diff --git a/linux/drivers/media/dvb/bt8xx/bt878.c b/linux/drivers/media/dvb/bt8xx/bt878.c
index 57f0f84b6..456cd8756 100644
--- a/linux/drivers/media/dvb/bt8xx/bt878.c
+++ b/linux/drivers/media/dvb/bt8xx/bt878.c
@@ -512,12 +512,6 @@ static int __devinit bt878_probe(struct pci_dev *dev,
pci_set_master(dev);
pci_set_drvdata(dev, bt);
-/* if(init_bt878(btv) < 0) {
- bt878_remove(dev);
- return -EIO;
- }
-*/
-
if ((result = bt878_mem_alloc(bt))) {
printk(KERN_ERR "bt878: failed to allocate memory!\n");
goto fail2;
@@ -583,7 +577,7 @@ static struct pci_driver bt878_pci_driver = {
.name = "bt878",
.id_table = bt878_pci_tbl,
.probe = bt878_probe,
- .remove = bt878_remove,
+ .remove = __devexit_p(bt878_remove),
};
static int bt878_pci_driver_registered;
diff --git a/linux/drivers/media/dvb/dm1105/dm1105.c b/linux/drivers/media/dvb/dm1105/dm1105.c
index ca1048fd4..17edeb66b 100644
--- a/linux/drivers/media/dvb/dm1105/dm1105.c
+++ b/linux/drivers/media/dvb/dm1105/dm1105.c
@@ -51,6 +51,9 @@
#ifndef PCI_VENDOR_ID_TRIGEM
#define PCI_VENDOR_ID_TRIGEM 0x109f
#endif
+#ifndef PCI_VENDOR_ID_AXESS
+#define PCI_VENDOR_ID_AXESS 0x195d
+#endif
#ifndef PCI_DEVICE_ID_DM1105
#define PCI_DEVICE_ID_DM1105 0x036f
#endif
@@ -60,6 +63,9 @@
#ifndef PCI_DEVICE_ID_DW2004
#define PCI_DEVICE_ID_DW2004 0x2004
#endif
+#ifndef PCI_DEVICE_ID_DM05
+#define PCI_DEVICE_ID_DM05 0x1105
+#endif
/* ----------------------------------------------- */
/* sdmc dm1105 registers */
@@ -150,6 +156,11 @@
#define DM1105_LNB_13V 0x00010100
#define DM1105_LNB_18V 0x00000100
+/* GPIO's for LNB power control for Axess DM05 */
+#define DM05_LNB_MASK 0x00000000
+#define DM05_LNB_13V 0x00020000
+#define DM05_LNB_18V 0x00030000
+
static int ir_debug;
module_param(ir_debug, int, 0644);
MODULE_PARM_DESC(ir_debug, "enable debugging information for IR decoding");
@@ -188,6 +199,8 @@ struct dm1105dvb {
/* irq */
struct work_struct work;
+ struct workqueue_struct *wq;
+ char wqn[16];
/* dma */
dma_addr_t dma_addr;
@@ -316,15 +329,25 @@ static inline struct dm1105dvb *frontend_to_dm1105dvb(struct dvb_frontend *fe)
static int dm1105dvb_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
{
struct dm1105dvb *dm1105dvb = frontend_to_dm1105dvb(fe);
+ u32 lnb_mask, lnb_13v, lnb_18v;
- if (voltage == SEC_VOLTAGE_18) {
- outl(DM1105_LNB_MASK, dm_io_mem(DM1105_GPIOCTR));
- outl(DM1105_LNB_18V, dm_io_mem(DM1105_GPIOVAL));
- } else {
- /*LNB ON-13V by default!*/
- outl(DM1105_LNB_MASK, dm_io_mem(DM1105_GPIOCTR));
- outl(DM1105_LNB_13V, dm_io_mem(DM1105_GPIOVAL));
- }
+ switch (dm1105dvb->pdev->subsystem_device) {
+ case PCI_DEVICE_ID_DM05:
+ lnb_mask = DM05_LNB_MASK;
+ lnb_13v = DM05_LNB_13V;
+ lnb_18v = DM05_LNB_18V;
+ break;
+ default:
+ lnb_mask = DM1105_LNB_MASK;
+ lnb_13v = DM1105_LNB_13V;
+ lnb_18v = DM1105_LNB_18V;
+ }
+
+ outl(lnb_mask, dm_io_mem(DM1105_GPIOCTR));
+ if (voltage == SEC_VOLTAGE_18)
+ outl(lnb_18v , dm_io_mem(DM1105_GPIOVAL));
+ else
+ outl(lnb_13v, dm_io_mem(DM1105_GPIOVAL));
return 0;
}
@@ -463,7 +486,7 @@ static irqreturn_t dm1105dvb_irq(int irq, void *dev_id)
case (INTSTS_TSIRQ | INTSTS_IR):
dm1105dvb->nextwrp = inl(dm_io_mem(DM1105_WRP)) -
inl(dm_io_mem(DM1105_STADR));
- schedule_work(&dm1105dvb->work);
+ queue_work(dm1105dvb->wq, &dm1105dvb->work);
break;
case INTSTS_IR:
dm1105dvb->ir.ir_command = inl(dm_io_mem(DM1105_IRCODE));
@@ -599,46 +622,44 @@ static int __devinit frontend_init(struct dm1105dvb *dm1105dvb)
int ret;
switch (dm1105dvb->pdev->subsystem_device) {
- case PCI_DEVICE_ID_DW2002:
+ case PCI_DEVICE_ID_DW2004:
dm1105dvb->fe = dvb_attach(
- stv0299_attach, &sharp_z0194a_config,
+ cx24116_attach, &serit_sp2633_config,
&dm1105dvb->i2c_adap);
+ if (dm1105dvb->fe)
+ dm1105dvb->fe->ops.set_voltage = dm1105dvb_set_voltage;
+ break;
+ default:
+ dm1105dvb->fe = dvb_attach(
+ stv0299_attach, &sharp_z0194a_config,
+ &dm1105dvb->i2c_adap);
if (dm1105dvb->fe) {
dm1105dvb->fe->ops.set_voltage =
dm1105dvb_set_voltage;
dvb_attach(dvb_pll_attach, dm1105dvb->fe, 0x60,
&dm1105dvb->i2c_adap, DVB_PLL_OPERA1);
+ break;
}
- if (!dm1105dvb->fe) {
- dm1105dvb->fe = dvb_attach(
- stv0288_attach, &earda_config,
- &dm1105dvb->i2c_adap);
- if (dm1105dvb->fe) {
- dm1105dvb->fe->ops.set_voltage =
- dm1105dvb_set_voltage;
- dvb_attach(stb6000_attach, dm1105dvb->fe, 0x61,
- &dm1105dvb->i2c_adap);
- }
+ dm1105dvb->fe = dvb_attach(
+ stv0288_attach, &earda_config,
+ &dm1105dvb->i2c_adap);
+ if (dm1105dvb->fe) {
+ dm1105dvb->fe->ops.set_voltage =
+ dm1105dvb_set_voltage;
+ dvb_attach(stb6000_attach, dm1105dvb->fe, 0x61,
+ &dm1105dvb->i2c_adap);
+ break;
}
- if (!dm1105dvb->fe) {
- dm1105dvb->fe = dvb_attach(
- si21xx_attach, &serit_config,
- &dm1105dvb->i2c_adap);
- if (dm1105dvb->fe)
- dm1105dvb->fe->ops.set_voltage =
- dm1105dvb_set_voltage;
- }
- break;
- case PCI_DEVICE_ID_DW2004:
dm1105dvb->fe = dvb_attach(
- cx24116_attach, &serit_sp2633_config,
+ si21xx_attach, &serit_config,
&dm1105dvb->i2c_adap);
if (dm1105dvb->fe)
- dm1105dvb->fe->ops.set_voltage = dm1105dvb_set_voltage;
- break;
+ dm1105dvb->fe->ops.set_voltage =
+ dm1105dvb_set_voltage;
+
}
if (!dm1105dvb->fe) {
@@ -662,10 +683,17 @@ static void __devinit dm1105dvb_read_mac(struct dm1105dvb *dm1105dvb, u8 *mac)
static u8 command[1] = { 0x28 };
struct i2c_msg msg[] = {
- { .addr = IIC_24C01_addr >> 1, .flags = 0,
- .buf = command, .len = 1 },
- { .addr = IIC_24C01_addr >> 1, .flags = I2C_M_RD,
- .buf = mac, .len = 6 },
+ {
+ .addr = IIC_24C01_addr >> 1,
+ .flags = 0,
+ .buf = command,
+ .len = 1
+ }, {
+ .addr = IIC_24C01_addr >> 1,
+ .flags = I2C_M_RD,
+ .buf = mac,
+ .len = 6
+ },
};
dm1105_i2c_xfer(&dm1105dvb->i2c_adap, msg , 2);
@@ -788,14 +816,22 @@ static int __devinit dm1105_probe(struct pci_dev *pdev,
#else
INIT_WORK(&dm1105dvb->work, dm1105_dmx_buffer);
#endif
+ sprintf(dm1105dvb->wqn, "%s/%d", dvb_adapter->name, dvb_adapter->num);
+ dm1105dvb->wq = create_singlethread_workqueue(dm1105dvb->wqn);
+ if (!dm1105dvb->wq)
+ goto err_dvb_net;
ret = request_irq(pdev->irq, dm1105dvb_irq, IRQF_SHARED,
DRIVER_NAME, dm1105dvb);
if (ret < 0)
- goto err_free_irq;
+ goto err_workqueue;
return 0;
+err_workqueue:
+ destroy_workqueue(dm1105dvb->wq);
+err_dvb_net:
+ dvb_net_release(&dm1105dvb->dvbnet);
err_disconnect_frontend:
dmx->disconnect_frontend(dmx);
err_remove_mem_frontend:
@@ -812,8 +848,6 @@ err_i2c_del_adapter:
i2c_del_adapter(&dm1105dvb->i2c_adap);
err_dm1105dvb_hw_exit:
dm1105dvb_hw_exit(dm1105dvb);
-err_free_irq:
- free_irq(pdev->irq, dm1105dvb);
err_pci_iounmap:
pci_iounmap(pdev, dm1105dvb->io_mem);
err_pci_release_regions:
@@ -870,6 +904,11 @@ static struct pci_device_id dm1105_id_table[] __devinitdata = {
.subvendor = PCI_ANY_ID,
.subdevice = PCI_DEVICE_ID_DW2004,
}, {
+ .vendor = PCI_VENDOR_ID_AXESS,
+ .device = PCI_DEVICE_ID_DM05,
+ .subvendor = PCI_VENDOR_ID_AXESS,
+ .subdevice = PCI_DEVICE_ID_DM05,
+ }, {
/* empty */
},
};
diff --git a/linux/drivers/media/dvb/dvb-core/dmxdev.c b/linux/drivers/media/dvb/dvb-core/dmxdev.c
index c35fbb8d8..6d6121eb5 100644
--- a/linux/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/linux/drivers/media/dvb/dvb-core/dmxdev.c
@@ -244,19 +244,13 @@ static ssize_t dvb_dvr_read(struct file *file, char __user *buf, size_t count,
{
struct dvb_device *dvbdev = file->private_data;
struct dmxdev *dmxdev = dvbdev->priv;
- int ret;
- if (dmxdev->exit) {
- mutex_unlock(&dmxdev->mutex);
+ if (dmxdev->exit)
return -ENODEV;
- }
- //mutex_lock(&dmxdev->mutex);
- ret = dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer,
- file->f_flags & O_NONBLOCK,
- buf, count, ppos);
- //mutex_unlock(&dmxdev->mutex);
- return ret;
+ return dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer,
+ file->f_flags & O_NONBLOCK,
+ buf, count, ppos);
}
static int dvb_dvr_set_buffer_size(struct dmxdev *dmxdev,
diff --git a/linux/drivers/media/dvb/dvb-core/dvb_demux.c b/linux/drivers/media/dvb/dvb-core/dvb_demux.c
index e2eca0b1f..cfe2768d2 100644
--- a/linux/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/linux/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -38,6 +38,16 @@
*/
// #define DVB_DEMUX_SECTION_LOSS_LOG
+static int dvb_demux_tscheck;
+module_param(dvb_demux_tscheck, int, 0644);
+MODULE_PARM_DESC(dvb_demux_tscheck,
+ "enable transport stream continuity and TEI check");
+
+#define dprintk_tscheck(x...) do { \
+ if (dvb_demux_tscheck && printk_ratelimit()) \
+ printk(x); \
+ } while (0)
+
/******************************************************************************
* static inlined helper functions
******************************************************************************/
@@ -376,6 +386,36 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
u16 pid = ts_pid(buf);
int dvr_done = 0;
+ if (dvb_demux_tscheck) {
+ if (!demux->cnt_storage)
+ demux->cnt_storage = vmalloc(MAX_PID + 1);
+
+ if (!demux->cnt_storage) {
+ printk(KERN_WARNING "Couldn't allocate memory for TS/TEI check. Disabling it\n");
+ dvb_demux_tscheck = 0;
+ goto no_dvb_demux_tscheck;
+ }
+
+ /* check pkt counter */
+ if (pid < MAX_PID) {
+ if (buf[1] & 0x80)
+ dprintk_tscheck("TEI detected. "
+ "PID=0x%x data1=0x%x\n",
+ pid, buf[1]);
+
+ if ((buf[3] & 0xf) != demux->cnt_storage[pid])
+ dprintk_tscheck("TS packet counter mismatch. "
+ "PID=0x%x expected 0x%x "
+ "got 0x%x\n",
+ pid, demux->cnt_storage[pid],
+ buf[3] & 0xf);
+
+ demux->cnt_storage[pid] = ((buf[3] & 0xf) + 1)&0xf;
+ };
+ /* end check */
+ };
+no_dvb_demux_tscheck:
+
list_for_each_entry(feed, &demux->feed_list, list_head) {
if ((feed->pid != pid) && (feed->pid != 0x2000))
continue;
@@ -1160,6 +1200,7 @@ int dvb_dmx_init(struct dvb_demux *dvbdemux)
int i;
struct dmx_demux *dmx = &dvbdemux->dmx;
+ dvbdemux->cnt_storage = NULL;
dvbdemux->users = 0;
dvbdemux->filter = vmalloc(dvbdemux->filternum * sizeof(struct dvb_demux_filter));
@@ -1226,6 +1267,7 @@ EXPORT_SYMBOL(dvb_dmx_init);
void dvb_dmx_release(struct dvb_demux *dvbdemux)
{
+ vfree(dvbdemux->cnt_storage);
vfree(dvbdemux->filter);
vfree(dvbdemux->feed);
}
diff --git a/linux/drivers/media/dvb/dvb-core/dvb_demux.h b/linux/drivers/media/dvb/dvb-core/dvb_demux.h
index 933397c24..1e0ade4ec 100644
--- a/linux/drivers/media/dvb/dvb-core/dvb_demux.h
+++ b/linux/drivers/media/dvb/dvb-core/dvb_demux.h
@@ -43,6 +43,8 @@
#define DVB_DEMUX_MASK_MAX 18
+#define MAX_PID 0x1fff
+
struct dvb_demux_filter {
struct dmx_section_filter filter;
u8 maskandmode[DMX_MAX_FILTER_SIZE];
@@ -128,6 +130,8 @@ struct dvb_demux {
struct mutex mutex;
spinlock_t lock;
+
+ uint8_t *cnt_storage; /* for TS continuity check */
};
int dvb_dmx_init(struct dvb_demux *dvbdemux);
diff --git a/linux/drivers/media/dvb/dvb-core/dvb_frontend.c b/linux/drivers/media/dvb/dvb-core/dvb_frontend.c
index da2890b22..41166d407 100644
--- a/linux/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/linux/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -554,6 +554,7 @@ restart:
if (kthread_should_stop() || dvb_frontend_is_exiting(fe)) {
/* got signal or quitting */
+ fepriv->exit = 1;
break;
}
@@ -667,6 +668,7 @@ restart:
}
fepriv->thread = NULL;
+ fepriv->exit = 0;
mb();
dvb_frontend_wakeup(fe);
diff --git a/linux/drivers/media/dvb/dvb-core/dvb_net.c b/linux/drivers/media/dvb/dvb-core/dvb_net.c
index 5f4856c6d..1eede48a9 100644
--- a/linux/drivers/media/dvb/dvb-core/dvb_net.c
+++ b/linux/drivers/media/dvb/dvb-core/dvb_net.c
@@ -126,7 +126,9 @@ static void hexdump( const unsigned char *buf, unsigned short len )
struct dvb_net_priv {
int in_use;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
struct net_device_stats stats;
+#endif
u16 pid;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
struct net_device *net;
@@ -391,8 +393,13 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
if (priv->ule_skb) {
dev_kfree_skb( priv->ule_skb );
/* Prepare for next SNDU. */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
priv->stats.rx_errors++;
priv->stats.rx_frame_errors++;
+#else
+ dev->stats.rx_errors++;
+ dev->stats.rx_frame_errors++;
+#endif
}
reset_ule(priv);
priv->need_pusi = 1;
@@ -445,8 +452,13 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
dev_kfree_skb( priv->ule_skb );
/* Prepare for next SNDU. */
// reset_ule(priv); moved to below.
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
priv->stats.rx_errors++;
priv->stats.rx_frame_errors++;
+#else
+ dev->stats.rx_errors++;
+ dev->stats.rx_frame_errors++;
+#endif
}
reset_ule(priv);
/* skip to next PUSI. */
@@ -467,8 +479,13 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
/* Drop partly decoded SNDU, reset state, resync on PUSI. */
if (priv->ule_skb) {
dev_kfree_skb( priv->ule_skb );
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
priv->stats.rx_errors++;
priv->stats.rx_frame_errors++;
+#else
+ dev->stats.rx_errors++;
+ dev->stats.rx_frame_errors++;
+#endif
}
reset_ule(priv);
priv->need_pusi = 1;
@@ -484,8 +501,13 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
if (priv->ule_sndu_remain > 183) {
/* Current SNDU lacks more data than there could be available in the
* current TS cell. */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
priv->stats.rx_errors++;
priv->stats.rx_length_errors++;
+#else
+ dev->stats.rx_errors++;
+ dev->stats.rx_length_errors++;
+#endif
printk(KERN_WARNING "%lu: Expected %d more SNDU bytes, but "
"got PUSI (pf %d, ts_remain %d). Flushing incomplete payload.\n",
priv->ts_count, priv->ule_sndu_remain, ts[4], ts_remain);
@@ -527,8 +549,13 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
if (priv->ule_sndu_len < 5) {
printk(KERN_WARNING "%lu: Invalid ULE SNDU length %u. "
"Resyncing.\n", priv->ts_count, priv->ule_sndu_len);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
priv->stats.rx_errors++;
priv->stats.rx_length_errors++;
+#else
+ dev->stats.rx_errors++;
+ dev->stats.rx_length_errors++;
+#endif
priv->ule_sndu_len = 0;
priv->need_pusi = 1;
new_ts = 1;
@@ -580,7 +607,11 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
if (priv->ule_skb == NULL) {
printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n",
dev->name);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
priv->stats.rx_dropped++;
+#else
+ dev->stats.rx_dropped++;
+#endif
return;
}
@@ -653,8 +684,13 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
ule_dump = 1;
#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
priv->stats.rx_errors++;
priv->stats.rx_crc_errors++;
+#else
+ dev->stats.rx_errors++;
+ dev->stats.rx_crc_errors++;
+#endif
dev_kfree_skb(priv->ule_skb);
} else {
/* CRC32 verified OK. */
@@ -764,8 +800,13 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
* receive the packet anyhow. */
/* if (priv->ule_dbit && skb->pkt_type == PACKET_OTHERHOST)
priv->ule_skb->pkt_type = PACKET_HOST; */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
priv->stats.rx_packets++;
priv->stats.rx_bytes += priv->ule_skb->len;
+#else
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += priv->ule_skb->len;
+#endif
netif_rx(priv->ule_skb);
}
sndu_done:
@@ -820,8 +861,12 @@ static void dvb_net_sec(struct net_device *dev,
{
u8 *eth;
struct sk_buff *skb;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
struct net_device_stats *stats =
&((struct dvb_net_priv *) netdev_priv(dev))->stats;
+#else
+ struct net_device_stats *stats = &dev->stats;
+#endif
int snap = 0;
/* note: pkt_len includes a 32bit checksum */
@@ -1269,11 +1314,12 @@ static int dvb_net_stop(struct net_device *dev)
return dvb_net_feed_stop(dev);
}
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
static struct net_device_stats * dvb_net_get_stats(struct net_device *dev)
{
return &((struct dvb_net_priv *) netdev_priv(dev))->stats;
}
-
+#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
static const struct header_ops dvb_header_ops = {
.create = eth_header,
@@ -1282,6 +1328,19 @@ static const struct header_ops dvb_header_ops = {
};
#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
+static const struct net_device_ops dvb_netdev_ops = {
+ .ndo_open = dvb_net_open,
+ .ndo_stop = dvb_net_stop,
+ .ndo_start_xmit = dvb_net_tx,
+ .ndo_set_multicast_list = dvb_net_set_multicast_list,
+ .ndo_set_mac_address = dvb_net_set_mac,
+ .ndo_change_mtu = eth_change_mtu,
+ .ndo_validate_addr = eth_validate_addr,
+};
+#endif
+
static void dvb_net_setup(struct net_device *dev)
{
ether_setup(dev);
@@ -1291,12 +1350,16 @@ static void dvb_net_setup(struct net_device *dev)
#else
dev->hard_header_cache = NULL;
#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
dev->open = dvb_net_open;
dev->stop = dvb_net_stop;
dev->hard_start_xmit = dvb_net_tx;
dev->get_stats = dvb_net_get_stats;
dev->set_multicast_list = dvb_net_set_multicast_list;
dev->set_mac_address = dvb_net_set_mac;
+#else
+ dev->netdev_ops = &dvb_netdev_ops;
+#endif
dev->mtu = 4096;
dev->mc_count = 0;
diff --git a/linux/drivers/media/dvb/dvb-usb/Kconfig b/linux/drivers/media/dvb/dvb-usb/Kconfig
index 60955a70d..496c1a370 100644
--- a/linux/drivers/media/dvb/dvb-usb/Kconfig
+++ b/linux/drivers/media/dvb/dvb-usb/Kconfig
@@ -216,7 +216,7 @@ config DVB_USB_TTUSB2
help
Say Y here to support the Pinnacle 400e DVB-S USB2.0 receiver. The
firmware protocol used by this module is similar to the one used by the
- old ttusb-driver - that's why the module is called dvb-usb-ttusb2.ko.
+ old ttusb-driver - that's why the module is called dvb-usb-ttusb2.
config DVB_USB_DTT200U
tristate "WideView WT-200U and WT-220U (pen) DVB-T USB2.0 support (Yakumo/Hama/Typhoon/Yuan)"
@@ -261,6 +261,7 @@ config DVB_USB_DW2102
select DVB_STB6000 if !DVB_FE_CUSTOMISE
select DVB_CX24116 if !DVB_FE_CUSTOMISE
select DVB_SI21XX if !DVB_FE_CUSTOMISE
+ select DVB_TDA10021 if !DVB_FE_CUSTOMISE
help
Say Y here to support the DvbWorld DVB-S/S2 USB2.0 receivers
and the TeVii S650.
diff --git a/linux/drivers/media/dvb/dvb-usb/af9015.c b/linux/drivers/media/dvb/dvb-usb/af9015.c
index 5d9aacd0a..b6fc8ddf3 100644
--- a/linux/drivers/media/dvb/dvb-usb/af9015.c
+++ b/linux/drivers/media/dvb/dvb-usb/af9015.c
@@ -541,7 +541,7 @@ exit:
/* dump eeprom */
static int af9015_eeprom_dump(struct dvb_usb_device *d)
{
- char buf[52], buf2[4];
+ char buf[4+3*16+1], buf2[4];
u8 reg, val;
for (reg = 0; ; reg++) {
@@ -1268,6 +1268,7 @@ static struct usb_device_id af9015_usb_table[] = {
{USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A805)},
{USB_DEVICE(USB_VID_KWORLD_2, USB_PID_CONCEPTRONIC_CTVDIGRCU)},
{USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_MC810)},
+ {USB_DEVICE(USB_VID_KYE, USB_PID_GENIUS_TVGO_DVB_T03)},
{0},
};
MODULE_DEVICE_TABLE(usb, af9015_usb_table);
@@ -1538,7 +1539,7 @@ static struct dvb_usb_device_properties af9015_properties[] = {
.i2c_algo = &af9015_i2c_algo,
- .num_device_descs = 3, /* max 9 */
+ .num_device_descs = 4, /* max 9 */
.devices = {
{
.name = "AverMedia AVerTV Volar GPS 805 (A805)",
@@ -1556,6 +1557,11 @@ static struct dvb_usb_device_properties af9015_properties[] = {
.cold_ids = {&af9015_usb_table[23], NULL},
.warm_ids = {NULL},
},
+ {
+ .name = "Genius TVGo DVB-T03",
+ .cold_ids = {&af9015_usb_table[24], NULL},
+ .warm_ids = {NULL},
+ },
}
},
};
diff --git a/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c b/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c
index e39993df0..eda025714 100644
--- a/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c
+++ b/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c
@@ -1346,9 +1346,9 @@ static int dib0700_xc5000_tuner_callback(void *priv, int component,
if (command == XC5000_TUNER_RESET) {
/* Reset the tuner */
dib0700_set_gpio(adap->dev, GPIO1, GPIO_OUT, 0);
- msleep(330); /* from Windows USB trace */
+ msleep(10);
dib0700_set_gpio(adap->dev, GPIO1, GPIO_OUT, 1);
- msleep(330); /* from Windows USB trace */
+ msleep(10);
} else {
err("xc5000: unknown tuner callback command: %d\n", command);
return -EINVAL;
@@ -1498,6 +1498,9 @@ struct usb_device_id dib0700_usb_id_table[] = {
{ USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_MC770) },
{ USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_DTT) },
/* 50 */{ USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_DTT_Dlx) },
+ { USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_H) },
+ { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_T3) },
+ { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_T5) },
{ 0 } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
@@ -1731,8 +1734,9 @@ struct dvb_usb_device_properties dib0700_devices[] = {
{ &dib0700_usb_id_table[30], NULL },
{ NULL },
},
- { "Terratec Cinergy T USB XXS",
- { &dib0700_usb_id_table[33], NULL },
+ { "Terratec Cinergy T USB XXS/ T3",
+ { &dib0700_usb_id_table[33],
+ &dib0700_usb_id_table[52], NULL },
{ NULL },
},
{ "Elgato EyeTV DTT",
@@ -1793,8 +1797,9 @@ struct dvb_usb_device_properties dib0700_devices[] = {
{ &dib0700_usb_id_table[36], NULL },
{ NULL },
},
- { "Terratec Cinergy DT USB XS Diversity",
- { &dib0700_usb_id_table[43], NULL },
+ { "Terratec Cinergy DT USB XS Diversity/ T5",
+ { &dib0700_usb_id_table[43],
+ &dib0700_usb_id_table[53], NULL},
{ NULL },
},
{ "Sony PlayTV",
@@ -1821,7 +1826,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
},
},
- .num_device_descs = 7,
+ .num_device_descs = 8,
.devices = {
{ "Terratec Cinergy HT USB XE",
{ &dib0700_usb_id_table[27], NULL },
@@ -1851,6 +1856,11 @@ struct dvb_usb_device_properties dib0700_devices[] = {
{ &dib0700_usb_id_table[48], NULL },
{ NULL },
},
+ { "Leadtek WinFast DTV Dongle H",
+ { &dib0700_usb_id_table[51], NULL },
+ { NULL },
+ },
+
},
.rc_interval = DEFAULT_RC_INTERVAL,
.rc_key_map = dib0700_rc_keys,
diff --git a/linux/drivers/media/dvb/dvb-usb/dibusb-common.c b/linux/drivers/media/dvb/dvb-usb/dibusb-common.c
index d774879df..99b3b9a43 100644
--- a/linux/drivers/media/dvb/dvb-usb/dibusb-common.c
+++ b/linux/drivers/media/dvb/dvb-usb/dibusb-common.c
@@ -133,14 +133,17 @@ static int dibusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num
for (i = 0; i < num; i++) {
/* write/read request */
- if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
+ if (i+1 < num && (msg[i].flags & I2C_M_RD) == 0
+ && (msg[i+1].flags & I2C_M_RD)) {
if (dibusb_i2c_msg(d, msg[i].addr, msg[i].buf,msg[i].len,
msg[i+1].buf,msg[i+1].len) < 0)
break;
i++;
- } else
+ } else if ((msg[i].flags & I2C_M_RD) == 0) {
if (dibusb_i2c_msg(d, msg[i].addr, msg[i].buf,msg[i].len,NULL,0) < 0)
break;
+ } else
+ break;
}
mutex_unlock(&d->i2c_mutex);
diff --git a/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
index 1b5e65f1d..9593b7289 100644
--- a/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+++ b/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
@@ -98,6 +98,7 @@
#define USB_PID_DPOSH_M9206_COLD 0x9206
#define USB_PID_DPOSH_M9206_WARM 0xa090
#define USB_PID_UNIWILL_STK7700P 0x6003
+#define USB_PID_GENIUS_TVGO_DVB_T03 0x4012
#define USB_PID_GRANDTEC_DVBT_USB_COLD 0x0fa0
#define USB_PID_GRANDTEC_DVBT_USB_WARM 0x0fa1
#define USB_PID_INTEL_CE9500 0x9500
@@ -181,6 +182,8 @@
#define USB_PID_TERRATEC_CINERGY_HT_EXPRESS 0x0060
#define USB_PID_TERRATEC_CINERGY_T_EXPRESS 0x0062
#define USB_PID_TERRATEC_CINERGY_T_XXS 0x0078
+#define USB_PID_TERRATEC_T3 0x10a0
+#define USB_PID_TERRATEC_T5 0x10a1
#define USB_PID_PINNACLE_EXPRESSCARD_320CX 0x022e
#define USB_PID_PINNACLE_PCTV2000E 0x022c
#define USB_PID_PINNACLE_PCTV_DVB_T_FLASH 0x0228
@@ -225,6 +228,7 @@
#define USB_PID_WINFAST_DTV_DONGLE_COLD 0x6025
#define USB_PID_WINFAST_DTV_DONGLE_WARM 0x6026
#define USB_PID_WINFAST_DTV_DONGLE_STK7700P 0x6f00
+#define USB_PID_WINFAST_DTV_DONGLE_H 0x60f6
#define USB_PID_WINFAST_DTV_DONGLE_STK7700P_2 0x6f01
#define USB_PID_WINFAST_DTV_DONGLE_GOLD 0x6029
#define USB_PID_GENPIX_8PSK_REV_1_COLD 0x0200
diff --git a/linux/drivers/media/dvb/dvb-usb/dw2102.c b/linux/drivers/media/dvb/dvb-usb/dw2102.c
index 2b8ee587b..0fc9be43a 100644
--- a/linux/drivers/media/dvb/dvb-usb/dw2102.c
+++ b/linux/drivers/media/dvb/dvb-usb/dw2102.c
@@ -1,7 +1,7 @@
/* DVB USB framework compliant Linux driver for the
-* DVBWorld DVB-S 2101, 2102, DVB-S2 2104 Card
-*
-* Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by)
+* DVBWorld DVB-S 2101, 2102, DVB-S2 2104, DVB-C 3101,
+* TeVii S600, S650 Cards
+* Copyright (C) 2008,2009 Igor M. Liplianin (liplianin@me.by)
*
* 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
@@ -17,6 +17,7 @@
#include "stb6000.h"
#include "eds1547.h"
#include "cx24116.h"
+#include "tda1002x.h"
#ifndef USB_PID_DW2102
#define USB_PID_DW2102 0x2102
@@ -26,10 +27,18 @@
#define USB_PID_DW2104 0x2104
#endif
+#ifndef USB_PID_DW3101
+#define USB_PID_DW3101 0x3101
+#endif
+
#ifndef USB_PID_CINERGY_S
#define USB_PID_CINERGY_S 0x0064
#endif
+#ifndef USB_PID_TEVII_S650
+#define USB_PID_TEVII_S650 0xd650
+#endif
+
#define DW210X_READ_MSG 0
#define DW210X_WRITE_MSG 1
@@ -40,18 +49,21 @@
#define DW2102_VOLTAGE_CTRL (0x1800)
#define DW2102_RC_QUERY (0x1a00)
-struct dw210x_state {
- u32 last_key_pressed;
-};
-struct dw210x_rc_keys {
- u32 keycode;
- u32 event;
+struct dvb_usb_rc_keys_table {
+ struct dvb_usb_rc_key *rc_keys;
+ int rc_keys_size;
};
/* debug */
static int dvb_usb_dw2102_debug;
module_param_named(debug, dvb_usb_dw2102_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=info 2=xfer (or-able))." DVB_USB_DEBUG_STATUS);
+MODULE_PARM_DESC(debug, "set debugging level (1=info 2=xfer 4=rc(or-able))."
+ DVB_USB_DEBUG_STATUS);
+
+/* keymaps */
+static int ir_keymap;
+module_param_named(keymap, ir_keymap, int, 0644);
+MODULE_PARM_DESC(keymap, "set keymap 0=default 1=dvbworld 2=tevii 3=tbs ...");
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
@@ -79,7 +91,7 @@ static int dw210x_op_rw(struct usb_device *dev, u8 request, u16 value,
static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
int num)
{
-struct dvb_usb_device *d = i2c_get_adapdata(adap);
+ struct dvb_usb_device *d = i2c_get_adapdata(adap);
int i = 0, ret = 0;
u8 buf6[] = {0x2c, 0x05, 0xc0, 0, 0, 0, 0};
u16 value;
@@ -205,6 +217,7 @@ static int dw2102_serit_i2c_transfer(struct i2c_adapter *adap,
mutex_unlock(&d->i2c_mutex);
return num;
}
+
static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num)
{
struct dvb_usb_device *d = i2c_get_adapdata(adap);
@@ -219,7 +232,7 @@ static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg ms
case 2: {
/* read */
/* first write first register number */
- u8 ibuf [msg[1].len + 2], obuf[3];
+ u8 ibuf[msg[1].len + 2], obuf[3];
obuf[0] = 0xd0;
obuf[1] = msg[0].len;
obuf[2] = msg[0].buf[0];
@@ -293,7 +306,7 @@ static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], i
case 2: {
/* read */
/* first write first register number */
- u8 ibuf [msg[1].len + 2], obuf[3];
+ u8 ibuf[msg[1].len + 2], obuf[3];
obuf[0] = 0xaa;
obuf[1] = msg[0].len;
obuf[2] = msg[0].buf[0];
@@ -360,6 +373,69 @@ static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], i
return num;
}
+static int dw3101_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+ int num)
+{
+ struct dvb_usb_device *d = i2c_get_adapdata(adap);
+ int ret = 0, i;
+
+ if (!d)
+ return -ENODEV;
+ if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+ return -EAGAIN;
+
+ switch (num) {
+ case 2: {
+ /* read */
+ /* first write first register number */
+ u8 ibuf[msg[1].len + 2], obuf[3];
+ obuf[0] = msg[0].addr << 1;
+ obuf[1] = msg[0].len;
+ obuf[2] = msg[0].buf[0];
+ ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
+ obuf, msg[0].len + 2, DW210X_WRITE_MSG);
+ /* second read registers */
+ ret = dw210x_op_rw(d->udev, 0xc3, 0x19 , 0,
+ ibuf, msg[1].len + 2, DW210X_READ_MSG);
+ memcpy(msg[1].buf, ibuf + 2, msg[1].len);
+
+ break;
+ }
+ case 1:
+ switch (msg[0].addr) {
+ case 0x60:
+ case 0x0c: {
+ /* write to register */
+ u8 obuf[msg[0].len + 2];
+ obuf[0] = msg[0].addr << 1;
+ obuf[1] = msg[0].len;
+ memcpy(obuf + 2, msg[0].buf, msg[0].len);
+ ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
+ obuf, msg[0].len + 2, DW210X_WRITE_MSG);
+ break;
+ }
+ case(DW2102_RC_QUERY): {
+ u8 ibuf[2];
+ ret = dw210x_op_rw(d->udev, 0xb8, 0, 0,
+ ibuf, 2, DW210X_READ_MSG);
+ memcpy(msg[0].buf, ibuf , 2);
+ break;
+ }
+ }
+
+ break;
+ }
+
+ for (i = 0; i < num; i++) {
+ deb_xfer("%02x:%02x: %s ", i, msg[i].addr,
+ msg[i].flags == 0 ? ">>>" : "<<<");
+ debug_dump(msg[i].buf, msg[i].len, deb_xfer);
+ }
+
+ mutex_unlock(&d->i2c_mutex);
+ return num;
+}
+
static u32 dw210x_i2c_func(struct i2c_adapter *adapter)
{
return I2C_FUNC_I2C;
@@ -397,6 +473,14 @@ static struct i2c_algorithm dw2104_i2c_algo = {
#endif
};
+static struct i2c_algorithm dw3101_i2c_algo = {
+ .master_xfer = dw3101_i2c_transfer,
+ .functionality = dw210x_i2c_func,
+#ifdef NEED_ALGO_CONTROL
+ .algo_control = dummy_algo_control,
+#endif
+};
+
static int dw210x_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
{
int i;
@@ -416,6 +500,7 @@ static int dw210x_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
debug_dump(eepromline, 16, deb_xfer);
}
}
+
memcpy(mac, eeprom + 8, 6);
return 0;
};
@@ -460,6 +545,11 @@ static struct si21xx_config serit_sp1511lhb_config = {
};
+static struct tda10023_config dw3101_tda10023_config = {
+ .demod_address = 0x0c,
+ .invert = 1,
+};
+
static int dw2104_frontend_attach(struct dvb_usb_adapter *d)
{
if ((d->fe = dvb_attach(cx24116_attach, &dw2104_config,
@@ -472,6 +562,7 @@ static int dw2104_frontend_attach(struct dvb_usb_adapter *d)
}
static struct dvb_usb_device_properties dw2102_properties;
+static struct dvb_usb_device_properties dw2104_properties;
static int dw2102_frontend_attach(struct dvb_usb_adapter *d)
{
@@ -509,6 +600,17 @@ static int dw2102_frontend_attach(struct dvb_usb_adapter *d)
return -EIO;
}
+static int dw3101_frontend_attach(struct dvb_usb_adapter *d)
+{
+ d->fe = dvb_attach(tda10023_attach, &dw3101_tda10023_config,
+ &d->dev->i2c_adap, 0x48);
+ if (d->fe != NULL) {
+ info("Attached tda10023!\n");
+ return 0;
+ }
+ return -EIO;
+}
+
static int dw2102_tuner_attach(struct dvb_usb_adapter *adap)
{
dvb_attach(dvb_pll_attach, adap->fe, 0x60,
@@ -524,6 +626,14 @@ static int dw2102_earda_tuner_attach(struct dvb_usb_adapter *adap)
return 0;
}
+static int dw3101_tuner_attach(struct dvb_usb_adapter *adap)
+{
+ dvb_attach(dvb_pll_attach, adap->fe, 0x60,
+ &adap->dev->i2c_adap, DVB_PLL_TUA6034);
+
+ return 0;
+}
+
static struct dvb_usb_rc_key dw210x_rc_keys[] = {
{ 0xf8, 0x0a, KEY_Q }, /*power*/
{ 0xf8, 0x0c, KEY_M }, /*mute*/
@@ -556,44 +666,147 @@ static struct dvb_usb_rc_key dw210x_rc_keys[] = {
{ 0xf8, 0x40, KEY_F }, /*full*/
{ 0xf8, 0x1e, KEY_W }, /*tvmode*/
{ 0xf8, 0x1b, KEY_B }, /*recall*/
+};
+static struct dvb_usb_rc_key tevii_rc_keys[] = {
+ { 0xf8, 0x0a, KEY_POWER },
+ { 0xf8, 0x0c, KEY_MUTE },
+ { 0xf8, 0x11, KEY_1 },
+ { 0xf8, 0x12, KEY_2 },
+ { 0xf8, 0x13, KEY_3 },
+ { 0xf8, 0x14, KEY_4 },
+ { 0xf8, 0x15, KEY_5 },
+ { 0xf8, 0x16, KEY_6 },
+ { 0xf8, 0x17, KEY_7 },
+ { 0xf8, 0x18, KEY_8 },
+ { 0xf8, 0x19, KEY_9 },
+ { 0xf8, 0x10, KEY_0 },
+ { 0xf8, 0x1c, KEY_MENU },
+ { 0xf8, 0x0f, KEY_VOLUMEDOWN },
+ { 0xf8, 0x1a, KEY_LAST },
+ { 0xf8, 0x0e, KEY_OPEN },
+ { 0xf8, 0x04, KEY_RECORD },
+ { 0xf8, 0x09, KEY_VOLUMEUP },
+ { 0xf8, 0x08, KEY_CHANNELUP },
+ { 0xf8, 0x07, KEY_PVR },
+ { 0xf8, 0x0b, KEY_TIME },
+ { 0xf8, 0x02, KEY_RIGHT },
+ { 0xf8, 0x03, KEY_LEFT },
+ { 0xf8, 0x00, KEY_UP },
+ { 0xf8, 0x1f, KEY_OK },
+ { 0xf8, 0x01, KEY_DOWN },
+ { 0xf8, 0x05, KEY_TUNER },
+ { 0xf8, 0x06, KEY_CHANNELDOWN },
+ { 0xf8, 0x40, KEY_PLAYPAUSE },
+ { 0xf8, 0x1e, KEY_REWIND },
+ { 0xf8, 0x1b, KEY_FAVORITES },
+ { 0xf8, 0x1d, KEY_BACK },
+ { 0xf8, 0x4d, KEY_FASTFORWARD },
+ { 0xf8, 0x44, KEY_EPG },
+ { 0xf8, 0x4c, KEY_INFO },
+ { 0xf8, 0x41, KEY_AB },
+ { 0xf8, 0x43, KEY_AUDIO },
+ { 0xf8, 0x45, KEY_SUBTITLE },
+ { 0xf8, 0x4a, KEY_LIST },
+ { 0xf8, 0x46, KEY_F1 },
+ { 0xf8, 0x47, KEY_F2 },
+ { 0xf8, 0x5e, KEY_F3 },
+ { 0xf8, 0x5c, KEY_F4 },
+ { 0xf8, 0x52, KEY_F5 },
+ { 0xf8, 0x5a, KEY_F6 },
+ { 0xf8, 0x56, KEY_MODE },
+ { 0xf8, 0x58, KEY_SWITCHVIDEOMODE },
};
+static struct dvb_usb_rc_key tbs_rc_keys[] = {
+ { 0xf8, 0x84, KEY_POWER },
+ { 0xf8, 0x94, KEY_MUTE },
+ { 0xf8, 0x87, KEY_1 },
+ { 0xf8, 0x86, KEY_2 },
+ { 0xf8, 0x85, KEY_3 },
+ { 0xf8, 0x8b, KEY_4 },
+ { 0xf8, 0x8a, KEY_5 },
+ { 0xf8, 0x89, KEY_6 },
+ { 0xf8, 0x8f, KEY_7 },
+ { 0xf8, 0x8e, KEY_8 },
+ { 0xf8, 0x8d, KEY_9 },
+ { 0xf8, 0x92, KEY_0 },
+ { 0xf8, 0x96, KEY_CHANNELUP },
+ { 0xf8, 0x91, KEY_CHANNELDOWN },
+ { 0xf8, 0x93, KEY_VOLUMEUP },
+ { 0xf8, 0x8c, KEY_VOLUMEDOWN },
+ { 0xf8, 0x83, KEY_RECORD },
+ { 0xf8, 0x98, KEY_PAUSE },
+ { 0xf8, 0x99, KEY_OK },
+ { 0xf8, 0x9a, KEY_SHUFFLE },
+ { 0xf8, 0x81, KEY_UP },
+ { 0xf8, 0x90, KEY_LEFT },
+ { 0xf8, 0x82, KEY_RIGHT },
+ { 0xf8, 0x88, KEY_DOWN },
+ { 0xf8, 0x95, KEY_FAVORITES },
+ { 0xf8, 0x97, KEY_SUBTITLE },
+ { 0xf8, 0x9d, KEY_ZOOM },
+ { 0xf8, 0x9f, KEY_EXIT },
+ { 0xf8, 0x9e, KEY_MENU },
+ { 0xf8, 0x9c, KEY_EPG },
+ { 0xf8, 0x80, KEY_PREVIOUS },
+ { 0xf8, 0x9b, KEY_MODE }
+};
+static struct dvb_usb_rc_keys_table keys_tables[] = {
+ { dw210x_rc_keys, ARRAY_SIZE(dw210x_rc_keys) },
+ { tevii_rc_keys, ARRAY_SIZE(tevii_rc_keys) },
+ { tbs_rc_keys, ARRAY_SIZE(tbs_rc_keys) },
+};
static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
{
- struct dw210x_state *st = d->priv;
+ struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
+ int keymap_size = d->props.rc_key_map_size;
u8 key[2];
- struct i2c_msg msg[] = {
- {.addr = DW2102_RC_QUERY, .flags = I2C_M_RD, .buf = key,
- .len = 2},
+ struct i2c_msg msg = {
+ .addr = DW2102_RC_QUERY,
+ .flags = I2C_M_RD,
+ .buf = key,
+ .len = 2
};
int i;
+ /* override keymap */
+ if ((ir_keymap > 0) && (ir_keymap <= ARRAY_SIZE(keys_tables))) {
+ keymap = keys_tables[ir_keymap - 1].rc_keys ;
+ keymap_size = keys_tables[ir_keymap - 1].rc_keys_size;
+ }
*state = REMOTE_NO_KEY_PRESSED;
- if (dw2102_i2c_transfer(&d->i2c_adap, msg, 1) == 1) {
- for (i = 0; i < ARRAY_SIZE(dw210x_rc_keys); i++) {
- if (dw210x_rc_keys[i].data == msg[0].buf[0]) {
+ if (dw2102_i2c_transfer(&d->i2c_adap, &msg, 1) == 1) {
+ for (i = 0; i < keymap_size ; i++) {
+ if (keymap[i].data == msg.buf[0]) {
*state = REMOTE_KEY_PRESSED;
- *event = dw210x_rc_keys[i].event;
- st->last_key_pressed =
- dw210x_rc_keys[i].event;
+ *event = keymap[i].event;
break;
}
- st->last_key_pressed = 0;
+
}
+
+ if ((*state) == REMOTE_KEY_PRESSED)
+ deb_rc("%s: found rc key: %x, %x, event: %x\n",
+ __func__, key[0], key[1], (*event));
+ else if (key[0] != 0xff)
+ deb_rc("%s: unknown rc key: %x, %x\n",
+ __func__, key[0], key[1]);
+
}
- /* info("key: %x %x\n",key[0],key[1]); */
+
return 0;
}
static struct usb_device_id dw2102_table[] = {
{USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2102)},
{USB_DEVICE(USB_VID_CYPRESS, 0x2101)},
- {USB_DEVICE(USB_VID_CYPRESS, 0x2104)},
- {USB_DEVICE(0x9022, 0xd650)},
+ {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2104)},
+ {USB_DEVICE(0x9022, USB_PID_TEVII_S650)},
{USB_DEVICE(USB_VID_TERRATEC, USB_PID_CINERGY_S)},
+ {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW3101)},
{ }
};
@@ -654,11 +867,16 @@ static int dw2102_load_firmware(struct usb_device *dev,
}
/* init registers */
switch (dev->descriptor.idProduct) {
+ case USB_PID_TEVII_S650:
+ dw2104_properties.rc_key_map = tevii_rc_keys;
+ dw2104_properties.rc_key_map_size =
+ ARRAY_SIZE(tevii_rc_keys);
case USB_PID_DW2104:
- case 0xd650:
reset = 1;
dw210x_op_rw(dev, 0xc4, 0x0000, 0, &reset, 1,
DW210X_WRITE_MSG);
+ /* break omitted intentionally */
+ case USB_PID_DW3101:
reset = 0;
dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0,
DW210X_WRITE_MSG);
@@ -702,6 +920,7 @@ static int dw2102_load_firmware(struct usb_device *dev,
DW210X_READ_MSG);
break;
}
+
msleep(100);
kfree(p);
}
@@ -712,7 +931,6 @@ static struct dvb_usb_device_properties dw2102_properties = {
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
.usb_ctrl = DEVICE_SPECIFIC,
.firmware = "dvb-usb-dw2102.fw",
- .size_of_priv = sizeof(struct dw210x_state),
.no_reconnect = 1,
.i2c_algo = &dw2102_serit_i2c_algo,
@@ -726,7 +944,7 @@ static struct dvb_usb_device_properties dw2102_properties = {
.num_adapters = 1,
.download_firmware = dw2102_load_firmware,
.read_mac_address = dw210x_read_mac_address,
- .adapter = {
+ .adapter = {
{
.frontend_attach = dw2102_frontend_attach,
.streaming_ctrl = NULL,
@@ -764,7 +982,6 @@ static struct dvb_usb_device_properties dw2104_properties = {
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
.usb_ctrl = DEVICE_SPECIFIC,
.firmware = "dvb-usb-dw2104.fw",
- .size_of_priv = sizeof(struct dw210x_state),
.no_reconnect = 1,
.i2c_algo = &dw2104_i2c_algo,
@@ -808,12 +1025,57 @@ static struct dvb_usb_device_properties dw2104_properties = {
}
};
+static struct dvb_usb_device_properties dw3101_properties = {
+ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+ .usb_ctrl = DEVICE_SPECIFIC,
+ .firmware = "dvb-usb-dw3101.fw",
+ .no_reconnect = 1,
+
+ .i2c_algo = &dw3101_i2c_algo,
+ .rc_key_map = dw210x_rc_keys,
+ .rc_key_map_size = ARRAY_SIZE(dw210x_rc_keys),
+ .rc_interval = 150,
+ .rc_query = dw2102_rc_query,
+
+ .generic_bulk_ctrl_endpoint = 0x81,
+ /* parameter for the MPEG2-data transfer */
+ .num_adapters = 1,
+ .download_firmware = dw2102_load_firmware,
+ .read_mac_address = dw210x_read_mac_address,
+ .adapter = {
+ {
+ .frontend_attach = dw3101_frontend_attach,
+ .streaming_ctrl = NULL,
+ .tuner_attach = dw3101_tuner_attach,
+ .stream = {
+ .type = USB_BULK,
+ .count = 8,
+ .endpoint = 0x82,
+ .u = {
+ .bulk = {
+ .buffersize = 4096,
+ }
+ }
+ },
+ }
+ },
+ .num_device_descs = 1,
+ .devices = {
+ { "DVBWorld DVB-C 3101 USB2.0",
+ {&dw2102_table[5], NULL},
+ {NULL},
+ },
+ }
+};
+
static int dw2102_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
if (0 == dvb_usb_device_init(intf, &dw2102_properties,
THIS_MODULE, NULL, adapter_nr) ||
0 == dvb_usb_device_init(intf, &dw2104_properties,
+ THIS_MODULE, NULL, adapter_nr) ||
+ 0 == dvb_usb_device_init(intf, &dw3101_properties,
THIS_MODULE, NULL, adapter_nr)) {
return 0;
}
@@ -845,6 +1107,8 @@ module_init(dw2102_module_init);
module_exit(dw2102_module_exit);
MODULE_AUTHOR("Igor M. Liplianin (c) liplianin@me.by");
-MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101, 2102, DVB-S2 2104 USB2.0 device");
+MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101, 2102, DVB-S2 2104,"
+ " DVB-C 3101 USB2.0,"
+ " TeVii S600, S650 USB2.0 devices");
MODULE_VERSION("0.1");
MODULE_LICENSE("GPL");
diff --git a/linux/drivers/media/dvb/dvb-usb/dw2102.h b/linux/drivers/media/dvb/dvb-usb/dw2102.h
index e3370734e..5cd0b0eb6 100644
--- a/linux/drivers/media/dvb/dvb-usb/dw2102.h
+++ b/linux/drivers/media/dvb/dvb-usb/dw2102.h
@@ -5,4 +5,5 @@
#include "dvb-usb.h"
#define deb_xfer(args...) dprintk(dvb_usb_dw2102_debug, 0x02, args)
+#define deb_rc(args...) dprintk(dvb_usb_dw2102_debug, 0x04, args)
#endif
diff --git a/linux/drivers/media/dvb/dvb-usb/gp8psk.c b/linux/drivers/media/dvb/dvb-usb/gp8psk.c
index 3dd684386..003d97f8c 100644
--- a/linux/drivers/media/dvb/dvb-usb/gp8psk.c
+++ b/linux/drivers/media/dvb/dvb-usb/gp8psk.c
@@ -223,7 +223,7 @@ static struct usb_device_id gp8psk_usb_table [] = {
{ USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_1_WARM) },
{ USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_2) },
{ USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_1) },
- { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_CW3K) },
+/* { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_CW3K) }, */
{ 0 },
};
MODULE_DEVICE_TABLE(usb, gp8psk_usb_table);
@@ -254,7 +254,7 @@ static struct dvb_usb_device_properties gp8psk_properties = {
.generic_bulk_ctrl_endpoint = 0x01,
- .num_device_descs = 4,
+ .num_device_descs = 3,
.devices = {
{ .name = "Genpix 8PSK-to-USB2 Rev.1 DVB-S receiver",
.cold_ids = { &gp8psk_usb_table[0], NULL },
@@ -268,10 +268,12 @@ static struct dvb_usb_device_properties gp8psk_properties = {
.cold_ids = { NULL },
.warm_ids = { &gp8psk_usb_table[3], NULL },
},
+#if 0
{ .name = "Genpix SkyWalker-CW3K DVB-S receiver",
.cold_ids = { NULL },
.warm_ids = { &gp8psk_usb_table[4], NULL },
},
+#endif
{ NULL },
}
};
diff --git a/linux/drivers/media/dvb/frontends/au8522_dig.c b/linux/drivers/media/dvb/frontends/au8522_dig.c
index 41aedcc99..9375905ee 100644
--- a/linux/drivers/media/dvb/frontends/au8522_dig.c
+++ b/linux/drivers/media/dvb/frontends/au8522_dig.c
@@ -367,11 +367,90 @@ static struct {
{ 0x8231, 0x13 },
};
-/* QAM Modulation table */
+/* QAM64 Modulation table */
static struct {
u16 reg;
u16 data;
-} QAM_mod_tab[] = {
+} QAM64_mod_tab[] = {
+ { 0x00a3, 0x09 },
+ { 0x00a4, 0x00 },
+ { 0x0081, 0xc4 },
+ { 0x00a5, 0x40 },
+ { 0x00aa, 0x77 },
+ { 0x00ad, 0x77 },
+ { 0x00a6, 0x67 },
+ { 0x0262, 0x20 },
+ { 0x021c, 0x30 },
+ { 0x00b8, 0x3e },
+ { 0x00b9, 0xf0 },
+ { 0x00ba, 0x01 },
+ { 0x00bb, 0x18 },
+ { 0x00bc, 0x50 },
+ { 0x00bd, 0x00 },
+ { 0x00be, 0xea },
+ { 0x00bf, 0xef },
+ { 0x00c0, 0xfc },
+ { 0x00c1, 0xbd },
+ { 0x00c2, 0x1f },
+ { 0x00c3, 0xfc },
+ { 0x00c4, 0xdd },
+ { 0x00c5, 0xaf },
+ { 0x00c6, 0x00 },
+ { 0x00c7, 0x38 },
+ { 0x00c8, 0x30 },
+ { 0x00c9, 0x05 },
+ { 0x00ca, 0x4a },
+ { 0x00cb, 0xd0 },
+ { 0x00cc, 0x01 },
+ { 0x00cd, 0xd9 },
+ { 0x00ce, 0x6f },
+ { 0x00cf, 0xf9 },
+ { 0x00d0, 0x70 },
+ { 0x00d1, 0xdf },
+ { 0x00d2, 0xf7 },
+ { 0x00d3, 0xc2 },
+ { 0x00d4, 0xdf },
+ { 0x00d5, 0x02 },
+ { 0x00d6, 0x9a },
+ { 0x00d7, 0xd0 },
+ { 0x0250, 0x0d },
+ { 0x0251, 0xcd },
+ { 0x0252, 0xe0 },
+ { 0x0253, 0x05 },
+ { 0x0254, 0xa7 },
+ { 0x0255, 0xff },
+ { 0x0256, 0xed },
+ { 0x0257, 0x5b },
+ { 0x0258, 0xae },
+ { 0x0259, 0xe6 },
+ { 0x025a, 0x3d },
+ { 0x025b, 0x0f },
+ { 0x025c, 0x0d },
+ { 0x025d, 0xea },
+ { 0x025e, 0xf2 },
+ { 0x025f, 0x51 },
+ { 0x0260, 0xf5 },
+ { 0x0261, 0x06 },
+ { 0x021a, 0x00 },
+ { 0x0546, 0x40 },
+ { 0x0210, 0xc7 },
+ { 0x0211, 0xaa },
+ { 0x0212, 0xab },
+ { 0x0213, 0x02 },
+ { 0x0502, 0x00 },
+ { 0x0121, 0x04 },
+ { 0x0122, 0x04 },
+ { 0x052e, 0x10 },
+ { 0x00a4, 0xca },
+ { 0x00a7, 0x40 },
+ { 0x0526, 0x01 },
+};
+
+/* QAM256 Modulation table */
+static struct {
+ u16 reg;
+ u16 data;
+} QAM256_mod_tab[] = {
{ 0x80a3, 0x09 },
{ 0x80a4, 0x00 },
{ 0x8081, 0xc4 },
@@ -464,12 +543,19 @@ static int au8522_enable_modulation(struct dvb_frontend *fe,
au8522_set_if(fe, state->config->vsb_if);
break;
case QAM_64:
+ dprintk("%s() QAM 64\n", __func__);
+ for (i = 0; i < ARRAY_SIZE(QAM64_mod_tab); i++)
+ au8522_writereg(state,
+ QAM64_mod_tab[i].reg,
+ QAM64_mod_tab[i].data);
+ au8522_set_if(fe, state->config->qam_if);
+ break;
case QAM_256:
- dprintk("%s() QAM 64/256\n", __func__);
- for (i = 0; i < ARRAY_SIZE(QAM_mod_tab); i++)
+ dprintk("%s() QAM 256\n", __func__);
+ for (i = 0; i < ARRAY_SIZE(QAM256_mod_tab); i++)
au8522_writereg(state,
- QAM_mod_tab[i].reg,
- QAM_mod_tab[i].data);
+ QAM256_mod_tab[i].reg,
+ QAM256_mod_tab[i].data);
au8522_set_if(fe, state->config->qam_if);
break;
default:
diff --git a/linux/drivers/media/dvb/frontends/lgdt3305.c b/linux/drivers/media/dvb/frontends/lgdt3305.c
index f0c0c8199..b16410c64 100644
--- a/linux/drivers/media/dvb/frontends/lgdt3305.c
+++ b/linux/drivers/media/dvb/frontends/lgdt3305.c
@@ -19,6 +19,7 @@
*
*/
+#include <asm/div64.h>
#include "compat.h"
#include <linux/dvb/frontend.h>
#include "dvb_math.h"
@@ -497,27 +498,15 @@ static int lgdt3305_set_if(struct lgdt3305_state *state,
nco = if_freq_khz / 10;
-#define LGDT3305_64BIT_DIVISION_ENABLED 0
- /* FIXME: 64bit division disabled to avoid linking error:
- * WARNING: "__udivdi3" [lgdt3305.ko] undefined!
- */
switch (param->u.vsb.modulation) {
case VSB_8:
-#if LGDT3305_64BIT_DIVISION_ENABLED
nco <<= 24;
- nco /= 625;
-#else
- nco *= ((1 << 24) / 625);
-#endif
+ do_div(nco, 625);
break;
case QAM_64:
case QAM_256:
-#if LGDT3305_64BIT_DIVISION_ENABLED
nco <<= 28;
- nco /= 625;
-#else
- nco *= ((1 << 28) / 625);
-#endif
+ do_div(nco, 625);
break;
default:
return -EINVAL;
diff --git a/linux/drivers/media/dvb/frontends/lgs8gxx.c b/linux/drivers/media/dvb/frontends/lgs8gxx.c
index 1395f3b5b..1ce30aa53 100644
--- a/linux/drivers/media/dvb/frontends/lgs8gxx.c
+++ b/linux/drivers/media/dvb/frontends/lgs8gxx.c
@@ -37,14 +37,14 @@
} while (0)
static int debug;
-static int fake_signal_str;
+static int fake_signal_str = 1;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
module_param(fake_signal_str, int, 0644);
MODULE_PARM_DESC(fake_signal_str, "fake signal strength for LGS8913."
-"Signal strength calculation is slow.(default:off).");
+"Signal strength calculation is slow.(default:on).");
/* LGS8GXX internal helper functions */
@@ -650,7 +650,7 @@ static int lgs8gxx_read_signal_agc(struct lgs8gxx_state *priv, u16 *signal)
else
cat = 0;
- *signal = cat;
+ *signal = cat * 65535 / 5;
return 0;
}
@@ -670,8 +670,8 @@ static int lgs8913_read_signal_strength(struct lgs8gxx_state *priv, u16 *signal)
if (fake_signal_str) {
if ((t & 0xC0) == 0xC0) {
- dprintk("Fake signal strength as 50\n");
- *signal = 0x32;
+ dprintk("Fake signal strength\n");
+ *signal = 0x7FFF;
} else
*signal = 0;
return 0;
diff --git a/linux/drivers/media/dvb/frontends/lnbp21.c b/linux/drivers/media/dvb/frontends/lnbp21.c
index 1dcc56f32..71f607fe8 100644
--- a/linux/drivers/media/dvb/frontends/lnbp21.c
+++ b/linux/drivers/media/dvb/frontends/lnbp21.c
@@ -133,7 +133,7 @@ static struct dvb_frontend *lnbx2x_attach(struct dvb_frontend *fe,
/* override frontend ops */
fe->ops.set_voltage = lnbp21_set_voltage;
fe->ops.enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage;
- printk(KERN_INFO "LNBx2x attached on addr=%x", lnbp21->i2c_addr);
+ printk(KERN_INFO "LNBx2x attached on addr=%x\n", lnbp21->i2c_addr);
return fe;
}
diff --git a/linux/drivers/media/dvb/frontends/mt312.c b/linux/drivers/media/dvb/frontends/mt312.c
index 5ac9b1592..a621f7279 100644
--- a/linux/drivers/media/dvb/frontends/mt312.c
+++ b/linux/drivers/media/dvb/frontends/mt312.c
@@ -77,7 +77,7 @@ static int mt312_read(struct mt312_state *state, const enum mt312_reg_addr reg,
ret = i2c_transfer(state->i2c, msg, 2);
if (ret != 2) {
- printk(KERN_ERR "%s: ret == %d\n", __func__, ret);
+ printk(KERN_DEBUG "%s: ret == %d\n", __func__, ret);
return -EREMOTEIO;
}
diff --git a/linux/drivers/media/dvb/frontends/stv0900.h b/linux/drivers/media/dvb/frontends/stv0900.h
index 8a1332c20..bf4e9b633 100644
--- a/linux/drivers/media/dvb/frontends/stv0900.h
+++ b/linux/drivers/media/dvb/frontends/stv0900.h
@@ -29,6 +29,11 @@
#include <linux/dvb/frontend.h>
#include "dvb_frontend.h"
+struct stv0900_reg {
+ u16 addr;
+ u8 val;
+};
+
struct stv0900_config {
u8 demod_address;
u32 xtal;
@@ -38,7 +43,7 @@ struct stv0900_config {
u8 path1_mode;
u8 path2_mode;
-
+ struct stv0900_reg *ts_config_regs;
u8 tun1_maddress;/* 0, 1, 2, 3 for 0xc0, 0xc2, 0xc4, 0xc6 */
u8 tun2_maddress;
u8 tun1_adc;/* 1 for stv6110, 2 for stb6100 */
diff --git a/linux/drivers/media/dvb/frontends/stv0900_core.c b/linux/drivers/media/dvb/frontends/stv0900_core.c
index 899b1e7ed..84bf35edb 100644
--- a/linux/drivers/media/dvb/frontends/stv0900_core.c
+++ b/linux/drivers/media/dvb/frontends/stv0900_core.c
@@ -149,31 +149,31 @@ void stv0900_write_reg(struct stv0900_internal *i_params, u16 reg_addr,
dprintk(KERN_ERR "%s: i2c error %d\n", __func__, ret);
}
-u8 stv0900_read_reg(struct stv0900_internal *i_params, u16 reg_addr)
+u8 stv0900_read_reg(struct stv0900_internal *i_params, u16 reg)
{
- u8 data[2];
int ret;
- struct i2c_msg i2cmsg = {
- .addr = i_params->i2c_addr,
- .flags = 0,
- .len = 2,
- .buf = data,
+ u8 b0[] = { MSB(reg), LSB(reg) };
+ u8 buf = 0;
+ struct i2c_msg msg[] = {
+ {
+ .addr = i_params->i2c_addr,
+ .flags = 0,
+ .buf = b0,
+ .len = 2,
+ }, {
+ .addr = i_params->i2c_addr,
+ .flags = I2C_M_RD,
+ .buf = &buf,
+ .len = 1,
+ },
};
- data[0] = MSB(reg_addr);
- data[1] = LSB(reg_addr);
-
- ret = i2c_transfer(i_params->i2c_adap, &i2cmsg, 1);
- if (ret != 1)
- dprintk(KERN_ERR "%s: i2c error %d\n", __func__, ret);
-
- i2cmsg.flags = I2C_M_RD;
- i2cmsg.len = 1;
- ret = i2c_transfer(i_params->i2c_adap, &i2cmsg, 1);
- if (ret != 1)
- dprintk(KERN_ERR "%s: i2c error %d\n", __func__, ret);
+ ret = i2c_transfer(i_params->i2c_adap, msg, 2);
+ if (ret != 2)
+ dprintk(KERN_ERR "%s: i2c error %d, reg[0x%02x]\n",
+ __func__, ret, reg);
- return data[0];
+ return buf;
}
void extract_mask_pos(u32 label, u8 *mask, u8 *pos)
@@ -716,6 +716,44 @@ static s32 stv0900_carr_get_quality(struct dvb_frontend *fe,
return c_n;
}
+static int stv0900_read_ucblocks(struct dvb_frontend *fe, u32 * ucblocks)
+{
+ struct stv0900_state *state = fe->demodulator_priv;
+ struct stv0900_internal *i_params = state->internal;
+ enum fe_stv0900_demod_num demod = state->demod;
+ u8 err_val1, err_val0;
+ s32 err_field1, err_field0;
+ u32 header_err_val = 0;
+
+ *ucblocks = 0x0;
+ if (stv0900_get_standard(fe, demod) == STV0900_DVBS2_STANDARD) {
+ /* DVB-S2 delineator errors count */
+
+ /* retreiving number for errnous headers */
+ dmd_reg(err_field0, R0900_P1_BBFCRCKO0,
+ R0900_P2_BBFCRCKO0);
+ dmd_reg(err_field1, R0900_P1_BBFCRCKO1,
+ R0900_P2_BBFCRCKO1);
+
+ err_val1 = stv0900_read_reg(i_params, err_field1);
+ err_val0 = stv0900_read_reg(i_params, err_field0);
+ header_err_val = (err_val1<<8) | err_val0;
+
+ /* retreiving number for errnous packets */
+ dmd_reg(err_field0, R0900_P1_UPCRCKO0,
+ R0900_P2_UPCRCKO0);
+ dmd_reg(err_field1, R0900_P1_UPCRCKO1,
+ R0900_P2_UPCRCKO1);
+
+ err_val1 = stv0900_read_reg(i_params, err_field1);
+ err_val0 = stv0900_read_reg(i_params, err_field0);
+ *ucblocks = (err_val1<<8) | err_val0;
+ *ucblocks += header_err_val;
+ }
+
+ return 0;
+}
+
static int stv0900_read_snr(struct dvb_frontend *fe, u16 *snr)
{
*snr = stv0900_carr_get_quality(fe,
@@ -1359,7 +1397,7 @@ static enum fe_stv0900_error stv0900_init_internal(struct dvb_frontend *fe,
struct stv0900_state *state = fe->demodulator_priv;
enum fe_stv0900_error error = STV0900_NO_ERROR;
enum fe_stv0900_error demodError = STV0900_NO_ERROR;
- int selosci;
+ int selosci, i;
struct stv0900_inode *temp_int = find_inode(state->i2c_adap,
state->config->demod_address);
@@ -1406,7 +1444,23 @@ static enum fe_stv0900_error stv0900_init_internal(struct dvb_frontend *fe,
stv0900_write_bits(state->internal, F0900_P1_ROLLOFF_CONTROL, p_init->rolloff);
stv0900_write_bits(state->internal, F0900_P2_ROLLOFF_CONTROL, p_init->rolloff);
- stv0900_set_ts_parallel_serial(state->internal, p_init->path1_ts_clock, p_init->path2_ts_clock);
+ state->internal->ts_config = p_init->ts_config;
+ if (state->internal->ts_config == NULL)
+ stv0900_set_ts_parallel_serial(state->internal,
+ p_init->path1_ts_clock,
+ p_init->path2_ts_clock);
+ else {
+ for (i = 0; state->internal->ts_config[i].addr != 0xffff; i++)
+ stv0900_write_reg(state->internal,
+ state->internal->ts_config[i].addr,
+ state->internal->ts_config[i].val);
+
+ stv0900_write_bits(state->internal, F0900_P2_RST_HWARE, 1);
+ stv0900_write_bits(state->internal, F0900_P2_RST_HWARE, 0);
+ stv0900_write_bits(state->internal, F0900_P1_RST_HWARE, 1);
+ stv0900_write_bits(state->internal, F0900_P1_RST_HWARE, 0);
+ }
+
stv0900_write_bits(state->internal, F0900_P1_TUN_MADDRESS, p_init->tun1_maddress);
switch (p_init->tuner1_adc) {
case 1:
@@ -1897,6 +1951,7 @@ static struct dvb_frontend_ops stv0900_ops = {
.read_ber = stv0900_read_ber,
.read_signal_strength = stv0900_read_signal_strength,
.read_snr = stv0900_read_snr,
+ .read_ucblocks = stv0900_read_ucblocks,
};
struct dvb_frontend *stv0900_attach(const struct stv0900_config *config,
@@ -1930,6 +1985,7 @@ struct dvb_frontend *stv0900_attach(const struct stv0900_config *config,
init_params.tun1_iq_inversion = STV0900_IQ_NORMAL;
init_params.tuner1_adc = config->tun1_adc;
init_params.path2_ts_clock = config->path2_mode;
+ init_params.ts_config = config->ts_config_regs;
init_params.tun2_maddress = config->tun2_maddress;
init_params.tuner2_adc = config->tun2_adc;
init_params.tun2_iq_inversion = STV0900_IQ_SWAPPED;
diff --git a/linux/drivers/media/dvb/frontends/stv0900_priv.h b/linux/drivers/media/dvb/frontends/stv0900_priv.h
index 67dc8ec63..5ed7a145c 100644
--- a/linux/drivers/media/dvb/frontends/stv0900_priv.h
+++ b/linux/drivers/media/dvb/frontends/stv0900_priv.h
@@ -271,6 +271,7 @@ struct stv0900_init_params{
/* IQ from the tuner2 to the demod */
enum stv0900_iq_inversion tun2_iq_inversion;
+ struct stv0900_reg *ts_config;
};
struct stv0900_search_params {
@@ -363,6 +364,7 @@ struct stv0900_internal{
u8 i2c_addr;
u8 clkmode;/* 0 for CLKI, 2 for XTALI */
u8 chip_id;
+ struct stv0900_reg *ts_config;
enum fe_stv0900_error errs;
int dmds_used;
};
diff --git a/linux/drivers/media/dvb/siano/Makefile b/linux/drivers/media/dvb/siano/Makefile
index 6354a4718..c6644d909 100644
--- a/linux/drivers/media/dvb/siano/Makefile
+++ b/linux/drivers/media/dvb/siano/Makefile
@@ -1,4 +1,4 @@
-sms1xxx-objs := smscoreapi.o sms-cards.o smsendian.o
+sms1xxx-objs := smscoreapi.o sms-cards.o smsendian.o smsir.o
obj-$(CONFIG_DVB_SIANO_SMS1XXX) += sms1xxx.o
obj-$(CONFIG_DVB_SIANO_SMS1XXX) += smsusb.o
diff --git a/linux/drivers/media/dvb/siano/sms-cards.c b/linux/drivers/media/dvb/siano/sms-cards.c
index 63e4d0ec6..d8b15d583 100644
--- a/linux/drivers/media/dvb/siano/sms-cards.c
+++ b/linux/drivers/media/dvb/siano/sms-cards.c
@@ -18,6 +18,7 @@
*/
#include "sms-cards.h"
+#include "smsir.h"
static int sms_dbg;
module_param_named(cards_dbg, sms_dbg, int, 0644);
@@ -30,17 +31,14 @@ static struct sms_board sms_boards[] = {
[SMS1XXX_BOARD_SIANO_STELLAR] = {
.name = "Siano Stellar Digital Receiver",
.type = SMS_STELLAR,
- .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-stellar-dvbt-01.fw",
},
[SMS1XXX_BOARD_SIANO_NOVA_A] = {
.name = "Siano Nova A Digital Receiver",
.type = SMS_NOVA_A0,
- .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-a-dvbt-01.fw",
},
[SMS1XXX_BOARD_SIANO_NOVA_B] = {
.name = "Siano Nova B Digital Receiver",
.type = SMS_NOVA_B0,
- .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-b-dvbt-01.fw",
},
[SMS1XXX_BOARD_SIANO_VEGA] = {
.name = "Siano Vega Digital Receiver",
@@ -65,6 +63,9 @@ static struct sms_board sms_boards[] = {
.name = "Hauppauge WinTV MiniStick",
.type = SMS_NOVA_B0,
.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
+ .board_cfg.leds_power = 26,
+ .board_cfg.led0 = 27,
+ .board_cfg.led1 = 28,
.led_power = 26,
.led_lo = 27,
.led_hi = 28,
@@ -74,7 +75,9 @@ static struct sms_board sms_boards[] = {
.type = SMS_NOVA_B0,
.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
.lna_ctrl = 29,
+ .board_cfg.foreign_lna0_ctrl = 29,
.rf_switch = 17,
+ .board_cfg.rf_switch_uhf = 17,
},
[SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2] = {
.name = "Hauppauge WinTV MiniCard",
@@ -82,6 +85,16 @@ static struct sms_board sms_boards[] = {
.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
.lna_ctrl = -1,
},
+ [SMS1XXX_BOARD_SIANO_NICE] = {
+ /* 11 */
+ .name = "Siano Nice Digital Receiver",
+ .type = SMS_NOVA_B0,
+ },
+ [SMS1XXX_BOARD_SIANO_VENICE] = {
+ /* 12 */
+ .name = "Siano Venice Digital Receiver",
+ .type = SMS_VEGA,
+ },
};
struct sms_board *sms_get_board(int id)
@@ -91,12 +104,179 @@ struct sms_board *sms_get_board(int id)
return &sms_boards[id];
}
EXPORT_SYMBOL_GPL(sms_get_board);
+static inline void sms_gpio_assign_11xx_default_led_config(
+ struct smscore_gpio_config *pGpioConfig) {
+ pGpioConfig->Direction = SMS_GPIO_DIRECTION_OUTPUT;
+ pGpioConfig->InputCharacteristics =
+ SMS_GPIO_INPUT_CHARACTERISTICS_NORMAL;
+ pGpioConfig->OutputDriving = SMS_GPIO_OUTPUT_DRIVING_4mA;
+ pGpioConfig->OutputSlewRate = SMS_GPIO_OUTPUT_SLEW_RATE_0_45_V_NS;
+ pGpioConfig->PullUpDown = SMS_GPIO_PULL_UP_DOWN_NONE;
+}
+
+int sms_board_event(struct smscore_device_t *coredev,
+ enum SMS_BOARD_EVENTS gevent) {
+ int board_id = smscore_get_board_id(coredev);
+ struct sms_board *board = sms_get_board(board_id);
+ struct smscore_gpio_config MyGpioConfig;
+
+ sms_gpio_assign_11xx_default_led_config(&MyGpioConfig);
+
+ switch (gevent) {
+ case BOARD_EVENT_POWER_INIT: /* including hotplug */
+ switch (board_id) {
+ case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
+ /* set I/O and turn off all LEDs */
+ smscore_gpio_configure(coredev,
+ board->board_cfg.leds_power,
+ &MyGpioConfig);
+ smscore_gpio_set_level(coredev,
+ board->board_cfg.leds_power, 0);
+ smscore_gpio_configure(coredev, board->board_cfg.led0,
+ &MyGpioConfig);
+ smscore_gpio_set_level(coredev,
+ board->board_cfg.led0, 0);
+ smscore_gpio_configure(coredev, board->board_cfg.led1,
+ &MyGpioConfig);
+ smscore_gpio_set_level(coredev,
+ board->board_cfg.led1, 0);
+ break;
+ case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
+ case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
+ /* set I/O and turn off LNA */
+ smscore_gpio_configure(coredev,
+ board->board_cfg.foreign_lna0_ctrl,
+ &MyGpioConfig);
+ smscore_gpio_set_level(coredev,
+ board->board_cfg.foreign_lna0_ctrl,
+ 0);
+ break;
+ }
+ break; /* BOARD_EVENT_BIND */
+
+ case BOARD_EVENT_POWER_SUSPEND:
+ switch (board_id) {
+ case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
+ smscore_gpio_set_level(coredev,
+ board->board_cfg.leds_power, 0);
+ smscore_gpio_set_level(coredev,
+ board->board_cfg.led0, 0);
+ smscore_gpio_set_level(coredev,
+ board->board_cfg.led1, 0);
+ break;
+ case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
+ case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
+ smscore_gpio_set_level(coredev,
+ board->board_cfg.foreign_lna0_ctrl,
+ 0);
+ break;
+ }
+ break; /* BOARD_EVENT_POWER_SUSPEND */
+
+ case BOARD_EVENT_POWER_RESUME:
+ switch (board_id) {
+ case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
+ smscore_gpio_set_level(coredev,
+ board->board_cfg.leds_power, 1);
+ smscore_gpio_set_level(coredev,
+ board->board_cfg.led0, 1);
+ smscore_gpio_set_level(coredev,
+ board->board_cfg.led1, 0);
+ break;
+ case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
+ case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
+ smscore_gpio_set_level(coredev,
+ board->board_cfg.foreign_lna0_ctrl,
+ 1);
+ break;
+ }
+ break; /* BOARD_EVENT_POWER_RESUME */
+
+ case BOARD_EVENT_BIND:
+ switch (board_id) {
+ case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
+ smscore_gpio_set_level(coredev,
+ board->board_cfg.leds_power, 1);
+ smscore_gpio_set_level(coredev,
+ board->board_cfg.led0, 1);
+ smscore_gpio_set_level(coredev,
+ board->board_cfg.led1, 0);
+ break;
+ case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
+ case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
+ smscore_gpio_set_level(coredev,
+ board->board_cfg.foreign_lna0_ctrl,
+ 1);
+ break;
+ }
+ break; /* BOARD_EVENT_BIND */
+
+ case BOARD_EVENT_SCAN_PROG:
+ break; /* BOARD_EVENT_SCAN_PROG */
+ case BOARD_EVENT_SCAN_COMP:
+ break; /* BOARD_EVENT_SCAN_COMP */
+ case BOARD_EVENT_EMERGENCY_WARNING_SIGNAL:
+ break; /* BOARD_EVENT_EMERGENCY_WARNING_SIGNAL */
+ case BOARD_EVENT_FE_LOCK:
+ switch (board_id) {
+ case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
+ smscore_gpio_set_level(coredev,
+ board->board_cfg.led1, 1);
+ break;
+ }
+ break; /* BOARD_EVENT_FE_LOCK */
+ case BOARD_EVENT_FE_UNLOCK:
+ switch (board_id) {
+ case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
+ smscore_gpio_set_level(coredev,
+ board->board_cfg.led1, 0);
+ break;
+ }
+ break; /* BOARD_EVENT_FE_UNLOCK */
+ case BOARD_EVENT_DEMOD_LOCK:
+ break; /* BOARD_EVENT_DEMOD_LOCK */
+ case BOARD_EVENT_DEMOD_UNLOCK:
+ break; /* BOARD_EVENT_DEMOD_UNLOCK */
+ case BOARD_EVENT_RECEPTION_MAX_4:
+ break; /* BOARD_EVENT_RECEPTION_MAX_4 */
+ case BOARD_EVENT_RECEPTION_3:
+ break; /* BOARD_EVENT_RECEPTION_3 */
+ case BOARD_EVENT_RECEPTION_2:
+ break; /* BOARD_EVENT_RECEPTION_2 */
+ case BOARD_EVENT_RECEPTION_1:
+ break; /* BOARD_EVENT_RECEPTION_1 */
+ case BOARD_EVENT_RECEPTION_LOST_0:
+ break; /* BOARD_EVENT_RECEPTION_LOST_0 */
+ case BOARD_EVENT_MULTIPLEX_OK:
+ switch (board_id) {
+ case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
+ smscore_gpio_set_level(coredev,
+ board->board_cfg.led1, 1);
+ break;
+ }
+ break; /* BOARD_EVENT_MULTIPLEX_OK */
+ case BOARD_EVENT_MULTIPLEX_ERRORS:
+ switch (board_id) {
+ case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
+ smscore_gpio_set_level(coredev,
+ board->board_cfg.led1, 0);
+ break;
+ }
+ break; /* BOARD_EVENT_MULTIPLEX_ERRORS */
+
+ default:
+ sms_err("Unknown SMS board event");
+ break;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(sms_board_event);
static int sms_set_gpio(struct smscore_device_t *coredev, int pin, int enable)
{
int lvl, ret;
u32 gpio;
- struct smscore_gpio_config gpioconfig = {
+ struct smscore_config_gpio gpioconfig = {
.direction = SMS_GPIO_DIRECTION_OUTPUT,
.pullupdown = SMS_GPIO_PULLUPDOWN_NONE,
.inputcharacteristics = SMS_GPIO_INPUTCHARACTERISTICS_NORMAL,
diff --git a/linux/drivers/media/dvb/siano/sms-cards.h b/linux/drivers/media/dvb/siano/sms-cards.h
index 64d74c59c..38f062f6a 100644
--- a/linux/drivers/media/dvb/siano/sms-cards.h
+++ b/linux/drivers/media/dvb/siano/sms-cards.h
@@ -22,6 +22,7 @@
#include <linux/usb.h>
#include "smscoreapi.h"
+#include "smsir.h"
#define SMS_BOARD_UNKNOWN 0
#define SMS1XXX_BOARD_SIANO_STELLAR 1
@@ -34,10 +35,47 @@
#define SMS1XXX_BOARD_HAUPPAUGE_WINDHAM 8
#define SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD 9
#define SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2 10
+#define SMS1XXX_BOARD_SIANO_NICE 11
+#define SMS1XXX_BOARD_SIANO_VENICE 12
+
+struct sms_board_gpio_cfg {
+ int lna_vhf_exist;
+ int lna_vhf_ctrl;
+ int lna_uhf_exist;
+ int lna_uhf_ctrl;
+ int lna_uhf_d_ctrl;
+ int lna_sband_exist;
+ int lna_sband_ctrl;
+ int lna_sband_d_ctrl;
+ int foreign_lna0_ctrl;
+ int foreign_lna1_ctrl;
+ int foreign_lna2_ctrl;
+ int rf_switch_vhf;
+ int rf_switch_uhf;
+ int rf_switch_sband;
+ int leds_power;
+ int led0;
+ int led1;
+ int led2;
+ int led3;
+ int led4;
+ int ir;
+ int eeprom_wp;
+ int mrc_sense;
+ int mrc_pdn_resetn;
+ int mrc_gp0; /* mrcs spi int */
+ int mrc_gp1;
+ int mrc_gp2;
+ int mrc_gp3;
+ int mrc_gp4;
+ int host_spi_gsp_ts_int;
+};
struct sms_board {
enum sms_device_type_st type;
char *name, *fw[DEVICE_MODE_MAX];
+ struct sms_board_gpio_cfg board_cfg;
+ enum ir_kb_type ir_kb_type;
/* gpios */
int led_power, led_hi, led_lo, lna_ctrl, rf_switch;
@@ -45,6 +83,32 @@ struct sms_board {
struct sms_board *sms_get_board(int id);
+extern struct smscore_device_t *coredev;
+
+enum SMS_BOARD_EVENTS {
+ BOARD_EVENT_POWER_INIT,
+ BOARD_EVENT_POWER_SUSPEND,
+ BOARD_EVENT_POWER_RESUME,
+ BOARD_EVENT_BIND,
+ BOARD_EVENT_SCAN_PROG,
+ BOARD_EVENT_SCAN_COMP,
+ BOARD_EVENT_EMERGENCY_WARNING_SIGNAL,
+ BOARD_EVENT_FE_LOCK,
+ BOARD_EVENT_FE_UNLOCK,
+ BOARD_EVENT_DEMOD_LOCK,
+ BOARD_EVENT_DEMOD_UNLOCK,
+ BOARD_EVENT_RECEPTION_MAX_4,
+ BOARD_EVENT_RECEPTION_3,
+ BOARD_EVENT_RECEPTION_2,
+ BOARD_EVENT_RECEPTION_1,
+ BOARD_EVENT_RECEPTION_LOST_0,
+ BOARD_EVENT_MULTIPLEX_OK,
+ BOARD_EVENT_MULTIPLEX_ERRORS
+};
+
+int sms_board_event(struct smscore_device_t *coredev,
+ enum SMS_BOARD_EVENTS gevent);
+
int sms_board_setup(struct smscore_device_t *coredev);
#define SMS_LED_OFF 0
diff --git a/linux/drivers/media/dvb/siano/smscoreapi.c b/linux/drivers/media/dvb/siano/smscoreapi.c
index 15272dbb5..54f59f24e 100644
--- a/linux/drivers/media/dvb/siano/smscoreapi.c
+++ b/linux/drivers/media/dvb/siano/smscoreapi.c
@@ -30,9 +30,13 @@
#include <linux/io.h>
#include <linux/firmware.h>
+#include <linux/wait.h>
+#include <asm/byteorder.h>
#include "smscoreapi.h"
#include "sms-cards.h"
+#include "smsir.h"
+#include "smsendian.h"
static int sms_dbg;
module_param_named(debug, sms_dbg, int, 0644);
@@ -348,6 +352,13 @@ int smscore_register_device(struct smsdevice_params_t *params,
init_completion(&dev->init_device_done);
init_completion(&dev->reload_start_done);
init_completion(&dev->resume_done);
+ init_completion(&dev->gpio_configuration_done);
+ init_completion(&dev->gpio_set_level_done);
+ init_completion(&dev->gpio_get_level_done);
+ init_completion(&dev->ir_init_done);
+
+ /* Buffer management */
+ init_waitqueue_head(&dev->buffer_mng_waitq);
/* alloc common buffer */
dev->common_buffer_size = params->buffer_size * params->num_buffers;
@@ -403,6 +414,71 @@ int smscore_register_device(struct smsdevice_params_t *params,
}
EXPORT_SYMBOL_GPL(smscore_register_device);
+
+static int smscore_sendrequest_and_wait(struct smscore_device_t *coredev,
+ void *buffer, size_t size, struct completion *completion) {
+ int rc = coredev->sendrequest_handler(coredev->context, buffer, size);
+ if (rc < 0) {
+ sms_info("sendrequest returned error %d", rc);
+ return rc;
+ }
+
+ return wait_for_completion_timeout(completion,
+ msecs_to_jiffies(SMS_PROTOCOL_MAX_RAOUNDTRIP_MS)) ?
+ 0 : -ETIME;
+}
+
+/**
+ * Starts & enables IR operations
+ *
+ * @return 0 on success, < 0 on error.
+ */
+static int smscore_init_ir(struct smscore_device_t *coredev)
+{
+ int ir_io;
+ int rc;
+ void *buffer;
+
+ coredev->ir.input_dev = NULL;
+ ir_io = sms_get_board(smscore_get_board_id(coredev))->board_cfg.ir;
+ if (ir_io) {/* only if IR port exist we use IR sub-module */
+ sms_info("IR loading");
+ rc = sms_ir_init(coredev);
+
+ if (rc != 0)
+ sms_err("Error initialization DTV IR sub-module");
+ else {
+ buffer = kmalloc(sizeof(struct SmsMsgData_ST2) +
+ SMS_DMA_ALIGNMENT,
+ GFP_KERNEL | GFP_DMA);
+ if (buffer) {
+ struct SmsMsgData_ST2 *msg =
+ (struct SmsMsgData_ST2 *)
+ SMS_ALIGN_ADDRESS(buffer);
+
+ SMS_INIT_MSG(&msg->xMsgHeader,
+ MSG_SMS_START_IR_REQ,
+ sizeof(struct SmsMsgData_ST2));
+ msg->msgData[0] = coredev->ir.controller;
+ msg->msgData[1] = coredev->ir.timeout;
+
+ smsendian_handle_tx_message(
+ (struct SmsMsgHdr_ST2 *)msg);
+ rc = smscore_sendrequest_and_wait(coredev, msg,
+ msg->xMsgHeader. msgLength,
+ &coredev->ir_init_done);
+
+ kfree(buffer);
+ } else
+ sms_err
+ ("Sending IR initialization message failed");
+ }
+ } else
+ sms_info("IR port has not been detected");
+
+ return 0;
+}
+
/**
* sets initial device mode and notifies client hotplugs that device is ready
*
@@ -423,6 +499,7 @@ int smscore_start_device(struct smscore_device_t *coredev)
kmutex_lock(&g_smscore_deviceslock);
rc = smscore_notify_callbacks(coredev, coredev->device, 1);
+ smscore_init_ir(coredev);
sms_info("device %p started, rc %d", coredev, rc);
@@ -432,29 +509,19 @@ int smscore_start_device(struct smscore_device_t *coredev)
}
EXPORT_SYMBOL_GPL(smscore_start_device);
-static int smscore_sendrequest_and_wait(struct smscore_device_t *coredev,
- void *buffer, size_t size,
- struct completion *completion)
-{
- int rc = coredev->sendrequest_handler(coredev->context, buffer, size);
- if (rc < 0) {
- sms_info("sendrequest returned error %d", rc);
- return rc;
- }
-
- return wait_for_completion_timeout(completion,
- msecs_to_jiffies(10000)) ?
- 0 : -ETIME;
-}
static int smscore_load_firmware_family2(struct smscore_device_t *coredev,
void *buffer, size_t size)
{
struct SmsFirmware_ST *firmware = (struct SmsFirmware_ST *) buffer;
struct SmsMsgHdr_ST *msg;
- u32 mem_address = firmware->StartAddress;
+ u32 mem_address;
u8 *payload = firmware->Payload;
int rc = 0;
+ firmware->StartAddress = le32_to_cpu(firmware->StartAddress);
+ firmware->Length = le32_to_cpu(firmware->Length);
+
+ mem_address = firmware->StartAddress;
sms_info("loading FW to addr 0x%x size %d",
mem_address, firmware->Length);
@@ -621,6 +688,9 @@ void smscore_unregister_device(struct smscore_device_t *coredev)
kmutex_lock(&g_smscore_deviceslock);
+ /* Release input device (IR) resources */
+ sms_ir_exit(coredev);
+
smscore_notify_clients(coredev);
smscore_notify_callbacks(coredev, NULL, 0);
@@ -628,7 +698,9 @@ void smscore_unregister_device(struct smscore_device_t *coredev)
* onresponse must no longer be called */
while (1) {
- while ((cb = smscore_getbuffer(coredev))) {
+ while (!list_empty(&coredev->buffers)) {
+ cb = (struct smscore_buffer_t *) coredev->buffers.next;
+ list_del(&cb->entry);
kfree(cb);
num_buffers++;
}
@@ -649,8 +721,10 @@ void smscore_unregister_device(struct smscore_device_t *coredev)
if (coredev->common_buffer)
dma_free_coherent(NULL, coredev->common_buffer_size,
- coredev->common_buffer,
- coredev->common_buffer_phys);
+ coredev->common_buffer, coredev->common_buffer_phys);
+
+ if (coredev->fw_buf != NULL)
+ kfree(coredev->fw_buf);
list_del(&coredev->entry);
kfree(coredev);
@@ -710,7 +784,7 @@ static char *smscore_fw_lkup[][SMS_NUM_OF_DEVICE_TYPES] = {
/*BDA*/
{"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
/*ISDBT*/
- {"none", "isdbt_nova_12mhz.inp", "dvb_nova_12mhz.inp", "none"},
+ {"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"},
/*ISDBTBDA*/
{"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"},
/*CMMB*/
@@ -834,7 +908,7 @@ int smscore_set_device_mode(struct smscore_device_t *coredev, int mode)
coredev->device_flags &= ~SMS_DEVICE_NOT_READY;
}
- if (rc != 0)
+ if (rc < 0)
sms_err("return error code %d.", rc);
return rc;
}
@@ -980,6 +1054,35 @@ void smscore_onresponse(struct smscore_device_t *coredev,
case MSG_SMS_SLEEP_RESUME_COMP_IND:
complete(&coredev->resume_done);
break;
+ case MSG_SMS_GPIO_CONFIG_EX_RES:
+ sms_debug("MSG_SMS_GPIO_CONFIG_EX_RES");
+ complete(&coredev->gpio_configuration_done);
+ break;
+ case MSG_SMS_GPIO_SET_LEVEL_RES:
+ sms_debug("MSG_SMS_GPIO_SET_LEVEL_RES");
+ complete(&coredev->gpio_set_level_done);
+ break;
+ case MSG_SMS_GPIO_GET_LEVEL_RES:
+ {
+ u32 *msgdata = (u32 *) phdr;
+ coredev->gpio_get_res = msgdata[1];
+ sms_debug("MSG_SMS_GPIO_GET_LEVEL_RES gpio level %d",
+ coredev->gpio_get_res);
+ complete(&coredev->gpio_get_level_done);
+ break;
+ }
+ case MSG_SMS_START_IR_RES:
+ complete(&coredev->ir_init_done);
+ break;
+ case MSG_SMS_IR_SAMPLES_IND:
+ sms_ir_event(coredev,
+ (const char *)
+ ((char *)phdr
+ + sizeof(struct SmsMsgHdr_ST)),
+ (int)phdr->msgLength
+ - sizeof(struct SmsMsgHdr_ST));
+ break;
+
default:
#if 0
sms_info("no client (%p) or error (%d), "
@@ -1006,12 +1109,24 @@ struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev)
struct smscore_buffer_t *cb = NULL;
unsigned long flags;
+ DEFINE_WAIT(wait);
+
spin_lock_irqsave(&coredev->bufferslock, flags);
- if (!list_empty(&coredev->buffers)) {
- cb = (struct smscore_buffer_t *) coredev->buffers.next;
- list_del(&cb->entry);
- }
+ /* This function must return a valid buffer, since the buffer list is
+ * finite, we check that there is an available buffer, if not, we wait
+ * until such buffer become available.
+ */
+
+ prepare_to_wait(&coredev->buffer_mng_waitq, &wait, TASK_INTERRUPTIBLE);
+
+ if (list_empty(&coredev->buffers))
+ schedule();
+
+ finish_wait(&coredev->buffer_mng_waitq, &wait);
+
+ cb = (struct smscore_buffer_t *) coredev->buffers.next;
+ list_del(&cb->entry);
spin_unlock_irqrestore(&coredev->bufferslock, flags);
@@ -1028,8 +1143,8 @@ EXPORT_SYMBOL_GPL(smscore_getbuffer);
*
*/
void smscore_putbuffer(struct smscore_device_t *coredev,
- struct smscore_buffer_t *cb)
-{
+ struct smscore_buffer_t *cb) {
+ wake_up_interruptible(&coredev->buffer_mng_waitq);
list_add_locked(&cb->entry, &coredev->buffers, &coredev->bufferslock);
}
EXPORT_SYMBOL_GPL(smscore_putbuffer);
@@ -1236,8 +1351,9 @@ static int smscore_map_common_buffer(struct smscore_device_t *coredev,
}
#endif
+/* old GPIO managments implementation */
int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin,
- struct smscore_gpio_config *pinconfig)
+ struct smscore_config_gpio *pinconfig)
{
struct {
struct SmsMsgHdr_ST hdr;
@@ -1306,110 +1422,254 @@ int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level)
&msg, sizeof(msg));
}
-static int __init smscore_module_init(void)
-{
- int rc = 0;
+/* new GPIO managment implementation */
+static int GetGpioPinParams(u32 PinNum, u32 *pTranslatedPinNum,
+ u32 *pGroupNum, u32 *pGroupCfg) {
+
+ *pGroupCfg = 1;
+
+ if (PinNum >= 0 && PinNum <= 1) {
+ *pTranslatedPinNum = 0;
+ *pGroupNum = 9;
+ *pGroupCfg = 2;
+ } else if (PinNum >= 2 && PinNum <= 6) {
+ *pTranslatedPinNum = 2;
+ *pGroupNum = 0;
+ *pGroupCfg = 2;
+ } else if (PinNum >= 7 && PinNum <= 11) {
+ *pTranslatedPinNum = 7;
+ *pGroupNum = 1;
+ } else if (PinNum >= 12 && PinNum <= 15) {
+ *pTranslatedPinNum = 12;
+ *pGroupNum = 2;
+ *pGroupCfg = 3;
+ } else if (PinNum == 16) {
+ *pTranslatedPinNum = 16;
+ *pGroupNum = 23;
+ } else if (PinNum >= 17 && PinNum <= 24) {
+ *pTranslatedPinNum = 17;
+ *pGroupNum = 3;
+ } else if (PinNum == 25) {
+ *pTranslatedPinNum = 25;
+ *pGroupNum = 6;
+ } else if (PinNum >= 26 && PinNum <= 28) {
+ *pTranslatedPinNum = 26;
+ *pGroupNum = 4;
+ } else if (PinNum == 29) {
+ *pTranslatedPinNum = 29;
+ *pGroupNum = 5;
+ *pGroupCfg = 2;
+ } else if (PinNum == 30) {
+ *pTranslatedPinNum = 30;
+ *pGroupNum = 8;
+ } else if (PinNum == 31) {
+ *pTranslatedPinNum = 31;
+ *pGroupNum = 17;
+ } else
+ return -1;
- INIT_LIST_HEAD(&g_smscore_notifyees);
- INIT_LIST_HEAD(&g_smscore_devices);
- kmutex_init(&g_smscore_deviceslock);
+ *pGroupCfg <<= 24;
- INIT_LIST_HEAD(&g_smscore_registry);
- kmutex_init(&g_smscore_registrylock);
+ return 0;
+}
-#if 0 /* def SMS_CHAR_CLIENT */
- /* Char interface Register */
- rc = smschar_register();
- if (rc) {
- sms_err("Error registering char device client.\n");
- goto smschar_error;
- }
-#endif
+int smscore_gpio_configure(struct smscore_device_t *coredev, u8 PinNum,
+ struct smscore_gpio_config *pGpioConfig) {
-#if 0 /* def SMS_DVB_CLIENT */
- /* DVB Register */
- rc = smsdvb_register();
- if (rc) {
- sms_err("Error registering DVB client.\n");
- goto smsdvb_error;
- }
-#endif
+ u32 totalLen;
+ u32 TranslatedPinNum = 0;
+ u32 GroupNum = 0;
+ u32 ElectricChar;
+ u32 groupCfg;
+ void *buffer;
+ int rc;
+
+ struct SetGpioMsg {
+ struct SmsMsgHdr_ST xMsgHeader;
+ u32 msgData[6];
+ } *pMsg;
+
+
+ if (PinNum > MAX_GPIO_PIN_NUMBER)
+ return -EINVAL;
-#if 0 /* def SMS_NET_CLIENT */
- /* DVB Register */
- rc = smsnet_register();
- if (rc) {
- sms_err("Error registering Network client.\n");
- goto smsnet_error;
+ if (pGpioConfig == NULL)
+ return -EINVAL;
+
+ totalLen = sizeof(struct SmsMsgHdr_ST) + (sizeof(u32) * 6);
+
+ buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT,
+ GFP_KERNEL | GFP_DMA);
+ if (!buffer)
+ return -ENOMEM;
+
+ pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer);
+
+ pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
+ pMsg->xMsgHeader.msgDstId = HIF_TASK;
+ pMsg->xMsgHeader.msgFlags = 0;
+ pMsg->xMsgHeader.msgLength = (u16) totalLen;
+ pMsg->msgData[0] = PinNum;
+
+ if (!(coredev->device_flags & SMS_DEVICE_FAMILY2)) {
+ pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_CONFIG_REQ;
+ if (GetGpioPinParams(PinNum, &TranslatedPinNum, &GroupNum,
+ &groupCfg) != 0)
+ return -EINVAL;
+
+ pMsg->msgData[1] = TranslatedPinNum;
+ pMsg->msgData[2] = GroupNum;
+ ElectricChar = (pGpioConfig->PullUpDown)
+ | (pGpioConfig->InputCharacteristics << 2)
+ | (pGpioConfig->OutputSlewRate << 3)
+ | (pGpioConfig->OutputDriving << 4);
+ pMsg->msgData[3] = ElectricChar;
+ pMsg->msgData[4] = pGpioConfig->Direction;
+ pMsg->msgData[5] = groupCfg;
+ } else {
+ pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_CONFIG_EX_REQ;
+ pMsg->msgData[1] = pGpioConfig->PullUpDown;
+ pMsg->msgData[2] = pGpioConfig->OutputSlewRate;
+ pMsg->msgData[3] = pGpioConfig->OutputDriving;
+ pMsg->msgData[4] = pGpioConfig->Direction;
+ pMsg->msgData[5] = 0;
}
-#endif
-#if 0 /* def SMS_USB_BUS_DRV */
- /* USB Register */
- rc = smsusb_register();
- if (rc) {
- sms_err("Error registering USB bus driver.\n");
- goto sms_bus_drv_error;
+ smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg);
+ rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen,
+ &coredev->gpio_configuration_done);
+
+ if (rc != 0) {
+ if (rc == -ETIME)
+ sms_err("smscore_gpio_configure timeout");
+ else
+ sms_err("smscore_gpio_configure error");
}
-#endif
+ kfree(buffer);
+
+ return rc;
+}
+
+int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 PinNum,
+ u8 NewLevel) {
-#if 0 /* def SMS_SPI_BUS_DRV */
- /* USB Register */
- rc = smsspi_register();
- if (rc) {
- sms_err("Error registering spi bus driver.\n");
- goto sms_bus_drv_error;
+ u32 totalLen;
+ int rc;
+ void *buffer;
+
+ struct SetGpioMsg {
+ struct SmsMsgHdr_ST xMsgHeader;
+ u32 msgData[3]; /* keep it 3 ! */
+ } *pMsg;
+
+ if ((NewLevel > 1) || (PinNum > MAX_GPIO_PIN_NUMBER) ||
+ (PinNum > MAX_GPIO_PIN_NUMBER))
+ return -EINVAL;
+
+ totalLen = sizeof(struct SmsMsgHdr_ST) +
+ (3 * sizeof(u32)); /* keep it 3 ! */
+
+ buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT,
+ GFP_KERNEL | GFP_DMA);
+ if (!buffer)
+ return -ENOMEM;
+
+ pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer);
+
+ pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
+ pMsg->xMsgHeader.msgDstId = HIF_TASK;
+ pMsg->xMsgHeader.msgFlags = 0;
+ pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_SET_LEVEL_REQ;
+ pMsg->xMsgHeader.msgLength = (u16) totalLen;
+ pMsg->msgData[0] = PinNum;
+ pMsg->msgData[1] = NewLevel;
+
+ /* Send message to SMS */
+ smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg);
+ rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen,
+ &coredev->gpio_set_level_done);
+
+ if (rc != 0) {
+ if (rc == -ETIME)
+ sms_err("smscore_gpio_set_level timeout");
+ else
+ sms_err("smscore_gpio_set_level error");
}
-#endif
+ kfree(buffer);
return rc;
-#if 0
-sms_bus_drv_error:
-#endif /* 0 */
-#if 0 /* def SMS_NET_CLIENT */
- smsnet_unregister();
-smsnet_error:
-#endif
-#if 0 /* def SMS_DVB_CLIENT */
- smsdvb_unregister();
-smsdvb_error:
-#endif
-#if 0 /* def SMS_CHAR_CLIENT */
- smschar_unregister();
-smschar_error:
-#endif
- sms_debug("rc %d", rc);
+}
+
+int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 PinNum,
+ u8 *level) {
+
+ u32 totalLen;
+ int rc;
+ void *buffer;
+
+ struct SetGpioMsg {
+ struct SmsMsgHdr_ST xMsgHeader;
+ u32 msgData[2];
+ } *pMsg;
+
+
+ if (PinNum > MAX_GPIO_PIN_NUMBER)
+ return -EINVAL;
+
+ totalLen = sizeof(struct SmsMsgHdr_ST) + (2 * sizeof(u32));
+
+ buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT,
+ GFP_KERNEL | GFP_DMA);
+ if (!buffer)
+ return -ENOMEM;
+
+ pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer);
+
+ pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
+ pMsg->xMsgHeader.msgDstId = HIF_TASK;
+ pMsg->xMsgHeader.msgFlags = 0;
+ pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_GET_LEVEL_REQ;
+ pMsg->xMsgHeader.msgLength = (u16) totalLen;
+ pMsg->msgData[0] = PinNum;
+ pMsg->msgData[1] = 0;
+
+ /* Send message to SMS */
+ smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg);
+ rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen,
+ &coredev->gpio_get_level_done);
+
+ if (rc != 0) {
+ if (rc == -ETIME)
+ sms_err("smscore_gpio_get_level timeout");
+ else
+ sms_err("smscore_gpio_get_level error");
+ }
+ kfree(buffer);
+
+ /* Its a race between other gpio_get_level() and the copy of the single
+ * global 'coredev->gpio_get_res' to the function's variable 'level'
+ */
+ *level = coredev->gpio_get_res;
return rc;
}
-static void __exit smscore_module_exit(void)
+static int __init smscore_module_init(void)
{
-#if 0 /* def SMS_CHAR_CLIENT */
- /* Char interface UnRegister */
- smschar_unregister();
-#endif
-
-#if 0 /* def SMS_DVB_CLIENT */
- /* DVB UnRegister */
- smsdvb_unregister();
-#endif
+ int rc = 0;
-#if 0 /* def SMS_NET_CLIENT */
- /* NET UnRegister */
- smsnet_unregister();
-#endif
+ INIT_LIST_HEAD(&g_smscore_notifyees);
+ INIT_LIST_HEAD(&g_smscore_devices);
+ kmutex_init(&g_smscore_deviceslock);
-#if 0 /* def SMS_USB_BUS_DRV */
- /* Unregister USB */
- smsusb_unregister();
-#endif
+ INIT_LIST_HEAD(&g_smscore_registry);
+ kmutex_init(&g_smscore_registrylock);
-#if 0 /* def SMS_SPI_BUS_DRV */
- /* Unregister SPI */
- smsspi_unregister();
-#endif
+ return rc;
+}
+static void __exit smscore_module_exit(void)
+{
kmutex_lock(&g_smscore_deviceslock);
while (!list_empty(&g_smscore_notifyees)) {
struct smscore_device_notifyee_t *notifyee =
diff --git a/linux/drivers/media/dvb/siano/smscoreapi.h b/linux/drivers/media/dvb/siano/smscoreapi.h
index d98b4a749..bc4572de6 100644
--- a/linux/drivers/media/dvb/siano/smscoreapi.h
+++ b/linux/drivers/media/dvb/siano/smscoreapi.h
@@ -35,13 +35,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <asm/page.h>
#include "compat.h"
-#define SMS_DVB3_SUBSYS
-#ifdef SMS_DVB3_SUBSYS
-#include "dmxdev.h"
-#include "dvbdev.h"
-#include "dvb_demux.h"
-#include "dvb_frontend.h"
-#endif
+#include "smsir.h"
#define kmutex_init(_p_) mutex_init(_p_)
#define kmutex_lock(_p_) mutex_lock(_p_)
@@ -175,7 +169,7 @@ struct smscore_device_t {
u32 fw_buf_size;
/* Infrared (IR) */
- /* struct ir_t ir; */
+ struct ir_t ir;
int led_state;
};
@@ -556,7 +550,7 @@ struct SMSHOSTLIB_I2C_RES_ST {
};
-struct smscore_gpio_config {
+struct smscore_config_gpio {
#define SMS_GPIO_DIRECTION_INPUT 0
#define SMS_GPIO_DIRECTION_OUTPUT 1
u8 direction;
@@ -582,6 +576,47 @@ struct smscore_gpio_config {
u8 outputdriving;
};
+struct smscore_gpio_config {
+#define SMS_GPIO_DIRECTION_INPUT 0
+#define SMS_GPIO_DIRECTION_OUTPUT 1
+ u8 Direction;
+
+#define SMS_GPIO_PULL_UP_DOWN_NONE 0
+#define SMS_GPIO_PULL_UP_DOWN_PULLDOWN 1
+#define SMS_GPIO_PULL_UP_DOWN_PULLUP 2
+#define SMS_GPIO_PULL_UP_DOWN_KEEPER 3
+ u8 PullUpDown;
+
+#define SMS_GPIO_INPUT_CHARACTERISTICS_NORMAL 0
+#define SMS_GPIO_INPUT_CHARACTERISTICS_SCHMITT 1
+ u8 InputCharacteristics;
+
+#define SMS_GPIO_OUTPUT_SLEW_RATE_SLOW 1 /* 10xx */
+#define SMS_GPIO_OUTPUT_SLEW_RATE_FAST 0 /* 10xx */
+
+
+#define SMS_GPIO_OUTPUT_SLEW_RATE_0_45_V_NS 0 /* 11xx */
+#define SMS_GPIO_OUTPUT_SLEW_RATE_0_9_V_NS 1 /* 11xx */
+#define SMS_GPIO_OUTPUT_SLEW_RATE_1_7_V_NS 2 /* 11xx */
+#define SMS_GPIO_OUTPUT_SLEW_RATE_3_3_V_NS 3 /* 11xx */
+ u8 OutputSlewRate;
+
+#define SMS_GPIO_OUTPUT_DRIVING_S_4mA 0 /* 10xx */
+#define SMS_GPIO_OUTPUT_DRIVING_S_8mA 1 /* 10xx */
+#define SMS_GPIO_OUTPUT_DRIVING_S_12mA 2 /* 10xx */
+#define SMS_GPIO_OUTPUT_DRIVING_S_16mA 3 /* 10xx */
+
+#define SMS_GPIO_OUTPUT_DRIVING_1_5mA 0 /* 11xx */
+#define SMS_GPIO_OUTPUT_DRIVING_2_8mA 1 /* 11xx */
+#define SMS_GPIO_OUTPUT_DRIVING_4mA 2 /* 11xx */
+#define SMS_GPIO_OUTPUT_DRIVING_7mA 3 /* 11xx */
+#define SMS_GPIO_OUTPUT_DRIVING_10mA 4 /* 11xx */
+#define SMS_GPIO_OUTPUT_DRIVING_11mA 5 /* 11xx */
+#define SMS_GPIO_OUTPUT_DRIVING_14mA 6 /* 11xx */
+#define SMS_GPIO_OUTPUT_DRIVING_16mA 7 /* 11xx */
+ u8 OutputDriving;
+};
+
extern void smscore_registry_setmode(char *devpath, int mode);
extern int smscore_registry_getmode(char *devpath);
@@ -610,7 +645,6 @@ extern int smsclient_sendrequest(struct smscore_client_t *client,
extern void smscore_onresponse(struct smscore_device_t *coredev,
struct smscore_buffer_t *cb);
-#if 1
extern int smscore_get_common_buffer_size(struct smscore_device_t *coredev);
extern int smscore_map_common_buffer(struct smscore_device_t *coredev,
struct vm_area_struct *vma);
@@ -618,17 +652,25 @@ extern int smscore_get_fw_filename(struct smscore_device_t *coredev,
int mode, char *filename);
extern int smscore_send_fw_file(struct smscore_device_t *coredev,
u8 *ufwbuf, int size);
-#endif
extern
struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev);
extern void smscore_putbuffer(struct smscore_device_t *coredev,
struct smscore_buffer_t *cb);
+/* old GPIO managment */
int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin,
- struct smscore_gpio_config *pinconfig);
+ struct smscore_config_gpio *pinconfig);
int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level);
+/* new GPIO managment */
+extern int smscore_gpio_configure(struct smscore_device_t *coredev, u8 PinNum,
+ struct smscore_gpio_config *pGpioConfig);
+extern int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 PinNum,
+ u8 NewLevel);
+extern int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 PinNum,
+ u8 *level);
+
void smscore_set_board_id(struct smscore_device_t *core, int id);
int smscore_get_board_id(struct smscore_device_t *core);
diff --git a/linux/drivers/media/dvb/siano/smsdvb.c b/linux/drivers/media/dvb/siano/smsdvb.c
index f43c7f543..f8856d9c8 100644
--- a/linux/drivers/media/dvb/siano/smsdvb.c
+++ b/linux/drivers/media/dvb/siano/smsdvb.c
@@ -22,6 +22,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <linux/module.h>
#include <linux/init.h>
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+
#include "smscoreapi.h"
#include "smsendian.h"
#include "sms-cards.h"
@@ -61,6 +66,54 @@ MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");
/* Events that may come from DVB v3 adapter */
static void sms_board_dvb3_event(struct smsdvb_client_t *client,
enum SMS_DVB3_EVENTS event) {
+
+ struct smscore_device_t *coredev = client->coredev;
+ switch (event) {
+ case DVB3_EVENT_INIT:
+ sms_debug("DVB3_EVENT_INIT");
+ sms_board_event(coredev, BOARD_EVENT_BIND);
+ break;
+ case DVB3_EVENT_SLEEP:
+ sms_debug("DVB3_EVENT_SLEEP");
+ sms_board_event(coredev, BOARD_EVENT_POWER_SUSPEND);
+ break;
+ case DVB3_EVENT_HOTPLUG:
+ sms_debug("DVB3_EVENT_HOTPLUG");
+ sms_board_event(coredev, BOARD_EVENT_POWER_INIT);
+ break;
+ case DVB3_EVENT_FE_LOCK:
+ if (client->event_fe_state != DVB3_EVENT_FE_LOCK) {
+ client->event_fe_state = DVB3_EVENT_FE_LOCK;
+ sms_debug("DVB3_EVENT_FE_LOCK");
+ sms_board_event(coredev, BOARD_EVENT_FE_LOCK);
+ }
+ break;
+ case DVB3_EVENT_FE_UNLOCK:
+ if (client->event_fe_state != DVB3_EVENT_FE_UNLOCK) {
+ client->event_fe_state = DVB3_EVENT_FE_UNLOCK;
+ sms_debug("DVB3_EVENT_FE_UNLOCK");
+ sms_board_event(coredev, BOARD_EVENT_FE_UNLOCK);
+ }
+ break;
+ case DVB3_EVENT_UNC_OK:
+ if (client->event_unc_state != DVB3_EVENT_UNC_OK) {
+ client->event_unc_state = DVB3_EVENT_UNC_OK;
+ sms_debug("DVB3_EVENT_UNC_OK");
+ sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_OK);
+ }
+ break;
+ case DVB3_EVENT_UNC_ERR:
+ if (client->event_unc_state != DVB3_EVENT_UNC_ERR) {
+ client->event_unc_state = DVB3_EVENT_UNC_ERR;
+ sms_debug("DVB3_EVENT_UNC_ERR");
+ sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_ERRORS);
+ }
+ break;
+
+ default:
+ sms_err("Unknown dvb3 api event");
+ break;
+ }
}
static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
diff --git a/linux/drivers/media/dvb/siano/smsendian.h b/linux/drivers/media/dvb/siano/smsendian.h
index 7fbedc6a6..1624d6fd3 100644
--- a/linux/drivers/media/dvb/siano/smsendian.h
+++ b/linux/drivers/media/dvb/siano/smsendian.h
@@ -24,9 +24,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <asm/byteorder.h>
-void smsendian_handle_tx_message(void *buffer);
-void smsendian_handle_rx_message(void *buffer);
-void smsendian_handle_message_header(void *msg);
+extern void smsendian_handle_tx_message(void *buffer);
+extern void smsendian_handle_rx_message(void *buffer);
+extern void smsendian_handle_message_header(void *msg);
#endif /* __SMS_ENDIAN_H__ */
diff --git a/linux/drivers/media/dvb/siano/smsir.c b/linux/drivers/media/dvb/siano/smsir.c
index a5f302c58..ac876859c 100644
--- a/linux/drivers/media/dvb/siano/smsir.c
+++ b/linux/drivers/media/dvb/siano/smsir.c
@@ -99,7 +99,7 @@ static void sms_ir_rc5_event(struct smscore_device_t *coredev,
bool toggle_changed;
u16 keycode;
- sms_info("IR RC5 word: address %d, command %d, toggle %d",
+ sms_log("IR RC5 word: address %d, command %d, toggle %d",
addr, cmd, toggle);
toggle_changed = ir_toggle != toggle;
@@ -118,7 +118,7 @@ static void sms_ir_rc5_event(struct smscore_device_t *coredev,
(keycode != KEY_VOLUMEUP && keycode != KEY_VOLUMEDOWN))
return; /* accept only repeated volume, reject other keys */
- sms_info("kernel input keycode (from ir) %d", keycode);
+ sms_log("kernel input keycode (from ir) %d", keycode);
input_report_key(coredev->ir.input_dev, keycode, 1);
input_sync(coredev->ir.input_dev);
@@ -147,7 +147,7 @@ static u32 ir_rc5_decode(unsigned int code)
break;
case 3:
/* dprintk(1, "ir-common: ir_rc5_decode(%x) bad code\n", org_code);*/
- sms_info("bad code");
+ sms_log("bad code");
return 0;
}
}
@@ -175,7 +175,7 @@ static void sms_rc5_parse_word(struct smscore_device_t *coredev)
RC5_PUSH_BIT(rc5_word, (ir_word>>i)&1, j)
rc5_word = ir_rc5_decode(rc5_word);
- /* sms_info("temp = 0x%x, rc5_code = 0x%x", ir_word, rc5_word); */
+ /* sms_log("temp = 0x%x, rc5_code = 0x%x", ir_word, rc5_word); */
sms_ir_rc5_event(coredev,
RC5_TOGGLE(rc5_word),
@@ -210,11 +210,11 @@ static void sms_rc5_accumulate_bits(struct smscore_device_t *coredev,
if (ir_pos == RC5_WORD_LEN)
sms_rc5_parse_word(coredev);
else if (ir_pos) /* timeout within a word */
- sms_info("IR error parsing a word");
+ sms_log("IR error parsing a word");
ir_pos = 0;
ir_word = 0;
- /* sms_info("timeout %d", time); */
+ /* sms_log("timeout %d", time); */
break;
}
/* The time is within the range of this number of bits */
@@ -236,7 +236,7 @@ void sms_ir_event(struct smscore_device_t *coredev, const char *buf, int len)
int count = len>>2;
samples = (s32 *)buf;
-/* sms_info("IR buffer received, length = %d", count);*/
+/* sms_log("IR buffer received, length = %d", count);*/
for (i = 0; i < count; i++)
if (ir_protocol == IR_RC5)
@@ -248,7 +248,7 @@ int sms_ir_init(struct smscore_device_t *coredev)
{
struct input_dev *input_dev;
- sms_info("Allocating input device");
+ sms_log("Allocating input device");
input_dev = input_allocate_device();
if (!input_dev) {
sms_err("Not enough memory");
@@ -261,11 +261,11 @@ int sms_ir_init(struct smscore_device_t *coredev)
coredev->ir.keyboard_layout_map =
keyboard_layout_maps[coredev->ir.ir_kb_type].
keyboard_layout_map;
- sms_info("IR remote keyboard type is %d", coredev->ir.ir_kb_type);
+ sms_log("IR remote keyboard type is %d", coredev->ir.ir_kb_type);
coredev->ir.controller = 0; /* Todo: vega/nova SPI number */
coredev->ir.timeout = IR_DEFAULT_TIMEOUT;
- sms_info("IR port %d, timeout %d ms",
+ sms_log("IR port %d, timeout %d ms",
coredev->ir.controller, coredev->ir.timeout);
snprintf(coredev->ir.name,
@@ -274,13 +274,15 @@ int sms_ir_init(struct smscore_device_t *coredev)
coredev->ir.ir_kb_type);
input_dev->name = coredev->ir.name;
input_dev->phys = coredev->ir.name;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
input_dev->dev.parent = coredev->device;
+#endif
/* Key press events only */
input_dev->evbit[0] = BIT_MASK(EV_KEY);
input_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0);
- sms_info("Input device (IR) %s is set for key events", input_dev->name);
+ sms_log("Input device (IR) %s is set for key events", input_dev->name);
if (input_register_device(input_dev)) {
sms_err("Failed to register device");
@@ -296,6 +298,6 @@ void sms_ir_exit(struct smscore_device_t *coredev)
if (coredev->ir.input_dev)
input_unregister_device(coredev->ir.input_dev);
- sms_info("");
+ sms_log("");
}
diff --git a/linux/drivers/media/dvb/siano/smssdio.c b/linux/drivers/media/dvb/siano/smssdio.c
index 4f8fa59a9..dfaa49a53 100644
--- a/linux/drivers/media/dvb/siano/smssdio.c
+++ b/linux/drivers/media/dvb/siano/smssdio.c
@@ -332,7 +332,7 @@ static struct sdio_driver smssdio_driver = {
/* Module functions */
/*******************************************************************/
-int smssdio_register(void)
+int smssdio_module_init(void)
{
int ret = 0;
@@ -344,11 +344,14 @@ int smssdio_register(void)
return ret;
}
-void smssdio_unregister(void)
+void smssdio_module_exit(void)
{
sdio_unregister_driver(&smssdio_driver);
}
+module_init(smssdio_module_init);
+module_exit(smssdio_module_exit);
+
MODULE_DESCRIPTION("Siano SMS1xxx SDIO driver");
MODULE_AUTHOR("Pierre Ossman");
MODULE_LICENSE("GPL");
diff --git a/linux/drivers/media/dvb/siano/smsusb.c b/linux/drivers/media/dvb/siano/smsusb.c
index 7f0246fdb..c31a52d3a 100644
--- a/linux/drivers/media/dvb/siano/smsusb.c
+++ b/linux/drivers/media/dvb/siano/smsusb.c
@@ -78,6 +78,7 @@ static void smsusb_onresponse(struct urb *urb, struct pt_regs *regs)
if ((urb->actual_length > 0) && (urb->status == 0)) {
struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *)surb->cb->p;
+ smsendian_handle_message_header(phdr);
if (urb->actual_length >= phdr->msgLength) {
surb->cb->size = phdr->msgLength;
@@ -488,7 +489,6 @@ static int smsusb_resume(struct usb_interface *intf)
}
struct usb_device_id smsusb_id_table[] = {
-#ifdef CONFIG_DVB_SIANO_SMS1XXX_SMS_IDS
{ USB_DEVICE(0x187f, 0x0010),
.driver_info = SMS1XXX_BOARD_SIANO_STELLAR },
{ USB_DEVICE(0x187f, 0x0100),
@@ -499,7 +499,6 @@ struct usb_device_id smsusb_id_table[] = {
.driver_info = SMS1XXX_BOARD_SIANO_NOVA_B },
{ USB_DEVICE(0x187f, 0x0300),
.driver_info = SMS1XXX_BOARD_SIANO_VEGA },
-#endif
{ USB_DEVICE(0x2040, 0x1700),
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT },
{ USB_DEVICE(0x2040, 0x1800),
@@ -530,8 +529,13 @@ struct usb_device_id smsusb_id_table[] = {
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
{ USB_DEVICE(0x2040, 0x5590),
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
- { } /* Terminating entry */
-};
+ { USB_DEVICE(0x187f, 0x0202),
+ .driver_info = SMS1XXX_BOARD_SIANO_NICE },
+ { USB_DEVICE(0x187f, 0x0301),
+ .driver_info = SMS1XXX_BOARD_SIANO_VENICE },
+ { } /* Terminating entry */
+ };
+
MODULE_DEVICE_TABLE(usb, smsusb_id_table);
static struct usb_driver smsusb_driver = {
@@ -557,14 +561,14 @@ int smsusb_module_init(void)
void smsusb_module_exit(void)
{
- sms_debug("");
/* Regular USB Cleanup */
usb_deregister(&smsusb_driver);
+ sms_info("end");
}
module_init(smsusb_module_init);
module_exit(smsusb_module_exit);
-MODULE_DESCRIPTION("Driver for the Siano SMS1XXX USB dongle");
+MODULE_DESCRIPTION("Driver for the Siano SMS1xxx USB dongle");
MODULE_AUTHOR("Siano Mobile Silicon, INC. (uris@siano-ms.com)");
MODULE_LICENSE("GPL");
diff --git a/linux/drivers/media/radio/dsbr100.c b/linux/drivers/media/radio/dsbr100.c
index bd13bef85..2bb867720 100644
--- a/linux/drivers/media/radio/dsbr100.c
+++ b/linux/drivers/media/radio/dsbr100.c
@@ -33,6 +33,10 @@
History:
+ Version 0.46:
+ Removed usb_dsbr100_open/close calls and radio->users counter. Also,
+ radio->muted changed to radio->status and suspend/resume calls updated.
+
Version 0.45:
Converted to v4l2_device.
@@ -101,8 +105,8 @@
*/
#include <linux/version.h> /* for KERNEL_VERSION MACRO */
-#define DRIVER_VERSION "v0.45"
-#define RADIO_VERSION KERNEL_VERSION(0, 4, 5)
+#define DRIVER_VERSION "v0.46"
+#define RADIO_VERSION KERNEL_VERSION(0, 4, 6)
#define DRIVER_AUTHOR "Markus Demleitner <msdemlei@tucana.harvard.edu>"
#define DRIVER_DESC "D-Link DSB-R100 USB FM radio driver"
@@ -122,13 +126,15 @@ devices, that would be 76 and 91. */
#define FREQ_MAX 108.0
#define FREQ_MUL 16000
+/* defines for radio->status */
+#define STARTED 0
+#define STOPPED 1
+
#define videodev_to_radio(d) container_of(d, struct dsbr100_device, videodev)
static int usb_dsbr100_probe(struct usb_interface *intf,
const struct usb_device_id *id);
static void usb_dsbr100_disconnect(struct usb_interface *intf);
-static int usb_dsbr100_open(struct file *file);
-static int usb_dsbr100_close(struct file *file);
static int usb_dsbr100_suspend(struct usb_interface *intf,
pm_message_t message);
static int usb_dsbr100_resume(struct usb_interface *intf);
@@ -146,9 +152,8 @@ struct dsbr100_device {
struct mutex lock; /* buffer locking */
int curfreq;
int stereo;
- int users;
int removed;
- int muted;
+ int status;
};
static struct usb_device_id usb_dsbr100_device_table [] = {
@@ -204,7 +209,7 @@ static int dsbr100_start(struct dsbr100_device *radio)
goto usb_control_msg_failed;
}
- radio->muted = 0;
+ radio->status = STARTED;
mutex_unlock(&radio->lock);
return (radio->transfer_buffer)[0];
@@ -247,7 +252,7 @@ static int dsbr100_stop(struct dsbr100_device *radio)
goto usb_control_msg_failed;
}
- radio->muted = 1;
+ radio->status = STOPPED;
mutex_unlock(&radio->lock);
return (radio->transfer_buffer)[0];
@@ -261,12 +266,12 @@ usb_control_msg_failed:
}
/* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
-static int dsbr100_setfreq(struct dsbr100_device *radio, int freq)
+static int dsbr100_setfreq(struct dsbr100_device *radio)
{
int retval;
int request;
+ int freq = (radio->curfreq / 16 * 80) / 1000 + 856;
- freq = (freq / 16 * 80) / 1000 + 856;
mutex_lock(&radio->lock);
retval = usb_control_msg(radio->usbdev,
@@ -434,7 +439,7 @@ static int vidioc_s_frequency(struct file *file, void *priv,
radio->curfreq = f->frequency;
mutex_unlock(&radio->lock);
- retval = dsbr100_setfreq(radio, radio->curfreq);
+ retval = dsbr100_setfreq(radio);
if (retval < 0)
dev_warn(&radio->usbdev->dev, "Set frequency failed\n");
return 0;
@@ -476,7 +481,7 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
switch (ctrl->id) {
case V4L2_CID_AUDIO_MUTE:
- ctrl->value = radio->muted;
+ ctrl->value = radio->status;
return 0;
}
return -EINVAL;
@@ -546,65 +551,27 @@ static int vidioc_s_audio(struct file *file, void *priv,
return 0;
}
-static int usb_dsbr100_open(struct file *file)
-{
- struct dsbr100_device *radio = video_drvdata(file);
- int retval;
-
- lock_kernel();
- radio->users = 1;
- radio->muted = 1;
-
- retval = dsbr100_start(radio);
- if (retval < 0) {
- dev_warn(&radio->usbdev->dev,
- "Radio did not start up properly\n");
- radio->users = 0;
- unlock_kernel();
- return -EIO;
- }
-
- retval = dsbr100_setfreq(radio, radio->curfreq);
- if (retval < 0)
- dev_warn(&radio->usbdev->dev,
- "set frequency failed\n");
-
- unlock_kernel();
- return 0;
-}
-
-static int usb_dsbr100_close(struct file *file)
-{
- struct dsbr100_device *radio = video_drvdata(file);
- int retval;
-
- if (!radio)
- return -ENODEV;
-
- mutex_lock(&radio->lock);
- radio->users = 0;
- mutex_unlock(&radio->lock);
-
- if (!radio->removed) {
- retval = dsbr100_stop(radio);
- if (retval < 0) {
- dev_warn(&radio->usbdev->dev,
- "dsbr100_stop failed\n");
- }
-
- }
- return 0;
-}
-
/* Suspend device - stop device. */
static int usb_dsbr100_suspend(struct usb_interface *intf, pm_message_t message)
{
struct dsbr100_device *radio = usb_get_intfdata(intf);
int retval;
- retval = dsbr100_stop(radio);
- if (retval < 0)
- dev_warn(&intf->dev, "dsbr100_stop failed\n");
+ if (radio->status == STARTED) {
+ retval = dsbr100_stop(radio);
+ if (retval < 0)
+ dev_warn(&intf->dev, "dsbr100_stop failed\n");
+
+ /* After dsbr100_stop() status set to STOPPED.
+ * If we want driver to start radio on resume
+ * we set status equal to STARTED.
+ * On resume we will check status and run radio if needed.
+ */
+
+ mutex_lock(&radio->lock);
+ radio->status = STARTED;
+ mutex_unlock(&radio->lock);
+ }
dev_info(&intf->dev, "going into suspend..\n");
@@ -617,9 +584,11 @@ static int usb_dsbr100_resume(struct usb_interface *intf)
struct dsbr100_device *radio = usb_get_intfdata(intf);
int retval;
- retval = dsbr100_start(radio);
- if (retval < 0)
- dev_warn(&intf->dev, "dsbr100_start failed\n");
+ if (radio->status == STARTED) {
+ retval = dsbr100_start(radio);
+ if (retval < 0)
+ dev_warn(&intf->dev, "dsbr100_start failed\n");
+ }
dev_info(&intf->dev, "coming out of suspend..\n");
@@ -639,8 +608,6 @@ static void usb_dsbr100_video_device_release(struct video_device *videodev)
/* File system interface */
static const struct v4l2_file_operations usb_dsbr100_fops = {
.owner = THIS_MODULE,
- .open = usb_dsbr100_open,
- .release = usb_dsbr100_close,
.ioctl = video_ioctl2,
};
@@ -698,9 +665,9 @@ static int usb_dsbr100_probe(struct usb_interface *intf,
mutex_init(&radio->lock);
radio->removed = 0;
- radio->users = 0;
radio->usbdev = interface_to_usbdev(intf);
radio->curfreq = FREQ_MIN * FREQ_MUL;
+ radio->status = STOPPED;
video_set_drvdata(&radio->videodev, radio);
diff --git a/linux/drivers/media/radio/radio-mr800.c b/linux/drivers/media/radio/radio-mr800.c
index 93d5a7aa6..5ff444cee 100644
--- a/linux/drivers/media/radio/radio-mr800.c
+++ b/linux/drivers/media/radio/radio-mr800.c
@@ -64,6 +64,7 @@
#include <media/v4l2-ioctl.h>
#include <linux/usb.h>
#include <linux/version.h> /* for KERNEL_VERSION MACRO */
+#include <linux/mutex.h>
#include "compat.h"
/* driver and module definitions */
diff --git a/linux/drivers/media/radio/radio-tea5764.c b/linux/drivers/media/radio/radio-tea5764.c
index 9194a70aa..83a5aff7b 100644
--- a/linux/drivers/media/radio/radio-tea5764.c
+++ b/linux/drivers/media/radio/radio-tea5764.c
@@ -326,7 +326,9 @@ static int vidioc_g_tuner(struct file *file, void *priv,
v->rangehigh = FREQ_MAX * FREQ_MUL;
v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
if (r->tunchk & TEA5764_TUNCHK_STEREO)
- v->rxsubchans = V4L2_TUNER_SUB_STEREO;
+ v->rxsubchans = V4L2_TUNER_SUB_STEREO;
+ else
+ v->rxsubchans = V4L2_TUNER_SUB_MONO;
v->audmode = tea5764_get_audout_mode(radio);
v->signal = TEA5764_TUNCHK_LEVEL(r->tunchk) * 0xffff / 0xf;
v->afc = TEA5764_TUNCHK_IFCNT(r->tunchk);
diff --git a/linux/drivers/media/video/Kconfig b/linux/drivers/media/video/Kconfig
index 8de867d30..061e147f6 100644
--- a/linux/drivers/media/video/Kconfig
+++ b/linux/drivers/media/video/Kconfig
@@ -776,10 +776,14 @@ config VIDEO_MX1
---help---
This is a v4l2 driver for the i.MX1/i.MXL CMOS Sensor Interface
+config MX3_VIDEO
+ bool
+
config VIDEO_MX3
tristate "i.MX3x Camera Sensor Interface driver"
depends on VIDEO_DEV && MX3_IPU && SOC_CAMERA
select VIDEOBUF_DMA_CONTIG
+ select MX3_VIDEO
---help---
This is a v4l2 driver for the i.MX3x Camera Sensor Interface
@@ -862,9 +866,13 @@ config USB_W9968CF
module will be called w9968cf.
config USB_OV511
- tristate "USB OV511 Camera support"
+ tristate "USB OV511 Camera support (DEPRECATED)"
depends on VIDEO_V4L1
---help---
+ This driver is DEPRECATED please use the gspca ov519 module
+ instead. Note that for the ov511 / ov518 support of the gspca module
+ you need atleast version 0.6.0 of libv4l.
+
Say Y here if you want to connect this type of camera to your
computer's USB port. See <file:Documentation/video4linux/ov511.txt>
for more information and for a list of supported cameras.
diff --git a/linux/drivers/media/video/Makefile b/linux/drivers/media/video/Makefile
index f7d9a4c6f..7fb3add1b 100644
--- a/linux/drivers/media/video/Makefile
+++ b/linux/drivers/media/video/Makefile
@@ -12,6 +12,8 @@ omap2cam-objs := omap24xxcam.o omap24xxcam-dma.o
videodev-objs := v4l2-dev.o v4l2-ioctl.o v4l2-device.o
+# V4L2 core modules
+
obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-int-device.o
ifeq ($(CONFIG_COMPAT),y)
obj-$(CONFIG_VIDEO_DEV) += v4l2-compat-ioctl32.o
@@ -23,21 +25,15 @@ ifeq ($(CONFIG_VIDEO_V4L1_COMPAT),y)
obj-$(CONFIG_VIDEO_DEV) += v4l1-compat.o
endif
-obj-$(CONFIG_VIDEO_TUNER) += tuner.o
+# All i2c modules must come first:
-obj-$(CONFIG_VIDEO_BT848) += bt8xx/
-obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o
+obj-$(CONFIG_VIDEO_TUNER) += tuner.o
obj-$(CONFIG_VIDEO_TVAUDIO) += tvaudio.o
obj-$(CONFIG_VIDEO_TDA7432) += tda7432.o
obj-$(CONFIG_VIDEO_TDA9875) += tda9875.o
-
obj-$(CONFIG_VIDEO_SAA6588) += saa6588.o
obj-$(CONFIG_VIDEO_SAA5246A) += saa5246a.o
obj-$(CONFIG_VIDEO_SAA5249) += saa5249.o
-obj-$(CONFIG_VIDEO_CQCAM) += c-qcam.o
-obj-$(CONFIG_VIDEO_BWQCAM) += bw-qcam.o
-obj-$(CONFIG_VIDEO_W9966) += w9966.o
-
obj-$(CONFIG_VIDEO_TDA9840) += tda9840.o
obj-$(CONFIG_VIDEO_TEA6415C) += tea6415c.o
obj-$(CONFIG_VIDEO_TEA6420) += tea6420.o
@@ -56,11 +52,40 @@ obj-$(CONFIG_VIDEO_BT856) += bt856.o
obj-$(CONFIG_VIDEO_BT866) += bt866.o
obj-$(CONFIG_VIDEO_KS0127) += ks0127.o
obj-$(CONFIG_VIDEO_THS7303) += ths7303.o
+obj-$(CONFIG_VIDEO_VINO) += indycam.o
+obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o
+obj-$(CONFIG_VIDEO_TVP514X) += tvp514x.o
+obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o
+obj-$(CONFIG_VIDEO_CS5345) += cs5345.o
+obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o
+obj-$(CONFIG_VIDEO_M52790) += m52790.o
+obj-$(CONFIG_VIDEO_TLV320AIC23B) += tlv320aic23b.o
+obj-$(CONFIG_VIDEO_WM8775) += wm8775.o
+obj-$(CONFIG_VIDEO_WM8739) += wm8739.o
+obj-$(CONFIG_VIDEO_VP27SMPX) += vp27smpx.o
+obj-$(CONFIG_VIDEO_CX25840) += cx25840/
+obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o
+obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o
+obj-$(CONFIG_VIDEO_OV7670) += ov7670.o
+obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o
+obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o
-obj-$(CONFIG_VIDEO_ZORAN) += zoran/
+obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o
+obj-$(CONFIG_SOC_CAMERA_MT9M111) += mt9m111.o
+obj-$(CONFIG_SOC_CAMERA_MT9T031) += mt9t031.o
+obj-$(CONFIG_SOC_CAMERA_MT9V022) += mt9v022.o
+obj-$(CONFIG_SOC_CAMERA_OV772X) += ov772x.o
+obj-$(CONFIG_SOC_CAMERA_TW9910) += tw9910.o
+
+# And now the v4l2 drivers:
+obj-$(CONFIG_VIDEO_BT848) += bt8xx/
+obj-$(CONFIG_VIDEO_ZORAN) += zoran/
+obj-$(CONFIG_VIDEO_CQCAM) += c-qcam.o
+obj-$(CONFIG_VIDEO_BWQCAM) += bw-qcam.o
+obj-$(CONFIG_VIDEO_W9966) += w9966.o
obj-$(CONFIG_VIDEO_PMS) += pms.o
-obj-$(CONFIG_VIDEO_VINO) += vino.o indycam.o
+obj-$(CONFIG_VIDEO_VINO) += vino.o
obj-$(CONFIG_VIDEO_STRADIS) += stradis.o
obj-$(CONFIG_VIDEO_CPIA) += cpia.o
obj-$(CONFIG_VIDEO_CPIA_PP) += cpia_pp.o
@@ -71,17 +96,7 @@ obj-$(CONFIG_VIDEO_CX88) += cx88/
obj-$(CONFIG_VIDEO_EM28XX) += em28xx/
obj-$(CONFIG_VIDEO_CX231XX) += cx231xx/
obj-$(CONFIG_VIDEO_USBVISION) += usbvision/
-obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o
-obj-$(CONFIG_VIDEO_TVP514X) += tvp514x.o
obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/
-obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o
-obj-$(CONFIG_VIDEO_CS5345) += cs5345.o
-obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o
-obj-$(CONFIG_VIDEO_M52790) += m52790.o
-obj-$(CONFIG_VIDEO_TLV320AIC23B) += tlv320aic23b.o
-obj-$(CONFIG_VIDEO_WM8775) += wm8775.o
-obj-$(CONFIG_VIDEO_WM8739) += wm8739.o
-obj-$(CONFIG_VIDEO_VP27SMPX) += vp27smpx.o
obj-$(CONFIG_VIDEO_OVCAMCHIP) += ovcamchip/
obj-$(CONFIG_VIDEO_CPIA2) += cpia2/
obj-$(CONFIG_VIDEO_MXB) += mxb.o
@@ -94,19 +109,12 @@ obj-$(CONFIG_VIDEOBUF_DMA_CONTIG) += videobuf-dma-contig.o
obj-$(CONFIG_VIDEOBUF_VMALLOC) += videobuf-vmalloc.o
obj-$(CONFIG_VIDEOBUF_DVB) += videobuf-dvb.o
obj-$(CONFIG_VIDEO_BTCX) += btcx-risc.o
-obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o
obj-$(CONFIG_VIDEO_M32R_AR_M64278) += arv.o
-obj-$(CONFIG_VIDEO_CX25840) += cx25840/
-obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o
-obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o
obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o
obj-$(CONFIG_VIDEO_CAFE_CCIC) += cafe_ccic.o
-obj-$(CONFIG_VIDEO_OV7670) += ov7670.o
-
-obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o
obj-$(CONFIG_USB_DABUSB) += dabusb.o
obj-$(CONFIG_USB_OV511) += ov511.o
@@ -138,13 +146,7 @@ obj-$(CONFIG_VIDEO_CX23885) += cx23885/
obj-$(CONFIG_VIDEO_OMAP2) += omap2cam.o
obj-$(CONFIG_SOC_CAMERA) += soc_camera.o
-obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o
-obj-$(CONFIG_SOC_CAMERA_MT9M111) += mt9m111.o
-obj-$(CONFIG_SOC_CAMERA_MT9T031) += mt9t031.o
-obj-$(CONFIG_SOC_CAMERA_MT9V022) += mt9v022.o
-obj-$(CONFIG_SOC_CAMERA_OV772X) += ov772x.o
obj-$(CONFIG_SOC_CAMERA_PLATFORM) += soc_camera_platform.o
-obj-$(CONFIG_SOC_CAMERA_TW9910) += tw9910.o
# soc-camera host drivers have to be linked after camera drivers
obj-$(CONFIG_VIDEO_MX1) += mx1_camera.o
obj-$(CONFIG_VIDEO_MX3) += mx3_camera.o
@@ -155,6 +157,8 @@ obj-$(CONFIG_VIDEO_AU0828) += au0828/
obj-$(CONFIG_USB_VIDEO_CLASS) += uvc/
+obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o
+
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 053bbe8c8..830c4a933 100644
--- a/linux/drivers/media/video/au0828/au0828-cards.c
+++ b/linux/drivers/media/video/au0828/au0828-cards.c
@@ -136,9 +136,9 @@ int au0828_tuner_callback(void *priv, int component, int command, int arg)
/* Tuner Reset Command from xc5000 */
/* Drive the tuner into reset and out */
au0828_clear(dev, REG_001, 2);
- mdelay(200);
+ mdelay(10);
au0828_set(dev, REG_001, 2);
- mdelay(50);
+ mdelay(10);
return 0;
} else {
printk(KERN_ERR
diff --git a/linux/drivers/media/video/au0828/au0828-core.c b/linux/drivers/media/video/au0828/au0828-core.c
index 4da5b7909..0e2f0eb1a 100644
--- a/linux/drivers/media/video/au0828/au0828-core.c
+++ b/linux/drivers/media/video/au0828/au0828-core.c
@@ -37,6 +37,11 @@ int au0828_debug;
module_param_named(debug, au0828_debug, int, 0644);
MODULE_PARM_DESC(debug, "enable debug messages");
+static unsigned int disable_usb_speed_check;
+module_param(disable_usb_speed_check, int, 0444);
+MODULE_PARM_DESC(disable_usb_speed_check,
+ "override min bandwidth requirement of 480M bps");
+
#define _AU0828_BULKPIPE 0x03
#define _BULKPIPESIZE 0xffff
@@ -182,6 +187,18 @@ static int au0828_usb_probe(struct usb_interface *interface,
le16_to_cpu(usbdev->descriptor.idProduct),
ifnum);
+ /*
+ * Make sure we have 480 Mbps of bandwidth, otherwise things like
+ * video stream wouldn't likely work, since 12 Mbps is generally
+ * not enough even for most Digital TV streams.
+ */
+ if (usbdev->speed != USB_SPEED_HIGH && disable_usb_speed_check == 0) {
+ printk(KERN_ERR "au0828: Device initialization failed.\n");
+ printk(KERN_ERR "au0828: Device must be connected to a "
+ "high-speed USB 2.0 port.\n");
+ return -ENODEV;
+ }
+
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (dev == NULL) {
printk(KERN_ERR "%s() Unable to allocate memory\n", __func__);
diff --git a/linux/drivers/media/video/au0828/au0828-video.c b/linux/drivers/media/video/au0828/au0828-video.c
index 8bc0f0481..ef44aa831 100644
--- a/linux/drivers/media/video/au0828/au0828-video.c
+++ b/linux/drivers/media/video/au0828/au0828-video.c
@@ -834,6 +834,9 @@ static int au0828_v4l2_close(struct file *filp)
au0828_uninit_isoc(dev);
+ /* Save some power by putting tuner to sleep */
+ v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_standby);
+
/* When close the device, set the usb intf0 into alt0 to free
USB bandwidth */
ret = usb_set_interface(dev->usbdev, 0, 0);
@@ -915,11 +918,6 @@ static int au0828_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
rc = videobuf_mmap_mapper(&fh->vb_vidq, vma);
- dprintk(2, "vma start=0x%08lx, size=%ld, ret=%d\n",
- (unsigned long)vma->vm_start,
- (unsigned long)vma->vm_end-(unsigned long)vma->vm_start,
- rc);
-
return rc;
}
diff --git a/linux/drivers/media/video/bt8xx/bttv-driver.c b/linux/drivers/media/video/bt8xx/bttv-driver.c
index 622807b54..27be1694b 100644
--- a/linux/drivers/media/video/bt8xx/bttv-driver.c
+++ b/linux/drivers/media/video/bt8xx/bttv-driver.c
@@ -3180,6 +3180,7 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait)
struct bttv_fh *fh = file->private_data;
struct bttv_buffer *buf;
enum v4l2_field field;
+ unsigned int rc = POLLERR;
if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
if (!check_alloc_btres(fh->btv,fh,RESOURCE_VBI))
@@ -3188,9 +3189,10 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait)
}
if (check_btres(fh,RESOURCE_VIDEO_STREAM)) {
+ mutex_lock(&fh->cap.vb_lock);
/* streaming capture */
if (list_empty(&fh->cap.stream))
- return POLLERR;
+ goto err;
buf = list_entry(fh->cap.stream.next,struct bttv_buffer,vb.stream);
} else {
/* read() capture */
@@ -3219,11 +3221,12 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait)
poll_wait(file, &buf->vb.done, wait);
if (buf->vb.state == VIDEOBUF_DONE ||
buf->vb.state == VIDEOBUF_ERROR)
- return POLLIN|POLLRDNORM;
- return 0;
+ rc = POLLIN|POLLRDNORM;
+ else
+ rc = 0;
err:
mutex_unlock(&fh->cap.vb_lock);
- return POLLERR;
+ return rc;
}
static int bttv_open(struct file *file)
@@ -4198,7 +4201,6 @@ static struct video_device *vdev_init(struct bttv *btv,
if (NULL == vfd)
return NULL;
*vfd = *template;
- vfd->minor = -1;
vfd->v4l2_dev = &btv->c.v4l2_dev;
vfd->release = video_device_release;
vfd->debug = bttv_debug;
@@ -4666,7 +4668,7 @@ static int __init bttv_init_module(void)
#endif
if (gbuffers < 2 || gbuffers > VIDEO_MAX_FRAME)
gbuffers = 2;
- if (gbufsize < 0 || gbufsize > BTTV_MAX_FBUF)
+ if (gbufsize > BTTV_MAX_FBUF)
gbufsize = BTTV_MAX_FBUF;
gbufsize = (gbufsize + PAGE_SIZE - 1) & PAGE_MASK;
if (bttv_verbose)
diff --git a/linux/drivers/media/video/bt8xx/bttv-i2c.c b/linux/drivers/media/video/bt8xx/bttv-i2c.c
index bf94551c3..4febaf881 100644
--- a/linux/drivers/media/video/bt8xx/bttv-i2c.c
+++ b/linux/drivers/media/video/bt8xx/bttv-i2c.c
@@ -405,6 +405,29 @@ int __devinit init_bttv_i2c(struct bttv *btv)
}
if (0 == btv->i2c_rc && i2c_scan)
do_i2c_scan(btv->c.v4l2_dev.name, &btv->i2c_client);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
+
+ /* Instantiate the IR receiver device, if present */
+ if (0 == btv->i2c_rc) {
+ struct i2c_board_info info;
+ /* The external IR receiver is at i2c address 0x34 (0x35 for
+ reads). Future Hauppauge cards will have an internal
+ receiver at 0x30 (0x31 for reads). In theory, both can be
+ fitted, and Hauppauge suggest an external overrides an
+ internal.
+
+ That's why we probe 0x1a (~0x34) first. CB
+ */
+ const unsigned short addr_list[] = {
+ 0x1a, 0x18, 0x4b, 0x64, 0x30,
+ I2C_CLIENT_END
+ };
+
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
+ i2c_new_probed_device(&btv->c.i2c_adap, &info, addr_list);
+ }
+#endif
return btv->i2c_rc;
}
diff --git a/linux/drivers/media/video/cx18/cx18-av-core.c b/linux/drivers/media/video/cx18/cx18-av-core.c
index 2b07b1563..536dedb23 100644
--- a/linux/drivers/media/video/cx18/cx18-av-core.c
+++ b/linux/drivers/media/video/cx18/cx18-av-core.c
@@ -277,8 +277,15 @@ void cx18_av_std_setup(struct cx18 *cx)
struct cx18_av_state *state = &cx->av_state;
struct v4l2_subdev *sd = &state->sd;
v4l2_std_id std = state->std;
+
+ /*
+ * Video ADC crystal clock to pixel clock SRC decimation ratio
+ * 28.636360 MHz/13.5 Mpps * 256 = 0x21f.07b
+ */
+ const int src_decimation = 0x21f;
+
int hblank, hactive, burst, vblank, vactive, sc;
- int vblank656, src_decimation;
+ int vblank656;
int luma_lpf, uv_lpf, comb;
u32 pll_int, pll_frac, pll_post;
@@ -288,40 +295,96 @@ void cx18_av_std_setup(struct cx18 *cx)
else
cx18_av_write(cx, 0x49f, 0x14);
+ /*
+ * Note: At the end of a field, there are 3 sets of half line duration
+ * (double horizontal rate) pulses:
+ *
+ * 5 (625) or 6 (525) half-lines to blank for the vertical retrace
+ * 5 (625) or 6 (525) vertical sync pulses of half line duration
+ * 5 (625) or 6 (525) half-lines of equalization pulses
+ */
if (std & V4L2_STD_625_50) {
- /* FIXME - revisit these for Sliced VBI */
+ /*
+ * The following relationships of half line counts should hold:
+ * 625 = vblank656 + vactive
+ * 10 = vblank656 - vblank = vsync pulses + equalization pulses
+ *
+ * vblank656: half lines after line 625/mid-313 of blanked video
+ * vblank: half lines, after line 5/317, of blanked video
+ * vactive: half lines of active video +
+ * 5 half lines after the end of active video
+ *
+ * As far as I can tell:
+ * vblank656 starts counting from the falling edge of the first
+ * vsync pulse (start of line 1 or mid-313)
+ * vblank starts counting from the after the 5 vsync pulses and
+ * 5 or 4 equalization pulses (start of line 6 or 318)
+ *
+ * For 625 line systems the driver will extract VBI information
+ * from lines 6-23 and lines 318-335 (but the slicer can only
+ * handle 17 lines, not the 18 in the vblank region).
+ * In addition, we need vblank656 and vblank to be one whole
+ * line longer, to cover line 24 and 336, so the SAV/EAV RP
+ * codes get generated such that the encoder can actually
+ * extract line 23 & 335 (WSS). We'll lose 1 line in each field
+ * at the top of the screen.
+ *
+ * It appears the 5 half lines that happen after active
+ * video must be included in vactive (579 instead of 574),
+ * otherwise the colors get badly displayed in various regions
+ * of the screen. I guess the chroma comb filter gets confused
+ * without them (at least when a PVR-350 is the PAL source).
+ */
+ vblank656 = 48; /* lines 1 - 24 & 313 - 336 */
+ vblank = 38; /* lines 6 - 24 & 318 - 336 */
+ vactive = 579; /* lines 24 - 313 & 337 - 626 */
+
+ /*
+ * For a 13.5 Mpps clock and 15,625 Hz line rate, a line is
+ * is 864 pixels = 720 active + 144 blanking. ITU-R BT.601
+ * specifies 12 luma clock periods or ~ 0.9 * 13.5 Mpps after
+ * the end of active video to start a horizontal line, so that
+ * leaves 132 pixels of hblank to ignore.
+ */
hblank = 132;
hactive = 720;
- burst = 93;
- vblank = 36;
- vactive = 580;
- vblank656 = 40;
- src_decimation = 0x21f;
+ /*
+ * Burst gate delay (for 625 line systems)
+ * Hsync leading edge to color burst rise = 5.6 us
+ * Color burst width = 2.25 us
+ * Gate width = 4 pixel clocks
+ * (5.6 us + 2.25/2 us) * 13.5 Mpps + 4/2 clocks = 92.79 clocks
+ */
+ burst = 93;
luma_lpf = 2;
if (std & V4L2_STD_PAL) {
uv_lpf = 1;
comb = 0x20;
- sc = 688739;
+ /* sc = 4433618.75 * src_decimation/28636360 * 2^13 */
+ sc = 688700;
} else if (std == V4L2_STD_PAL_Nc) {
uv_lpf = 1;
comb = 0x20;
- sc = 556453;
+ /* sc = 3582056.25 * src_decimation/28636360 * 2^13 */
+ sc = 556422;
} else { /* SECAM */
uv_lpf = 0;
comb = 0;
- sc = 672351;
+ /* (fr + fb)/2 = (4406260 + 4250000)/2 = 4328130 */
+ /* sc = 4328130 * src_decimation/28636360 * 2^13 */
+ sc = 672314;
}
} else {
/*
* The following relationships of half line counts should hold:
- * 525 = vsync + vactive + vblank656
- * 12 = vblank656 - vblank
+ * 525 = prevsync + vblank656 + vactive
+ * 12 = vblank656 - vblank = vsync pulses + equalization pulses
*
- * vsync: always 6 half-lines of vsync pulses
- * vactive: half lines of active video
+ * prevsync: 6 half-lines before the vsync pulses
* vblank656: half lines, after line 3/mid-266, of blanked video
* vblank: half lines, after line 9/272, of blanked video
+ * vactive: half lines of active video
*
* As far as I can tell:
* vblank656 starts counting from the falling edge of the first
@@ -348,20 +411,30 @@ void cx18_av_std_setup(struct cx18 *cx)
luma_lpf = 1;
uv_lpf = 1;
- src_decimation = 0x21f;
+ /*
+ * Burst gate delay (for 525 line systems)
+ * Hsync leading edge to color burst rise = 5.3 us
+ * Color burst width = 2.5 us
+ * Gate width = 4 pixel clocks
+ * (5.3 us + 2.5/2 us) * 13.5 Mpps + 4/2 clocks = 90.425 clocks
+ */
if (std == V4L2_STD_PAL_60) {
- burst = 0x5b;
+ burst = 90;
luma_lpf = 2;
comb = 0x20;
- sc = 688739;
+ /* sc = 4433618.75 * src_decimation/28636360 * 2^13 */
+ sc = 688700;
} else if (std == V4L2_STD_PAL_M) {
- burst = 0x61;
+ /* The 97 needs to be verified against PAL-M timings */
+ burst = 97;
comb = 0x20;
- sc = 555452;
+ /* sc = 3575611.49 * src_decimation/28636360 * 2^13 */
+ sc = 555421;
} else {
- burst = 0x5b;
+ burst = 90;
comb = 0x66;
- sc = 556063;
+ /* sc = 3579545.45.. * src_decimation/28636360 * 2^13 */
+ sc = 556032;
}
}
@@ -373,23 +446,26 @@ void cx18_av_std_setup(struct cx18 *cx)
pll_int, pll_frac, pll_post);
if (pll_post) {
- int fin, fsc, pll;
+ int fsc, pll;
+ u64 tmp;
pll = (28636360L * ((((u64)pll_int) << 25) + pll_frac)) >> 25;
pll /= pll_post;
- CX18_DEBUG_INFO_DEV(sd, "PLL = %d.%06d MHz\n",
+ CX18_DEBUG_INFO_DEV(sd, "Video PLL = %d.%06d MHz\n",
pll / 1000000, pll % 1000000);
- CX18_DEBUG_INFO_DEV(sd, "PLL/8 = %d.%06d MHz\n",
+ CX18_DEBUG_INFO_DEV(sd, "Pixel rate = %d.%06d Mpixel/sec\n",
pll / 8000000, (pll / 8) % 1000000);
- fin = ((u64)src_decimation * pll) >> 12;
- CX18_DEBUG_INFO_DEV(sd, "ADC Sampling freq = %d.%06d MHz\n",
- fin / 1000000, fin % 1000000);
+ CX18_DEBUG_INFO_DEV(sd, "ADC XTAL/pixel clock decimation ratio "
+ "= %d.%03d\n", src_decimation / 256,
+ ((src_decimation % 256) * 1000) / 256);
- fsc = (((u64)sc) * pll) >> 24L;
+ tmp = 28636360 * (u64) sc;
+ do_div(tmp, src_decimation);
+ fsc = tmp >> 13;
CX18_DEBUG_INFO_DEV(sd,
- "Chroma sub-carrier freq = %d.%06d MHz\n",
- fsc / 1000000, fsc % 1000000);
+ "Chroma sub-carrier initial freq = %d.%06d "
+ "MHz\n", fsc / 1000000, fsc % 1000000);
CX18_DEBUG_INFO_DEV(sd, "hblank %i, hactive %i, vblank %i, "
"vactive %i, vblank656 %i, src_dec %i, "
@@ -954,9 +1030,9 @@ static int cx18_av_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
* cx18_av_std_setup(), above standard values:
*
* 480 + 1 for 60 Hz systems
- * 576 + 4 for 50 Hz systems
+ * 576 + 3 for 50 Hz systems
*/
- Vlines = pix->height + (is_50Hz ? 4 : 1);
+ Vlines = pix->height + (is_50Hz ? 3 : 1);
/*
* Invalid height and width scaling requests are:
diff --git a/linux/drivers/media/video/cx18/cx18-av-vbi.c b/linux/drivers/media/video/cx18/cx18-av-vbi.c
index 23b31670b..a51732bcc 100644
--- a/linux/drivers/media/video/cx18/cx18-av-vbi.c
+++ b/linux/drivers/media/video/cx18/cx18-av-vbi.c
@@ -255,8 +255,8 @@ int cx18_av_vbi_s_fmt(struct cx18 *cx, struct v4l2_format *fmt)
}
cx18_av_write(cx, 0x43c, 0x16);
- /* FIXME - should match vblank set in cx18_av_std_setup() */
- cx18_av_write(cx, 0x474, is_pal ? 0x2a : 26);
+ /* Should match vblank set in cx18_av_std_setup() */
+ cx18_av_write(cx, 0x474, is_pal ? 38 : 26);
return 0;
}
diff --git a/linux/drivers/media/video/cx18/cx18-cards.c b/linux/drivers/media/video/cx18/cx18-cards.c
index 8c25ca8e3..fa755a982 100644
--- a/linux/drivers/media/video/cx18/cx18-cards.c
+++ b/linux/drivers/media/video/cx18/cx18-cards.c
@@ -351,13 +351,12 @@ static const struct cx18_card cx18_card_toshiba_qosmio_dvbt = {
static const struct cx18_card_pci_info cx18_pci_leadtek_pvr2100[] = {
{ PCI_DEVICE_ID_CX23418, CX18_PCI_ID_LEADTEK, 0x6f27 }, /* PVR2100 */
- { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_LEADTEK, 0x6690 }, /* DVR3100 H */
{ 0, 0, 0 }
};
static const struct cx18_card cx18_card_leadtek_pvr2100 = {
.type = CX18_CARD_LEADTEK_PVR2100,
- .name = "Leadtek WinFast PVR2100/DVR3100 H",
+ .name = "Leadtek WinFast PVR2100",
.comment = "Experimenters and photos needed for device to work well.\n"
"\tTo help, mail the ivtv-devel list (www.ivtvdriver.org).\n",
.v4l2_capabilities = CX18_CAP_ENCODER,
@@ -376,15 +375,12 @@ static const struct cx18_card cx18_card_leadtek_pvr2100 = {
{ CX18_CARD_INPUT_LINE_IN1, CX18_AV_AUDIO_SERIAL1, 1 },
},
.tuners = {
- /* XC3028 tuner */
+ /* XC2028 tuner */
{ .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
},
.radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 2 },
.ddr = {
- /*
- * Pointer to proper DDR config values provided by
- * Terry Wu <terrywu at leadtek.com.tw>
- */
+ /* Pointer to proper DDR config values provided by Terry Wu */
.chip_config = 0x303,
.refresh = 0x3bb,
.timing1 = 0x24220e83,
@@ -403,6 +399,58 @@ static const struct cx18_card cx18_card_leadtek_pvr2100 = {
/* ------------------------------------------------------------------------- */
+/* Leadtek WinFast DVR3100 H */
+
+static const struct cx18_card_pci_info cx18_pci_leadtek_dvr3100h[] = {
+ { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_LEADTEK, 0x6690 }, /* DVR3100 H */
+ { 0, 0, 0 }
+};
+
+static const struct cx18_card cx18_card_leadtek_dvr3100h = {
+ .type = CX18_CARD_LEADTEK_DVR3100H,
+ .name = "Leadtek WinFast DVR3100 H",
+ .comment = "Simultaneous DVB-T and Analog capture supported,\n"
+ "\texcept when capturing Analog from the antenna input.\n",
+ .v4l2_capabilities = CX18_CAP_ENCODER,
+ .hw_audio_ctrl = CX18_HW_418_AV,
+ .hw_muxer = CX18_HW_GPIO_MUX,
+ .hw_all = CX18_HW_418_AV | CX18_HW_TUNER | CX18_HW_GPIO_MUX |
+ CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL,
+ .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_COMPOSITE7 },
+ },
+ .audio_inputs = {
+ { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 0 },
+ { CX18_CARD_INPUT_LINE_IN1, CX18_AV_AUDIO_SERIAL1, 1 },
+ },
+ .tuners = {
+ /* XC3028 tuner */
+ { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
+ },
+ .radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 2 },
+ .ddr = {
+ /* Pointer to proper DDR config values provided by Terry Wu */
+ .chip_config = 0x303,
+ .refresh = 0x3bb,
+ .timing1 = 0x24220e83,
+ .timing2 = 0x1f,
+ .tune_lane = 0,
+ .initial_emrs = 0x2,
+ },
+ .gpio_init.initial_value = 0x6,
+ .gpio_init.direction = 0x7,
+ .gpio_audio_input = { .mask = 0x7,
+ .tuner = 0x6, .linein = 0x2, .radio = 0x2 },
+ .xceive_pin = 1,
+ .pci_list = cx18_pci_leadtek_dvr3100h,
+ .i2c = &cx18_i2c_std,
+};
+
+/* ------------------------------------------------------------------------- */
+
static const struct cx18_card *cx18_card_list[] = {
&cx18_card_hvr1600_esmt,
&cx18_card_hvr1600_samsung,
@@ -411,6 +459,7 @@ static const struct cx18_card *cx18_card_list[] = {
&cx18_card_cnxt_raptor_pal,
&cx18_card_toshiba_qosmio_dvbt,
&cx18_card_leadtek_pvr2100,
+ &cx18_card_leadtek_dvr3100h,
};
const struct cx18_card *cx18_get_card(u16 index)
diff --git a/linux/drivers/media/video/cx18/cx18-controls.c b/linux/drivers/media/video/cx18/cx18-controls.c
index 8e35c3aed..5136df198 100644
--- a/linux/drivers/media/video/cx18/cx18-controls.c
+++ b/linux/drivers/media/video/cx18/cx18-controls.c
@@ -61,6 +61,8 @@ int cx18_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qctrl)
switch (qctrl->id) {
/* Standard V4L2 controls */
+ case V4L2_CID_USER_CLASS:
+ return v4l2_ctrl_query_fill(qctrl, 0, 0, 0, 0);
case V4L2_CID_BRIGHTNESS:
case V4L2_CID_HUE:
case V4L2_CID_SATURATION:
diff --git a/linux/drivers/media/video/cx18/cx18-driver.c b/linux/drivers/media/video/cx18/cx18-driver.c
index f42a97314..7ffdda49c 100644
--- a/linux/drivers/media/video/cx18/cx18-driver.c
+++ b/linux/drivers/media/video/cx18/cx18-driver.c
@@ -152,7 +152,8 @@ MODULE_PARM_DESC(cardtype,
"\t\t\t 4 = Yuan MPC718\n"
"\t\t\t 5 = Conexant Raptor PAL/SECAM\n"
"\t\t\t 6 = Toshiba Qosmio DVB-T/Analog\n"
- "\t\t\t 7 = Leadtek WinFast PVR2100/DVR3100 H\n"
+ "\t\t\t 7 = Leadtek WinFast PVR2100\n"
+ "\t\t\t 8 = Leadtek WinFast DVR3100 H\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");
diff --git a/linux/drivers/media/video/cx18/cx18-driver.h b/linux/drivers/media/video/cx18/cx18-driver.h
index f89b82367..c6a1e907f 100644
--- a/linux/drivers/media/video/cx18/cx18-driver.h
+++ b/linux/drivers/media/video/cx18/cx18-driver.h
@@ -80,8 +80,9 @@
#define CX18_CARD_YUAN_MPC718 3 /* Yuan MPC718 */
#define CX18_CARD_CNXT_RAPTOR_PAL 4 /* Conexant Raptor PAL */
#define CX18_CARD_TOSHIBA_QOSMIO_DVBT 5 /* Toshiba Qosmio Interal DVB-T/Analog*/
-#define CX18_CARD_LEADTEK_PVR2100 6 /* Leadtek WinFast PVR2100/DVR3100 H */
-#define CX18_CARD_LAST 6
+#define CX18_CARD_LEADTEK_PVR2100 6 /* Leadtek WinFast PVR2100 */
+#define CX18_CARD_LEADTEK_DVR3100H 7 /* Leadtek WinFast DVR3100 H */
+#define CX18_CARD_LAST 7
#define CX18_ENC_STREAM_TYPE_MPG 0
#define CX18_ENC_STREAM_TYPE_TS 1
diff --git a/linux/drivers/media/video/cx18/cx18-dvb.c b/linux/drivers/media/video/cx18/cx18-dvb.c
index e7285a109..6ea3fe623 100644
--- a/linux/drivers/media/video/cx18/cx18-dvb.c
+++ b/linux/drivers/media/video/cx18/cx18-dvb.c
@@ -26,12 +26,17 @@
#include "cx18-queue.h"
#include "cx18-streams.h"
#include "cx18-cards.h"
+#include "cx18-gpio.h"
#include "s5h1409.h"
#include "mxl5005s.h"
+#include "zl10353.h"
+#include "tuner-xc2028.h"
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
#define CX18_REG_DMUX_NUM_PORT_0_CONTROL 0xd5a000
+#define CX18_CLOCK_ENABLE2 0xc71024
+#define CX18_DMUX_CLK_MASK 0x0080
static struct mxl5005s_config hauppauge_hvr1600_tuner = {
.i2c_address = 0xC6 >> 1,
@@ -58,7 +63,15 @@ static struct s5h1409_config hauppauge_hvr1600_config = {
.inversion = S5H1409_INVERSION_OFF,
.status_mode = S5H1409_DEMODLOCKING,
.mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK
+};
+/* Information/confirmation of proper config values provided by Terry Wu */
+static struct zl10353_config leadtek_dvr3100h_demod = {
+ .demod_address = 0x1e >> 1, /* Datasheet suggested straps */
+ .if2 = 45600, /* 4.560 MHz IF from the XC3028 */
+ .parallel_ts = 1, /* Not a serial TS */
+ .no_tuner = 1, /* XC3028 is not behind the gate */
+ .disable_i2c_gate_ctrl = 1, /* Disable the I2C gate */
};
static int dvb_register(struct cx18_stream *stream);
@@ -99,6 +112,7 @@ static int cx18_dvb_start_feed(struct dvb_demux_feed *feed)
cx18_write_reg(cx, v, CX18_REG_DMUX_NUM_PORT_0_CONTROL);
break;
+ case CX18_CARD_LEADTEK_DVR3100H:
default:
/* Assumption - Parallel transport - Signalling
* undefined or default.
@@ -268,8 +282,7 @@ void cx18_dvb_unregister(struct cx18_stream *stream)
}
/* All the DVB attach calls go here, this function get's modified
- * for each new card. No other function in this file needs
- * to change.
+ * for each new card. cx18_dvb_start_feed() will also need changes.
*/
static int dvb_register(struct cx18_stream *stream)
{
@@ -290,6 +303,29 @@ static int dvb_register(struct cx18_stream *stream)
ret = 0;
}
break;
+ case CX18_CARD_LEADTEK_DVR3100H:
+ dvb->fe = dvb_attach(zl10353_attach,
+ &leadtek_dvr3100h_demod,
+ &cx->i2c_adap[1]);
+ if (dvb->fe != NULL) {
+ struct dvb_frontend *fe;
+ struct xc2028_config cfg = {
+ .i2c_adap = &cx->i2c_adap[1],
+ .i2c_addr = 0xc2 >> 1,
+ .ctrl = NULL,
+ };
+ static struct xc2028_ctrl ctrl = {
+ .fname = XC2028_DEFAULT_FIRMWARE,
+ .max_len = 64,
+ .demod = XC3028_FE_ZARLINK456,
+ .type = XC2028_AUTO,
+ };
+
+ fe = dvb_attach(xc2028_attach, dvb->fe, &cfg);
+ if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
+ fe->ops.tuner_ops.set_config(fe, &ctrl);
+ }
+ break;
default:
/* No Digital Tv Support */
break;
@@ -300,6 +336,8 @@ static int dvb_register(struct cx18_stream *stream)
return -1;
}
+ dvb->fe->callback = cx18_reset_tuner_gpio;
+
ret = dvb_register_frontend(&dvb->dvb_adapter, dvb->fe);
if (ret < 0) {
if (dvb->fe->ops.release)
@@ -307,5 +345,16 @@ static int dvb_register(struct cx18_stream *stream)
return ret;
}
+ /*
+ * The firmware seems to enable the TS DMUX clock
+ * under various circumstances. However, since we know we
+ * might use it, let's just turn it on ourselves here.
+ */
+ cx18_write_reg_expect(cx,
+ (CX18_DMUX_CLK_MASK << 16) | CX18_DMUX_CLK_MASK,
+ CX18_CLOCK_ENABLE2,
+ CX18_DMUX_CLK_MASK,
+ (CX18_DMUX_CLK_MASK << 16) | CX18_DMUX_CLK_MASK);
+
return ret;
}
diff --git a/linux/drivers/media/video/cx18/cx18-streams.c b/linux/drivers/media/video/cx18/cx18-streams.c
index 142302ba5..c134927b3 100644
--- a/linux/drivers/media/video/cx18/cx18-streams.c
+++ b/linux/drivers/media/video/cx18/cx18-streams.c
@@ -376,9 +376,14 @@ static void cx18_vbi_setup(struct cx18_stream *s)
* Tell the encoder to capture 21-4+1=18 lines per field,
* since we want lines 10 through 21.
*
- * FIXME - revisit for 625/50 systems
+ * For 625/50 systems, according to the VIP 2 & BT.656 std:
+ * The EAV RP code's Field bit toggles on line 1, a few lines
+ * after the Vertcal Blank bit has already toggled.
+ * (We've actually set the digitizer so that the Field bit
+ * toggles on line 2.) Tell the encoder to capture 23-2+1=22
+ * lines per field, since we want lines 6 through 23.
*/
- lines = cx->is_60hz ? (21 - 4 + 1) * 2 : 38;
+ lines = cx->is_60hz ? (21 - 4 + 1) * 2 : (23 - 2 + 1) * 2;
}
data[0] = s->handle;
diff --git a/linux/drivers/media/video/cx231xx/cx231xx-avcore.c b/linux/drivers/media/video/cx231xx/cx231xx-avcore.c
index 6a9464079..28f48f41f 100644
--- a/linux/drivers/media/video/cx231xx/cx231xx-avcore.c
+++ b/linux/drivers/media/video/cx231xx/cx231xx-avcore.c
@@ -1052,22 +1052,13 @@ int cx231xx_set_audio_decoder_input(struct cx231xx *dev,
/* Set resolution of the video */
int cx231xx_resolution_set(struct cx231xx *dev)
{
- int width, height;
- u32 hscale, vscale;
- int status = 0;
-
- width = dev->width;
- height = dev->height;
-
- get_scale(dev, width, height, &hscale, &vscale);
-
/* set horzontal scale */
- status = vid_blk_write_word(dev, HSCALE_CTRL, hscale);
+ int status = vid_blk_write_word(dev, HSCALE_CTRL, dev->hscale);
+ if (status)
+ return status;
/* set vertical scale */
- status = vid_blk_write_word(dev, VSCALE_CTRL, vscale);
-
- return status;
+ return vid_blk_write_word(dev, VSCALE_CTRL, dev->vscale);
}
/******************************************************************************
@@ -2055,7 +2046,7 @@ int cx231xx_initialize_stream_xfer(struct cx231xx *dev, u32 media_type)
int cx231xx_capture_start(struct cx231xx *dev, int start, u8 media_type)
{
- int rc;
+ int rc = -1;
u32 ep_mask = -1;
struct pcb_config *pcb_config;
diff --git a/linux/drivers/media/video/cx231xx/cx231xx-cards.c b/linux/drivers/media/video/cx231xx/cx231xx-cards.c
index af6169516..f388262bd 100644
--- a/linux/drivers/media/video/cx231xx/cx231xx-cards.c
+++ b/linux/drivers/media/video/cx231xx/cx231xx-cards.c
@@ -282,12 +282,25 @@ static void cx231xx_config_tuner(struct cx231xx *dev)
}
/* ----------------------------------------------------------------------- */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
void cx231xx_set_ir(struct cx231xx *dev, struct IR_i2c *ir)
+#else
+void cx231xx_register_i2c_ir(struct cx231xx *dev)
+#endif
{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
if (disable_ir) {
ir->get_key = NULL;
+#else
+ if (disable_ir)
+#endif
return;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
}
+#else
+
+ /* REVISIT: instantiate IR device */
+#endif
/* detect & configure */
switch (dev->model) {
diff --git a/linux/drivers/media/video/cx231xx/cx231xx-i2c.c b/linux/drivers/media/video/cx231xx/cx231xx-i2c.c
index d196fe666..4525fab35 100644
--- a/linux/drivers/media/video/cx231xx/cx231xx-i2c.c
+++ b/linux/drivers/media/video/cx231xx/cx231xx-i2c.c
@@ -424,34 +424,6 @@ static u32 functionality(struct i2c_adapter *adap)
return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C;
}
-/*
- * attach_inform()
- * gets called when a device attaches to the i2c bus
- * does some basic configuration
- */
-static int attach_inform(struct i2c_client *client)
-{
- struct cx231xx_i2c *bus = i2c_get_adapdata(client->adapter);
- struct cx231xx *dev = bus->dev;
-
- switch (client->addr << 1) {
- case 0x8e:
- {
- struct IR_i2c *ir = i2c_get_clientdata(client);
- dprintk1(1, "attach_inform: IR detected (%s).\n",
- ir->phys);
- cx231xx_set_ir(dev, ir);
- break;
- }
- break;
-
- default:
- break;
- }
-
- return 0;
-}
-
static struct i2c_algorithm cx231xx_algo = {
.master_xfer = cx231xx_i2c_xfer,
.functionality = functionality,
@@ -465,7 +437,6 @@ static struct i2c_adapter cx231xx_adap_template = {
.name = "cx231xx",
.id = I2C_HW_B_CX231XX,
.algo = &cx231xx_algo,
- .client_register = attach_inform,
};
static struct i2c_client cx231xx_client_template = {
@@ -540,6 +511,11 @@ int cx231xx_i2c_register(struct cx231xx_i2c *bus)
if (0 == bus->i2c_rc) {
if (i2c_scan)
cx231xx_do_i2c_scan(dev, &bus->i2c_client);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
+
+ /* Instantiate the IR receiver device, if present */
+ cx231xx_register_i2c_ir(dev);
+#endif
} else
cx231xx_warn("%s: i2c bus %d register FAILED\n",
dev->name, bus->nr);
diff --git a/linux/drivers/media/video/cx231xx/cx231xx-input.c b/linux/drivers/media/video/cx231xx/cx231xx-input.c
index 04d954cca..3171b0177 100644
--- a/linux/drivers/media/video/cx231xx/cx231xx-input.c
+++ b/linux/drivers/media/video/cx231xx/cx231xx-input.c
@@ -37,7 +37,7 @@ MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]");
#define i2cdprintk(fmt, arg...) \
if (ir_debug) { \
- printk(KERN_DEBUG "%s/ir: " fmt, ir->c.name , ## arg); \
+ printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg); \
}
#define dprintk(fmt, arg...) \
diff --git a/linux/drivers/media/video/cx231xx/cx231xx-video.c b/linux/drivers/media/video/cx231xx/cx231xx-video.c
index 638a8d3e4..e00edd0aa 100644
--- a/linux/drivers/media/video/cx231xx/cx231xx-video.c
+++ b/linux/drivers/media/video/cx231xx/cx231xx-video.c
@@ -893,9 +893,9 @@ static int check_dev(struct cx231xx *dev)
return 0;
}
-void get_scale(struct cx231xx *dev,
- unsigned int width, unsigned int height,
- unsigned int *hscale, unsigned int *vscale)
+static void get_scale(struct cx231xx *dev,
+ unsigned int width, unsigned int height,
+ unsigned int *hscale, unsigned int *vscale)
{
unsigned int maxw = norm_maxw(dev);
unsigned int maxh = norm_maxh(dev);
@@ -907,10 +907,6 @@ void get_scale(struct cx231xx *dev,
*vscale = (((unsigned long)maxh) << 12) / height - 4096L;
if (*vscale >= 0x4000)
*vscale = 0x3fff;
-
- dev->hscale = *hscale;
- dev->vscale = *vscale;
-
}
/* ------------------------------------------------------------------
@@ -955,8 +951,8 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
{
struct cx231xx_fh *fh = priv;
struct cx231xx *dev = fh->dev;
- int width = f->fmt.pix.width;
- int height = f->fmt.pix.height;
+ unsigned int width = f->fmt.pix.width;
+ unsigned int height = f->fmt.pix.height;
unsigned int maxw = norm_maxw(dev);
unsigned int maxh = norm_maxh(dev);
unsigned int hscale, vscale;
@@ -971,17 +967,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
/* width must even because of the YUYV format
height must be even because of interlacing */
- height &= 0xfffe;
- width &= 0xfffe;
-
- if (unlikely(height < 32))
- height = 32;
- if (unlikely(height > maxh))
- height = maxh;
- if (unlikely(width < 48))
- width = 48;
- if (unlikely(width > maxw))
- width = maxw;
+ v4l_bound_align_image(&width, 48, maxw, 1, &height, 32, maxh, 1, 0);
get_scale(dev, width, height, &hscale, &vscale);
diff --git a/linux/drivers/media/video/cx231xx/cx231xx.h b/linux/drivers/media/video/cx231xx/cx231xx.h
index 21b4023dd..051ca21c1 100644
--- a/linux/drivers/media/video/cx231xx/cx231xx.h
+++ b/linux/drivers/media/video/cx231xx/cx231xx.h
@@ -731,9 +731,6 @@ int cx231xx_set_video_input_mux(struct cx231xx *dev, u8 input);
int cx231xx_set_decoder_video_input(struct cx231xx *dev, u8 pin_type, u8 input);
int cx231xx_do_mode_ctrl_overrides(struct cx231xx *dev);
int cx231xx_set_audio_input(struct cx231xx *dev, u8 input);
-void get_scale(struct cx231xx *dev,
- unsigned int width, unsigned int height,
- unsigned int *hscale, unsigned int *vscale);
/* Provided by cx231xx-video.c */
int cx231xx_register_extension(struct cx231xx_ops *dev);
@@ -747,7 +744,11 @@ extern void cx231xx_card_setup(struct cx231xx *dev);
extern struct cx231xx_board cx231xx_boards[];
extern struct usb_device_id cx231xx_id_table[];
extern const unsigned int cx231xx_bcount;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
void cx231xx_set_ir(struct cx231xx *dev, struct IR_i2c *ir);
+#else
+void cx231xx_register_i2c_ir(struct cx231xx *dev);
+#endif
int cx231xx_tuner_callback(void *ptr, int component, int command, int arg);
/* Provided by cx231xx-input.c */
diff --git a/linux/drivers/media/video/cx2341x.c b/linux/drivers/media/video/cx2341x.c
index 2cf0c5fee..8c468fc86 100644
--- a/linux/drivers/media/video/cx2341x.c
+++ b/linux/drivers/media/video/cx2341x.c
@@ -501,6 +501,8 @@ int cx2341x_ctrl_query(const struct cx2341x_mpeg_params *params,
int err;
switch (qctrl->id) {
+ case V4L2_CID_MPEG_CLASS:
+ return v4l2_ctrl_query_fill(qctrl, 0, 0, 0, 0);
case V4L2_CID_MPEG_STREAM_TYPE:
return v4l2_ctrl_query_fill(qctrl,
V4L2_MPEG_STREAM_TYPE_MPEG2_PS,
diff --git a/linux/drivers/media/video/cx23885/cx23885-417.c b/linux/drivers/media/video/cx23885/cx23885-417.c
index 574cdb385..9974d9a78 100644
--- a/linux/drivers/media/video/cx23885/cx23885-417.c
+++ b/linux/drivers/media/video/cx23885/cx23885-417.c
@@ -1749,7 +1749,6 @@ static struct video_device *cx23885_video_dev_alloc(
if (NULL == vfd)
return NULL;
*vfd = *template;
- vfd->minor = -1;
snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name,
type, cx23885_boards[tsport->dev->board].name);
vfd->parent = &pci->dev;
diff --git a/linux/drivers/media/video/cx23885/cx23885-cards.c b/linux/drivers/media/video/cx23885/cx23885-cards.c
index 93176fe4b..35b2abd6a 100644
--- a/linux/drivers/media/video/cx23885/cx23885-cards.c
+++ b/linux/drivers/media/video/cx23885/cx23885-cards.c
@@ -198,6 +198,10 @@ struct cx23885_board cx23885_boards[] = {
.name = "Hauppauge WinTV-HVR1210",
.portc = CX23885_MPEG_DVB,
},
+ [CX23885_BOARD_MYGICA_X8506] = {
+ .name = "Mygica X8506 DMB-TH",
+ .portb = CX23885_MPEG_DVB,
+ },
};
const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
@@ -317,6 +321,10 @@ struct cx23885_subid cx23885_subids[] = {
.subvendor = 0x0070,
.subdevice = 0x2295,
.card = CX23885_BOARD_HAUPPAUGE_HVR1210,
+ }, {
+ .subvendor = 0x14f1,
+ .subdevice = 0x8651,
+ .card = CX23885_BOARD_MYGICA_X8506,
},
};
const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
@@ -707,6 +715,15 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
mdelay(20);
cx23885_gpio_set(dev, GPIO_9);
break;
+ case CX23885_BOARD_MYGICA_X8506:
+ /* GPIO-1 reset XC5000 */
+ /* GPIO-2 reset LGS8GL5 */
+ cx_set(GP0_IO, 0x00060000);
+ cx_clear(GP0_IO, 0x00000006);
+ mdelay(100);
+ cx_set(GP0_IO, 0x00060006);
+ mdelay(100);
+ break;
}
}
@@ -810,6 +827,11 @@ void cx23885_card_setup(struct cx23885_dev *dev)
ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
break;
+ case CX23885_BOARD_MYGICA_X8506:
+ ts1->gen_ctrl_val = 0x5; /* Parallel */
+ ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+ ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+ break;
case CX23885_BOARD_HAUPPAUGE_HVR1250:
case CX23885_BOARD_HAUPPAUGE_HVR1500:
case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
diff --git a/linux/drivers/media/video/cx23885/cx23885-dvb.c b/linux/drivers/media/video/cx23885/cx23885-dvb.c
index 499beaf3d..71f196ec5 100644
--- a/linux/drivers/media/video/cx23885/cx23885-dvb.c
+++ b/linux/drivers/media/video/cx23885/cx23885-dvb.c
@@ -46,10 +46,12 @@
#include "dibx000_common.h"
#include "zl10353.h"
#include "stv0900.h"
+#include "stv0900_reg.h"
#include "stv6110.h"
#include "lnbh24.h"
#include "cx24116.h"
#include "cimax2.h"
+#include "lgs8gxx.h"
#include "netup-eeprom.h"
#include "netup-init.h"
#include "lgdt3305.h"
@@ -380,13 +382,25 @@ static struct zl10353_config dvico_fusionhdtv_xc3028 = {
.disable_i2c_gate_ctrl = 1,
};
+static struct stv0900_reg stv0900_ts_regs[] = {
+ { R0900_TSGENERAL, 0x00 },
+ { R0900_P1_TSSPEED, 0x40 },
+ { R0900_P2_TSSPEED, 0x40 },
+ { R0900_P1_TSCFGM, 0xc0 },
+ { R0900_P2_TSCFGM, 0xc0 },
+ { R0900_P1_TSCFGH, 0xe0 },
+ { R0900_P2_TSCFGH, 0xe0 },
+ { R0900_P1_TSCFGL, 0x20 },
+ { R0900_P2_TSCFGL, 0x20 },
+ { 0xffff, 0xff }, /* terminate */
+};
+
static struct stv0900_config netup_stv0900_config = {
.demod_address = 0x68,
.xtal = 27000000,
.clkmode = 3,/* 0-CLKI, 2-XTALI, else AUTO */
.diseqc_mode = 2,/* 2/3 PWM */
- .path1_mode = 2,/*Serial continues clock */
- .path2_mode = 2,/*Serial continues clock */
+ .ts_config_regs = stv0900_ts_regs,
.tun1_maddress = 0,/* 0x60 */
.tun2_maddress = 3,/* 0x63 */
.tun1_adc = 1,/* 1 Vpp */
@@ -431,10 +445,29 @@ static struct cx24116_config dvbworld_cx24116_config = {
.demod_address = 0x05,
};
+static struct lgs8gxx_config mygica_x8506_lgs8gl5_config = {
+ .prod = LGS8GXX_PROD_LGS8GL5,
+ .demod_address = 0x19,
+ .serial_ts = 0,
+ .ts_clk_pol = 1,
+ .ts_clk_gated = 1,
+ .if_clk_freq = 30400, /* 30.4 MHz */
+ .if_freq = 5380, /* 5.38 MHz */
+ .if_neg_center = 1,
+ .ext_adc = 0,
+ .adc_signed = 0,
+ .if_neg_edge = 0,
+};
+
+static struct xc5000_config mygica_x8506_xc5000_config = {
+ .i2c_address = 0x61,
+ .if_khz = 5380,
+};
+
static int dvb_register(struct cx23885_tsport *port)
{
struct cx23885_dev *dev = port->dev;
- struct cx23885_i2c *i2c_bus = NULL;
+ struct cx23885_i2c *i2c_bus = NULL, *i2c_bus2 = NULL;
struct videobuf_dvb_frontend *fe0;
int ret;
@@ -727,7 +760,8 @@ static int dvb_register(struct cx23885_tsport *port)
if (!dvb_attach(lnbh24_attach,
fe0->dvb.frontend,
&i2c_bus->i2c_adap,
- LNBH24_PCL, 0, 0x09))
+ LNBH24_PCL,
+ LNBH24_TTX, 0x09))
printk(KERN_ERR
"No LNBH24 found!\n");
@@ -747,7 +781,8 @@ static int dvb_register(struct cx23885_tsport *port)
if (!dvb_attach(lnbh24_attach,
fe0->dvb.frontend,
&i2c_bus->i2c_adap,
- LNBH24_PCL, 0, 0x0a))
+ LNBH24_PCL,
+ LNBH24_TTX, 0x0a))
printk(KERN_ERR
"No LNBH24 found!\n");
@@ -756,6 +791,19 @@ static int dvb_register(struct cx23885_tsport *port)
break;
}
break;
+ case CX23885_BOARD_MYGICA_X8506:
+ i2c_bus = &dev->i2c_bus[0];
+ i2c_bus2 = &dev->i2c_bus[1];
+ fe0->dvb.frontend = dvb_attach(lgs8gxx_attach,
+ &mygica_x8506_lgs8gl5_config,
+ &i2c_bus->i2c_adap);
+ if (fe0->dvb.frontend != NULL) {
+ dvb_attach(xc5000_attach,
+ fe0->dvb.frontend,
+ &i2c_bus2->i2c_adap,
+ &mygica_x8506_xc5000_config);
+ }
+ break;
default:
printk(KERN_INFO "%s: The frontend of your DVB/ATSC card "
" isn't supported yet\n",
diff --git a/linux/drivers/media/video/cx23885/cx23885-i2c.c b/linux/drivers/media/video/cx23885/cx23885-i2c.c
index a5d9f7530..2e3f3d37c 100644
--- a/linux/drivers/media/video/cx23885/cx23885-i2c.c
+++ b/linux/drivers/media/video/cx23885/cx23885-i2c.c
@@ -364,6 +364,20 @@ int cx23885_i2c_register(struct cx23885_i2c *bus)
printk(KERN_WARNING "%s: i2c bus %d register FAILED\n",
dev->name, bus->nr);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
+ /* Instantiate the IR receiver device, if present */
+ if (0 == bus->i2c_rc) {
+ struct i2c_board_info info;
+ const unsigned short addr_list[] = {
+ 0x6b, I2C_CLIENT_END
+ };
+
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
+ i2c_new_probed_device(&bus->i2c_adap, &info, addr_list);
+ }
+
+#endif
return bus->i2c_rc;
}
diff --git a/linux/drivers/media/video/cx23885/cx23885-video.c b/linux/drivers/media/video/cx23885/cx23885-video.c
index 2855a49b5..2248e0216 100644
--- a/linux/drivers/media/video/cx23885/cx23885-video.c
+++ b/linux/drivers/media/video/cx23885/cx23885-video.c
@@ -865,6 +865,7 @@ static unsigned int video_poll(struct file *file,
{
struct cx23885_fh *fh = file->private_data;
struct cx23885_buffer *buf;
+ unsigned int rc = POLLERR;
if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
if (!res_get(fh->dev, fh, RESOURCE_VBI))
@@ -872,23 +873,28 @@ static unsigned int video_poll(struct file *file,
return videobuf_poll_stream(file, &fh->vbiq, wait);
}
+ mutex_lock(&fh->vidq.vb_lock);
if (res_check(fh, RESOURCE_VIDEO)) {
/* streaming capture */
if (list_empty(&fh->vidq.stream))
- return POLLERR;
+ goto done;
buf = list_entry(fh->vidq.stream.next,
struct cx23885_buffer, vb.stream);
} else {
/* read() capture */
buf = (struct cx23885_buffer *)fh->vidq.read_buf;
if (NULL == buf)
- return POLLERR;
+ goto done;
}
poll_wait(file, &buf->vb.done, wait);
if (buf->vb.state == VIDEOBUF_DONE ||
buf->vb.state == VIDEOBUF_ERROR)
- return POLLIN|POLLRDNORM;
- return 0;
+ rc = POLLIN|POLLRDNORM;
+ else
+ rc = 0;
+done:
+ mutex_unlock(&fh->vidq.vb_lock);
+ return rc;
}
static int video_release(struct file *file)
@@ -1035,15 +1041,8 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
}
f->fmt.pix.field = field;
- if (f->fmt.pix.height < 32)
- f->fmt.pix.height = 32;
- if (f->fmt.pix.height > maxh)
- f->fmt.pix.height = maxh;
- if (f->fmt.pix.width < 48)
- f->fmt.pix.width = 48;
- if (f->fmt.pix.width > maxw)
- f->fmt.pix.width = maxw;
- f->fmt.pix.width &= ~0x03;
+ v4l_bound_align_image(&f->fmt.pix.width, 48, maxw, 2,
+ &f->fmt.pix.height, 32, maxh, 0, 0);
f->fmt.pix.bytesperline =
(f->fmt.pix.width * fmt->depth) >> 3;
f->fmt.pix.sizeimage =
diff --git a/linux/drivers/media/video/cx23885/cx23885.h b/linux/drivers/media/video/cx23885/cx23885.h
index 8dba2fdd6..2022ed7de 100644
--- a/linux/drivers/media/video/cx23885/cx23885.h
+++ b/linux/drivers/media/video/cx23885/cx23885.h
@@ -76,6 +76,7 @@
#define CX23885_BOARD_HAUPPAUGE_HVR1275 19
#define CX23885_BOARD_HAUPPAUGE_HVR1255 20
#define CX23885_BOARD_HAUPPAUGE_HVR1210 21
+#define CX23885_BOARD_MYGICA_X8506 22
#define GPIO_0 0x00000001
#define GPIO_1 0x00000002
diff --git a/linux/drivers/media/video/cx88/cx88-alsa.c b/linux/drivers/media/video/cx88/cx88-alsa.c
index 077c9f0d7..4b9f1bb22 100644
--- a/linux/drivers/media/video/cx88/cx88-alsa.c
+++ b/linux/drivers/media/video/cx88/cx88-alsa.c
@@ -939,7 +939,7 @@ static struct pci_driver cx88_audio_pci_driver = {
.name = "cx88_audio",
.id_table = cx88_audio_pci_tbl,
.probe = cx88_audio_initdev,
- .remove = cx88_audio_finidev,
+ .remove = __devexit_p(cx88_audio_finidev),
};
/****************************************************************************
@@ -949,7 +949,7 @@ static struct pci_driver cx88_audio_pci_driver = {
/*
* module init
*/
-static int cx88_audio_init(void)
+static int __init cx88_audio_init(void)
{
printk(KERN_INFO "cx2388x alsa driver version %d.%d.%d loaded\n",
(CX88_VERSION_CODE >> 16) & 0xff,
@@ -965,9 +965,8 @@ static int cx88_audio_init(void)
/*
* module remove
*/
-static void cx88_audio_fini(void)
+static void __exit cx88_audio_fini(void)
{
-
pci_unregister_driver(&cx88_audio_pci_driver);
}
diff --git a/linux/drivers/media/video/cx88/cx88-cards.c b/linux/drivers/media/video/cx88/cx88-cards.c
index c9bfa835e..bf0f26c03 100644
--- a/linux/drivers/media/video/cx88/cx88-cards.c
+++ b/linux/drivers/media/video/cx88/cx88-cards.c
@@ -1557,33 +1557,45 @@ static const struct cx88_board cx88_boards[] = {
},
.mpeg = CX88_MPEG_DVB,
},
+ /* Terry Wu <terrywu2009@gmail.com> */
+ /* TV Audio : set GPIO 2, 18, 19 value to 0, 1, 0 */
+ /* FM Audio : set GPIO 2, 18, 19 value to 0, 0, 0 */
+ /* Line-in Audio : set GPIO 2, 18, 19 value to 0, 1, 1 */
+ /* Mute Audio : set GPIO 2 value to 1 */
[CX88_BOARD_WINFAST_TV2000_XP_GLOBAL] = {
- .name = "Winfast TV2000 XP Global",
+ .name = "Leadtek TV2000 XP Global",
.tuner_type = TUNER_XC2028,
.tuner_addr = 0x61,
+ .radio_type = TUNER_XC2028,
+ .radio_addr = 0x61,
.input = { {
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
- .gpio0 = 0x0400, /* pin 2:mute = 0 (off?) */
+ .gpio0 = 0x0400, /* pin 2 = 0 */
.gpio1 = 0x0000,
- .gpio2 = 0x0800, /* pin 19:audio = 0 (tv) */
-
+ .gpio2 = 0x0C04, /* pin 18 = 1, pin 19 = 0 */
+ .gpio3 = 0x0000,
}, {
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
- .gpio0 = 0x0400, /* probably? or 0x0404 to turn mute on */
+ .gpio0 = 0x0400, /* pin 2 = 0 */
.gpio1 = 0x0000,
- .gpio2 = 0x0808, /* pin 19:audio = 1 (line) */
-
+ .gpio2 = 0x0C0C, /* pin 18 = 1, pin 19 = 1 */
+ .gpio3 = 0x0000,
}, {
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
+ .gpio0 = 0x0400, /* pin 2 = 0 */
+ .gpio1 = 0x0000,
+ .gpio2 = 0x0C0C, /* pin 18 = 1, pin 19 = 1 */
+ .gpio3 = 0x0000,
} },
.radio = {
.type = CX88_RADIO,
- .gpio0 = 0x004ff,
- .gpio1 = 0x010ff,
- .gpio2 = 0x0ff,
+ .gpio0 = 0x0400, /* pin 2 = 0 */
+ .gpio1 = 0x0000,
+ .gpio2 = 0x0C00, /* pin 18 = 0, pin 19 = 0 */
+ .gpio3 = 0x0000,
},
},
[CX88_BOARD_POWERCOLOR_REAL_ANGEL] = {
@@ -2009,6 +2021,47 @@ static const struct cx88_board cx88_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
+ [CX88_BOARD_WINFAST_DTV1800H] = {
+ .name = "Leadtek WinFast DTV1800 Hybrid",
+ .tuner_type = TUNER_XC2028,
+ .radio_type = TUNER_XC2028,
+ .tuner_addr = 0x61,
+ .radio_addr = 0x61,
+ /*
+ * GPIO setting
+ *
+ * 2: mute (0=off,1=on)
+ * 12: tuner reset pin
+ * 13: audio source (0=tuner audio,1=line in)
+ * 14: FM (0=on,1=off ???)
+ */
+ .input = {{
+ .type = CX88_VMUX_TELEVISION,
+ .vmux = 0,
+ .gpio0 = 0x0400, /* pin 2 = 0 */
+ .gpio1 = 0x6040, /* pin 13 = 0, pin 14 = 1 */
+ .gpio2 = 0x0000,
+ }, {
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
+ .gpio0 = 0x0400, /* pin 2 = 0 */
+ .gpio1 = 0x6060, /* pin 13 = 1, pin 14 = 1 */
+ .gpio2 = 0x0000,
+ }, {
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
+ .gpio0 = 0x0400, /* pin 2 = 0 */
+ .gpio1 = 0x6060, /* pin 13 = 1, pin 14 = 1 */
+ .gpio2 = 0x0000,
+ } },
+ .radio = {
+ .type = CX88_RADIO,
+ .gpio0 = 0x0400, /* pin 2 = 0 */
+ .gpio1 = 0x6000, /* pin 13 = 0, pin 14 = 0 */
+ .gpio2 = 0x0000,
+ },
+ .mpeg = CX88_MPEG_DVB,
+ },
};
/* ------------------------------------------------------------------ */
@@ -2426,6 +2479,45 @@ static const struct cx88_subid cx88_subids[] = {
.subvendor = 0x0070,
.subdevice = 0x9290,
.card = CX88_BOARD_HAUPPAUGE_IRONLY,
+ }, {
+ .subvendor = 0x107d,
+ .subdevice = 0x6654,
+ .card = CX88_BOARD_WINFAST_DTV1800H,
+ }, {
+ /* PVR2000 PAL Model [107d:6630] */
+ .subvendor = 0x107d,
+ .subdevice = 0x6630,
+ .card = CX88_BOARD_LEADTEK_PVR2000,
+ }, {
+ /* PVR2000 PAL Model [107d:6638] */
+ .subvendor = 0x107d,
+ .subdevice = 0x6638,
+ .card = CX88_BOARD_LEADTEK_PVR2000,
+ }, {
+ /* PVR2000 NTSC Model [107d:6631] */
+ .subvendor = 0x107d,
+ .subdevice = 0x6631,
+ .card = CX88_BOARD_LEADTEK_PVR2000,
+ }, {
+ /* PVR2000 NTSC Model [107d:6637] */
+ .subvendor = 0x107d,
+ .subdevice = 0x6637,
+ .card = CX88_BOARD_LEADTEK_PVR2000,
+ }, {
+ /* PVR2000 NTSC Model [107d:663d] */
+ .subvendor = 0x107d,
+ .subdevice = 0x663d,
+ .card = CX88_BOARD_LEADTEK_PVR2000,
+ }, {
+ /* DV2000 NTSC Model [107d:6621] */
+ .subvendor = 0x107d,
+ .subdevice = 0x6621,
+ .card = CX88_BOARD_WINFAST_DV2000,
+ }, {
+ /* TV2000 XP Global [107d:6618] */
+ .subvendor = 0x107d,
+ .subdevice = 0x6618,
+ .card = CX88_BOARD_WINFAST_TV2000_XP_GLOBAL,
},
};
@@ -2434,12 +2526,6 @@ static const struct cx88_subid cx88_subids[] = {
static void leadtek_eeprom(struct cx88_core *core, u8 *eeprom_data)
{
- /* This is just for the "Winfast 2000XP Expert" board ATM; I don't have data on
- * any others.
- *
- * Byte 0 is 1 on the NTSC board.
- */
-
if (eeprom_data[4] != 0x7d ||
eeprom_data[5] != 0x10 ||
eeprom_data[7] != 0x66) {
@@ -2447,8 +2533,19 @@ static void leadtek_eeprom(struct cx88_core *core, u8 *eeprom_data)
return;
}
- core->board.tuner_type = (eeprom_data[6] == 0x13) ?
- TUNER_PHILIPS_FM1236_MK3 : TUNER_PHILIPS_FM1216ME_MK3;
+ /* Terry Wu <terrywu2009@gmail.com> */
+ switch (eeprom_data[6]) {
+ case 0x13: /* SSID 6613 for TV2000 XP Expert NTSC Model */
+ case 0x21: /* SSID 6621 for DV2000 NTSC Model */
+ case 0x31: /* SSID 6631 for PVR2000 NTSC Model */
+ case 0x37: /* SSID 6637 for PVR2000 NTSC Model */
+ case 0x3d: /* SSID 6637 for PVR2000 NTSC Model */
+ core->board.tuner_type = TUNER_PHILIPS_FM1236_MK3;
+ break;
+ default:
+ core->board.tuner_type = TUNER_PHILIPS_FM1216ME_MK3;
+ break;
+ }
info_printk(core, "Leadtek Winfast 2000XP Expert config: "
"tuner=%d, eeprom[0]=0x%02x\n",
@@ -2624,6 +2721,23 @@ static int cx88_xc3028_geniatech_tuner_callback(struct cx88_core *core,
return -EINVAL;
}
+static int cx88_xc3028_winfast1800h_callback(struct cx88_core *core,
+ int command, int arg)
+{
+ switch (command) {
+ case XC2028_TUNER_RESET:
+ /* GPIO 12 (xc3028 tuner reset) */
+ cx_set(MO_GP1_IO, 0x1010);
+ mdelay(50);
+ cx_clear(MO_GP1_IO, 0x10);
+ mdelay(50);
+ cx_set(MO_GP1_IO, 0x10);
+ mdelay(50);
+ return 0;
+ }
+ return -EINVAL;
+}
+
/* ------------------------------------------------------------------- */
/* some Divco specific stuff */
static int cx88_pv_8000gt_callback(struct cx88_core *core,
@@ -2684,7 +2798,6 @@ static int cx88_xc2028_tuner_callback(struct cx88_core *core,
{
/* Board-specific callbacks */
switch (core->boardnr) {
- case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL:
case CX88_BOARD_POWERCOLOR_REAL_ANGEL:
case CX88_BOARD_GENIATECH_X8000_MT:
case CX88_BOARD_KWORLD_ATSC_120:
@@ -2696,6 +2809,9 @@ static int cx88_xc2028_tuner_callback(struct cx88_core *core,
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO:
case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO:
return cx88_dvico_xc2028_callback(core, command, arg);
+ case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL:
+ case CX88_BOARD_WINFAST_DTV1800H:
+ return cx88_xc3028_winfast1800h_callback(core, command, arg);
}
switch (command) {
@@ -2735,10 +2851,22 @@ static int cx88_xc5000_tuner_callback(struct cx88_core *core,
switch (core->boardnr) {
case CX88_BOARD_PINNACLE_PCTV_HD_800i:
if (command == 0) { /* This is the reset command from xc5000 */
- /* Reset XC5000 tuner via SYS_RSTO_pin */
- cx_write(MO_SRST_IO, 0);
- msleep(10);
- cx_write(MO_SRST_IO, 1);
+
+ /* djh - According to the engineer at PCTV Systems,
+ the xc5000 reset pin is supposed to be on GPIO12.
+ However, despite three nights of effort, pulling
+ that GPIO low didn't reset the xc5000. While
+ pulling MO_SRST_IO low does reset the xc5000, this
+ also resets in the s5h1409 being reset as well.
+ This causes tuning to always fail since the internal
+ state of the s5h1409 does not match the driver's
+ state. Given that the only two conditions in which
+ the driver performs a reset is during firmware load
+ and powering down the chip, I am taking out the
+ reset. We know that the chip is being reset
+ when the cx88 comes online, and not being able to
+ do power management for this board is worse than
+ not having any tuning at all. */
return 0;
} else {
err_printk(core, "xc5000: unknown tuner "
@@ -2870,6 +2998,17 @@ static void cx88_card_setup_pre_i2c(struct cx88_core *core)
cx_set(MO_GP0_IO, 0x00000080); /* 702 out of reset */
udelay(1000);
break;
+
+ case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL:
+ case CX88_BOARD_WINFAST_DTV1800H:
+ /* GPIO 12 (xc3028 tuner reset) */
+ cx_set(MO_GP1_IO, 0x1010);
+ mdelay(50);
+ cx_clear(MO_GP1_IO, 0x10);
+ mdelay(50);
+ cx_set(MO_GP1_IO, 0x10);
+ mdelay(50);
+ break;
}
}
@@ -2890,12 +3029,14 @@ void cx88_setup_xc3028(struct cx88_core *core, struct xc2028_ctrl *ctl)
core->i2c_algo.udelay = 16;
break;
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO:
+ case CX88_BOARD_WINFAST_DTV1800H:
ctl->demod = XC3028_FE_ZARLINK456;
break;
case CX88_BOARD_KWORLD_ATSC_120:
case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO:
ctl->demod = XC3028_FE_OREN538;
break;
+ case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL:
case CX88_BOARD_PROLINK_PV_GLOBAL_XTREME:
case CX88_BOARD_PROLINK_PV_8000GT:
/*
@@ -2939,6 +3080,8 @@ static void cx88_card_setup(struct cx88_core *core)
if (0 == core->i2c_rc)
gdi_eeprom(core, eeprom);
break;
+ case CX88_BOARD_LEADTEK_PVR2000:
+ case CX88_BOARD_WINFAST_DV2000:
case CX88_BOARD_WINFAST2000XP_EXPERT:
if (0 == core->i2c_rc)
leadtek_eeprom(core, eeprom);
diff --git a/linux/drivers/media/video/cx88/cx88-core.c b/linux/drivers/media/video/cx88/cx88-core.c
index 39cbd152a..fddba2d51 100644
--- a/linux/drivers/media/video/cx88/cx88-core.c
+++ b/linux/drivers/media/video/cx88/cx88-core.c
@@ -1057,7 +1057,6 @@ struct video_device *cx88_vdev_init(struct cx88_core *core,
if (NULL == vfd)
return NULL;
*vfd = *template;
- vfd->minor = -1;
vfd->v4l2_dev = &core->v4l2_dev;
vfd->parent = &pci->dev;
vfd->release = video_device_release;
diff --git a/linux/drivers/media/video/cx88/cx88-dvb.c b/linux/drivers/media/video/cx88/cx88-dvb.c
index f32cece95..36f35f0b5 100644
--- a/linux/drivers/media/video/cx88/cx88-dvb.c
+++ b/linux/drivers/media/video/cx88/cx88-dvb.c
@@ -1021,6 +1021,7 @@ static int dvb_register(struct cx8802_dev *dev)
}
break;
case CX88_BOARD_PINNACLE_HYBRID_PCTV:
+ case CX88_BOARD_WINFAST_DTV1800H:
fe0->dvb.frontend = dvb_attach(zl10353_attach,
&cx88_pinnacle_hybrid_pctv,
&core->i2c_adap);
diff --git a/linux/drivers/media/video/cx88/cx88-i2c.c b/linux/drivers/media/video/cx88/cx88-i2c.c
index 680a8c889..b5833aa29 100644
--- a/linux/drivers/media/video/cx88/cx88-i2c.c
+++ b/linux/drivers/media/video/cx88/cx88-i2c.c
@@ -186,6 +186,21 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci)
do_i2c_scan(core->name,&core->i2c_client);
} else
printk("%s: i2c register FAILED\n", core->name);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
+
+ /* Instantiate the IR receiver device, if present */
+ if (0 == core->i2c_rc) {
+ struct i2c_board_info info;
+ const unsigned short addr_list[] = {
+ 0x18, 0x6b, 0x71,
+ I2C_CLIENT_END
+ };
+
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
+ i2c_new_probed_device(&core->i2c_adap, &info, addr_list);
+ }
+#endif
return core->i2c_rc;
}
diff --git a/linux/drivers/media/video/cx88/cx88-input.c b/linux/drivers/media/video/cx88/cx88-input.c
index dad809335..7c5e94916 100644
--- a/linux/drivers/media/video/cx88/cx88-input.c
+++ b/linux/drivers/media/video/cx88/cx88-input.c
@@ -92,6 +92,7 @@ static void cx88_ir_handle_key(struct cx88_IR *ir)
gpio=(gpio & 0x7fd) + (auxgpio & 0xef);
break;
case CX88_BOARD_WINFAST_DTV1000:
+ case CX88_BOARD_WINFAST_DTV1800H:
case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL:
gpio = (gpio & 0x6ff) | ((cx_read(MO_GP1_IO) << 8) & 0x900);
auxgpio = gpio;
@@ -237,6 +238,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
ir->sampling = 1;
break;
case CX88_BOARD_WINFAST_DTV2000H:
+ case CX88_BOARD_WINFAST_DTV1800H:
ir_codes = ir_codes_winfast;
ir->gpio_addr = MO_GP0_IO;
ir->mask_keycode = 0x8f8;
diff --git a/linux/drivers/media/video/cx88/cx88-video.c b/linux/drivers/media/video/cx88/cx88-video.c
index 88a326f61..a55053767 100644
--- a/linux/drivers/media/video/cx88/cx88-video.c
+++ b/linux/drivers/media/video/cx88/cx88-video.c
@@ -1095,6 +1095,7 @@ video_poll(struct file *file, struct poll_table_struct *wait)
{
struct cx8800_fh *fh = file->private_data;
struct cx88_buffer *buf;
+ unsigned int rc = POLLERR;
if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
if (!res_get(fh->dev,fh,RESOURCE_VBI))
@@ -1102,22 +1103,27 @@ video_poll(struct file *file, struct poll_table_struct *wait)
return videobuf_poll_stream(file, &fh->vbiq, wait);
}
+ mutex_lock(&fh->vidq.vb_lock);
if (res_check(fh,RESOURCE_VIDEO)) {
/* streaming capture */
if (list_empty(&fh->vidq.stream))
- return POLLERR;
+ goto done;
buf = list_entry(fh->vidq.stream.next,struct cx88_buffer,vb.stream);
} else {
/* read() capture */
buf = (struct cx88_buffer*)fh->vidq.read_buf;
if (NULL == buf)
- return POLLERR;
+ goto done;
}
poll_wait(file, &buf->vb.done, wait);
if (buf->vb.state == VIDEOBUF_DONE ||
buf->vb.state == VIDEOBUF_ERROR)
- return POLLIN|POLLRDNORM;
- return 0;
+ rc = POLLIN|POLLRDNORM;
+ else
+ rc = 0;
+done:
+ mutex_unlock(&fh->vidq.vb_lock);
+ return rc;
}
static int video_release(struct file *file)
@@ -1152,8 +1158,10 @@ static int video_release(struct file *file)
file->private_data = NULL;
kfree(fh);
+ mutex_lock(&dev->core->lock);
if(atomic_dec_and_test(&dev->core->users))
call_all(dev->core, tuner, s_standby);
+ mutex_unlock(&dev->core->lock);
return 0;
}
@@ -1337,15 +1345,8 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
}
f->fmt.pix.field = field;
- if (f->fmt.pix.height < 32)
- f->fmt.pix.height = 32;
- if (f->fmt.pix.height > maxh)
- f->fmt.pix.height = maxh;
- if (f->fmt.pix.width < 48)
- f->fmt.pix.width = 48;
- if (f->fmt.pix.width > maxw)
- f->fmt.pix.width = maxw;
- f->fmt.pix.width &= ~0x03;
+ v4l_bound_align_image(&f->fmt.pix.width, 48, maxw, 2,
+ &f->fmt.pix.height, 32, maxh, 0, 0);
f->fmt.pix.bytesperline =
(f->fmt.pix.width * fmt->depth) >> 3;
f->fmt.pix.sizeimage =
diff --git a/linux/drivers/media/video/cx88/cx88.h b/linux/drivers/media/video/cx88/cx88.h
index 0c00c34bc..59fc01a53 100644
--- a/linux/drivers/media/video/cx88/cx88.h
+++ b/linux/drivers/media/video/cx88/cx88.h
@@ -237,6 +237,7 @@ extern struct sram_channel cx88_sram_channels[];
#define CX88_BOARD_PROF_6200 78
#define CX88_BOARD_TERRATEC_CINERGY_HT_PCI_MKII 79
#define CX88_BOARD_HAUPPAUGE_IRONLY 80
+#define CX88_BOARD_WINFAST_DTV1800H 81
enum cx88_itype {
CX88_VMUX_COMPOSITE1 = 1,
diff --git a/linux/drivers/media/video/em28xx/em28xx-audio.c b/linux/drivers/media/video/em28xx/em28xx-audio.c
index 089764d42..66aace7cf 100644
--- a/linux/drivers/media/video/em28xx/em28xx-audio.c
+++ b/linux/drivers/media/video/em28xx/em28xx-audio.c
@@ -385,6 +385,11 @@ static int snd_em28xx_pcm_close(struct snd_pcm_substream *substream)
mutex_lock(&dev->lock);
dev->adev.users--;
em28xx_audio_analog_set(dev);
+ if (substream->runtime->dma_area) {
+ dprintk("freeing\n");
+ vfree(substream->runtime->dma_area);
+ substream->runtime->dma_area = NULL;
+ }
mutex_unlock(&dev->lock);
return 0;
diff --git a/linux/drivers/media/video/em28xx/em28xx-cards.c b/linux/drivers/media/video/em28xx/em28xx-cards.c
index fb83e4f6e..b824eed46 100644
--- a/linux/drivers/media/video/em28xx/em28xx-cards.c
+++ b/linux/drivers/media/video/em28xx/em28xx-cards.c
@@ -50,6 +50,11 @@ static unsigned int disable_ir;
module_param(disable_ir, int, 0444);
MODULE_PARM_DESC(disable_ir, "disable infrared remote support");
+static unsigned int disable_usb_speed_check;
+module_param(disable_usb_speed_check, int, 0444);
+MODULE_PARM_DESC(disable_usb_speed_check,
+ "override min bandwidth requirement of 480M bps");
+
static unsigned int card[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
module_param_array(card, int, NULL, 0444);
MODULE_PARM_DESC(card, "card type");
@@ -117,6 +122,24 @@ static struct em28xx_reg_seq em2870_kworld_355u_digital[] = {
};
#endif
+/* Board - EM2882 Kworld 315U digital */
+static struct em28xx_reg_seq em2882_kworld_315u_digital[] = {
+ {EM28XX_R08_GPIO, 0xff, 0xff, 10},
+ {EM28XX_R08_GPIO, 0xfe, 0xff, 10},
+ {EM2880_R04_GPO, 0x04, 0xff, 10},
+ {EM2880_R04_GPO, 0x0c, 0xff, 10},
+ {EM28XX_R08_GPIO, 0x7e, 0xff, 10},
+ { -1, -1, -1, -1},
+};
+
+static struct em28xx_reg_seq em2882_kworld_315u_tuner_gpio[] = {
+ {EM2880_R04_GPO, 0x08, 0xff, 10},
+ {EM2880_R04_GPO, 0x0c, 0xff, 10},
+ {EM2880_R04_GPO, 0x08, 0xff, 10},
+ {EM2880_R04_GPO, 0x0c, 0xff, 10},
+ { -1, -1, -1, -1},
+};
+
static struct em28xx_reg_seq kworld_330u_analog[] = {
{EM28XX_R08_GPIO, 0x6d, ~EM_GPIO_4, 10},
{EM2880_R04_GPO, 0x00, 0xff, 10},
@@ -129,6 +152,24 @@ static struct em28xx_reg_seq kworld_330u_digital[] = {
{ -1, -1, -1, -1},
};
+/* Evga inDtube
+ GPIO0 - Enable digital power (s5h1409) - low to enable
+ GPIO1 - Enable analog power (tvp5150/emp202) - low to enable
+ GPIO4 - xc3028 reset
+ GOP3 - s5h1409 reset
+ */
+static struct em28xx_reg_seq evga_indtube_analog[] = {
+ {EM28XX_R08_GPIO, 0x79, 0xff, 60},
+ { -1, -1, -1, -1},
+};
+
+static struct em28xx_reg_seq evga_indtube_digital[] = {
+ {EM28XX_R08_GPIO, 0x7a, 0xff, 1},
+ {EM2880_R04_GPO, 0x04, 0xff, 10},
+ {EM2880_R04_GPO, 0x0c, 0xff, 1},
+ { -1, -1, -1, -1},
+};
+
/* Callback for the most boards */
static struct em28xx_reg_seq default_tuner_gpio[] = {
{EM28XX_R08_GPIO, EM_GPIO_4, EM_GPIO_4, 10},
@@ -153,6 +194,16 @@ static struct em28xx_reg_seq compro_mute_gpio[] = {
{ -1, -1, -1, -1},
};
+/* Terratec AV350 */
+static struct em28xx_reg_seq terratec_av350_mute_gpio[] = {
+ {EM28XX_R08_GPIO, 0xff, 0x7f, 10},
+ { -1, -1, -1, -1},
+};
+
+static struct em28xx_reg_seq terratec_av350_unmute_gpio[] = {
+ {EM28XX_R08_GPIO, 0xff, 0xff, 10},
+ { -1, -1, -1, -1},
+};
/*
* Board definitions
*/
@@ -1033,16 +1084,17 @@ struct em28xx_board em28xx_boards[] = {
.amux = EM28XX_AMUX_LINE_IN,
} },
},
- [EM2860_BOARD_POINTNIX_INTRAORAL_CAMERA] = {
- .name = "PointNix Intra-Oral Camera",
+ [EM2860_BOARD_SAA711X_REFERENCE_DESIGN] = {
+ .name = "EM2860/SAA711X Reference Design",
.has_snapshot_button = 1,
- .tda9887_conf = TDA9887_PRESENT,
.tuner_type = TUNER_ABSENT,
.decoder = EM28XX_SAA711X,
.input = { {
.type = EM28XX_VMUX_SVIDEO,
.vmux = SAA7115_SVIDEO3,
- .amux = EM28XX_AMUX_VIDEO,
+ }, {
+ .type = EM28XX_VMUX_COMPOSITE1,
+ .vmux = SAA7115_COMPOSITE0,
} },
},
[EM2880_BOARD_MSI_DIGIVOX_AD] = {
@@ -1144,6 +1196,38 @@ struct em28xx_board em28xx_boards[] = {
.gpio = default_analog,
} },
},
+ [EM2882_BOARD_KWORLD_ATSC_315U] = {
+ .name = "KWorld ATSC 315U HDTV TV Box",
+ .valid = EM28XX_BOARD_NOT_VALIDATED,
+ .tuner_type = TUNER_THOMSON_DTT761X,
+ .tuner_gpio = em2882_kworld_315u_tuner_gpio,
+ .tda9887_conf = TDA9887_PRESENT,
+ .decoder = EM28XX_SAA711X,
+ .has_dvb = 1,
+ .dvb_gpio = em2882_kworld_315u_digital,
+ .xclk = EM28XX_XCLK_FREQUENCY_12MHZ,
+ .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE,
+ /* Analog mode - still not ready */
+ /*.input = { {
+ .type = EM28XX_VMUX_TELEVISION,
+ .vmux = SAA7115_COMPOSITE2,
+ .amux = EM28XX_AMUX_VIDEO,
+ .gpio = em2882_kworld_315u_analog,
+ .aout = EM28XX_AOUT_PCM_IN | EM28XX_AOUT_PCM_STEREO,
+ }, {
+ .type = EM28XX_VMUX_COMPOSITE1,
+ .vmux = SAA7115_COMPOSITE0,
+ .amux = EM28XX_AMUX_LINE_IN,
+ .gpio = em2882_kworld_315u_analog1,
+ .aout = EM28XX_AOUT_PCM_IN | EM28XX_AOUT_PCM_STEREO,
+ }, {
+ .type = EM28XX_VMUX_SVIDEO,
+ .vmux = SAA7115_SVIDEO3,
+ .amux = EM28XX_AMUX_LINE_IN,
+ .gpio = em2882_kworld_315u_analog1,
+ .aout = EM28XX_AOUT_PCM_IN | EM28XX_AOUT_PCM_STEREO,
+ } }, */
+ },
[EM2880_BOARD_EMPIRE_DUAL_TV] = {
.name = "Empire dual TV",
.tuner_type = TUNER_XC2028,
@@ -1412,6 +1496,69 @@ struct em28xx_board em28xx_boards[] = {
.amux = EM28XX_AMUX_VIDEO,
} },
},
+ [EM2860_BOARD_TERRATEC_GRABBY] = {
+ .name = "Terratec Grabby",
+ .vchannels = 2,
+ .tuner_type = TUNER_ABSENT,
+ .decoder = EM28XX_SAA711X,
+ .xclk = EM28XX_XCLK_FREQUENCY_12MHZ,
+ .input = { {
+ .type = EM28XX_VMUX_COMPOSITE1,
+ .vmux = SAA7115_COMPOSITE0,
+ .amux = EM28XX_AMUX_VIDEO2,
+ }, {
+ .type = EM28XX_VMUX_SVIDEO,
+ .vmux = SAA7115_SVIDEO3,
+ .amux = EM28XX_AMUX_VIDEO2,
+ } },
+ },
+ [EM2860_BOARD_TERRATEC_AV350] = {
+ .name = "Terratec AV350",
+ .vchannels = 2,
+ .tuner_type = TUNER_ABSENT,
+ .decoder = EM28XX_TVP5150,
+ .xclk = EM28XX_XCLK_FREQUENCY_12MHZ,
+ .mute_gpio = terratec_av350_mute_gpio,
+ .input = { {
+ .type = EM28XX_VMUX_COMPOSITE1,
+ .vmux = TVP5150_COMPOSITE1,
+ .amux = EM28XX_AUDIO_SRC_LINE,
+ .gpio = terratec_av350_unmute_gpio,
+
+ }, {
+ .type = EM28XX_VMUX_SVIDEO,
+ .vmux = TVP5150_SVIDEO,
+ .amux = EM28XX_AUDIO_SRC_LINE,
+ .gpio = terratec_av350_unmute_gpio,
+ } },
+ },
+ [EM2882_BOARD_EVGA_INDTUBE] = {
+ .name = "Evga inDtube",
+ .tuner_type = TUNER_XC2028,
+ .tuner_gpio = default_tuner_gpio,
+ .decoder = EM28XX_TVP5150,
+ .xclk = EM28XX_XCLK_FREQUENCY_12MHZ, /* NEC IR */
+ .mts_firmware = 1,
+ .has_dvb = 1,
+ .dvb_gpio = evga_indtube_digital,
+ .ir_codes = ir_codes_evga_indtube,
+ .input = { {
+ .type = EM28XX_VMUX_TELEVISION,
+ .vmux = TVP5150_COMPOSITE0,
+ .amux = EM28XX_AMUX_VIDEO,
+ .gpio = evga_indtube_analog,
+ }, {
+ .type = EM28XX_VMUX_COMPOSITE1,
+ .vmux = TVP5150_COMPOSITE1,
+ .amux = EM28XX_AMUX_LINE_IN,
+ .gpio = evga_indtube_analog,
+ }, {
+ .type = EM28XX_VMUX_SVIDEO,
+ .vmux = TVP5150_SVIDEO,
+ .amux = EM28XX_AMUX_LINE_IN,
+ .gpio = evga_indtube_analog,
+ } },
+ },
};
const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards);
@@ -1449,6 +1596,8 @@ struct usb_device_id em28xx_id_table[] = {
{ USB_DEVICE(0xeb1a, 0xe310),
.driver_info = EM2880_BOARD_KWORLD_DVB_310U },
#endif
+ { USB_DEVICE(0xeb1a, 0xa313),
+ .driver_info = EM2882_BOARD_KWORLD_ATSC_315U },
{ USB_DEVICE(0xeb1a, 0xa316),
.driver_info = EM2883_BOARD_KWORLD_HYBRID_330U },
{ USB_DEVICE(0xeb1a, 0xe320),
@@ -1479,6 +1628,10 @@ struct usb_device_id em28xx_id_table[] = {
.driver_info = EM2870_BOARD_TERRATEC_XS },
{ USB_DEVICE(0x0ccd, 0x0047),
.driver_info = EM2880_BOARD_TERRATEC_PRODIGY_XS },
+ { USB_DEVICE(0x0ccd, 0x0084),
+ .driver_info = EM2860_BOARD_TERRATEC_AV350 },
+ { USB_DEVICE(0x0ccd, 0x0096),
+ .driver_info = EM2860_BOARD_TERRATEC_GRABBY },
{ USB_DEVICE(0x185b, 0x2870),
.driver_info = EM2870_BOARD_COMPRO_VIDEOMATE },
{ USB_DEVICE(0x185b, 0x2041),
@@ -1532,13 +1685,14 @@ static struct em28xx_hash_table em28xx_eeprom_hash[] = {
{0x72cc5a8b, EM2820_BOARD_PROLINK_PLAYTV_BOX4_USB2, TUNER_YMEC_TVF_5533MF},
{0x966a0441, EM2880_BOARD_KWORLD_DVB_310U, TUNER_XC2028},
{0x9567eb1a, EM2880_BOARD_EMPIRE_DUAL_TV, TUNER_XC2028},
+ {0xcee44a99, EM2882_BOARD_EVGA_INDTUBE, TUNER_XC2028},
};
/* I2C devicelist hash table for devices with generic USB IDs */
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},
+ {0x1ba50080, EM2860_BOARD_SAA711X_REFERENCE_DESIGN, TUNER_ABSENT},
{0xc51200e3, EM2820_BOARD_GADMEI_TVR200, TUNER_LG_PAL_NEW_TAPC},
};
@@ -1714,6 +1868,17 @@ void em28xx_pre_card_setup(struct em28xx *dev)
em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfd);
break;
+ case EM2882_BOARD_KWORLD_ATSC_315U:
+ em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xff);
+ msleep(10);
+ em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfe);
+ msleep(10);
+ em28xx_write_reg(dev, EM2880_R04_GPO, 0x00);
+ msleep(10);
+ em28xx_write_reg(dev, EM2880_R04_GPO, 0x08);
+ msleep(10);
+ break;
+
case EM2860_BOARD_KAIOMY_TVNPC_U2:
em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x07", 1);
em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1);
@@ -1784,6 +1949,10 @@ static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl)
ctl->demod = XC3028_FE_CHINA;
ctl->fname = XC2028_DEFAULT_FIRMWARE;
break;
+ case EM2882_BOARD_EVGA_INDTUBE:
+ ctl->demod = XC3028_FE_CHINA;
+ ctl->fname = XC3028L_DEFAULT_FIRMWARE;
+ break;
default:
ctl->demod = XC3028_FE_OREN538;
}
@@ -1931,12 +2100,31 @@ static int em28xx_hint_board(struct em28xx *dev)
}
/* ----------------------------------------------------------------------- */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir)
+#else
+void em28xx_register_i2c_ir(struct em28xx *dev)
+#endif
{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
if (disable_ir) {
ir->get_key = NULL;
return ;
}
+#else
+ struct i2c_board_info info;
+ struct IR_i2c_init_data init_data;
+ const unsigned short addr_list[] = {
+ 0x30, 0x47, I2C_CLIENT_END
+ };
+
+ if (disable_ir)
+ return;
+
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ memset(&init_data, 0, sizeof(struct IR_i2c_init_data));
+ strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
+#endif
/* detect & configure */
switch (dev->model) {
@@ -1946,22 +2134,40 @@ void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir)
break;
case (EM2800_BOARD_TERRATEC_CINERGY_200):
case (EM2820_BOARD_TERRATEC_CINERGY_250):
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
ir->ir_codes = ir_codes_em_terratec;
ir->get_key = em28xx_get_key_terratec;
- snprintf(ir->c.name, sizeof(ir->c.name),
+ snprintf(ir->name, sizeof(ir->name),
"i2c IR (EM28XX Terratec)");
+#else
+ init_data.ir_codes = ir_codes_em_terratec;
+ init_data.get_key = em28xx_get_key_terratec;
+ init_data.name = "i2c IR (EM28XX Terratec)";
+#endif
break;
case (EM2820_BOARD_PINNACLE_USB_2):
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
ir->ir_codes = ir_codes_pinnacle_grey;
ir->get_key = em28xx_get_key_pinnacle_usb_grey;
- snprintf(ir->c.name, sizeof(ir->c.name),
+ snprintf(ir->name, sizeof(ir->name),
"i2c IR (EM28XX Pinnacle PCTV)");
+#else
+ init_data.ir_codes = ir_codes_pinnacle_grey;
+ init_data.get_key = em28xx_get_key_pinnacle_usb_grey;
+ init_data.name = "i2c IR (EM28XX Pinnacle PCTV)";
+#endif
break;
case (EM2820_BOARD_HAUPPAUGE_WINTV_USB_2):
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
ir->ir_codes = ir_codes_hauppauge_new;
ir->get_key = em28xx_get_key_em_haup;
- snprintf(ir->c.name, sizeof(ir->c.name),
+ snprintf(ir->name, sizeof(ir->name),
"i2c IR (EM2840 Hauppauge)");
+#else
+ init_data.ir_codes = ir_codes_hauppauge_new;
+ init_data.get_key = em28xx_get_key_em_haup;
+ init_data.name = "i2c IR (EM2840 Hauppauge)";
+#endif
break;
case (EM2820_BOARD_MSI_VOX_USB_2):
break;
@@ -1972,6 +2178,12 @@ void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir)
case (EM2800_BOARD_GRABBEEX_USB2800):
break;
}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
+
+ if (init_data.name)
+ info.platform_data = &init_data;
+ i2c_new_probed_device(&dev->i2c_adap, &info, addr_list);
+#endif
}
void em28xx_card_setup(struct em28xx *dev)
@@ -1982,6 +2194,9 @@ void em28xx_card_setup(struct em28xx *dev)
if (em28xx_boards[dev->model].tuner_addr)
dev->tuner_addr = em28xx_boards[dev->model].tuner_addr;
+ if (em28xx_boards[dev->model].tda9887_conf)
+ dev->tda9887_conf = em28xx_boards[dev->model].tda9887_conf;
+
/* request some modules */
switch (dev->model) {
case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2:
@@ -2011,6 +2226,12 @@ void em28xx_card_setup(struct em28xx *dev)
#endif
break;
}
+ case EM2882_BOARD_KWORLD_ATSC_315U:
+ em28xx_write_reg(dev, 0x0d, 0x42);
+ msleep(10);
+ em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfd);
+ msleep(10);
+ break;
case EM2820_BOARD_KWORLD_PVRTV2800RF:
/* GPIO enables sound on KWORLD PVR TV 2800RF */
em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xf9);
@@ -2033,6 +2254,12 @@ void em28xx_card_setup(struct em28xx *dev)
case EM2880_BOARD_MSI_DIGIVOX_AD:
if (!em28xx_hint_board(dev))
em28xx_set_model(dev);
+
+ /* In cases where we had to use a board hint, the call to
+ em28xx_set_mode() in em28xx_pre_card_setup() was a no-op,
+ so make the call now so the analog GPIOs are set properly
+ before probing the i2c bus. */
+ em28xx_set_mode(dev, EM28XX_ANALOG_MODE);
break;
}
@@ -2389,6 +2616,20 @@ static int em28xx_usb_probe(struct usb_interface *interface,
ifnum,
interface->altsetting->desc.bInterfaceNumber);
+ /*
+ * Make sure we have 480 Mbps of bandwidth, otherwise things like
+ * video stream wouldn't likely work, since 12 Mbps is generally
+ * not enough even for most Digital TV streams.
+ */
+ if (udev->speed != USB_SPEED_HIGH && disable_usb_speed_check == 0) {
+ printk(DRIVER_NAME ": Device initialization failed.\n");
+ printk(DRIVER_NAME ": Device must be connected to a high-speed"
+ " USB 2.0 port.\n");
+ em28xx_devused &= ~(1<<nr);
+ retval = -ENODEV;
+ goto err;
+ }
+
if (nr >= EM28XX_MAXBOARDS) {
printk(DRIVER_NAME ": Supports only %i em28xx boards.\n",
EM28XX_MAXBOARDS);
diff --git a/linux/drivers/media/video/em28xx/em28xx-core.c b/linux/drivers/media/video/em28xx/em28xx-core.c
index 401dc4e39..2bce72e4f 100644
--- a/linux/drivers/media/video/em28xx/em28xx-core.c
+++ b/linux/drivers/media/video/em28xx/em28xx-core.c
@@ -500,18 +500,21 @@ int em28xx_audio_setup(struct em28xx *dev)
/* See how this device is configured */
cfg = em28xx_read_reg(dev, EM28XX_R00_CHIPCFG);
- if (cfg < 0)
+ em28xx_info("Config register raw data: 0x%02x\n", cfg);
+ if (cfg < 0) {
+ /* Register read error? */
cfg = EM28XX_CHIPCFG_AC97; /* Be conservative */
- else
- em28xx_info("Config register raw data: 0x%02x\n", cfg);
-
- if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) ==
- EM28XX_CHIPCFG_I2S_3_SAMPRATES) {
+ } else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) == 0x00) {
+ /* The device doesn't have vendor audio at all */
+ dev->has_alsa_audio = 0;
+ dev->audio_mode.has_audio = 0;
+ return 0;
+ } else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) ==
+ EM28XX_CHIPCFG_I2S_3_SAMPRATES) {
em28xx_info("I2S Audio (3 sample rates)\n");
dev->audio_mode.i2s_3rates = 1;
- }
- if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) ==
- EM28XX_CHIPCFG_I2S_5_SAMPRATES) {
+ } else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) ==
+ EM28XX_CHIPCFG_I2S_5_SAMPRATES) {
em28xx_info("I2S Audio (5 sample rates)\n");
dev->audio_mode.i2s_5rates = 1;
}
@@ -1021,6 +1024,41 @@ int em28xx_init_isoc(struct em28xx *dev, int max_packets,
}
EXPORT_SYMBOL_GPL(em28xx_init_isoc);
+/* Determine the packet size for the DVB stream for the given device
+ (underlying value programmed into the eeprom) */
+int em28xx_isoc_dvb_max_packetsize(struct em28xx *dev)
+{
+ unsigned int chip_cfg2;
+ unsigned int packet_size = 564;
+
+ if (dev->chip_id == CHIP_ID_EM2874) {
+ /* FIXME - for now assume 564 like it was before, but the
+ em2874 code should be added to return the proper value... */
+ packet_size = 564;
+ } else {
+ /* TS max packet size stored in bits 1-0 of R01 */
+ chip_cfg2 = em28xx_read_reg(dev, EM28XX_R01_CHIPCFG2);
+ switch (chip_cfg2 & EM28XX_CHIPCFG2_TS_PACKETSIZE_MASK) {
+ case EM28XX_CHIPCFG2_TS_PACKETSIZE_188:
+ packet_size = 188;
+ break;
+ case EM28XX_CHIPCFG2_TS_PACKETSIZE_376:
+ packet_size = 376;
+ break;
+ case EM28XX_CHIPCFG2_TS_PACKETSIZE_564:
+ packet_size = 564;
+ break;
+ case EM28XX_CHIPCFG2_TS_PACKETSIZE_752:
+ packet_size = 752;
+ break;
+ }
+ }
+
+ em28xx_coredbg("dvb max packet size=%d\n", packet_size);
+ return packet_size;
+}
+EXPORT_SYMBOL_GPL(em28xx_isoc_dvb_max_packetsize);
+
/*
* em28xx_wake_i2c()
* configure i2c attached devices
diff --git a/linux/drivers/media/video/em28xx/em28xx-dvb.c b/linux/drivers/media/video/em28xx/em28xx-dvb.c
index dd749442d..85afa0be0 100644
--- a/linux/drivers/media/video/em28xx/em28xx-dvb.c
+++ b/linux/drivers/media/video/em28xx/em28xx-dvb.c
@@ -26,6 +26,8 @@
#include "em28xx.h"
#include <media/v4l2-common.h>
#include <media/videobuf-vmalloc.h>
+#include <media/tuner.h>
+#include "tuner-simple.h"
#include "lgdt330x.h"
#include "zl10353.h"
@@ -47,7 +49,6 @@ if (debug >= level) \
} while (0)
#define EM28XX_DVB_NUM_BUFS 5
-#define EM28XX_DVB_MAX_PACKETSIZE 564
#define EM28XX_DVB_MAX_PACKETS 64
struct em28xx_dvb {
@@ -143,14 +144,17 @@ static int start_streaming(struct em28xx_dvb *dvb)
{
int rc;
struct em28xx *dev = dvb->adapter.priv;
+ int max_dvb_packet_size;
usb_set_interface(dev->udev, 0, 1);
rc = em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
if (rc < 0)
return rc;
+ max_dvb_packet_size = em28xx_isoc_dvb_max_packetsize(dev);
+
return em28xx_init_isoc(dev, EM28XX_DVB_MAX_PACKETS,
- EM28XX_DVB_NUM_BUFS, EM28XX_DVB_MAX_PACKETSIZE,
+ EM28XX_DVB_NUM_BUFS, max_dvb_packet_size,
dvb_isoc_copy);
}
@@ -442,6 +446,7 @@ static int dvb_init(struct em28xx *dev)
}
break;
case EM2883_BOARD_KWORLD_HYBRID_330U:
+ case EM2882_BOARD_EVGA_INDTUBE:
dvb->frontend = dvb_attach(s5h1409_attach,
&em28xx_s5h1409_with_xc3028,
&dev->i2c_adap);
@@ -450,6 +455,18 @@ static int dvb_init(struct em28xx *dev)
goto out_free;
}
break;
+ case EM2882_BOARD_KWORLD_ATSC_315U:
+ dvb->frontend = dvb_attach(lgdt330x_attach,
+ &em2880_lgdt3303_dev,
+ &dev->i2c_adap);
+ if (dvb->frontend != NULL) {
+ if (!dvb_attach(simple_tuner_attach, dvb->frontend,
+ &dev->i2c_adap, 0x61, TUNER_THOMSON_DTT761X)) {
+ result = -EINVAL;
+ 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
diff --git a/linux/drivers/media/video/em28xx/em28xx-i2c.c b/linux/drivers/media/video/em28xx/em28xx-i2c.c
index 24456cebd..1cdd88361 100644
--- a/linux/drivers/media/video/em28xx/em28xx-i2c.c
+++ b/linux/drivers/media/video/em28xx/em28xx-i2c.c
@@ -451,27 +451,6 @@ static u32 functionality(struct i2c_adapter *adap)
return I2C_FUNC_SMBUS_EMUL;
}
-/*
- * attach_inform()
- * gets called when a device attaches to the i2c bus
- * does some basic configuration
- */
-static int attach_inform(struct i2c_client *client)
-{
- struct em28xx *dev = client->adapter->algo_data;
- struct IR_i2c *ir = i2c_get_clientdata(client);
-
- switch (client->addr << 1) {
- case 0x60:
- case 0x8e:
- dprintk1(1, "attach_inform: IR detected (%s).\n", ir->phys);
- em28xx_set_ir(dev, ir);
- break;
- }
-
- return 0;
-}
-
static struct i2c_algorithm em28xx_algo = {
.master_xfer = em28xx_i2c_xfer,
.functionality = functionality,
@@ -488,7 +467,6 @@ static struct i2c_adapter em28xx_adap_template = {
.name = "em28xx",
.id = I2C_HW_B_EM28XX,
.algo = &em28xx_algo,
- .client_register = attach_inform,
};
static struct i2c_client em28xx_client_template = {
@@ -581,6 +559,11 @@ int em28xx_i2c_register(struct em28xx *dev)
if (i2c_scan)
em28xx_do_i2c_scan(dev);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
+ /* Instantiate the IR receiver device, if present */
+ em28xx_register_i2c_ir(dev);
+
+#endif
return 0;
}
diff --git a/linux/drivers/media/video/em28xx/em28xx-input.c b/linux/drivers/media/video/em28xx/em28xx-input.c
index 5382a6064..df58b4c5b 100644
--- a/linux/drivers/media/video/em28xx/em28xx-input.c
+++ b/linux/drivers/media/video/em28xx/em28xx-input.c
@@ -41,7 +41,7 @@ MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]");
#define i2cdprintk(fmt, arg...) \
if (ir_debug) { \
- printk(KERN_DEBUG "%s/ir: " fmt, ir->c.name , ## arg); \
+ printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg); \
}
#define dprintk(fmt, arg...) \
@@ -86,7 +86,11 @@ int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
unsigned char b;
/* poll IR chip */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
if (1 != i2c_master_recv(&ir->c, &b, 1)) {
+#else
+ if (1 != i2c_master_recv(ir->c, &b, 1)) {
+#endif
i2cdprintk("read error\n");
return -EIO;
}
@@ -115,7 +119,11 @@ int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
unsigned char code;
/* poll IR chip */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
if (2 != i2c_master_recv(&ir->c, buf, 2))
+#else
+ if (2 != i2c_master_recv(ir->c, buf, 2))
+#endif
return -EIO;
/* Does eliminate repeated parity code */
@@ -153,7 +161,11 @@ int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key,
/* poll IR chip */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
if (3 != i2c_master_recv(&ir->c, buf, 3)) {
+#else
+ if (3 != i2c_master_recv(ir->c, buf, 3)) {
+#endif
i2cdprintk("read error\n");
return -EIO;
}
diff --git a/linux/drivers/media/video/em28xx/em28xx-reg.h b/linux/drivers/media/video/em28xx/em28xx-reg.h
index 24e39c568..a2676d63c 100644
--- a/linux/drivers/media/video/em28xx/em28xx-reg.h
+++ b/linux/drivers/media/video/em28xx/em28xx-reg.h
@@ -27,6 +27,22 @@
#define EM28XX_CHIPCFG_AC97 0x10
#define EM28XX_CHIPCFG_AUDIOMASK 0x30
+#define EM28XX_R01_CHIPCFG2 0x01
+
+/* em28xx Chip Configuration 2 0x01 */
+#define EM28XX_CHIPCFG2_TS_PRESENT 0x10
+#define EM28XX_CHIPCFG2_TS_REQ_INTERVAL_MASK 0x0c /* bits 3-2 */
+#define EM28XX_CHIPCFG2_TS_REQ_INTERVAL_1MF 0x00
+#define EM28XX_CHIPCFG2_TS_REQ_INTERVAL_2MF 0x04
+#define EM28XX_CHIPCFG2_TS_REQ_INTERVAL_4MF 0x08
+#define EM28XX_CHIPCFG2_TS_REQ_INTERVAL_8MF 0x0c
+#define EM28XX_CHIPCFG2_TS_PACKETSIZE_MASK 0x03 /* bits 0-1 */
+#define EM28XX_CHIPCFG2_TS_PACKETSIZE_188 0x00
+#define EM28XX_CHIPCFG2_TS_PACKETSIZE_376 0x01
+#define EM28XX_CHIPCFG2_TS_PACKETSIZE_564 0x02
+#define EM28XX_CHIPCFG2_TS_PACKETSIZE_752 0x03
+
+
/* GPIO/GPO registers */
#define EM2880_R04_GPO 0x04 /* em2880-em2883 only */
#define EM28XX_R08_GPIO 0x08 /* em2820 or upper */
diff --git a/linux/drivers/media/video/em28xx/em28xx-video.c b/linux/drivers/media/video/em28xx/em28xx-video.c
index 1614e5fc4..63d21698c 100644
--- a/linux/drivers/media/video/em28xx/em28xx-video.c
+++ b/linux/drivers/media/video/em28xx/em28xx-video.c
@@ -691,8 +691,8 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
{
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
- int width = f->fmt.pix.width;
- int height = f->fmt.pix.height;
+ unsigned int width = f->fmt.pix.width;
+ unsigned int height = f->fmt.pix.height;
unsigned int maxw = norm_maxw(dev);
unsigned int maxh = norm_maxh(dev);
unsigned int hscale, vscale;
@@ -705,34 +705,20 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
return -EINVAL;
}
- /* width must even because of the YUYV format
- height must be even because of interlacing */
- height &= 0xfffe;
- width &= 0xfffe;
-
- if (unlikely(height < 32))
- height = 32;
- if (unlikely(height > maxh))
- height = maxh;
- if (unlikely(width < 48))
- width = 48;
- if (unlikely(width > maxw))
- width = maxw;
-
if (dev->board.is_em2800) {
/* the em2800 can only scale down to 50% */
- if (height % (maxh / 2))
- height = maxh;
- if (width % (maxw / 2))
- width = maxw;
- /* according to empiatech support */
- /* the MaxPacketSize is to small to support */
- /* framesizes larger than 640x480 @ 30 fps */
- /* or 640x576 @ 25 fps. As this would cut */
- /* of a part of the image we prefer */
- /* 360x576 or 360x480 for now */
+ height = height > (3 * maxh / 4) ? maxh : maxh / 2;
+ width = width > (3 * maxw / 4) ? maxw : maxw / 2;
+ /* According to empiatech support the MaxPacketSize is too small
+ * to support framesizes larger than 640x480 @ 30 fps or 640x576
+ * @ 25 fps. As this would cut of a part of the image we prefer
+ * 360x576 or 360x480 for now */
if (width == maxw && height == maxh)
width /= 2;
+ } else {
+ /* width must even because of the YUYV format
+ height must be even because of interlacing */
+ v4l_bound_align_image(&width, 48, maxw, 1, &height, 32, maxh, 1, 0);
}
get_scale(dev, width, height, &hscale, &vscale);
diff --git a/linux/drivers/media/video/em28xx/em28xx.h b/linux/drivers/media/video/em28xx/em28xx.h
index 966a3b924..6fb890efa 100644
--- a/linux/drivers/media/video/em28xx/em28xx.h
+++ b/linux/drivers/media/video/em28xx/em28xx.h
@@ -59,7 +59,7 @@
#define EM2883_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
+#define EM2860_BOARD_SAA711X_REFERENCE_DESIGN 19
#define EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600 20
#define EM2800_BOARD_GRABBEEX_USB2800 21
#define EM2750_BOARD_UNKNOWN 22
@@ -104,6 +104,10 @@
#define EM2860_BOARD_EASYCAP 64
#define EM2820_BOARD_IODATA_GVMVP_SZ 65
#define EM2880_BOARD_EMPIRE_DUAL_TV 66
+#define EM2860_BOARD_TERRATEC_GRABBY 67
+#define EM2860_BOARD_TERRATEC_AV350 68
+#define EM2882_BOARD_KWORLD_ATSC_315U 69
+#define EM2882_BOARD_EVGA_INDTUBE 70
/* Limits minimum and default number of buffers */
#define EM28XX_MIN_BUF 4
@@ -625,6 +629,7 @@ int em28xx_init_isoc(struct em28xx *dev, int max_packets,
int num_bufs, int max_pkt_size,
int (*isoc_copy) (struct em28xx *dev, struct urb *urb));
void em28xx_uninit_isoc(struct em28xx *dev);
+int em28xx_isoc_dvb_max_packetsize(struct em28xx *dev);
int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode);
int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio);
void em28xx_wake_i2c(struct em28xx *dev);
@@ -649,7 +654,7 @@ extern void em28xx_card_setup(struct em28xx *dev);
extern struct em28xx_board em28xx_boards[];
extern struct usb_device_id em28xx_id_table[];
extern const unsigned int em28xx_bcount;
-void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir);
+void em28xx_register_i2c_ir(struct em28xx *dev);
int em28xx_tuner_callback(void *ptr, int component, int command, int arg);
void em28xx_release_resources(struct em28xx *dev);
diff --git a/linux/drivers/media/video/gspca/gspca.c b/linux/drivers/media/video/gspca/gspca.c
index c3c17faa3..f06aac676 100644
--- a/linux/drivers/media/video/gspca/gspca.c
+++ b/linux/drivers/media/video/gspca/gspca.c
@@ -875,6 +875,32 @@ out:
return ret;
}
+static int vidioc_enum_framesizes(struct file *file, void *priv,
+ struct v4l2_frmsizeenum *fsize)
+{
+ struct gspca_dev *gspca_dev = priv;
+ int i;
+ __u32 index = 0;
+
+ for (i = 0; i < gspca_dev->cam.nmodes; i++) {
+ if (fsize->pixel_format !=
+ gspca_dev->cam.cam_mode[i].pixelformat)
+ continue;
+
+ if (fsize->index == index) {
+ fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+ fsize->discrete.width =
+ gspca_dev->cam.cam_mode[i].width;
+ fsize->discrete.height =
+ gspca_dev->cam.cam_mode[i].height;
+ return 0;
+ }
+ index++;
+ }
+
+ return -EINVAL;
+}
+
static void gspca_release(struct video_device *vfd)
{
struct gspca_dev *gspca_dev = container_of(vfd, struct gspca_dev, vdev);
@@ -995,43 +1021,52 @@ out:
return ret;
}
+static const struct ctrl *get_ctrl(struct gspca_dev *gspca_dev,
+ int id)
+{
+ const struct ctrl *ctrls;
+ int i;
+
+ for (i = 0, ctrls = gspca_dev->sd_desc->ctrls;
+ i < gspca_dev->sd_desc->nctrls;
+ i++, ctrls++) {
+ if (gspca_dev->ctrl_dis & (1 << i))
+ continue;
+ if (id == ctrls->qctrl.id)
+ return ctrls;
+ }
+ return NULL;
+}
+
static int vidioc_queryctrl(struct file *file, void *priv,
struct v4l2_queryctrl *q_ctrl)
{
struct gspca_dev *gspca_dev = priv;
- int i, ix;
+ const struct ctrl *ctrls;
+ int i;
u32 id;
- ix = -1;
+ ctrls = NULL;
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 (gspca_dev->sd_desc->ctrls[i].qctrl.id < id)
+ if (gspca_dev->ctrl_dis & (1 << i))
continue;
- if (ix < 0) {
- ix = i;
+ if (gspca_dev->sd_desc->ctrls[i].qctrl.id < id)
continue;
- }
- if (gspca_dev->sd_desc->ctrls[i].qctrl.id
- > gspca_dev->sd_desc->ctrls[ix].qctrl.id)
+ if (ctrls && gspca_dev->sd_desc->ctrls[i].qctrl.id
+ > ctrls->qctrl.id)
continue;
- ix = i;
- }
- }
- for (i = 0; i < gspca_dev->sd_desc->nctrls; i++) {
- if (id == gspca_dev->sd_desc->ctrls[i].qctrl.id) {
- ix = i;
- break;
+ ctrls = &gspca_dev->sd_desc->ctrls[i];
}
+ } else {
+ ctrls = get_ctrl(gspca_dev, id);
}
- if (ix < 0)
+ if (ctrls == NULL)
return -EINVAL;
- memcpy(q_ctrl, &gspca_dev->sd_desc->ctrls[ix].qctrl,
- sizeof *q_ctrl);
- if (gspca_dev->ctrl_dis & (1 << ix))
- q_ctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
+ memcpy(q_ctrl, ctrls, sizeof *q_ctrl);
return 0;
}
@@ -1040,56 +1075,45 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
{
struct gspca_dev *gspca_dev = priv;
const struct ctrl *ctrls;
- int i, ret;
+ int 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 (gspca_dev->ctrl_dis & (1 << i))
- return -EINVAL;
- 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;
- if (gspca_dev->present)
- ret = ctrls->set(gspca_dev, ctrl->value);
- else
- ret = -ENODEV;
- mutex_unlock(&gspca_dev->usb_lock);
- return ret;
- }
- return -EINVAL;
+ ctrls = get_ctrl(gspca_dev, ctrl->id);
+ if (ctrls == NULL)
+ return -EINVAL;
+
+ 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;
+ if (gspca_dev->present)
+ ret = ctrls->set(gspca_dev, ctrl->value);
+ else
+ ret = -ENODEV;
+ mutex_unlock(&gspca_dev->usb_lock);
+ return ret;
}
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;
+ int 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 (gspca_dev->ctrl_dis & (1 << i))
- return -EINVAL;
- if (mutex_lock_interruptible(&gspca_dev->usb_lock))
- return -ERESTARTSYS;
- if (gspca_dev->present)
- ret = ctrls->get(gspca_dev, &ctrl->value);
- else
- ret = -ENODEV;
- mutex_unlock(&gspca_dev->usb_lock);
- return ret;
- }
- return -EINVAL;
+ ctrls = get_ctrl(gspca_dev, ctrl->id);
+ if (ctrls == NULL)
+ return -EINVAL;
+
+ if (mutex_lock_interruptible(&gspca_dev->usb_lock))
+ return -ERESTARTSYS;
+ if (gspca_dev->present)
+ ret = ctrls->get(gspca_dev, &ctrl->value);
+ else
+ ret = -ENODEV;
+ mutex_unlock(&gspca_dev->usb_lock);
+ return ret;
}
/*fixme: have an audio flag in gspca_dev?*/
@@ -1870,6 +1894,7 @@ static const struct v4l2_ioctl_ops dev_ioctl_ops = {
.vidioc_g_parm = vidioc_g_parm,
.vidioc_s_parm = vidioc_s_parm,
.vidioc_s_std = vidioc_s_std,
+ .vidioc_enum_framesizes = vidioc_enum_framesizes,
#ifdef CONFIG_VIDEO_V4L1_COMPAT
.vidiocgmbuf = vidiocgmbuf,
#endif
diff --git a/linux/drivers/media/video/gspca/m5602/m5602_ov9650.c b/linux/drivers/media/video/gspca/m5602/m5602_ov9650.c
index bbf9935df..a1245cca1 100644
--- a/linux/drivers/media/video/gspca/m5602/m5602_ov9650.c
+++ b/linux/drivers/media/video/gspca/m5602/m5602_ov9650.c
@@ -47,53 +47,60 @@ static
#endif
struct dmi_system_id ov9650_flip_dmi_table[] = {
{
- .ident = "ASUS A6VA",
+ .ident = "ASUS A6Ja",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
- DMI_MATCH(DMI_PRODUCT_NAME, "A6VA")
+ DMI_MATCH(DMI_PRODUCT_NAME, "A6J")
}
},
{
-
- .ident = "ASUS A6VC",
+ .ident = "ASUS A6JC",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
- DMI_MATCH(DMI_PRODUCT_NAME, "A6VC")
+ DMI_MATCH(DMI_PRODUCT_NAME, "A6JC")
}
},
{
- .ident = "ASUS A6VM",
+ .ident = "ASUS A6K",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
- DMI_MATCH(DMI_PRODUCT_NAME, "A6VM")
+ DMI_MATCH(DMI_PRODUCT_NAME, "A6K")
}
},
{
- .ident = "ASUS A6JC",
+ .ident = "ASUS A6Kt",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
- DMI_MATCH(DMI_PRODUCT_NAME, "A6JC")
+ DMI_MATCH(DMI_PRODUCT_NAME, "A6Kt")
}
},
{
- .ident = "ASUS A6Ja",
+ .ident = "ASUS A6VA",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
- DMI_MATCH(DMI_PRODUCT_NAME, "A6J")
+ DMI_MATCH(DMI_PRODUCT_NAME, "A6VA")
}
},
{
- .ident = "ASUS A6Kt",
+
+ .ident = "ASUS A6VC",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
- DMI_MATCH(DMI_PRODUCT_NAME, "A6Kt")
+ DMI_MATCH(DMI_PRODUCT_NAME, "A6VC")
}
},
{
- .ident = "ASUS A6K",
+ .ident = "ASUS A6VM",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
- DMI_MATCH(DMI_PRODUCT_NAME, "A6K")
+ DMI_MATCH(DMI_PRODUCT_NAME, "A6VM")
+ }
+ },
+ {
+ .ident = "ASUS A7V",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "A7V")
}
},
{
diff --git a/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.c b/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.c
index 81f24d413..4a105cb38 100644
--- a/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.c
+++ b/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.c
@@ -67,6 +67,12 @@ static
DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
DMI_MATCH(DMI_PRODUCT_NAME, "MS-1717X")
}
+ }, {
+ .ident = "Lenovo Y300",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "L3000 Y300"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Y300")
+ }
},
{ }
};
diff --git a/linux/drivers/media/video/gspca/ov519.c b/linux/drivers/media/video/gspca/ov519.c
index bd70e9adb..cde3a0177 100644
--- a/linux/drivers/media/video/gspca/ov519.c
+++ b/linux/drivers/media/video/gspca/ov519.c
@@ -50,6 +50,19 @@ static int i2c_detect_tries = 10;
struct sd {
struct gspca_dev gspca_dev; /* !! must be the first item */
+ __u8 packet_nr;
+
+ char bridge;
+#define BRIDGE_OV511 0
+#define BRIDGE_OV511PLUS 1
+#define BRIDGE_OV518 2
+#define BRIDGE_OV518PLUS 3
+#define BRIDGE_OV519 4
+#define BRIDGE_MASK 7
+
+ char invert_led;
+#define BRIDGE_INVERT_LED 8
+
/* Determined by sensor type */
__u8 sif;
@@ -58,22 +71,25 @@ struct sd {
__u8 colors;
__u8 hflip;
__u8 vflip;
+ __u8 autobrightness;
+ __u8 freq;
__u8 stopped; /* Streaming is temporarily paused */
- __u8 frame_rate; /* current Framerate (OV519 only) */
- __u8 clockdiv; /* clockdiv override for OV519 only */
+ __u8 frame_rate; /* current Framerate */
+ __u8 clockdiv; /* clockdiv override */
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_OV7640 5
-#define SEN_OV7670 6
-#define SEN_OV76BE 7
-#define SEN_OV8610 8
+#define SEN_OV66308AF 3
+#define SEN_OV7610 4
+#define SEN_OV7620 5
+#define SEN_OV7640 6
+#define SEN_OV7670 7
+#define SEN_OV76BE 8
+#define SEN_OV8610 9
};
/* V4L2 controls supported by the driver */
@@ -87,8 +103,17 @@ static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val);
static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val);
-
-static struct ctrl sd_ctrls[] = {
+static int sd_setautobrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getautobrightness(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 void setbrightness(struct gspca_dev *gspca_dev);
+static void setcontrast(struct gspca_dev *gspca_dev);
+static void setcolors(struct gspca_dev *gspca_dev);
+static void setautobrightness(struct sd *sd);
+static void setfreq(struct sd *sd);
+
+static const struct ctrl sd_ctrls[] = {
{
{
.id = V4L2_CID_BRIGHTNESS,
@@ -131,7 +156,7 @@ static struct ctrl sd_ctrls[] = {
.set = sd_setcolors,
.get = sd_getcolors,
},
-/* next controls work with ov7670 only */
+/* The flip controls work with ov7670 only */
#define HFLIP_IDX 3
{
{
@@ -162,9 +187,54 @@ static struct ctrl sd_ctrls[] = {
.set = sd_setvflip,
.get = sd_getvflip,
},
+#define AUTOBRIGHT_IDX 5
+ {
+ {
+ .id = V4L2_CID_AUTOBRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Auto Brightness",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+#define AUTOBRIGHT_DEF 1
+ .default_value = AUTOBRIGHT_DEF,
+ },
+ .set = sd_setautobrightness,
+ .get = sd_getautobrightness,
+ },
+#define FREQ_IDX 6
+ {
+ {
+ .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,
+#define FREQ_DEF 0
+ .default_value = FREQ_DEF,
+ },
+ .set = sd_setfreq,
+ .get = sd_getfreq,
+ },
+#define OV7670_FREQ_IDX 7
+ {
+ {
+ .id = V4L2_CID_POWER_LINE_FREQUENCY,
+ .type = V4L2_CTRL_TYPE_MENU,
+ .name = "Light frequency filter",
+ .minimum = 0,
+ .maximum = 3, /* 0: 0, 1: 50Hz, 2:60Hz 3: Auto Hz */
+ .step = 1,
+#define OV7670_FREQ_DEF 3
+ .default_value = OV7670_FREQ_DEF,
+ },
+ .set = sd_setfreq,
+ .get = sd_getfreq,
+ },
};
-static const struct v4l2_pix_format vga_mode[] = {
+static const struct v4l2_pix_format ov519_vga_mode[] = {
{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
.bytesperline = 320,
.sizeimage = 320 * 240 * 3 / 8 + 590,
@@ -176,12 +246,22 @@ static const struct v4l2_pix_format vga_mode[] = {
.colorspace = V4L2_COLORSPACE_JPEG,
.priv = 0},
};
-static const struct v4l2_pix_format sif_mode[] = {
+static const struct v4l2_pix_format ov519_sif_mode[] = {
+ {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 160,
+ .sizeimage = 160 * 120 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 3},
{176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
.bytesperline = 176,
.sizeimage = 176 * 144 * 3 / 8 + 590,
.colorspace = V4L2_COLORSPACE_JPEG,
.priv = 1},
+ {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,
@@ -189,6 +269,123 @@ static const struct v4l2_pix_format sif_mode[] = {
.priv = 0},
};
+/* Note some of the sizeimage values for the ov511 / ov518 may seem
+ larger then necessary, however they need to be this big as the ov511 /
+ ov518 always fills the entire isoc frame, using 0 padding bytes when
+ it doesn't have any data. So with low framerates the amount of data
+ transfered can become quite large (libv4l will remove all the 0 padding
+ in userspace). */
+static const struct v4l2_pix_format ov518_vga_mode[] = {
+ {320, 240, V4L2_PIX_FMT_OV518, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240 * 3,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 1},
+ {640, 480, V4L2_PIX_FMT_OV518, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480 * 2,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 0},
+};
+static const struct v4l2_pix_format ov518_sif_mode[] = {
+ {160, 120, V4L2_PIX_FMT_OV518, V4L2_FIELD_NONE,
+ .bytesperline = 160,
+ .sizeimage = 70000,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 3},
+ {176, 144, V4L2_PIX_FMT_OV518, V4L2_FIELD_NONE,
+ .bytesperline = 176,
+ .sizeimage = 70000,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 1},
+ {320, 240, V4L2_PIX_FMT_OV518, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240 * 3,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 2},
+ {352, 288, V4L2_PIX_FMT_OV518, V4L2_FIELD_NONE,
+ .bytesperline = 352,
+ .sizeimage = 352 * 288 * 3,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 0},
+};
+
+static const struct v4l2_pix_format ov511_vga_mode[] = {
+ {320, 240, V4L2_PIX_FMT_OV511, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240 * 3,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 1},
+ {640, 480, V4L2_PIX_FMT_OV511, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480 * 2,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 0},
+};
+static const struct v4l2_pix_format ov511_sif_mode[] = {
+ {160, 120, V4L2_PIX_FMT_OV511, V4L2_FIELD_NONE,
+ .bytesperline = 160,
+ .sizeimage = 70000,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 3},
+ {176, 144, V4L2_PIX_FMT_OV511, V4L2_FIELD_NONE,
+ .bytesperline = 176,
+ .sizeimage = 70000,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 1},
+ {320, 240, V4L2_PIX_FMT_OV511, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240 * 3,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 2},
+ {352, 288, V4L2_PIX_FMT_OV511, V4L2_FIELD_NONE,
+ .bytesperline = 352,
+ .sizeimage = 352 * 288 * 3,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 0},
+};
+
+/* Registers common to OV511 / OV518 */
+#define R51x_FIFO_PSIZE 0x30 /* 2 bytes wide w/ OV518(+) */
+#define R51x_SYS_RESET 0x50
+ /* Reset type flags */
+ #define OV511_RESET_OMNICE 0x08
+#define R51x_SYS_INIT 0x53
+#define R51x_SYS_SNAP 0x52
+#define R51x_SYS_CUST_ID 0x5F
+#define R51x_COMP_LUT_BEGIN 0x80
+
+/* OV511 Camera interface register numbers */
+#define R511_CAM_DELAY 0x10
+#define R511_CAM_EDGE 0x11
+#define R511_CAM_PXCNT 0x12
+#define R511_CAM_LNCNT 0x13
+#define R511_CAM_PXDIV 0x14
+#define R511_CAM_LNDIV 0x15
+#define R511_CAM_UV_EN 0x16
+#define R511_CAM_LINE_MODE 0x17
+#define R511_CAM_OPTS 0x18
+
+#define R511_SNAP_FRAME 0x19
+#define R511_SNAP_PXCNT 0x1A
+#define R511_SNAP_LNCNT 0x1B
+#define R511_SNAP_PXDIV 0x1C
+#define R511_SNAP_LNDIV 0x1D
+#define R511_SNAP_UV_EN 0x1E
+#define R511_SNAP_UV_EN 0x1E
+#define R511_SNAP_OPTS 0x1F
+
+#define R511_DRAM_FLOW_CTL 0x20
+#define R511_FIFO_OPTS 0x31
+#define R511_I2C_CTL 0x40
+#define R511_SYS_LED_CTL 0x55 /* OV511+ only */
+#define R511_COMP_EN 0x78
+#define R511_COMP_LUT_EN 0x79
+
+/* OV518 Camera interface register numbers */
+#define R518_GPIO_OUT 0x56 /* OV518(+) only */
+#define R518_GPIO_CTL 0x57 /* OV518(+) only */
+
/* OV519 Camera interface register numbers */
#define OV519_R10_H_SIZE 0x10
#define OV519_R11_V_SIZE 0x11
@@ -224,6 +421,8 @@ static const struct v4l2_pix_format sif_mode[] = {
/* OV7610 registers */
#define OV7610_REG_GAIN 0x00 /* gain setting (5:0) */
+#define OV7610_REG_BLUE 0x01 /* blue channel balance */
+#define OV7610_REG_RED 0x02 /* red channel balance */
#define OV7610_REG_SAT 0x03 /* saturation */
#define OV8610_REG_HUE 0x04 /* 04 reserved */
#define OV7610_REG_CNT 0x05 /* Y contrast */
@@ -330,7 +529,7 @@ static const struct ov_i2c_regvals norm_6x20[] = {
{ 0x28, 0x05 },
{ 0x2a, 0x04 }, /* Disable framerate adjust */
/* { 0x2b, 0xac }, * Framerate; Set 2a[7] first */
- { 0x2d, 0x99 },
+ { 0x2d, 0x85 },
{ 0x33, 0xa0 }, /* Color Processing Parameter */
{ 0x34, 0xd2 }, /* Max A/D range */
{ 0x38, 0x8b },
@@ -363,7 +562,7 @@ static const struct ov_i2c_regvals norm_6x30[] = {
{ 0x07, 0x2d }, /* Sharpness */
{ 0x0c, 0x20 },
{ 0x0d, 0x20 },
- { 0x0e, 0x20 },
+ { 0x0e, 0xa0 }, /* Was 0x20, bit7 enables a 2x gain which we need */
{ 0x0f, 0x05 },
{ 0x10, 0x9a },
{ 0x11, 0x00 }, /* Pixel clock = fastest */
@@ -505,7 +704,7 @@ static const struct ov_i2c_regvals norm_7620[] = {
{ 0x23, 0x00 },
{ 0x26, 0xa2 },
{ 0x27, 0xea },
- { 0x28, 0x20 },
+ { 0x28, 0x22 }, /* Was 0x20, bit1 enables a 2x gain which we need */
{ 0x29, 0x00 },
{ 0x2a, 0x10 },
{ 0x2b, 0x00 },
@@ -846,11 +1045,12 @@ static unsigned char ov7670_abs_to_sm(unsigned char v)
static int reg_w(struct sd *sd, __u16 index, __u8 value)
{
int ret;
+ int req = (sd->bridge <= BRIDGE_OV511PLUS) ? 2 : 1;
sd->gspca_dev.usb_buf[0] = value;
ret = usb_control_msg(sd->gspca_dev.dev,
usb_sndctrlpipe(sd->gspca_dev.dev, 0),
- 1, /* REQ_IO (ov518/519) */
+ req,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0, index,
sd->gspca_dev.usb_buf, 1, 500);
@@ -864,10 +1064,11 @@ static int reg_w(struct sd *sd, __u16 index, __u8 value)
static int reg_r(struct sd *sd, __u16 index)
{
int ret;
+ int req = (sd->bridge <= BRIDGE_OV511PLUS) ? 3 : 1;
ret = usb_control_msg(sd->gspca_dev.dev,
usb_rcvctrlpipe(sd->gspca_dev.dev, 0),
- 1, /* REQ_IO */
+ req,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0, index, sd->gspca_dev.usb_buf, 1, 500);
@@ -924,11 +1125,152 @@ static int reg_w_mask(struct sd *sd,
}
/*
+ * Writes multiple (n) byte value to a single register. Only valid with certain
+ * registers (0x30 and 0xc4 - 0xce).
+ */
+static int ov518_reg_w32(struct sd *sd, __u16 index, u32 value, int n)
+{
+ int ret;
+
+ *((u32 *)sd->gspca_dev.usb_buf) = __cpu_to_le32(value);
+
+ ret = usb_control_msg(sd->gspca_dev.dev,
+ usb_sndctrlpipe(sd->gspca_dev.dev, 0),
+ 1 /* REG_IO */,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, index,
+ sd->gspca_dev.usb_buf, n, 500);
+ if (ret < 0)
+ PDEBUG(D_ERR, "Write reg32 [%02x] %08x failed", index, value);
+ return ret;
+}
+
+static int ov511_i2c_w(struct sd *sd, __u8 reg, __u8 value)
+{
+ int rc, retries;
+
+ PDEBUG(D_USBO, "i2c 0x%02x -> [0x%02x]", value, reg);
+
+ /* Three byte write cycle */
+ for (retries = 6; ; ) {
+ /* 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, R511_I2C_CTL, 0x01);
+ if (rc < 0)
+ return rc;
+
+ do
+ rc = reg_r(sd, R511_I2C_CTL);
+ while (rc > 0 && ((rc & 1) == 0)); /* Retry until idle */
+
+ if (rc < 0)
+ return rc;
+
+ if ((rc & 2) == 0) /* Ack? */
+ break;
+#if 0
+ /* I2C abort */
+ reg_w(sd, R511_I2C_CTL, 0x10);
+#endif
+ if (--retries < 0) {
+ PDEBUG(D_USBO, "i2c write retries exhausted");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static int ov511_i2c_r(struct sd *sd, __u8 reg)
+{
+ int rc, value, retries;
+
+ /* Two byte write cycle */
+ for (retries = 6; ; ) {
+ /* 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, R511_I2C_CTL, 0x03);
+ if (rc < 0)
+ return rc;
+
+ do
+ rc = reg_r(sd, R511_I2C_CTL);
+ while (rc > 0 && ((rc & 1) == 0)); /* Retry until idle */
+
+ if (rc < 0)
+ return rc;
+
+ if ((rc & 2) == 0) /* Ack? */
+ break;
+
+ /* I2C abort */
+ reg_w(sd, R511_I2C_CTL, 0x10);
+
+ if (--retries < 0) {
+ PDEBUG(D_USBI, "i2c write retries exhausted");
+ return -1;
+ }
+ }
+
+ /* Two byte read cycle */
+ for (retries = 6; ; ) {
+ /* Initiate 2-byte read cycle */
+ rc = reg_w(sd, R511_I2C_CTL, 0x05);
+ if (rc < 0)
+ return rc;
+
+ do
+ rc = reg_r(sd, R511_I2C_CTL);
+ while (rc > 0 && ((rc & 1) == 0)); /* Retry until idle */
+
+ if (rc < 0)
+ return rc;
+
+ if ((rc & 2) == 0) /* Ack? */
+ break;
+
+ /* I2C abort */
+ rc = reg_w(sd, R511_I2C_CTL, 0x10);
+ if (rc < 0)
+ return rc;
+
+ if (--retries < 0) {
+ PDEBUG(D_USBI, "i2c read retries exhausted");
+ return -1;
+ }
+ }
+
+ value = reg_r(sd, R51x_I2C_DATA);
+
+ PDEBUG(D_USBI, "i2c [0x%02X] -> 0x%02X", reg, value);
+
+ /* This is needed to make i2c_w() work */
+ rc = reg_w(sd, R511_I2C_CTL, 0x05);
+ if (rc < 0)
+ return rc;
+
+ return 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,
+static int ov518_i2c_w(struct sd *sd,
__u8 reg,
__u8 value)
{
@@ -963,7 +1305,7 @@ static int i2c_w(struct sd *sd,
* 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)
+static int ov518_i2c_r(struct sd *sd, __u8 reg)
{
int rc, value;
@@ -986,6 +1328,34 @@ static int i2c_r(struct sd *sd, __u8 reg)
return value;
}
+static int i2c_w(struct sd *sd, __u8 reg, __u8 value)
+{
+ switch (sd->bridge) {
+ case BRIDGE_OV511:
+ case BRIDGE_OV511PLUS:
+ return ov511_i2c_w(sd, reg, value);
+ case BRIDGE_OV518:
+ case BRIDGE_OV518PLUS:
+ case BRIDGE_OV519:
+ return ov518_i2c_w(sd, reg, value);
+ }
+ return -1; /* Should never happen */
+}
+
+static int i2c_r(struct sd *sd, __u8 reg)
+{
+ switch (sd->bridge) {
+ case BRIDGE_OV511:
+ case BRIDGE_OV511PLUS:
+ return ov511_i2c_r(sd, reg);
+ case BRIDGE_OV518:
+ case BRIDGE_OV518PLUS:
+ case BRIDGE_OV519:
+ return ov518_i2c_r(sd, reg);
+ }
+ return -1; /* Should never happen */
+}
+
/* 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
@@ -1014,20 +1384,47 @@ static inline int ov51x_stop(struct sd *sd)
{
PDEBUG(D_STREAM, "stopping");
sd->stopped = 1;
- return reg_w(sd, OV519_SYS_RESET1, 0x0f);
+ switch (sd->bridge) {
+ case BRIDGE_OV511:
+ case BRIDGE_OV511PLUS:
+ return reg_w(sd, R51x_SYS_RESET, 0x3d);
+ case BRIDGE_OV518:
+ case BRIDGE_OV518PLUS:
+ return reg_w_mask(sd, R51x_SYS_RESET, 0x3a, 0x3a);
+ case BRIDGE_OV519:
+ return reg_w(sd, OV519_SYS_RESET1, 0x0f);
+ }
+
+ return 0;
}
/* 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)
{
+ int rc;
+
PDEBUG(D_STREAM, "restarting");
if (!sd->stopped)
return 0;
sd->stopped = 0;
/* Reinitialize the stream */
- return reg_w(sd, OV519_SYS_RESET1, 0x00);
+ switch (sd->bridge) {
+ case BRIDGE_OV511:
+ case BRIDGE_OV511PLUS:
+ return reg_w(sd, R51x_SYS_RESET, 0x00);
+ case BRIDGE_OV518:
+ case BRIDGE_OV518PLUS:
+ rc = reg_w(sd, 0x2f, 0x80);
+ if (rc < 0)
+ return rc;
+ return reg_w(sd, R51x_SYS_RESET, 0x00);
+ case BRIDGE_OV519:
+ return reg_w(sd, OV519_SYS_RESET1, 0x00);
+ }
+
+ return 0;
}
/* This does an initial reset of an OmniVision sensor and ensures that I2C
@@ -1138,7 +1535,6 @@ static int ov8xx0_configure(struct sd *sd)
}
/* Set sensor-specific vars */
-/* sd->sif = 0; already done */
return 0;
}
@@ -1175,15 +1571,13 @@ static int ov7xx0_configure(struct sd *sd)
}
} else if ((rc & 3) == 1) {
/* I don't know what's different about the 76BE yet. */
- if (i2c_r(sd, 0x15) & 1)
+ if (i2c_r(sd, 0x15) & 1) {
PDEBUG(D_PROBE, "Sensor is an OV7620AE");
- else
+ sd->sensor = SEN_OV7620;
+ } 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;
+ sd->sensor = SEN_OV76BE;
+ }
} else if ((rc & 3) == 0) {
/* try to read product id registers */
high = i2c_r(sd, 0x0a);
@@ -1229,7 +1623,6 @@ static int ov7xx0_configure(struct sd *sd)
}
/* Set sensor-specific vars */
-/* sd->sif = 0; already done */
return 0;
}
@@ -1258,13 +1651,14 @@ static int ov6xx0_configure(struct sd *sd)
break;
case 0x01:
sd->sensor = SEN_OV6620;
+ PDEBUG(D_PROBE, "Sensor is an OV6620");
break;
case 0x02:
sd->sensor = SEN_OV6630;
PDEBUG(D_PROBE, "Sensor is an OV66308AE");
break;
case 0x03:
- sd->sensor = SEN_OV6630;
+ sd->sensor = SEN_OV66308AF;
PDEBUG(D_PROBE, "Sensor is an OV66308AF");
break;
case 0x90:
@@ -1287,16 +1681,276 @@ static int ov6xx0_configure(struct sd *sd)
/* Turns on or off the LED. Only has an effect with OV511+/OV518(+)/OV519 */
static void ov51x_led_control(struct sd *sd, int on)
{
- reg_w_mask(sd, OV519_GPIO_DATA_OUT0, !on, 1); /* 0 / 1 */
+ if (sd->invert_led)
+ on = !on;
+
+ switch (sd->bridge) {
+ /* OV511 has no LED control */
+ case BRIDGE_OV511PLUS:
+ reg_w(sd, R511_SYS_LED_CTL, on ? 1 : 0);
+ break;
+ case BRIDGE_OV518:
+ case BRIDGE_OV518PLUS:
+ reg_w_mask(sd, R518_GPIO_OUT, on ? 0x02 : 0x00, 0x02);
+ break;
+ case BRIDGE_OV519:
+ reg_w_mask(sd, OV519_GPIO_DATA_OUT0, !on, 1); /* 0 / 1 */
+ break;
+ }
}
-/* this function is called at probe time */
-static int sd_config(struct gspca_dev *gspca_dev,
- const struct usb_device_id *id)
+static int ov51x_upload_quan_tables(struct sd *sd)
+{
+ const unsigned char yQuanTable511[] = {
+ 0, 1, 1, 2, 2, 3, 3, 4,
+ 1, 1, 1, 2, 2, 3, 4, 4,
+ 1, 1, 2, 2, 3, 4, 4, 4,
+ 2, 2, 2, 3, 4, 4, 4, 4,
+ 2, 2, 3, 4, 4, 5, 5, 5,
+ 3, 3, 4, 4, 5, 5, 5, 5,
+ 3, 4, 4, 4, 5, 5, 5, 5,
+ 4, 4, 4, 4, 5, 5, 5, 5
+ };
+
+ const unsigned char uvQuanTable511[] = {
+ 0, 2, 2, 3, 4, 4, 4, 4,
+ 2, 2, 2, 4, 4, 4, 4, 4,
+ 2, 2, 3, 4, 4, 4, 4, 4,
+ 3, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4
+ };
+
+ /* OV518 quantization tables are 8x4 (instead of 8x8) */
+ const unsigned char yQuanTable518[] = {
+ 5, 4, 5, 6, 6, 7, 7, 7,
+ 5, 5, 5, 5, 6, 7, 7, 7,
+ 6, 6, 6, 6, 7, 7, 7, 8,
+ 7, 7, 6, 7, 7, 7, 8, 8
+ };
+
+ const unsigned char uvQuanTable518[] = {
+ 6, 6, 6, 7, 7, 7, 7, 7,
+ 6, 6, 6, 7, 7, 7, 7, 7,
+ 6, 6, 6, 7, 7, 7, 7, 8,
+ 7, 7, 7, 7, 7, 7, 8, 8
+ };
+
+ const unsigned char *pYTable, *pUVTable;
+ unsigned char val0, val1;
+ int i, size, rc, reg = R51x_COMP_LUT_BEGIN;
+
+ PDEBUG(D_PROBE, "Uploading quantization tables");
+
+ if (sd->bridge == BRIDGE_OV511 || sd->bridge == BRIDGE_OV511PLUS) {
+ pYTable = yQuanTable511;
+ pUVTable = uvQuanTable511;
+ size = 32;
+ } else {
+ pYTable = yQuanTable518;
+ pUVTable = uvQuanTable518;
+ size = 16;
+ }
+
+ for (i = 0; i < size; i++) {
+ val0 = *pYTable++;
+ val1 = *pYTable++;
+ val0 &= 0x0f;
+ val1 &= 0x0f;
+ val0 |= val1 << 4;
+ rc = reg_w(sd, reg, val0);
+ if (rc < 0)
+ return rc;
+
+ val0 = *pUVTable++;
+ val1 = *pUVTable++;
+ val0 &= 0x0f;
+ val1 &= 0x0f;
+ val0 |= val1 << 4;
+ rc = reg_w(sd, reg + size, val0);
+ if (rc < 0)
+ return rc;
+
+ reg++;
+ }
+
+ return 0;
+}
+
+/* This initializes the OV511/OV511+ and the sensor */
+static int ov511_configure(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- struct cam *cam;
+ int rc;
+
+ /* For 511 and 511+ */
+ const struct ov_regvals init_511[] = {
+ { R51x_SYS_RESET, 0x7f },
+ { R51x_SYS_INIT, 0x01 },
+ { R51x_SYS_RESET, 0x7f },
+ { R51x_SYS_INIT, 0x01 },
+ { R51x_SYS_RESET, 0x3f },
+ { R51x_SYS_INIT, 0x01 },
+ { R51x_SYS_RESET, 0x3d },
+ };
+
+ const struct ov_regvals norm_511[] = {
+ { R511_DRAM_FLOW_CTL, 0x01 },
+ { R51x_SYS_SNAP, 0x00 },
+ { R51x_SYS_SNAP, 0x02 },
+ { R51x_SYS_SNAP, 0x00 },
+ { R511_FIFO_OPTS, 0x1f },
+ { R511_COMP_EN, 0x00 },
+ { R511_COMP_LUT_EN, 0x03 },
+ };
+
+ const struct ov_regvals norm_511_p[] = {
+ { R511_DRAM_FLOW_CTL, 0xff },
+ { R51x_SYS_SNAP, 0x00 },
+ { R51x_SYS_SNAP, 0x02 },
+ { R51x_SYS_SNAP, 0x00 },
+ { R511_FIFO_OPTS, 0xff },
+ { R511_COMP_EN, 0x00 },
+ { R511_COMP_LUT_EN, 0x03 },
+ };
+
+ const struct ov_regvals compress_511[] = {
+ { 0x70, 0x1f },
+ { 0x71, 0x05 },
+ { 0x72, 0x06 },
+ { 0x73, 0x06 },
+ { 0x74, 0x14 },
+ { 0x75, 0x03 },
+ { 0x76, 0x04 },
+ { 0x77, 0x04 },
+ };
+
+ PDEBUG(D_PROBE, "Device custom id %x", reg_r(sd, R51x_SYS_CUST_ID));
+
+ rc = write_regvals(sd, init_511, ARRAY_SIZE(init_511));
+ if (rc < 0)
+ return rc;
+
+ switch (sd->bridge) {
+ case BRIDGE_OV511:
+ rc = write_regvals(sd, norm_511, ARRAY_SIZE(norm_511));
+ if (rc < 0)
+ return rc;
+ break;
+ case BRIDGE_OV511PLUS:
+ rc = write_regvals(sd, norm_511_p, ARRAY_SIZE(norm_511_p));
+ if (rc < 0)
+ return rc;
+ break;
+ }
+
+ /* Init compression */
+ rc = write_regvals(sd, compress_511, ARRAY_SIZE(compress_511));
+ if (rc < 0)
+ return rc;
+
+ rc = ov51x_upload_quan_tables(sd);
+ if (rc < 0) {
+ PDEBUG(D_ERR, "Error uploading quantization tables");
+ return rc;
+ }
+
+ return 0;
+}
+
+/* This initializes the OV518/OV518+ and the sensor */
+static int ov518_configure(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int rc;
+
+ /* For 518 and 518+ */
+ const struct ov_regvals init_518[] = {
+ { R51x_SYS_RESET, 0x40 },
+ { R51x_SYS_INIT, 0xe1 },
+ { R51x_SYS_RESET, 0x3e },
+ { R51x_SYS_INIT, 0xe1 },
+ { R51x_SYS_RESET, 0x00 },
+ { R51x_SYS_INIT, 0xe1 },
+ { 0x46, 0x00 },
+ { 0x5d, 0x03 },
+ };
+
+ const struct ov_regvals norm_518[] = {
+ { R51x_SYS_SNAP, 0x02 }, /* Reset */
+ { R51x_SYS_SNAP, 0x01 }, /* Enable */
+ { 0x31, 0x0f },
+ { 0x5d, 0x03 },
+ { 0x24, 0x9f },
+ { 0x25, 0x90 },
+ { 0x20, 0x00 },
+ { 0x51, 0x04 },
+ { 0x71, 0x19 },
+ { 0x2f, 0x80 },
+ };
+
+ const struct ov_regvals norm_518_p[] = {
+ { R51x_SYS_SNAP, 0x02 }, /* Reset */
+ { R51x_SYS_SNAP, 0x01 }, /* Enable */
+ { 0x31, 0x0f },
+ { 0x5d, 0x03 },
+ { 0x24, 0x9f },
+ { 0x25, 0x90 },
+ { 0x20, 0x60 },
+ { 0x51, 0x02 },
+ { 0x71, 0x19 },
+ { 0x40, 0xff },
+ { 0x41, 0x42 },
+ { 0x46, 0x00 },
+ { 0x33, 0x04 },
+ { 0x21, 0x19 },
+ { 0x3f, 0x10 },
+ { 0x2f, 0x80 },
+ };
+
+ /* First 5 bits of custom ID reg are a revision ID on OV518 */
+ PDEBUG(D_PROBE, "Device revision %d",
+ 0x1F & reg_r(sd, R51x_SYS_CUST_ID));
+
+ rc = write_regvals(sd, init_518, ARRAY_SIZE(init_518));
+ if (rc < 0)
+ return rc;
+
+ /* Set LED GPIO pin to output mode */
+ rc = reg_w_mask(sd, R518_GPIO_CTL, 0x00, 0x02);
+ if (rc < 0)
+ return rc;
+
+ switch (sd->bridge) {
+ case BRIDGE_OV518:
+ rc = write_regvals(sd, norm_518, ARRAY_SIZE(norm_518));
+ if (rc < 0)
+ return rc;
+ break;
+ case BRIDGE_OV518PLUS:
+ rc = write_regvals(sd, norm_518_p, ARRAY_SIZE(norm_518_p));
+ if (rc < 0)
+ return rc;
+ break;
+ }
+ rc = ov51x_upload_quan_tables(sd);
+ if (rc < 0) {
+ PDEBUG(D_ERR, "Error uploading quantization tables");
+ return rc;
+ }
+
+ rc = reg_w(sd, 0x2f, 0x80);
+ if (rc < 0)
+ return rc;
+
+ return 0;
+}
+
+static int ov519_configure(struct sd *sd)
+{
static const struct ov_regvals init_519[] = {
{ 0x5a, 0x6d }, /* EnableSystem */
{ 0x53, 0x9b },
@@ -1313,8 +1967,37 @@ static int sd_config(struct gspca_dev *gspca_dev,
/* windows reads 0x55 at this point*/
};
- if (write_regvals(sd, init_519, ARRAY_SIZE(init_519)))
+ return write_regvals(sd, init_519, ARRAY_SIZE(init_519));
+}
+
+/* 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 ret = 0;
+
+ sd->bridge = id->driver_info & BRIDGE_MASK;
+ sd->invert_led = id->driver_info & BRIDGE_INVERT_LED;
+
+ switch (sd->bridge) {
+ case BRIDGE_OV511:
+ case BRIDGE_OV511PLUS:
+ ret = ov511_configure(gspca_dev);
+ break;
+ case BRIDGE_OV518:
+ case BRIDGE_OV518PLUS:
+ ret = ov518_configure(gspca_dev);
+ break;
+ case BRIDGE_OV519:
+ ret = ov519_configure(sd);
+ break;
+ }
+
+ if (ret)
goto error;
+
ov51x_led_control(sd, 0); /* turn LED off */
/* Test for 76xx */
@@ -1360,21 +2043,60 @@ static int sd_config(struct gspca_dev *gspca_dev,
}
cam = &gspca_dev->cam;
- if (!sd->sif) {
- cam->cam_mode = vga_mode;
- cam->nmodes = ARRAY_SIZE(vga_mode);
- } else {
- cam->cam_mode = sif_mode;
- cam->nmodes = ARRAY_SIZE(sif_mode);
+ switch (sd->bridge) {
+ case BRIDGE_OV511:
+ case BRIDGE_OV511PLUS:
+ if (!sd->sif) {
+ cam->cam_mode = ov511_vga_mode;
+ cam->nmodes = ARRAY_SIZE(ov511_vga_mode);
+ } else {
+ cam->cam_mode = ov511_sif_mode;
+ cam->nmodes = ARRAY_SIZE(ov511_sif_mode);
+ }
+ break;
+ case BRIDGE_OV518:
+ case BRIDGE_OV518PLUS:
+ if (!sd->sif) {
+ cam->cam_mode = ov518_vga_mode;
+ cam->nmodes = ARRAY_SIZE(ov518_vga_mode);
+ } else {
+ cam->cam_mode = ov518_sif_mode;
+ cam->nmodes = ARRAY_SIZE(ov518_sif_mode);
+ }
+ break;
+ case BRIDGE_OV519:
+ if (!sd->sif) {
+ cam->cam_mode = ov519_vga_mode;
+ cam->nmodes = ARRAY_SIZE(ov519_vga_mode);
+ } else {
+ cam->cam_mode = ov519_sif_mode;
+ cam->nmodes = ARRAY_SIZE(ov519_sif_mode);
+ }
+ break;
}
sd->brightness = BRIGHTNESS_DEF;
- sd->contrast = CONTRAST_DEF;
+ if (sd->sensor == SEN_OV6630 || sd->sensor == SEN_OV66308AF)
+ sd->contrast = 200; /* The default is too low for the ov6630 */
+ else
+ sd->contrast = CONTRAST_DEF;
sd->colors = COLOR_DEF;
sd->hflip = HFLIP_DEF;
sd->vflip = VFLIP_DEF;
- if (sd->sensor != SEN_OV7670)
- gspca_dev->ctrl_dis = (1 << HFLIP_IDX)
- | (1 << VFLIP_IDX);
+ sd->autobrightness = AUTOBRIGHT_DEF;
+ if (sd->sensor == SEN_OV7670) {
+ sd->freq = OV7670_FREQ_DEF;
+ gspca_dev->ctrl_dis = 1 << FREQ_IDX;
+ } else {
+ sd->freq = FREQ_DEF;
+ gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX) |
+ (1 << OV7670_FREQ_IDX);
+ }
+ if (sd->sensor == SEN_OV7640 || sd->sensor == SEN_OV7670)
+ gspca_dev->ctrl_dis |= 1 << AUTOBRIGHT_IDX;
+ /* OV8610 Frequency filter control should work but needs testing */
+ if (sd->sensor == SEN_OV8610)
+ gspca_dev->ctrl_dis |= 1 << FREQ_IDX;
+
return 0;
error:
PDEBUG(D_ERR, "OV519 Config failed");
@@ -1393,6 +2115,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
return -EIO;
break;
case SEN_OV6630:
+ case SEN_OV66308AF:
if (write_i2c_regvals(sd, norm_6x30, ARRAY_SIZE(norm_6x30)))
return -EIO;
break;
@@ -1401,6 +2124,8 @@ static int sd_init(struct gspca_dev *gspca_dev)
/* case SEN_OV76BE: */
if (write_i2c_regvals(sd, norm_7610, ARRAY_SIZE(norm_7610)))
return -EIO;
+ if (i2c_w_mask(sd, 0x0e, 0x00, 0x40))
+ return -EIO;
break;
case SEN_OV7620:
if (write_i2c_regvals(sd, norm_7620, ARRAY_SIZE(norm_7620)))
@@ -1422,6 +2147,248 @@ static int sd_init(struct gspca_dev *gspca_dev)
return 0;
}
+/* Set up the OV511/OV511+ with the given image parameters.
+ *
+ * Do not put any sensor-specific code in here (including I2C I/O functions)
+ */
+static int ov511_mode_init_regs(struct sd *sd)
+{
+ int hsegs, vsegs, packet_size, fps, needed;
+ int interlaced = 0;
+ struct usb_host_interface *alt;
+ struct usb_interface *intf;
+
+ intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface);
+ alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt);
+ if (!alt) {
+ PDEBUG(D_ERR, "Couldn't get altsetting");
+ return -EIO;
+ }
+
+ packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
+ reg_w(sd, R51x_FIFO_PSIZE, packet_size >> 5);
+
+ reg_w(sd, R511_CAM_UV_EN, 0x01);
+ reg_w(sd, R511_SNAP_UV_EN, 0x01);
+ reg_w(sd, R511_SNAP_OPTS, 0x03);
+
+ /* Here I'm assuming that snapshot size == image size.
+ * I hope that's always true. --claudio
+ */
+ hsegs = (sd->gspca_dev.width >> 3) - 1;
+ vsegs = (sd->gspca_dev.height >> 3) - 1;
+
+ reg_w(sd, R511_CAM_PXCNT, hsegs);
+ reg_w(sd, R511_CAM_LNCNT, vsegs);
+ reg_w(sd, R511_CAM_PXDIV, 0x00);
+ reg_w(sd, R511_CAM_LNDIV, 0x00);
+
+ /* YUV420, low pass filter on */
+ reg_w(sd, R511_CAM_OPTS, 0x03);
+
+ /* Snapshot additions */
+ reg_w(sd, R511_SNAP_PXCNT, hsegs);
+ reg_w(sd, R511_SNAP_LNCNT, vsegs);
+ reg_w(sd, R511_SNAP_PXDIV, 0x00);
+ reg_w(sd, R511_SNAP_LNDIV, 0x00);
+
+ /******** Set the framerate ********/
+ if (frame_rate > 0)
+ sd->frame_rate = frame_rate;
+
+ switch (sd->sensor) {
+ case SEN_OV6620:
+ /* No framerate control, doesn't like higher rates yet */
+ sd->clockdiv = 3;
+ break;
+
+ /* Note once the FIXME's in mode_init_ov_sensor_regs() are fixed
+ for more sensors we need to do this for them too */
+ case SEN_OV7620:
+ case SEN_OV7640:
+ case SEN_OV76BE:
+ if (sd->gspca_dev.width == 320)
+ interlaced = 1;
+ /* Fall through */
+ case SEN_OV6630:
+ case SEN_OV7610:
+ case SEN_OV7670:
+ switch (sd->frame_rate) {
+ case 30:
+ case 25:
+ /* Not enough bandwidth to do 640x480 @ 30 fps */
+ if (sd->gspca_dev.width != 640) {
+ sd->clockdiv = 0;
+ break;
+ }
+ /* Fall through for 640x480 case */
+ default:
+/* case 20: */
+/* case 15: */
+ sd->clockdiv = 1;
+ break;
+ case 10:
+ sd->clockdiv = 2;
+ break;
+ case 5:
+ sd->clockdiv = 5;
+ break;
+ }
+ if (interlaced) {
+ sd->clockdiv = (sd->clockdiv + 1) * 2 - 1;
+ /* Higher then 10 does not work */
+ if (sd->clockdiv > 10)
+ sd->clockdiv = 10;
+ }
+ break;
+
+ case SEN_OV8610:
+ /* No framerate control ?? */
+ sd->clockdiv = 0;
+ break;
+ }
+
+ /* Check if we have enough bandwidth to disable compression */
+ fps = (interlaced ? 60 : 30) / (sd->clockdiv + 1) + 1;
+ needed = fps * sd->gspca_dev.width * sd->gspca_dev.height * 3 / 2;
+ /* 1400 is a conservative estimate of the max nr of isoc packets/sec */
+ if (needed > 1400 * packet_size) {
+ /* Enable Y and UV quantization and compression */
+ reg_w(sd, R511_COMP_EN, 0x07);
+ reg_w(sd, R511_COMP_LUT_EN, 0x03);
+ } else {
+ reg_w(sd, R511_COMP_EN, 0x06);
+ reg_w(sd, R511_COMP_LUT_EN, 0x00);
+ }
+
+ reg_w(sd, R51x_SYS_RESET, OV511_RESET_OMNICE);
+ reg_w(sd, R51x_SYS_RESET, 0);
+
+ return 0;
+}
+
+/* Sets up the OV518/OV518+ with the given image parameters
+ *
+ * OV518 needs a completely different approach, until we can figure out what
+ * the individual registers do. Also, only 15 FPS is supported now.
+ *
+ * Do not put any sensor-specific code in here (including I2C I/O functions)
+ */
+static int ov518_mode_init_regs(struct sd *sd)
+{
+ int hsegs, vsegs, packet_size;
+ struct usb_host_interface *alt;
+ struct usb_interface *intf;
+
+ intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface);
+ alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt);
+ if (!alt) {
+ PDEBUG(D_ERR, "Couldn't get altsetting");
+ return -EIO;
+ }
+
+ packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
+ ov518_reg_w32(sd, R51x_FIFO_PSIZE, packet_size & ~7, 2);
+
+ /******** Set the mode ********/
+
+ reg_w(sd, 0x2b, 0);
+ reg_w(sd, 0x2c, 0);
+ reg_w(sd, 0x2d, 0);
+ reg_w(sd, 0x2e, 0);
+ reg_w(sd, 0x3b, 0);
+ reg_w(sd, 0x3c, 0);
+ reg_w(sd, 0x3d, 0);
+ reg_w(sd, 0x3e, 0);
+
+ if (sd->bridge == BRIDGE_OV518) {
+ /* Set 8-bit (YVYU) input format */
+ reg_w_mask(sd, 0x20, 0x08, 0x08);
+
+ /* Set 12-bit (4:2:0) output format */
+ reg_w_mask(sd, 0x28, 0x80, 0xf0);
+ reg_w_mask(sd, 0x38, 0x80, 0xf0);
+ } else {
+ reg_w(sd, 0x28, 0x80);
+ reg_w(sd, 0x38, 0x80);
+ }
+
+ hsegs = sd->gspca_dev.width / 16;
+ vsegs = sd->gspca_dev.height / 4;
+
+ reg_w(sd, 0x29, hsegs);
+ reg_w(sd, 0x2a, vsegs);
+
+ reg_w(sd, 0x39, hsegs);
+ reg_w(sd, 0x3a, vsegs);
+
+ /* Windows driver does this here; who knows why */
+ reg_w(sd, 0x2f, 0x80);
+
+ /******** Set the framerate ********/
+ sd->clockdiv = 1;
+
+ /* Mode independent, but framerate dependent, regs */
+ /* 0x51: Clock divider; Only works on some cams which use 2 crystals */
+ reg_w(sd, 0x51, 0x04);
+ reg_w(sd, 0x22, 0x18);
+ reg_w(sd, 0x23, 0xff);
+
+ if (sd->bridge == BRIDGE_OV518PLUS) {
+ switch (sd->sensor) {
+ case SEN_OV7620:
+ if (sd->gspca_dev.width == 320) {
+ reg_w(sd, 0x20, 0x00);
+ reg_w(sd, 0x21, 0x19);
+ } else {
+ reg_w(sd, 0x20, 0x60);
+ reg_w(sd, 0x21, 0x1f);
+ }
+ break;
+ default:
+ reg_w(sd, 0x21, 0x19);
+ }
+ } else
+ reg_w(sd, 0x71, 0x17); /* Compression-related? */
+
+ /* FIXME: Sensor-specific */
+ /* Bit 5 is what matters here. Of course, it is "reserved" */
+ i2c_w(sd, 0x54, 0x23);
+
+ reg_w(sd, 0x2f, 0x80);
+
+ if (sd->bridge == BRIDGE_OV518PLUS) {
+ reg_w(sd, 0x24, 0x94);
+ reg_w(sd, 0x25, 0x90);
+ ov518_reg_w32(sd, 0xc4, 400, 2); /* 190h */
+ ov518_reg_w32(sd, 0xc6, 540, 2); /* 21ch */
+ ov518_reg_w32(sd, 0xc7, 540, 2); /* 21ch */
+ ov518_reg_w32(sd, 0xc8, 108, 2); /* 6ch */
+ ov518_reg_w32(sd, 0xca, 131098, 3); /* 2001ah */
+ ov518_reg_w32(sd, 0xcb, 532, 2); /* 214h */
+ ov518_reg_w32(sd, 0xcc, 2400, 2); /* 960h */
+ ov518_reg_w32(sd, 0xcd, 32, 2); /* 20h */
+ ov518_reg_w32(sd, 0xce, 608, 2); /* 260h */
+ } else {
+ reg_w(sd, 0x24, 0x9f);
+ reg_w(sd, 0x25, 0x90);
+ ov518_reg_w32(sd, 0xc4, 400, 2); /* 190h */
+ ov518_reg_w32(sd, 0xc6, 381, 2); /* 17dh */
+ ov518_reg_w32(sd, 0xc7, 381, 2); /* 17dh */
+ ov518_reg_w32(sd, 0xc8, 128, 2); /* 80h */
+ ov518_reg_w32(sd, 0xca, 183331, 3); /* 2cc23h */
+ ov518_reg_w32(sd, 0xcb, 746, 2); /* 2eah */
+ ov518_reg_w32(sd, 0xcc, 1750, 2); /* 6d6h */
+ ov518_reg_w32(sd, 0xcd, 45, 2); /* 2dh */
+ ov518_reg_w32(sd, 0xce, 851, 2); /* 353h */
+ }
+
+ reg_w(sd, 0x2f, 0x80);
+
+ return 0;
+}
+
+
/* Sets up the OV519 with the given image parameters
*
* OV519 needs a completely different approach, until we can figure out what
@@ -1492,7 +2459,11 @@ static int ov519_mode_init_regs(struct sd *sd)
reg_w(sd, OV519_R10_H_SIZE, sd->gspca_dev.width >> 4);
reg_w(sd, OV519_R11_V_SIZE, sd->gspca_dev.height >> 3);
- reg_w(sd, OV519_R12_X_OFFSETL, 0x00);
+ if (sd->sensor == SEN_OV7670 &&
+ sd->gspca_dev.cam.cam_mode[sd->gspca_dev.curr_mode].priv)
+ reg_w(sd, OV519_R12_X_OFFSETL, 0x04);
+ else
+ reg_w(sd, OV519_R12_X_OFFSETL, 0x00);
reg_w(sd, OV519_R13_X_OFFSETH, 0x00);
reg_w(sd, OV519_R14_Y_OFFSETL, 0x00);
reg_w(sd, OV519_R15_Y_OFFSETH, 0x00);
@@ -1584,7 +2555,7 @@ static int mode_init_ov_sensor_regs(struct sd *sd)
int qvga;
gspca_dev = &sd->gspca_dev;
- qvga = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
+ qvga = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv & 1;
/******** Mode (VGA/QVGA) and sensor specific regs ********/
switch (sd->sensor) {
@@ -1612,30 +2583,16 @@ static int mode_init_ov_sensor_regs(struct sd *sd)
#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); */
@@ -1654,6 +2611,7 @@ static int mode_init_ov_sensor_regs(struct sd *sd)
break;
case SEN_OV6620:
case SEN_OV6630:
+ case SEN_OV66308AF:
i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);
break;
default:
@@ -1661,10 +2619,6 @@ static int mode_init_ov_sensor_regs(struct sd *sd)
}
/******** Palette-specific regs ********/
- 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
@@ -1674,25 +2628,12 @@ static int mode_init_ov_sensor_regs(struct sd *sd)
/* OV7640 is 8-bit only */
- if (sd->sensor != SEN_OV6630 && sd->sensor != SEN_OV7640)
+ if (sd->sensor != SEN_OV6630 && sd->sensor != SEN_OV66308AF &&
+ 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, sd->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 {
- i2c_w(sd, 0x11, sd->clockdiv);
- }
+ i2c_w(sd, 0x11, sd->clockdiv);
/******** Special Features ********/
/* no evidence this is possible with OV7670, either */
@@ -1736,13 +2677,14 @@ static void sethvflip(struct sd *sd)
static int set_ov_sensor_window(struct sd *sd)
{
struct gspca_dev *gspca_dev;
- int qvga;
+ int qvga, crop;
int hwsbase, hwebase, vwsbase, vwebase, hwscale, vwscale;
int ret, hstart, hstop, vstop, vstart;
__u8 v;
gspca_dev = &sd->gspca_dev;
- qvga = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
+ qvga = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv & 1;
+ crop = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv & 2;
/* The different sensor ICs handle setting up of window differently.
* IF YOU SET IT WRONG, YOU WILL GET ALL ZERO ISOC DATA FROM OV51x!! */
@@ -1761,10 +2703,20 @@ static int set_ov_sensor_window(struct sd *sd)
break;
case SEN_OV6620:
case SEN_OV6630:
+ case SEN_OV66308AF:
hwsbase = 0x38;
hwebase = 0x3a;
vwsbase = 0x05;
vwebase = 0x06;
+ if (sd->sensor == SEN_OV66308AF && qvga)
+ /* HDG: this fixes U and V getting swapped */
+ hwsbase++;
+ if (crop) {
+ hwsbase += 8;
+ hwebase += 8;
+ vwsbase += 11;
+ vwebase += 11;
+ }
break;
case SEN_OV7620:
hwsbase = 0x2f; /* From 7620.SET (spec is wrong) */
@@ -1788,6 +2740,7 @@ static int set_ov_sensor_window(struct sd *sd)
switch (sd->sensor) {
case SEN_OV6620:
case SEN_OV6630:
+ case SEN_OV66308AF:
if (qvga) { /* QCIF */
hwscale = 0;
vwscale = 0;
@@ -1840,7 +2793,7 @@ static int set_ov_sensor_window(struct sd *sd)
if (qvga) { /* QVGA from ov7670.c by
* Jonathan Corbet */
hstart = 164;
- hstop = 20;
+ hstop = 28;
vstart = 14;
vstop = 494;
} else { /* VGA */
@@ -1866,7 +2819,6 @@ static int set_ov_sensor_window(struct sd *sd)
msleep(10); /* need to sleep between read and write to
* same reg! */
i2c_w(sd, OV7670_REG_VREF, v);
- sethvflip(sd);
} else {
i2c_w(sd, 0x17, hwsbase);
i2c_w(sd, 0x18, hwebase + (sd->gspca_dev.width >> hwscale));
@@ -1880,15 +2832,35 @@ static int set_ov_sensor_window(struct sd *sd)
static int sd_start(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- int ret;
+ int ret = 0;
- ret = ov519_mode_init_regs(sd);
+ switch (sd->bridge) {
+ case BRIDGE_OV511:
+ case BRIDGE_OV511PLUS:
+ ret = ov511_mode_init_regs(sd);
+ break;
+ case BRIDGE_OV518:
+ case BRIDGE_OV518PLUS:
+ ret = ov518_mode_init_regs(sd);
+ break;
+ case BRIDGE_OV519:
+ ret = ov519_mode_init_regs(sd);
+ break;
+ }
if (ret < 0)
goto out;
+
ret = set_ov_sensor_window(sd);
if (ret < 0)
goto out;
+ setcontrast(gspca_dev);
+ setbrightness(gspca_dev);
+ setcolors(gspca_dev);
+ sethvflip(sd);
+ setautobrightness(sd);
+ setfreq(sd);
+
ret = ov51x_restart(sd);
if (ret < 0)
goto out;
@@ -1907,7 +2879,95 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
ov51x_led_control(sd, 0);
}
-static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+static void ov511_pkt_scan(struct gspca_dev *gspca_dev,
+ struct gspca_frame *frame, /* target */
+ __u8 *in, /* isoc packet */
+ int len) /* iso packet length */
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ /* SOF/EOF packets have 1st to 8th bytes zeroed and the 9th
+ * byte non-zero. The EOF packet has image width/height in the
+ * 10th and 11th bytes. The 9th byte is given as follows:
+ *
+ * bit 7: EOF
+ * 6: compression enabled
+ * 5: 422/420/400 modes
+ * 4: 422/420/400 modes
+ * 3: 1
+ * 2: snapshot button on
+ * 1: snapshot frame
+ * 0: even/odd field
+ */
+ if (!(in[0] | in[1] | in[2] | in[3] | in[4] | in[5] | in[6] | in[7]) &&
+ (in[8] & 0x08)) {
+ if (in[8] & 0x80) {
+ /* Frame end */
+ if ((in[9] + 1) * 8 != gspca_dev->width ||
+ (in[10] + 1) * 8 != gspca_dev->height) {
+ PDEBUG(D_ERR, "Invalid frame size, got: %dx%d,"
+ " requested: %dx%d\n",
+ (in[9] + 1) * 8, (in[10] + 1) * 8,
+ gspca_dev->width, gspca_dev->height);
+ gspca_dev->last_packet_type = DISCARD_PACKET;
+ return;
+ }
+ /* Add 11 byte footer to frame, might be usefull */
+ gspca_frame_add(gspca_dev, LAST_PACKET, frame, in, 11);
+ return;
+ } else {
+ /* Frame start */
+ gspca_frame_add(gspca_dev, FIRST_PACKET, frame, in, 0);
+ sd->packet_nr = 0;
+ }
+ }
+
+ /* Ignore the packet number */
+ len--;
+
+ /* intermediate packet */
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame, in, len);
+}
+
+static void ov518_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;
+
+ /* A false positive here is likely, until OVT gives me
+ * the definitive SOF/EOF format */
+ if ((!(data[0] | data[1] | data[2] | data[3] | data[5])) && data[6]) {
+ gspca_frame_add(gspca_dev, LAST_PACKET, frame, data, 0);
+ gspca_frame_add(gspca_dev, FIRST_PACKET, frame, data, 0);
+ sd->packet_nr = 0;
+ }
+
+ if (gspca_dev->last_packet_type == DISCARD_PACKET)
+ return;
+
+ /* Does this device use packet numbers ? */
+ if (len & 7) {
+ len--;
+ if (sd->packet_nr == data[len])
+ sd->packet_nr++;
+ /* The last few packets of the frame (which are all 0's
+ except that they may contain part of the footer), are
+ numbered 0 */
+ else if (sd->packet_nr == 0 || data[len]) {
+ PDEBUG(D_ERR, "Invalid packet nr: %d (expect: %d)",
+ (int)data[len], (int)sd->packet_nr);
+ gspca_dev->last_packet_type = DISCARD_PACKET;
+ return;
+ }
+ }
+
+ /* intermediate packet */
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+}
+
+static void ov519_pkt_scan(struct gspca_dev *gspca_dev,
struct gspca_frame *frame, /* target */
__u8 *data, /* isoc packet */
int len) /* iso packet length */
@@ -1951,6 +3011,28 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
data, len);
}
+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 (sd->bridge) {
+ case BRIDGE_OV511:
+ case BRIDGE_OV511PLUS:
+ ov511_pkt_scan(gspca_dev, frame, data, len);
+ break;
+ case BRIDGE_OV518:
+ case BRIDGE_OV518PLUS:
+ ov518_pkt_scan(gspca_dev, frame, data, len);
+ break;
+ case BRIDGE_OV519:
+ ov519_pkt_scan(gspca_dev, frame, data, len);
+ break;
+ }
+}
+
/* -- management routines -- */
static void setbrightness(struct gspca_dev *gspca_dev)
@@ -1965,13 +3047,13 @@ static void setbrightness(struct gspca_dev *gspca_dev)
case SEN_OV76BE:
case SEN_OV6620:
case SEN_OV6630:
+ case SEN_OV66308AF:
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) */
+ if (!sd->autobrightness)
i2c_w(sd, OV7610_REG_BRT, val);
break;
case SEN_OV7670:
@@ -1994,7 +3076,9 @@ static void setcontrast(struct gspca_dev *gspca_dev)
i2c_w(sd, OV7610_REG_CNT, val);
break;
case SEN_OV6630:
+ case SEN_OV66308AF:
i2c_w_mask(sd, OV7610_REG_CNT, val >> 4, 0x0f);
+ break;
case SEN_OV8610: {
static const __u8 ctab[] = {
0x03, 0x09, 0x0b, 0x0f, 0x53, 0x6f, 0x35, 0x7f
@@ -2037,6 +3121,7 @@ static void setcolors(struct gspca_dev *gspca_dev)
case SEN_OV76BE:
case SEN_OV6620:
case SEN_OV6630:
+ case SEN_OV66308AF:
i2c_w(sd, OV7610_REG_SAT, val);
break;
case SEN_OV7620:
@@ -2057,6 +3142,72 @@ static void setcolors(struct gspca_dev *gspca_dev)
}
}
+static void setautobrightness(struct sd *sd)
+{
+ if (sd->sensor == SEN_OV7640 || sd->sensor == SEN_OV7670)
+ return;
+
+ i2c_w_mask(sd, 0x2d, sd->autobrightness ? 0x10 : 0x00, 0x10);
+}
+
+static void setfreq(struct sd *sd)
+{
+ if (sd->sensor == SEN_OV7670) {
+ switch (sd->freq) {
+ case 0: /* Banding filter disabled */
+ i2c_w_mask(sd, OV7670_REG_COM8, 0, OV7670_COM8_BFILT);
+ break;
+ case 1: /* 50 hz */
+ i2c_w_mask(sd, OV7670_REG_COM8, OV7670_COM8_BFILT,
+ OV7670_COM8_BFILT);
+ i2c_w_mask(sd, OV7670_REG_COM11, 0x08, 0x18);
+ break;
+ case 2: /* 60 hz */
+ i2c_w_mask(sd, OV7670_REG_COM8, OV7670_COM8_BFILT,
+ OV7670_COM8_BFILT);
+ i2c_w_mask(sd, OV7670_REG_COM11, 0x00, 0x18);
+ break;
+ case 3: /* Auto hz */
+ i2c_w_mask(sd, OV7670_REG_COM8, OV7670_COM8_BFILT,
+ OV7670_COM8_BFILT);
+ i2c_w_mask(sd, OV7670_REG_COM11, OV7670_COM11_HZAUTO,
+ 0x18);
+ break;
+ }
+ } else {
+ switch (sd->freq) {
+ case 0: /* Banding filter disabled */
+ i2c_w_mask(sd, 0x2d, 0x00, 0x04);
+ i2c_w_mask(sd, 0x2a, 0x00, 0x80);
+ break;
+ case 1: /* 50 hz (filter on and framerate adj) */
+ i2c_w_mask(sd, 0x2d, 0x04, 0x04);
+ i2c_w_mask(sd, 0x2a, 0x80, 0x80);
+ /* 20 fps -> 16.667 fps */
+ if (sd->sensor == SEN_OV6620 ||
+ sd->sensor == SEN_OV6630 ||
+ sd->sensor == SEN_OV66308AF)
+ i2c_w(sd, 0x2b, 0x5e);
+ else
+ i2c_w(sd, 0x2b, 0xac);
+ break;
+ case 2: /* 60 hz (filter on, ...) */
+ i2c_w_mask(sd, 0x2d, 0x04, 0x04);
+ if (sd->sensor == SEN_OV6620 ||
+ sd->sensor == SEN_OV6630 ||
+ sd->sensor == SEN_OV66308AF) {
+ /* 20 fps -> 15 fps */
+ i2c_w_mask(sd, 0x2a, 0x80, 0x80);
+ i2c_w(sd, 0x2b, 0xa8);
+ } else {
+ /* no framerate adj. */
+ i2c_w_mask(sd, 0x2a, 0x00, 0x80);
+ }
+ break;
+ }
+ }
+}
+
static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -2147,6 +3298,71 @@ static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
return 0;
}
+static int sd_setautobrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->autobrightness = val;
+ if (gspca_dev->streaming)
+ setautobrightness(sd);
+ return 0;
+}
+
+static int sd_getautobrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->autobrightness;
+ 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)
+ setfreq(sd);
+ 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_querymenu(struct gspca_dev *gspca_dev,
+ struct v4l2_querymenu *menu)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ 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;
+ case 3:
+ if (sd->sensor != SEN_OV7670)
+ return -EINVAL;
+
+ strcpy((char *) menu->name, "Automatic");
+ return 0;
+ }
+ break;
+ }
+ return -EINVAL;
+}
+
/* sub-driver description */
static const struct sd_desc sd_desc = {
.name = MODULE_NAME,
@@ -2157,23 +3373,31 @@ static const struct sd_desc sd_desc = {
.start = sd_start,
.stopN = sd_stopN,
.pkt_scan = sd_pkt_scan,
+ .querymenu = sd_querymenu,
};
/* -- module initialisation -- */
static const __devinitdata struct usb_device_id device_table[] = {
- {USB_DEVICE(0x041e, 0x4052)},
- {USB_DEVICE(0x041e, 0x405f)},
- {USB_DEVICE(0x041e, 0x4060)},
- {USB_DEVICE(0x041e, 0x4061)},
- {USB_DEVICE(0x041e, 0x4064)},
- {USB_DEVICE(0x041e, 0x4068)},
- {USB_DEVICE(0x045e, 0x028c)},
- {USB_DEVICE(0x054c, 0x0154)},
- {USB_DEVICE(0x054c, 0x0155)},
- {USB_DEVICE(0x05a9, 0x0519)},
- {USB_DEVICE(0x05a9, 0x0530)},
- {USB_DEVICE(0x05a9, 0x4519)},
- {USB_DEVICE(0x05a9, 0x8519)},
+ {USB_DEVICE(0x041e, 0x4052), .driver_info = BRIDGE_OV519 },
+ {USB_DEVICE(0x041e, 0x405f), .driver_info = BRIDGE_OV519 },
+ {USB_DEVICE(0x041e, 0x4060), .driver_info = BRIDGE_OV519 },
+ {USB_DEVICE(0x041e, 0x4061), .driver_info = BRIDGE_OV519 },
+ {USB_DEVICE(0x041e, 0x4064),
+ .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED },
+ {USB_DEVICE(0x041e, 0x4068),
+ .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED },
+ {USB_DEVICE(0x045e, 0x028c), .driver_info = BRIDGE_OV519 },
+ {USB_DEVICE(0x054c, 0x0154), .driver_info = BRIDGE_OV519 },
+ {USB_DEVICE(0x054c, 0x0155), .driver_info = BRIDGE_OV519 },
+ {USB_DEVICE(0x05a9, 0x0511), .driver_info = BRIDGE_OV511 },
+ {USB_DEVICE(0x05a9, 0x0518), .driver_info = BRIDGE_OV518 },
+ {USB_DEVICE(0x05a9, 0x0519), .driver_info = BRIDGE_OV519 },
+ {USB_DEVICE(0x05a9, 0x0530), .driver_info = BRIDGE_OV519 },
+ {USB_DEVICE(0x05a9, 0x4519), .driver_info = BRIDGE_OV519 },
+ {USB_DEVICE(0x05a9, 0x8519), .driver_info = BRIDGE_OV519 },
+ {USB_DEVICE(0x05a9, 0xa511), .driver_info = BRIDGE_OV511PLUS },
+ {USB_DEVICE(0x05a9, 0xa518), .driver_info = BRIDGE_OV518PLUS },
+ {USB_DEVICE(0x0813, 0x0002), .driver_info = BRIDGE_OV511PLUS },
{}
};
diff --git a/linux/drivers/media/video/gspca/ov534.c b/linux/drivers/media/video/gspca/ov534.c
index 1e00e46b1..21a9366c7 100644
--- a/linux/drivers/media/video/gspca/ov534.c
+++ b/linux/drivers/media/video/gspca/ov534.c
@@ -60,10 +60,23 @@ struct sd {
static struct ctrl sd_ctrls[] = {
};
-static const struct v4l2_pix_format vga_mode[] = {
+static const struct v4l2_pix_format vga_yuyv_mode[] = {
{640, 480, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
.bytesperline = 640 * 2,
.sizeimage = 640 * 480 * 2,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0},
+};
+
+static const struct v4l2_pix_format vga_jpeg_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},
};
@@ -244,7 +257,7 @@ static const u8 bridge_init_ov965x[][2] = {
};
static const u8 sensor_init_ov965x[][2] = {
- {0x12, 0x80}, /* com7 - reset */
+ {0x12, 0x80}, /* com7 - SSCB reset */
{0x00, 0x00}, /* gain */
{0x01, 0x80}, /* blue */
{0x02, 0x80}, /* red */
@@ -254,10 +267,10 @@ static const u8 sensor_init_ov965x[][2] = {
{0x0e, 0x61}, /* com5 */
{0x0f, 0x42}, /* com6 */
{0x11, 0x00}, /* clkrc */
- {0x12, 0x02}, /* com7 */
+ {0x12, 0x02}, /* com7 - 15fps VGA YUYV */
{0x13, 0xe7}, /* com8 - everything (AGC, AWB and AEC) */
{0x14, 0x28}, /* com9 */
- {0x16, 0x24}, /* rsvd16 */
+ {0x16, 0x24}, /* reg16 */
{0x17, 0x1d}, /* hstart*/
{0x18, 0xbd}, /* hstop */
{0x19, 0x01}, /* vstrt */
@@ -269,24 +282,24 @@ static const u8 sensor_init_ov965x[][2] = {
{0x27, 0x08}, /* bbias */
{0x28, 0x08}, /* gbbias */
{0x29, 0x15}, /* gr com */
- {0x2a, 0x00},
- {0x2b, 0x00},
+ {0x2a, 0x00}, /* exhch */
+ {0x2b, 0x00}, /* exhcl */
{0x2c, 0x08}, /* rbias */
{0x32, 0xff}, /* href */
{0x33, 0x00}, /* chlf */
- {0x34, 0x3f}, /* arblm */
- {0x35, 0x00}, /* rsvd35 */
- {0x36, 0xf8}, /* rsvd36 */
- {0x38, 0x72}, /* acom38 */
- {0x39, 0x57}, /* ofon */
- {0x3a, 0x80}, /* tslb */
- {0x3b, 0xc4},
+ {0x34, 0x3f}, /* aref1 */
+ {0x35, 0x00}, /* aref2 */
+ {0x36, 0xf8}, /* aref3 */
+ {0x38, 0x72}, /* adc2 */
+ {0x39, 0x57}, /* aref4 */
+ {0x3a, 0x80}, /* tslb - yuyv */
+ {0x3b, 0xc4}, /* com11 - night mode 1/4 frame rate */
{0x3d, 0x99}, /* com13 */
- {0x3f, 0xc1},
+ {0x3f, 0xc1}, /* edge */
{0x40, 0xc0}, /* com15 */
{0x41, 0x40}, /* com16 */
- {0x42, 0xc0},
- {0x43, 0x0a},
+ {0x42, 0xc0}, /* com17 */
+ {0x43, 0x0a}, /* rsvd */
{0x44, 0xf0},
{0x45, 0x46},
{0x46, 0x62},
@@ -297,22 +310,22 @@ static const u8 sensor_init_ov965x[][2] = {
{0x4c, 0x7f},
{0x4d, 0x7f},
{0x4e, 0x7f},
- {0x4f, 0x98},
+ {0x4f, 0x98}, /* matrix */
{0x50, 0x98},
{0x51, 0x00},
{0x52, 0x28},
{0x53, 0x70},
{0x54, 0x98},
- {0x58, 0x1a},
- {0x59, 0x85},
+ {0x58, 0x1a}, /* matrix coef sign */
+ {0x59, 0x85}, /* AWB control */
{0x5a, 0xa9},
{0x5b, 0x64},
{0x5c, 0x84},
{0x5d, 0x53},
{0x5e, 0x0e},
- {0x5f, 0xf0},
- {0x60, 0xf0},
- {0x61, 0xf0},
+ {0x5f, 0xf0}, /* AWB blue limit */
+ {0x60, 0xf0}, /* AWB red limit */
+ {0x61, 0xf0}, /* AWB green limit */
{0x62, 0x00}, /* lcc1 */
{0x63, 0x00}, /* lcc2 */
{0x64, 0x02}, /* lcc3 */
@@ -324,15 +337,15 @@ static const u8 sensor_init_ov965x[][2] = {
{0x6d, 0x55},
{0x6e, 0x00},
{0x6f, 0x9d},
- {0x70, 0x21},
+ {0x70, 0x21}, /* dnsth */
{0x71, 0x78},
- {0x72, 0x00},
- {0x73, 0x01},
- {0x74, 0x3a},
- {0x75, 0x35},
+ {0x72, 0x00}, /* poidx */
+ {0x73, 0x01}, /* pckdv */
+ {0x74, 0x3a}, /* xindx */
+ {0x75, 0x35}, /* yindx */
{0x76, 0x01},
{0x77, 0x02},
- {0x7a, 0x12},
+ {0x7a, 0x12}, /* gamma curve */
{0x7b, 0x08},
{0x7c, 0x16},
{0x7d, 0x30},
@@ -349,33 +362,33 @@ static const u8 sensor_init_ov965x[][2] = {
{0x88, 0xe6},
{0x89, 0xf2},
{0x8a, 0x03},
- {0x8c, 0x89},
+ {0x8c, 0x89}, /* com19 */
{0x14, 0x28}, /* com9 */
{0x90, 0x7d},
{0x91, 0x7b},
- {0x9d, 0x03},
- {0x9e, 0x04},
+ {0x9d, 0x03}, /* lcc6 */
+ {0x9e, 0x04}, /* lcc7 */
{0x9f, 0x7a},
{0xa0, 0x79},
{0xa1, 0x40}, /* aechm */
- {0xa4, 0x50},
+ {0xa4, 0x50}, /* com21 */
{0xa5, 0x68}, /* com26 */
- {0xa6, 0x4a},
- {0xa8, 0xc1}, /* acoma8 */
- {0xa9, 0xef}, /* acoma9 */
+ {0xa6, 0x4a}, /* AWB green */
+ {0xa8, 0xc1}, /* refa8 */
+ {0xa9, 0xef}, /* refa9 */
{0xaa, 0x92},
{0xab, 0x04},
- {0xac, 0x80},
+ {0xac, 0x80}, /* black level control */
{0xad, 0x80},
{0xae, 0x80},
{0xaf, 0x80},
{0xb2, 0xf2},
{0xb3, 0x20},
- {0xb4, 0x20},
+ {0xb4, 0x20}, /* ctrlb4 */
{0xb5, 0x00},
{0xb6, 0xaf},
{0xbb, 0xae},
- {0xbc, 0x7f},
+ {0xbc, 0x7f}, /* ADC channel offsets */
{0xdb, 0x7f},
{0xbe, 0x7f},
{0xbf, 0x7f},
@@ -384,7 +397,7 @@ static const u8 sensor_init_ov965x[][2] = {
{0xc2, 0x01},
{0xc3, 0x4e},
{0xc6, 0x85},
- {0xc7, 0x80},
+ {0xc7, 0x80}, /* com24 */
{0xc9, 0xe0},
{0xca, 0xe8},
{0xcb, 0xf0},
@@ -399,11 +412,11 @@ static const u8 sensor_init_ov965x[][2] = {
{0x58, 0x1a},
{0xff, 0x41}, /* read 41, write ff 00 */
{0x41, 0x40}, /* com16 */
- {0xc5, 0x03},
- {0x6a, 0x02},
+ {0xc5, 0x03}, /* 60 Hz banding filter */
+ {0x6a, 0x02}, /* 50 Hz banding filter */
- {0x12, 0x62}, /* com7 - VGA + CIF */
- {0x36, 0xfa}, /* rsvd36 */
+ {0x12, 0x62}, /* com7 - 30fps VGA YUV */
+ {0x36, 0xfa}, /* aref3 */
{0x69, 0x0a}, /* hv */
{0x8c, 0x89}, /* com22 */
{0x14, 0x28}, /* com9 */
@@ -442,8 +455,8 @@ static const u8 bridge_init_ov965x_2[][2] = {
{0x52, 0x3c},
{0x53, 0x00},
{0x54, 0x00},
- {0x55, 0x00},
- {0x57, 0x00},
+ {0x55, 0x00}, /* brightness */
+ {0x57, 0x00}, /* contrast 2 */
{0x5c, 0x00},
{0x5a, 0xa0},
{0x5b, 0x78},
@@ -489,8 +502,31 @@ static const u8 sensor_init_ov965x_2[][2] = {
{0x13, 0xe7}, /* com8 - everything (AGC, AWB and AEC) */
};
+static const u8 sensor_start_ov965x[][2] = {
+ {0x12, 0x62}, /* com7 - 30fps VGA YUV */
+ {0x36, 0xfa}, /* aref3 */
+ {0x69, 0x0a}, /* hv */
+ {0x8c, 0x89}, /* com22 */
+ {0x14, 0x28}, /* com9 */
+ {0x3e, 0x0c}, /* com14 */
+ {0x41, 0x40}, /* com16 */
+ {0x72, 0x00},
+ {0x73, 0x00},
+ {0x74, 0x3a},
+ {0x75, 0x35},
+ {0x76, 0x01},
+ {0xc7, 0x80}, /* com24 */
+ {0x03, 0x12}, /* vref */
+ {0x17, 0x16}, /* hstart */
+ {0x18, 0x02}, /* hstop */
+ {0x19, 0x01}, /* vstrt */
+ {0x1a, 0x3d}, /* vstop */
+ {0x32, 0xff}, /* href */
+ {0xc0, 0xaa},
+ {}
+};
+
static const u8 bridge_start_ov965x[][2] = {
-#if 0
{0x94, 0xaa},
{0xf1, 0x60},
{0xe5, 0x04},
@@ -499,9 +535,33 @@ static const u8 bridge_start_ov965x[][2] = {
{0x8c, 0x00},
{0x8d, 0x1c},
{0x34, 0x05},
-#endif
+ {}
+};
+
+static const u8 bridge_start_ov965x_vga[][2] = {
+ {0xc2, 0x0c},
+ {0xc3, 0xf9},
+ {0xda, 0x01},
+ {0x50, 0x00},
+ {0x51, 0xa0},
+ {0x52, 0x3c},
+ {0x53, 0x00},
+ {0x54, 0x00},
+ {0x55, 0x00},
+ {0x57, 0x00},
+ {0x5c, 0x00},
+ {0x5a, 0xa0},
+ {0x5b, 0x78},
+ {0x35, 0x02},
+ {0xd9, 0x10},
+ {0x94, 0x11},
+ {}
+};
+
+static const u8 bridge_start_ov965x_cif[][2] = {
{0xc2, 0x4c},
{0xc3, 0xf9},
+ {0xda, 0x00},
{0x50, 0x00},
{0x51, 0xa0},
{0x52, 0x78},
@@ -510,39 +570,64 @@ static const u8 bridge_start_ov965x[][2] = {
{0x55, 0x00},
{0x57, 0x00},
{0x5c, 0x00},
- {0x5a, 0x28},
- {0x5b, 0x1e},
- {0x35, 0x00},
- {0xd9, 0x21},
+ {0x5a, 0x50},
+ {0x5b, 0x3c},
+ {0x35, 0x02},
+ {0xd9, 0x10},
{0x94, 0x11},
+ {}
};
-static const u8 sensor_start_ov965x[][2] = {
- {0x3b, 0xe4},
+static const u8 sensor_start_ov965x_vga[][2] = {
+ {0x3b, 0xc4}, /* com11 - night mode 1/4 frame rate */
+ {0x1e, 0x04}, /* mvfp */
+ {0x13, 0xe0}, /* com8 */
+ {0x00, 0x00},
+ {0x13, 0xe7}, /* com8 - everything (AGC, AWB and AEC) */
+ {0x11, 0x03}, /* clkrc */
+ {0x6b, 0x5a}, /* dblv */
+ {0x6a, 0x05}, /* 50 Hz banding filter */
+ {0xc5, 0x07}, /* 60 Hz banding filter */
+ {0xa2, 0x4b}, /* bd50 */
+ {0xa3, 0x3e}, /* bd60 */
+
+ {0x2d, 0x00}, /* advfl */
+ {}
+};
+
+static const u8 sensor_start_ov965x_cif[][2] = {
+ {0x3b, 0xe4}, /* com11 - night mode 1/4 frame rate */
{0x1e, 0x04}, /* mvfp */
{0x13, 0xe0}, /* com8 */
{0x00, 0x00},
{0x13, 0xe7}, /* com8 - everything (AGC, AWB and AEC) */
{0x11, 0x01}, /* clkrc */
{0x6b, 0x5a}, /* dblv */
- {0x6a, 0x02},
- {0xc5, 0x03},
- {0xa2, 0x96},
- {0xa3, 0x7d},
+ {0x6a, 0x02}, /* 50 Hz banding filter */
+ {0xc5, 0x03}, /* 60 Hz banding filter */
+ {0xa2, 0x96}, /* bd50 */
+ {0xa3, 0x7d}, /* bd60 */
+
{0xff, 0x13}, /* read 13, write ff 00 */
{0x13, 0xe7},
- {0x3a, 0x80},
+ {0x3a, 0x80}, /* tslb - yuyv */
+ {}
+};
+
+static const u8 sensor_start_ov965x_2[][2] = {
{0xff, 0x42}, /* read 42, write ff 00 */
- {0x42, 0xc1},
+ {0x42, 0xc1}, /* com17 - 50 Hz filter */
+ {}
};
#if 0
-static const u8 sensor_start_ov965x_2[][2] = {
+static const u8 sensor_start_ov965x_3[][2] = {
{0xff, 0x13}, /* read 13, write ff 00 */
{0x13, 0xe7},
{0x3a, 0x80},
{0xff, 0x42}, /* read 42, write ff 00 */
{0x42, 0xc1},
+ {}
};
#endif
@@ -724,13 +809,16 @@ static int sd_config(struct gspca_dev *gspca_dev,
cam = &gspca_dev->cam;
- cam->cam_mode = vga_mode;
- cam->nmodes = ARRAY_SIZE(vga_mode);
-
if (sd->sensor == SENSOR_OV772X) {
+ cam->cam_mode = vga_yuyv_mode;
+ cam->nmodes = ARRAY_SIZE(vga_yuyv_mode);
+
cam->bulk = 1;
cam->bulk_size = 16384;
cam->bulk_nurbs = 2;
+ } else { /* ov965x */
+ cam->cam_mode = vga_jpeg_mode;
+ cam->nmodes = ARRAY_SIZE(vga_jpeg_mode);
}
return 0;
@@ -800,6 +888,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
static int sd_start(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
+ int mode;
switch (sd->sensor) {
case SENSOR_OV772X:
@@ -808,17 +897,28 @@ static int sd_start(struct gspca_dev *gspca_dev)
break;
default:
/* case SENSOR_OV965X: */
-#if 0
- sccb_w_array(gspca_dev, sensor_init_ov965x,
- ARRAY_SIZE(sensor_init_ov965x));
-#endif
- reg_w_array(gspca_dev, bridge_start_ov965x,
- ARRAY_SIZE(bridge_start_ov965x));
+
sccb_w_array(gspca_dev, sensor_start_ov965x,
ARRAY_SIZE(sensor_start_ov965x));
+ reg_w_array(gspca_dev, bridge_start_ov965x,
+ ARRAY_SIZE(bridge_start_ov965x));
+ mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
+ if (mode != 0) { /* 320x240 */
+ reg_w_array(gspca_dev, bridge_start_ov965x_cif,
+ ARRAY_SIZE(bridge_start_ov965x_cif));
+ sccb_w_array(gspca_dev, sensor_start_ov965x_cif,
+ ARRAY_SIZE(sensor_start_ov965x_cif));
+ } else { /* 640x480 */
+ reg_w_array(gspca_dev, bridge_start_ov965x_vga,
+ ARRAY_SIZE(bridge_start_ov965x_vga));
+ sccb_w_array(gspca_dev, sensor_start_ov965x_vga,
+ ARRAY_SIZE(sensor_start_ov965x_vga));
+ }
+ sccb_w_array(gspca_dev, sensor_start_ov965x_2,
+ ARRAY_SIZE(sensor_start_ov965x_2));
+ ov534_reg_write(gspca_dev, 0xe0, 0x00);
ov534_reg_write(gspca_dev, 0xe0, 0x00);
ov534_set_led(gspca_dev, 1);
-/*fixme: other sensor start omitted*/
}
return 0;
}
@@ -858,9 +958,11 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame,
__u32 this_pts;
u16 this_fid;
int remaining_len = len;
+ int payload_len;
+ payload_len = gspca_dev->cam.bulk ? 2048 : 2040;
do {
- len = min(remaining_len, 2040); /*fixme: was 2048*/
+ len = min(remaining_len, payload_len);
/* Payloads are prefixed with a UVC-style header. We
consider a frame to start when the FID toggles, or the PTS
@@ -901,12 +1003,14 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame,
/* If this packet is marked as EOF, end the frame */
} else if (data[1] & UVC_STREAM_EOF) {
sd->last_pts = 0;
-
+#if 0
+/*fixme: check if not jpeg*/
if (frame->data_end - frame->data !=
gspca_dev->width * gspca_dev->height * 2) {
PDEBUG(D_PACK, "short frame");
goto discard;
}
+#endif
frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
data + 12, len - 12);
} else {
diff --git a/linux/drivers/media/video/gspca/sonixj.c b/linux/drivers/media/video/gspca/sonixj.c
index a4c935d69..a2fb94eb7 100644
--- a/linux/drivers/media/video/gspca/sonixj.c
+++ b/linux/drivers/media/video/gspca/sonixj.c
@@ -46,6 +46,7 @@ struct sd {
u8 gamma;
u8 vflip; /* ov7630/ov7648 only */
u8 infrared; /* mt9v111 only */
+ u8 freq; /* ov76xx only */
u8 quality; /* image quality */
#define QUALITY_MIN 60
#define QUALITY_MAX 95
@@ -96,8 +97,11 @@ static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_setinfrared(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getinfrared(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 BRIGHTNESS_IDX 0
{
{
.id = V4L2_CID_BRIGHTNESS,
@@ -113,6 +117,7 @@ static struct ctrl sd_ctrls[] = {
.set = sd_setbrightness,
.get = sd_getbrightness,
},
+#define CONTRAST_IDX 1
{
{
.id = V4L2_CID_CONTRAST,
@@ -128,20 +133,22 @@ static struct ctrl sd_ctrls[] = {
.set = sd_setcontrast,
.get = sd_getcontrast,
},
+#define COLOR_IDX 2
{
{
.id = V4L2_CID_SATURATION,
.type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Color",
+ .name = "Saturation",
.minimum = 0,
.maximum = 40,
.step = 1,
-#define COLOR_DEF 32
+#define COLOR_DEF 25
.default_value = COLOR_DEF,
},
.set = sd_setcolors,
.get = sd_getcolors,
},
+#define BLUE_BALANCE_IDX 3
{
{
.id = V4L2_CID_BLUE_BALANCE,
@@ -156,6 +163,7 @@ static struct ctrl sd_ctrls[] = {
.set = sd_setblue_balance,
.get = sd_getblue_balance,
},
+#define RED_BALANCE_IDX 4
{
{
.id = V4L2_CID_RED_BALANCE,
@@ -170,6 +178,7 @@ static struct ctrl sd_ctrls[] = {
.set = sd_setred_balance,
.get = sd_getred_balance,
},
+#define GAMMA_IDX 5
{
{
.id = V4L2_CID_GAMMA,
@@ -184,7 +193,7 @@ static struct ctrl sd_ctrls[] = {
.set = sd_setgamma,
.get = sd_getgamma,
},
-#define AUTOGAIN_IDX 5
+#define AUTOGAIN_IDX 6
{
{
.id = V4L2_CID_AUTOGAIN,
@@ -200,7 +209,7 @@ static struct ctrl sd_ctrls[] = {
.get = sd_getautogain,
},
/* ov7630/ov7648 only */
-#define VFLIP_IDX 6
+#define VFLIP_IDX 7
{
{
.id = V4L2_CID_VFLIP,
@@ -209,14 +218,14 @@ static struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 1,
.step = 1,
-#define VFLIP_DEF 0 /* vflip def = 1 for ov7630 */
+#define VFLIP_DEF 0
.default_value = VFLIP_DEF,
},
.set = sd_setvflip,
.get = sd_getvflip,
},
/* mt9v111 only */
-#define INFRARED_IDX 7
+#define INFRARED_IDX 8
{
{
.id = V4L2_CID_INFRARED,
@@ -231,32 +240,48 @@ static struct ctrl sd_ctrls[] = {
.set = sd_setinfrared,
.get = sd_getinfrared,
},
+/* ov7630/ov7648/ov7660 only */
+#define FREQ_IDX 9
+ {
+ {
+ .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,
+#define FREQ_DEF 2
+ .default_value = FREQ_DEF,
+ },
+ .set = sd_setfreq,
+ .get = sd_getfreq,
+ },
};
/* table of the disabled controls */
static __u32 ctrl_dis[] = {
- (1 << INFRARED_IDX) | (1 << VFLIP_IDX),
+ (1 << INFRARED_IDX) | (1 << VFLIP_IDX) | (1 << FREQ_IDX),
/* SENSOR_HV7131R 0 */
- (1 << INFRARED_IDX) | (1 << VFLIP_IDX),
+ (1 << INFRARED_IDX) | (1 << VFLIP_IDX) | (1 << FREQ_IDX),
/* SENSOR_MI0360 1 */
- (1 << INFRARED_IDX) | (1 << VFLIP_IDX),
+ (1 << INFRARED_IDX) | (1 << VFLIP_IDX) | (1 << FREQ_IDX),
/* SENSOR_MO4000 2 */
#if 1
- (1 << VFLIP_IDX),
+ (1 << VFLIP_IDX) | (1 << FREQ_IDX),
#else
- (1 << AUTOGAIN_IDX) | (1 << VFLIP_IDX),
+ (1 << AUTOGAIN_IDX) | (1 << VFLIP_IDX) | (1 << FREQ_IDX),
#endif
/* SENSOR_MT9V111 3 */
- (1 << INFRARED_IDX) | (1 << VFLIP_IDX),
+ (1 << INFRARED_IDX) | (1 << VFLIP_IDX) | (1 << FREQ_IDX),
/* SENSOR_OM6802 4 */
- (1 << AUTOGAIN_IDX) | (1 << INFRARED_IDX),
+ (1 << INFRARED_IDX),
/* SENSOR_OV7630 5 */
(1 << INFRARED_IDX),
/* SENSOR_OV7648 6 */
(1 << AUTOGAIN_IDX) | (1 << INFRARED_IDX) | (1 << VFLIP_IDX),
/* SENSOR_OV7660 7 */
- (1 << AUTOGAIN_IDX) | (1 << INFRARED_IDX) | (1 << VFLIP_IDX),
- /* SENSOR_SP80708 8 */
+ (1 << AUTOGAIN_IDX) | (1 << INFRARED_IDX) | (1 << VFLIP_IDX) |
+ (1 << FREQ_IDX), /* SENSOR_SP80708 8 */
};
static const struct v4l2_pix_format vga_mode[] = {
@@ -272,7 +297,8 @@ static const struct v4l2_pix_format vga_mode[] = {
.priv = 1},
{640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
.bytesperline = 640,
- .sizeimage = 640 * 480 * 3 / 8 + 590,
+ /* Note 3 / 8 is not large enough, not even 5 / 8 is ?! */
+ .sizeimage = 640 * 480 * 3 / 4 + 590,
.colorspace = V4L2_COLORSPACE_JPEG,
.priv = 0},
};
@@ -612,7 +638,9 @@ static const u8 ov7630_sensor_init[][8] = {
/* win: i2c_r from 00 to 80 */
{0xd1, 0x21, 0x03, 0x80, 0x10, 0x20, 0x80, 0x10},
{0xb1, 0x21, 0x0c, 0x20, 0x20, 0x00, 0x00, 0x10},
- {0xd1, 0x21, 0x11, 0x00, 0x48, 0xc0, 0x00, 0x10},
+/* HDG: 0x11 was 0x00 change to 0x01 for better exposure (15 fps instead of 30)
+ 0x13 was 0xc0 change to 0xc3 for auto gain and exposure */
+ {0xd1, 0x21, 0x11, 0x01, 0x48, 0xc3, 0x00, 0x10},
{0xb1, 0x21, 0x15, 0x80, 0x03, 0x00, 0x00, 0x10},
{0xd1, 0x21, 0x17, 0x1b, 0xbd, 0x05, 0xf6, 0x10},
{0xa1, 0x21, 0x1b, 0x04, 0x00, 0x00, 0x00, 0x10},
@@ -646,9 +674,8 @@ static const u8 ov7630_sensor_init[][8] = {
{0xa1, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10},
{0xb1, 0x21, 0x01, 0x80, 0x80, 0x00, 0x00, 0x10},
/* */
- {0xa1, 0x21, 0x11, 0x00, 0x00, 0x00, 0x00, 0x10},
- {0xa1, 0x21, 0x2a, 0x88, 0x00, 0x00, 0x00, 0x10},
- {0xa1, 0x21, 0x2b, 0x34, 0x00, 0x00, 0x00, 0x10},
+/* {0xa1, 0x21, 0x2a, 0x88, 0x00, 0x00, 0x00, 0x10}, * set by setfreq */
+/* {0xa1, 0x21, 0x2b, 0x34, 0x00, 0x00, 0x00, 0x10}, * set by setfreq */
/* */
{0xa1, 0x21, 0x10, 0x83, 0x00, 0x00, 0x00, 0x10},
/* {0xb1, 0x21, 0x01, 0x88, 0x70, 0x00, 0x00, 0x10}, */
@@ -681,7 +708,7 @@ static const u8 ov7648_sensor_init[][8] = {
{0xd1, 0x21, 0x21, 0x86, 0x00, 0xde, 0xa0, 0x10},
/* {0xd1, 0x21, 0x25, 0x80, 0x32, 0xfe, 0xa0, 0x10}, jfm done */
/* {0xd1, 0x21, 0x29, 0x00, 0x91, 0x00, 0x88, 0x10}, jfm done */
- {0xb1, 0x21, 0x2d, 0x85, 0x00, 0x00, 0x00, 0x10},
+/* {0xb1, 0x21, 0x2d, 0x85, 0x00, 0x00, 0x00, 0x10}, set by setfreq */
/*...*/
/* {0xa1, 0x21, 0x12, 0x08, 0x00, 0x00, 0x00, 0x10}, jfm done */
/* {0xa1, 0x21, 0x75, 0x06, 0x00, 0x00, 0x00, 0x10}, * COMN
@@ -1310,11 +1337,9 @@ static int sd_config(struct gspca_dev *gspca_dev,
sd->gamma = GAMMA_DEF;
sd->autogain = AUTOGAIN_DEF;
sd->ag_cnt = -1;
- if (sd->sensor != SENSOR_OV7630)
- sd->vflip = 0;
- else
- sd->vflip = 1;
+ sd->vflip = VFLIP_DEF;
sd->infrared = INFRARED_DEF;
+ sd->freq = FREQ_DEF;
sd->quality = QUALITY_DEF;
sd->jpegqual = 80;
@@ -1595,7 +1620,7 @@ static void setautogain(struct gspca_dev *gspca_dev)
else
comb = 0xa0;
if (sd->autogain)
- comb |= 0x02;
+ comb |= 0x03;
i2c_w1(&sd->gspca_dev, 0x13, comb);
return;
}
@@ -1611,12 +1636,15 @@ static void setvflip(struct sd *sd)
{
u8 comn;
- if (sd->sensor == SENSOR_OV7630)
+ if (sd->sensor == SENSOR_OV7630) {
comn = 0x02;
- else
+ if (!sd->vflip)
+ comn |= 0x80;
+ } else {
comn = 0x06;
- if (sd->vflip)
- comn |= 0x80;
+ if (sd->vflip)
+ comn |= 0x80;
+ }
i2c_w1(&sd->gspca_dev, 0x75, comn);
}
@@ -1634,6 +1662,58 @@ static void setinfrared(struct sd *sd)
#endif
}
+static void setfreq(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (sd->sensor == SENSOR_OV7660) {
+ switch (sd->freq) {
+ case 0: /* Banding filter disabled */
+ i2c_w1(gspca_dev, 0x13, 0xdf);
+ break;
+ case 1: /* 50 hz */
+ i2c_w1(gspca_dev, 0x13, 0xff);
+ i2c_w1(gspca_dev, 0x3b, 0x0a);
+ break;
+ case 2: /* 60 hz */
+ i2c_w1(gspca_dev, 0x13, 0xff);
+ i2c_w1(gspca_dev, 0x3b, 0x02);
+ break;
+ }
+ } else {
+ u8 reg2a = 0, reg2b = 0, reg2d = 0;
+
+ /* Get reg2a / reg2d base values */
+ switch (sd->sensor) {
+ case SENSOR_OV7630:
+ reg2a = 0x08;
+ reg2d = 0x01;
+ break;
+ case SENSOR_OV7648:
+ reg2a = 0x11;
+ reg2d = 0x81;
+ break;
+ }
+
+ switch (sd->freq) {
+ case 0: /* Banding filter disabled */
+ break;
+ case 1: /* 50 hz (filter on and framerate adj) */
+ reg2a |= 0x80;
+ reg2b = 0xac;
+ reg2d |= 0x04;
+ break;
+ case 2: /* 60 hz (filter on, no framerate adj) */
+ reg2a |= 0x80;
+ reg2d |= 0x04;
+ break;
+ }
+ i2c_w1(gspca_dev, 0x2a, reg2a);
+ i2c_w1(gspca_dev, 0x2b, reg2b);
+ i2c_w1(gspca_dev, 0x2d, reg2d);
+ }
+}
+
static void setjpegqual(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -1865,6 +1945,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
setbrightness(gspca_dev);
setcontrast(gspca_dev);
setautogain(gspca_dev);
+ setfreq(gspca_dev);
return 0;
}
@@ -2168,6 +2249,24 @@ static int sd_getinfrared(struct gspca_dev *gspca_dev, __s32 *val)
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)
+ 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->freq;
+ return 0;
+}
+
static int sd_set_jcomp(struct gspca_dev *gspca_dev,
struct v4l2_jpegcompression *jcomp)
{
@@ -2196,6 +2295,27 @@ static int sd_get_jcomp(struct gspca_dev *gspca_dev,
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,
@@ -2210,6 +2330,7 @@ static const struct sd_desc sd_desc = {
.dq_callback = do_autogain,
.get_jcomp = sd_get_jcomp,
.set_jcomp = sd_set_jcomp,
+ .querymenu = sd_querymenu,
};
/* -- module initialisation -- */
@@ -2270,7 +2391,7 @@ static const __devinitdata struct usb_device_id device_table[] = {
{USB_DEVICE(0x0c45, 0x613b), BSI(SN9C120, OV7660, 0x21)},
#endif
{USB_DEVICE(0x0c45, 0x613c), BSI(SN9C120, HV7131R, 0x11)},
-/* {USB_DEVICE(0x0c45, 0x613e), BSI(SN9C120, OV7630, 0x??)}, */
+ {USB_DEVICE(0x0c45, 0x613e), BSI(SN9C120, OV7630, 0x21)},
{USB_DEVICE(0x0c45, 0x6143), BSI(SN9C120, SP80708, 0x18)},
{}
};
diff --git a/linux/drivers/media/video/gspca/spca505.c b/linux/drivers/media/video/gspca/spca505.c
index 2acec58b1..ea8c9fe2e 100644
--- a/linux/drivers/media/video/gspca/spca505.c
+++ b/linux/drivers/media/video/gspca/spca505.c
@@ -637,19 +637,19 @@ static int sd_config(struct gspca_dev *gspca_dev,
cam->nmodes = ARRAY_SIZE(vga_mode) - 1;
sd->brightness = BRIGHTNESS_DEF;
- 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 probe and resume time */
static int sd_init(struct gspca_dev *gspca_dev)
{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (write_vector(gspca_dev,
+ sd->subtype == Nxultra
+ ? spca505b_init_data
+ : spca505_init_data))
+ return -EIO;
return 0;
}
diff --git a/linux/drivers/media/video/gspca/spca508.c b/linux/drivers/media/video/gspca/spca508.c
index e3afc9e7f..7fd8079c2 100644
--- a/linux/drivers/media/video/gspca/spca508.c
+++ b/linux/drivers/media/video/gspca/spca508.c
@@ -1,7 +1,7 @@
/*
* SPCA508 chip based cameras subdriver
*
- * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ * Copyright (C) 2009 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
@@ -30,9 +30,9 @@ MODULE_LICENSE("GPL");
struct sd {
struct gspca_dev gspca_dev; /* !! must be the first item */
- unsigned char brightness;
+ u8 brightness;
- char subtype;
+ u8 subtype;
#define CreativeVista 0
#define HamaUSBSightcam 1
#define HamaUSBSightcam2 2
@@ -86,58 +86,54 @@ static const struct v4l2_pix_format sif_mode[] = {
};
/* Frame packet header offsets for the spca508 */
+#if 0
+#define SPCA508_OFFSET_
#define SPCA508_OFFSET_TYPE 1
+#define SPCA508_IMAGE_TYPE_MASK 0x1f
+#define SPCA508_SNAPBIT 0x20
+#define SPCA508_SNAPCTRL 0x40
#define SPCA508_OFFSET_COMPRESS 2
#define SPCA508_OFFSET_FRAMSEQ 8
+#define SPCA508_OFFSET_GPIO 9
+#define SPCA508_OFFSET_GLBINF 10
#define SPCA508_OFFSET_WIN1LUM 11
+#define SPCA508_OFFSET_WIN2LUM 12
+#define SPCA508_OFFSET_WIN1RG 13
+#define SPCA508_OFFSET_WIN1BG 14
+#define SPCA508_OFFSET_WIN2RG 15
+#define SPCA508_OFFSET_WIN2BG 16
+#define SPCA508_OFFSET_21 21
+#define SPCA508_GAMMAEN 0x01
+#define SPCA508_EDGEMODE 0x02
+#endif
#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[][2] =
{
- /* 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 */
+ {0x0000, 0x870b},
+
+ {0x0020, 0x8112}, /* Video drop enable, ISO streaming disable */
+ {0x0003, 0x8111}, /* Reset compression & memory */
+ {0x0000, 0x8110}, /* Disable all outputs */
+ /* READ {0x0000, 0x8114} -> 0000: 00 */
+ {0x0000, 0x8114}, /* SW GPIO data */
+ {0x0008, 0x8110}, /* Enable charge pump output */
+ {0x0002, 0x8116}, /* 200 kHz pump clock */
+ /* UNKNOWN DIRECTION (URB_FUNCTION_SELECT_INTERFACE:) */
+ {0x0003, 0x8111}, /* Reset compression & memory */
+ {0x0000, 0x8111}, /* Normal mode (not reset) */
+ {0x0098, 0x8110},
+ /* Enable charge pump output, sync.serial,external 2x clock */
+ {0x000d, 0x8114}, /* SW GPIO data */
+ {0x0002, 0x8116}, /* 200 kHz pump clock */
+ {0x0020, 0x8112}, /* Video drop enable, ISO streaming disable */
/* --------------------------------------- */
- /* 44740 1819 */ {0x000f, 0x8402},
- /* memory bank */
- /* 44765 1820 */ {0x0000, 0x8403},
- /* ... address */
+ {0x000f, 0x8402}, /* memory bank */
+ {0x0000, 0x8403}, /* ... address */
/* --------------------------------------- */
/* 0x88__ is Synchronous Serial Interface. */
/* TBD: This table could be expressed more compactly */
@@ -145,342 +141,307 @@ static const u16 spca508_init_data[][2] =
/* 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 */
+ {0x00c0, 0x8804}, /* SSI slave addr */
+ {0x0008, 0x8802}, /* 375 Khz SSI clock */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802}, /* 375 Khz SSI clock */
+ {0x0012, 0x8801}, /* SSI reg addr */
+ {0x0080, 0x8800}, /* SSI data to write */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802}, /* 375 Khz SSI clock */
+ {0x0012, 0x8801}, /* SSI reg addr */
+ {0x0000, 0x8800}, /* SSI data to write */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802}, /* 375 Khz SSI clock */
+ {0x0011, 0x8801}, /* SSI reg addr */
+ {0x0040, 0x8800}, /* SSI data to write */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x0013, 0x8801},
+ {0x0000, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x0014, 0x8801},
+ {0x0000, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x0015, 0x8801},
+ {0x0001, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x0016, 0x8801},
+ {0x0003, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x0017, 0x8801},
+ {0x0036, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x0018, 0x8801},
+ {0x00ec, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x001a, 0x8801},
+ {0x0094, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x001b, 0x8801},
+ {0x0000, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x0027, 0x8801},
+ {0x00a2, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x0028, 0x8801},
+ {0x0040, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x002a, 0x8801},
+ {0x0084, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x002b, 0x8801},
+ {0x00a8, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x002c, 0x8801},
+ {0x00fe, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x002d, 0x8801},
+ {0x0003, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x0038, 0x8801},
+ {0x0083, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x0033, 0x8801},
+ {0x0081, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x0034, 0x8801},
+ {0x004a, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x0039, 0x8801},
+ {0x0000, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x0010, 0x8801},
+ {0x00a8, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x0006, 0x8801},
+ {0x0058, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x0000, 0x8801},
+ {0x0004, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x0040, 0x8801},
+ {0x0080, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x0041, 0x8801},
+ {0x000c, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x0042, 0x8801},
+ {0x000c, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x0043, 0x8801},
+ {0x0028, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x0044, 0x8801},
+ {0x0080, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x0045, 0x8801},
+ {0x0020, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x0046, 0x8801},
+ {0x0020, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x0047, 0x8801},
+ {0x0080, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x0048, 0x8801},
+ {0x004c, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x0049, 0x8801},
+ {0x0084, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x004a, 0x8801},
+ {0x0084, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x004b, 0x8801},
+ {0x0084, 0x8800},
+ /* READ { 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 */
+ {0x0012, 0x8700}, /* Clock speed 48Mhz/(2+2)/2= 6 Mhz */
+ {0x0000, 0x8701}, /* CKx1 clock delay adj */
+ {0x0000, 0x8701}, /* CKx1 clock delay adj */
+ {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,
+ {0x0080, 0x8600}, /* Line memory read counter (L) */
+ {0x0001, 0x8606}, /* reserved */
+ {0x0064, 0x8607}, /* Line memory read counter (H) 0x6480=25,728 */
+ {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 */
+ {0x0000, 0x8602}, /* optical black level for user settng = 0 */
+ {0x0080, 0x8600}, /* Line memory read counter (L) */
+ {0x000a, 0x8603}, /* optical black level calc mode:
+ * auto; optical black offset = 10 */
+ {0x00df, 0x865b}, /* Horiz offset for valid pixels (L)=0xdf */
+ {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 */
+ {0x0058, 0x865d}, /* Horiz valid pixels (*4) (L) = 352 */
+ {0x0048, 0x865e}, /* Vert valid lines (*4) (L) = 288 */
+
+ {0x0015, 0x8608}, /* A11 Coef ... */
+ {0x0030, 0x8609},
+ {0x00fb, 0x860a},
+ {0x003e, 0x860b},
+ {0x00ce, 0x860c},
+ {0x00f4, 0x860d},
+ {0x00eb, 0x860e},
+ {0x00dc, 0x860f},
+ {0x0039, 0x8610},
+ {0x0001, 0x8611}, /* R offset for white balance ... */
+ {0x0000, 0x8612},
+ {0x0001, 0x8613},
+ {0x0000, 0x8614},
+ {0x005b, 0x8651}, /* R gain for white balance ... */
+ {0x0040, 0x8652},
+ {0x0060, 0x8653},
+ {0x0040, 0x8654},
+ {0x0000, 0x8655},
+ {0x0001, 0x863f}, /* Fixed gamma correction enable, USB control,
+ * lum filter disable, lum noise clip disable */
+ {0x00a1, 0x8656}, /* Window1 size 256x256, Windows2 size 64x64,
+ * gamma look-up disable,
+ * new edge enhancement enable */
+ {0x0018, 0x8657}, /* Edge gain high thresh */
+ {0x0020, 0x8658}, /* Edge gain low thresh */
+ {0x000a, 0x8659}, /* Edge bandwidth high threshold */
+ {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},
+ {0x0030, 0x8112}, /* Video drop enable, ISO streaming enable */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0xa908, 0x8802},
+ {0x0034, 0x8801}, /* SSI reg addr */
+ {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 { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x1f08, 0x8802},
+ {0x0006, 0x8801},
+ {0x0080, 0x8800},
+ /* READ { 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 */
+ /* READ { 0x0000, 0x8608 } -> 0000: 15 */
+ /* READ { 0x0000, 0x8609 } -> 0000: 30 */
+ /* READ { 0x0000, 0x860a } -> 0000: fb */
+ /* READ { 0x0000, 0x860b } -> 0000: 3e */
+ /* READ { 0x0000, 0x860c } -> 0000: ce */
+ /* READ { 0x0000, 0x860d } -> 0000: f4 */
+ /* READ { 0x0000, 0x860e } -> 0000: eb */
+ /* READ { 0x0000, 0x860f } -> 0000: dc */
+ /* READ { 0x0000, 0x8610 } -> 0000: 39 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0xb008, 0x8802},
+ {0x0006, 0x8801},
+ {0x007d, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
#if 0
/* experimental. dark version. */
@@ -504,114 +465,86 @@ static const u16 spca508_init_data[][2] =
/* 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},
+ {0x0015, 0x8608},
+ {0x0030, 0x8609},
+ {0xfffb, 0x860a},
+ {0x003e, 0x860b},
+ {0xffce, 0x860c},
+ {0xfff4, 0x860d},
+ {0xffeb, 0x860e},
+ {0xffdc, 0x860f},
+ {0x0039, 0x8610},
+ {0x0018, 0x8657},
#endif
- /* 52039 2116 */ {0x0000, 0x8508},
- /* Disable compression. */
+ {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 */
+ {0x0021, 0x8508}, * Enable compression. */
+ {0x0032, 0x850b}, /* compression stuff */
+ {0x0003, 0x8509}, /* compression stuff */
+ {0x0011, 0x850a}, /* compression stuff */
+ {0x0021, 0x850d}, /* compression stuff */
+ {0x0010, 0x850c}, /* compression stuff */
+ {0x0003, 0x8500}, /* *** Video mode: 160x120 */
+ {0x0001, 0x8501}, /* Hardware-dominated snap control */
+ {0x0061, 0x8656}, /* Window1 size 128x128, Windows2 size 128x128,
+ * gamma look-up disable,
+ * new edge enhancement enable */
+ {0x0018, 0x8617}, /* Window1 start X (*2) */
+ {0x0008, 0x8618}, /* Window1 start Y (*2) */
+ {0x0061, 0x8656}, /* Window1 size 128x128, Windows2 size 128x128,
+ * gamma look-up disable,
+ * new edge enhancement enable */
+ {0x0058, 0x8619}, /* Window2 start X (*2) */
+ {0x0008, 0x861a}, /* Window2 start Y (*2) */
+ {0x00ff, 0x8615}, /* High lum thresh for white balance */
+ {0x0000, 0x8616}, /* Low lum thresh for white balance */
+ {0x0012, 0x8700}, /* Clock speed 48Mhz/(2+2)/2= 6 Mhz */
+ {0x0012, 0x8700}, /* Clock speed 48Mhz/(2+2)/2= 6 Mhz */
+ /* READ { 0x0000, 0x8656 } -> 0000: 61 */
+ {0x0028, 0x8802}, /* 375 Khz SSI clock, SSI r/w sync with VSYNC */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 28 */
+ {0x1f28, 0x8802}, /* 375 Khz SSI clock, SSI r/w sync with VSYNC */
+ {0x0010, 0x8801}, /* SSI reg addr */
+ {0x003e, 0x8800}, /* SSI data to write */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ {0x0028, 0x8802},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 28 */
+ {0x1f28, 0x8802},
+ {0x0000, 0x8801},
+ {0x001f, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ {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 */
+ {0x002f, 0x8700}, /* Clock speed */
#else
/* Original: */
- /* 52882 2150 */ {0x0023, 0x8700},
- /* Clock speed 48Mhz/(3+2)/4= 2.4 Mhz */
+ {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) ) */
+ {0x000f, 0x8602}, /* optical black level for user settning = 15 */
+
+ {0x0028, 0x8802},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 28 */
+ {0x1f28, 0x8802},
+ {0x0010, 0x8801},
+ {0x007b, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ {0x002f, 0x8651}, /* R gain for white balance ... */
+ {0x0080, 0x8653},
+ /* READ { 0x0000, 0x8655 } -> 0000: 00 */
+ {0x0000, 0x8655},
+
+ {0x0030, 0x8112}, /* Video drop enable, ISO streaming enable */
+ {0x0020, 0x8112}, /* Video drop enable, ISO streaming disable */
+ /* UNKNOWN DIRECTION (URB_FUNCTION_SELECT_INTERFACE: (ALT=0) ) */
{}
};
@@ -619,27 +552,27 @@ static const u16 spca508_init_data[][2] =
* Initialization data for Intel EasyPC Camera CS110
*/
static const u16 spca508cs110_init_data[][2] = {
- {0x0000, 0x870b}, /* Reset CTL3 */
- {0x0003, 0x8111}, /* Soft Reset compression, memory, TG & CDSP */
- {0x0000, 0x8111}, /* Normal operation on reset */
+ {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 */
+ {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 */
+ {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 */
+ {0x000a, 0x8805}, /* a - NWG: Dunno what this is about */
{0x0000, 0x8800},
{0x0010, 0x8802},
@@ -673,459 +606,459 @@ static const u16 spca508cs110_init_data[][2] = {
{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) */
+ {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 */
+ {0x0006, 0x8660}, /* Nibble data + input order */
- {0x000a, 0x8602}, /* Optical black level set to 0x0a */
-/* 1945 */ {0x0000, 0x8603}, /* Optical black level Offset */
+ {0x000a, 0x8602}, /* Optical black level set to 0x0a */
+ {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 */
+/* {0x0000, 0x8611}, * 0 R Offset for white Balance */
+/* {0x0000, 0x8612}, * 1 Gr Offset for white Balance */
+/* {0x0000, 0x8613}, * 1f B Offset for white Balance */
+/* {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) */
+ {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*** */
+ {0x0000, 0x8655},
+ /* High bits for white balance*****brightness control*** */
{}
};
static const u16 spca508_sightcam_init_data[][2] = {
/* This line seems to setup the frame/canvas */
- /*368 */ {0x000f, 0x8402},
+ {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},
+ {0x0090, 0x8110},
+ {0x0001, 0x8114},
+ {0x0001, 0x8114},
+ {0x0001, 0x8114},
+ {0x0003, 0x8114},
+ {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},
+ {0x0001, 0x8801},
+ {0x0004, 0x8800},
+ {0x0003, 0x8801},
+ {0x00e0, 0x8800},
+ {0x0004, 0x8801},
+ {0x00b4, 0x8800},
+ {0x0005, 0x8801},
+ {0x0000, 0x8800},
+
+ {0x0006, 0x8801},
+ {0x00e0, 0x8800},
+ {0x0007, 0x8801},
+ {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},
+ {0x0014, 0x8801},
+ {0x0008, 0x8800},
+ {0x0015, 0x8801},
+ {0x0067, 0x8800},
+ {0x0016, 0x8801},
+ {0x0000, 0x8800},
+ {0x0017, 0x8801},
+ {0x0020, 0x8800},
+ {0x0018, 0x8801},
+ {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},
+ {0x001e, 0x8801},
+ {0x00ea, 0x8800},
+ {0x001f, 0x8801},
+ {0x0001, 0x8800},
+ {0x0003, 0x8801},
+ {0x00e0, 0x8800},
/* seems to place the colors ontop of each other #1 */
- /*517 */ {0x0006, 0x8704},
- /*518 */ {0x0001, 0x870c},
- /*519 */ {0x0016, 0x8600},
- /*520 */ {0x0002, 0x8606},
+ {0x0006, 0x8704},
+ {0x0001, 0x870c},
+ {0x0016, 0x8600},
+ {0x0002, 0x8606},
/* if not included the pictures becomes _very_ dark */
- /*521 */ {0x0064, 0x8607},
- /*522 */ {0x003a, 0x8601},
- /*523 */ {0x0000, 0x8602},
+ {0x0064, 0x8607},
+ {0x003a, 0x8601},
+ {0x0000, 0x8602},
/* seems to place the colors ontop of each other #2 */
- /*524 */ {0x0016, 0x8600},
- /*525 */ {0x0018, 0x8617},
- /*526 */ {0x0008, 0x8618},
- /*527 */ {0x00a1, 0x8656},
+ {0x0016, 0x8600},
+ {0x0018, 0x8617},
+ {0x0008, 0x8618},
+ {0x00a1, 0x8656},
/* webcam won't start if not included */
- /*528 */ {0x0007, 0x865b},
- /*529 */ {0x0001, 0x865c},
- /*530 */ {0x0058, 0x865d},
- /*531 */ {0x0048, 0x865e},
+ {0x0007, 0x865b},
+ {0x0001, 0x865c},
+ {0x0058, 0x865d},
+ {0x0048, 0x865e},
/* adjusts the colors */
- /*541 */ {0x0049, 0x8651},
- /*542 */ {0x0040, 0x8652},
- /*543 */ {0x004c, 0x8653},
- /*544 */ {0x0040, 0x8654},
+ {0x0049, 0x8651},
+ {0x0040, 0x8652},
+ {0x004c, 0x8653},
+ {0x0040, 0x8654},
{}
};
static const u16 spca508_sightcam2_init_data[][2] = {
-/* 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},
+ {0x0020, 0x8112},
+
+ {0x000f, 0x8402},
+ {0x0000, 0x8403},
+
+ {0x0008, 0x8201},
+ {0x0008, 0x8200},
+ {0x0001, 0x8200},
+ {0x0009, 0x8201},
+ {0x0008, 0x8200},
+ {0x0001, 0x8200},
+ {0x000a, 0x8201},
+ {0x0008, 0x8200},
+ {0x0001, 0x8200},
+ {0x000b, 0x8201},
+ {0x0008, 0x8200},
+ {0x0001, 0x8200},
+ {0x000c, 0x8201},
+ {0x0008, 0x8200},
+ {0x0001, 0x8200},
+ {0x000d, 0x8201},
+ {0x0008, 0x8200},
+ {0x0001, 0x8200},
+ {0x000e, 0x8201},
+ {0x0008, 0x8200},
+ {0x0001, 0x8200},
+ {0x0007, 0x8201},
+ {0x0008, 0x8200},
+ {0x0001, 0x8200},
+ {0x000f, 0x8201},
+ {0x0008, 0x8200},
+ {0x0001, 0x8200},
+
+ {0x0018, 0x8660},
+ {0x0010, 0x8201},
+
+ {0x0008, 0x8200},
+ {0x0001, 0x8200},
+ {0x0011, 0x8201},
+ {0x0008, 0x8200},
+ {0x0001, 0x8200},
+
+ {0x0000, 0x86b0},
+ {0x0034, 0x86b1},
+ {0x0000, 0x86b2},
+ {0x0049, 0x86b3},
+ {0x0000, 0x86b4},
+ {0x0000, 0x86b4},
+
+ {0x0012, 0x8201},
+ {0x0008, 0x8200},
+ {0x0001, 0x8200},
+ {0x0013, 0x8201},
+ {0x0008, 0x8200},
+ {0x0001, 0x8200},
+
+ {0x0001, 0x86b0},
+ {0x00aa, 0x86b1},
+ {0x0000, 0x86b2},
+ {0x00e4, 0x86b3},
+ {0x0000, 0x86b4},
+ {0x0000, 0x86b4},
+
+ {0x0018, 0x8660},
+
+ {0x0090, 0x8110},
+ {0x0001, 0x8114},
+ {0x0001, 0x8114},
+ {0x0001, 0x8114},
+ {0x0003, 0x8114},
+
+ {0x0080, 0x8804},
+ {0x0003, 0x8801},
+ {0x0012, 0x8800},
+ {0x0004, 0x8801},
+ {0x0005, 0x8800},
+ {0x0005, 0x8801},
+ {0x0000, 0x8800},
+ {0x0006, 0x8801},
+ {0x0000, 0x8800},
+ {0x0007, 0x8801},
+ {0x0000, 0x8800},
+ {0x0008, 0x8801},
+ {0x0005, 0x8800},
+ {0x000a, 0x8700},
+ {0x000e, 0x8801},
+ {0x0004, 0x8800},
+ {0x0005, 0x8801},
+ {0x0047, 0x8800},
+ {0x0006, 0x8801},
+ {0x0000, 0x8800},
+ {0x0007, 0x8801},
+ {0x00c0, 0x8800},
+ {0x0008, 0x8801},
+ {0x0003, 0x8800},
+ {0x0013, 0x8801},
+ {0x0001, 0x8800},
+ {0x0009, 0x8801},
+ {0x0000, 0x8800},
+ {0x000a, 0x8801},
+ {0x0000, 0x8800},
+ {0x000b, 0x8801},
+ {0x0000, 0x8800},
+ {0x000c, 0x8801},
+ {0x0000, 0x8800},
+ {0x000e, 0x8801},
+ {0x0004, 0x8800},
+ {0x000f, 0x8801},
+ {0x0000, 0x8800},
+ {0x0010, 0x8801},
+ {0x0006, 0x8800},
+ {0x0011, 0x8801},
+ {0x0006, 0x8800},
+ {0x0012, 0x8801},
+ {0x0000, 0x8800},
+ {0x0013, 0x8801},
+ {0x0001, 0x8800},
+
+ {0x000a, 0x8700},
+ {0x0000, 0x8702},
+ {0x0000, 0x8703},
+ {0x00c2, 0x8704},
+ {0x0001, 0x870c},
+
+ {0x0044, 0x8600},
+ {0x0002, 0x8606},
+ {0x0064, 0x8607},
+ {0x003a, 0x8601},
+ {0x0008, 0x8602},
+ {0x0044, 0x8600},
+ {0x0018, 0x8617},
+ {0x0008, 0x8618},
+ {0x00a1, 0x8656},
+ {0x0004, 0x865b},
+ {0x0002, 0x865c},
+ {0x0058, 0x865d},
+ {0x0048, 0x865e},
+ {0x0012, 0x8608},
+ {0x002c, 0x8609},
+ {0x0002, 0x860a},
+ {0x002c, 0x860b},
+ {0x00db, 0x860c},
+ {0x00f9, 0x860d},
+ {0x00f1, 0x860e},
+ {0x00e3, 0x860f},
+ {0x002c, 0x8610},
+ {0x006c, 0x8651},
+ {0x0041, 0x8652},
+ {0x0059, 0x8653},
+ {0x0040, 0x8654},
+ {0x00fa, 0x8611},
+ {0x00ff, 0x8612},
+ {0x00f8, 0x8613},
+ {0x0000, 0x8614},
+ {0x0001, 0x863f},
+ {0x0000, 0x8640},
+ {0x0026, 0x8641},
+ {0x0045, 0x8642},
+ {0x0060, 0x8643},
+ {0x0075, 0x8644},
+ {0x0088, 0x8645},
+ {0x009b, 0x8646},
+ {0x00b0, 0x8647},
+ {0x00c5, 0x8648},
+ {0x00d2, 0x8649},
+ {0x00dc, 0x864a},
+ {0x00e5, 0x864b},
+ {0x00eb, 0x864c},
+ {0x00f0, 0x864d},
+ {0x00f6, 0x864e},
+ {0x00fa, 0x864f},
+ {0x00ff, 0x8650},
+ {0x0060, 0x8657},
+ {0x0010, 0x8658},
+ {0x0018, 0x8659},
+ {0x0005, 0x865a},
+ {0x0018, 0x8660},
+ {0x0003, 0x8509},
+ {0x0011, 0x850a},
+ {0x0032, 0x850b},
+ {0x0010, 0x850c},
+ {0x0021, 0x850d},
+ {0x0001, 0x8500},
+ {0x0000, 0x8508},
+ {0x0012, 0x8608},
+ {0x002c, 0x8609},
+ {0x0002, 0x860a},
+ {0x0039, 0x860b},
+ {0x00d0, 0x860c},
+ {0x00f7, 0x860d},
+ {0x00ed, 0x860e},
+ {0x00db, 0x860f},
+ {0x0039, 0x8610},
+ {0x0012, 0x8657},
+ {0x000c, 0x8619},
+ {0x0004, 0x861a},
+ {0x00a1, 0x8656},
+ {0x00c8, 0x8615},
+ {0x0032, 0x8616},
+
+ {0x0030, 0x8112},
+ {0x0020, 0x8112},
+ {0x0020, 0x8112},
+ {0x000f, 0x8402},
+ {0x0000, 0x8403},
+
+ {0x0090, 0x8110},
+ {0x0001, 0x8114},
+ {0x0001, 0x8114},
+ {0x0001, 0x8114},
+ {0x0003, 0x8114},
+ {0x0080, 0x8804},
+
+ {0x0003, 0x8801},
+ {0x0012, 0x8800},
+ {0x0004, 0x8801},
+ {0x0005, 0x8800},
+ {0x0005, 0x8801},
+ {0x0047, 0x8800},
+ {0x0006, 0x8801},
+ {0x0000, 0x8800},
+ {0x0007, 0x8801},
+ {0x00c0, 0x8800},
+ {0x0008, 0x8801},
+ {0x0003, 0x8800},
+ {0x000a, 0x8700},
+ {0x000e, 0x8801},
+ {0x0004, 0x8800},
+ {0x0005, 0x8801},
+ {0x0047, 0x8800},
+ {0x0006, 0x8801},
+ {0x0000, 0x8800},
+ {0x0007, 0x8801},
+ {0x00c0, 0x8800},
+ {0x0008, 0x8801},
+ {0x0003, 0x8800},
+ {0x0013, 0x8801},
+ {0x0001, 0x8800},
+ {0x0009, 0x8801},
+ {0x0000, 0x8800},
+ {0x000a, 0x8801},
+ {0x0000, 0x8800},
+ {0x000b, 0x8801},
+ {0x0000, 0x8800},
+ {0x000c, 0x8801},
+ {0x0000, 0x8800},
+ {0x000e, 0x8801},
+ {0x0004, 0x8800},
+ {0x000f, 0x8801},
+ {0x0000, 0x8800},
+ {0x0010, 0x8801},
+ {0x0006, 0x8800},
+ {0x0011, 0x8801},
+ {0x0006, 0x8800},
+ {0x0012, 0x8801},
+ {0x0000, 0x8800},
+ {0x0013, 0x8801},
+ {0x0001, 0x8800},
+ {0x000a, 0x8700},
+ {0x0000, 0x8702},
+ {0x0000, 0x8703},
+ {0x00c2, 0x8704},
+ {0x0001, 0x870c},
+ {0x0044, 0x8600},
+ {0x0002, 0x8606},
+ {0x0064, 0x8607},
+ {0x003a, 0x8601},
+ {0x0008, 0x8602},
+ {0x0044, 0x8600},
+ {0x0018, 0x8617},
+ {0x0008, 0x8618},
+ {0x00a1, 0x8656},
+ {0x0004, 0x865b},
+ {0x0002, 0x865c},
+ {0x0058, 0x865d},
+ {0x0048, 0x865e},
+ {0x0012, 0x8608},
+ {0x002c, 0x8609},
+ {0x0002, 0x860a},
+ {0x002c, 0x860b},
+ {0x00db, 0x860c},
+ {0x00f9, 0x860d},
+ {0x00f1, 0x860e},
+ {0x00e3, 0x860f},
+ {0x002c, 0x8610},
+ {0x006c, 0x8651},
+ {0x0041, 0x8652},
+ {0x0059, 0x8653},
+ {0x0040, 0x8654},
+ {0x00fa, 0x8611},
+ {0x00ff, 0x8612},
+ {0x00f8, 0x8613},
+ {0x0000, 0x8614},
+ {0x0001, 0x863f},
+ {0x0000, 0x8640},
+ {0x0026, 0x8641},
+ {0x0045, 0x8642},
+ {0x0060, 0x8643},
+ {0x0075, 0x8644},
+ {0x0088, 0x8645},
+ {0x009b, 0x8646},
+ {0x00b0, 0x8647},
+ {0x00c5, 0x8648},
+ {0x00d2, 0x8649},
+ {0x00dc, 0x864a},
+ {0x00e5, 0x864b},
+ {0x00eb, 0x864c},
+ {0x00f0, 0x864d},
+ {0x00f6, 0x864e},
+ {0x00fa, 0x864f},
+ {0x00ff, 0x8650},
+ {0x0060, 0x8657},
+ {0x0010, 0x8658},
+ {0x0018, 0x8659},
+ {0x0005, 0x865a},
+ {0x0018, 0x8660},
+ {0x0003, 0x8509},
+ {0x0011, 0x850a},
+ {0x0032, 0x850b},
+ {0x0010, 0x850c},
+ {0x0021, 0x850d},
+ {0x0001, 0x8500},
+ {0x0000, 0x8508},
+
+ {0x0012, 0x8608},
+ {0x002c, 0x8609},
+ {0x0002, 0x860a},
+ {0x0039, 0x860b},
+ {0x00d0, 0x860c},
+ {0x00f7, 0x860d},
+ {0x00ed, 0x860e},
+ {0x00db, 0x860f},
+ {0x0039, 0x8610},
+ {0x0012, 0x8657},
+ {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}, */
+/* {0x0030, 0x8112}, */
{}
};
@@ -1136,14 +1069,14 @@ static const u16 spca508_vista_init_data[][2] = {
{0x0008, 0x8200}, /* Clear register */
{0x0000, 0x870b}, /* Reset CTL3 */
{0x0020, 0x8112}, /* Video Drop packet enable */
- {0x0003, 0x8111}, /* Soft Reset compression, memory, TG & CDSP */
+ {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 */
+ {0x0090, 0x8110}, /* Enable: SSI output, External 2X clock output */
{0x0020, 0x8112},
{0x0000, 0x8114},
{0x0001, 0x8114},
@@ -1156,191 +1089,143 @@ static const u16 spca508_vista_init_data[][2] = {
{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 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 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 { 0x0001, 0x8803 } -> 0000: 00 */
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
- /* READ { 0, 0x0001, 0x8802 } ->
- 0000: 10 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 10 */
{0x0010, 0x8802},
{0x0009, 0x8801},
{0x0042, 0x8805},
{0x0001, 0x8800},
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
- /* READ { 0, 0x0001, 0x8802 } ->
- 0000: 10 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 10 */
{0x0010, 0x8802},
{0x003c, 0x8801},
{0x0001, 0x8805},
{0x0000, 0x8800},
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
- /* READ { 0, 0x0001, 0x8802 } ->
- 0000: 10 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 10 */
{0x0010, 0x8802},
{0x0001, 0x8801},
{0x000a, 0x8805},
{0x0000, 0x8800},
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
- /* READ { 0, 0x0001, 0x8802 } ->
- 0000: 10 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 10 */
{0x0010, 0x8802},
{0x0002, 0x8801},
{0x0000, 0x8805},
{0x0000, 0x8800},
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
- /* READ { 0, 0x0001, 0x8802 } ->
- 0000: 10 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 10 */
{0x0010, 0x8802},
{0x0003, 0x8801},
{0x0027, 0x8805},
{0x0001, 0x8800},
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
- /* READ { 0, 0x0001, 0x8802 } ->
- 0000: 10 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 10 */
{0x0010, 0x8802},
{0x0004, 0x8801},
{0x0065, 0x8805},
{0x0001, 0x8800},
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
- /* READ { 0, 0x0001, 0x8802 } ->
- 0000: 10 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 10 */
{0x0010, 0x8802},
{0x0005, 0x8801},
{0x0003, 0x8805},
{0x0000, 0x8800},
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
- /* READ { 0, 0x0001, 0x8802 } ->
- 0000: 10 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 10 */
{0x0010, 0x8802},
{0x0006, 0x8801},
{0x001c, 0x8805},
{0x0000, 0x8800},
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
- /* READ { 0, 0x0001, 0x8802 } ->
- 0000: 10 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 10 */
{0x0010, 0x8802},
{0x0007, 0x8801},
{0x002a, 0x8805},
{0x0000, 0x8800},
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
- /* READ { 0, 0x0001, 0x8802 } ->
- 0000: 10 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 10 */
{0x0010, 0x8802},
{0x000e, 0x8801},
{0x0000, 0x8805},
{0x0000, 0x8800},
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
- /* READ { 0, 0x0001, 0x8802 } ->
- 0000: 10 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 10 */
{0x0010, 0x8802},
{0x0028, 0x8801},
{0x002e, 0x8805},
{0x0000, 0x8800},
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
- /* READ { 0, 0x0001, 0x8802 } ->
- 0000: 10 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 10 */
{0x0010, 0x8802},
{0x0039, 0x8801},
{0x0013, 0x8805},
{0x0000, 0x8800},
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
- /* READ { 0, 0x0001, 0x8802 } ->
- 0000: 10 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 10 */
{0x0010, 0x8802},
{0x003b, 0x8801},
{0x000c, 0x8805},
{0x0000, 0x8800},
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
- /* READ { 0, 0x0001, 0x8802 } ->
- 0000: 10 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 10 */
{0x0010, 0x8802},
{0x0035, 0x8801},
{0x0028, 0x8805},
{0x0000, 0x8800},
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
- /* READ { 0, 0x0001, 0x8802 } ->
- 0000: 10 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 10 */
{0x0010, 0x8802},
{0x0009, 0x8801},
{0x0042, 0x8805},
{0x0001, 0x8800},
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
+ /* READ { 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 */
+ {0x0001, 0x8606}, /* 1 Line memory Read Counter (H) Result: (d)410 */
{0x0023, 0x8601},
{0x0010, 0x8602},
{0x000a, 0x8603},
- {0x009A, 0x8600},
+ {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) */
@@ -1356,7 +1241,7 @@ static const u16 spca508_vista_init_data[][2] = {
{0x0005, 0x860a}, /* ... */
{0x0025, 0x860b},
{0x00e1, 0x860c},
- {0x00fa, 0x860D},
+ {0x00fa, 0x860d},
{0x00f4, 0x860e},
{0x00e8, 0x860f},
{0x0025, 0x8610}, /* A33 Coef. */
@@ -1371,11 +1256,12 @@ static const u16 spca508_vista_init_data[][2] = {
{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 */
+ {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 */
+ {0x000a, 0x8659}, /* Edge bandwidth high threshold */
{0x0005, 0x865a}, /* Edge bandwidth low threshold */
{0x0064, 0x8607}, /* UV filter enable */
@@ -1411,29 +1297,20 @@ static const u16 spca508_vista_init_data[][2] = {
{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 */
+ /* READ { 0x0000, 0x8608 } -> 0000: 13 */
+ /* READ { 0x0000, 0x8609 } -> 0000: 28 */
+ /* READ { 0x0000, 0x8610 } -> 0000: 05 */
+ /* READ { 0x0000, 0x8611 } -> 0000: 25 */
+ /* READ { 0x0000, 0x8612 } -> 0000: e1 */
+ /* READ { 0x0000, 0x8613 } -> 0000: fa */
+ /* READ { 0x0000, 0x8614 } -> 0000: f4 */
+ /* READ { 0x0000, 0x8615 } -> 0000: e8 */
+ /* READ { 0x0000, 0x8616 } -> 0000: 25 */
{}
};
static int reg_write(struct usb_device *dev,
- __u16 index, __u16 value)
+ u16 index, u16 value)
{
int ret;
@@ -1452,7 +1329,7 @@ static int reg_write(struct usb_device *dev,
/* read 1 byte */
/* returns: negative is error, pos or zero is data */
static int reg_read(struct gspca_dev *gspca_dev,
- __u16 index) /* wIndex */
+ u16 index) /* wIndex */
{
int ret;
@@ -1474,16 +1351,16 @@ static int reg_read(struct gspca_dev *gspca_dev,
}
static int write_vector(struct gspca_dev *gspca_dev,
- const u16 data[][2])
+ const u16 (*data)[2])
{
struct usb_device *dev = gspca_dev->dev;
- int ret, i = 0;
+ int ret;
- while (data[i][1] != 0) {
- ret = reg_write(dev, data[i][1], data[i][0]);
+ while ((*data)[1] != 0) {
+ ret = reg_write(dev, (*data)[1], (*data)[0]);
if (ret < 0)
return ret;
- i++;
+ data++;
}
return 0;
}
@@ -1495,6 +1372,15 @@ static int sd_config(struct gspca_dev *gspca_dev,
struct sd *sd = (struct sd *) gspca_dev;
struct cam *cam;
int data1, data2;
+ const u16 (*init_data)[2];
+ static const u16 (*(init_data_tb[]))[2] = {
+ spca508_vista_init_data, /* CreativeVista 0 */
+ spca508_sightcam_init_data, /* HamaUSBSightcam 1 */
+ spca508_sightcam2_init_data, /* HamaUSBSightcam2 2 */
+ spca508cs110_init_data, /* IntelEasyPCCamera 3 */
+ spca508cs110_init_data, /* MicroInnovationIC200 4 */
+ spca508_init_data, /* ViewQuestVQ110 5 */
+ };
/* Read from global register the USB product and vendor IDs, just to
* prove that we can communicate with the device. This works, which
@@ -1518,37 +1404,13 @@ static int sd_config(struct gspca_dev *gspca_dev,
sd->subtype = id->driver_info;
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 */
+ init_data = init_data_tb[sd->subtype];
+ return write_vector(gspca_dev, init_data);
}
/* this function is called at probe and resume time */
static int sd_init(struct gspca_dev *gspca_dev)
{
-/* write_vector(gspca_dev, spca508_open_data); */
return 0;
}
@@ -1556,7 +1418,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
{
int mode;
- mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
+ mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
reg_write(gspca_dev->dev, 0x8500, mode);
switch (mode) {
case 0:
@@ -1581,7 +1443,7 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
struct gspca_frame *frame, /* target */
- __u8 *data, /* isoc packet */
+ u8 *data, /* isoc packet */
int len) /* iso packet length */
{
switch (data[0]) {
@@ -1594,7 +1456,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
data, len);
break;
case 0xff: /* drop */
-/* gspca_dev->last_packet_type = DISCARD_PACKET; */
break;
default:
data += 1;
@@ -1608,7 +1469,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
static void setbrightness(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- __u8 brightness = sd->brightness;
+ u8 brightness = sd->brightness;
/* MX seem contrast */
reg_write(gspca_dev->dev, 0x8651, brightness);
diff --git a/linux/drivers/media/video/gspca/spca561.c b/linux/drivers/media/video/gspca/spca561.c
index c8dd036a6..cb3313e19 100644
--- a/linux/drivers/media/video/gspca/spca561.c
+++ b/linux/drivers/media/video/gspca/spca561.c
@@ -34,8 +34,8 @@ struct sd {
__u16 exposure; /* rev12a only */
#define EXPOSURE_MIN 1
-#define EXPOSURE_DEF 200
-#define EXPOSURE_MAX (4095 - 900) /* see set_exposure */
+#define EXPOSURE_DEF 700 /* == 10 fps */
+#define EXPOSURE_MAX (2047 + 325) /* see setexposure */
__u8 contrast; /* rev72a only */
#define CONTRAST_MIN 0x00
@@ -48,9 +48,9 @@ struct sd {
#define BRIGHTNESS_MAX 0x3f
__u8 white;
-#define WHITE_MIN 1
-#define WHITE_DEF 0x40
-#define WHITE_MAX 0x7f
+#define HUE_MIN 1
+#define HUE_DEF 0x40
+#define HUE_MAX 0x7f
__u8 autogain;
#define AUTOGAIN_MIN 0
@@ -58,9 +58,9 @@ struct sd {
#define AUTOGAIN_MAX 1
__u8 gain; /* rev12a only */
-#define GAIN_MIN 0x0
-#define GAIN_DEF 0x24
-#define GAIN_MAX 0x24
+#define GAIN_MIN 0
+#define GAIN_DEF 63
+#define GAIN_MAX 255
#define EXPO12A_DEF 3
__u8 expo12a; /* expo/gain? for rev 12a */
@@ -492,7 +492,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
}
sd->brightness = BRIGHTNESS_DEF;
sd->contrast = CONTRAST_DEF;
- sd->white = WHITE_DEF;
+ sd->white = HUE_DEF;
sd->exposure = EXPOSURE_DEF;
sd->autogain = AUTOGAIN_DEF;
sd->gain = GAIN_DEF;
@@ -580,8 +580,7 @@ static void setcontrast(struct gspca_dev *gspca_dev)
static void setexposure(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- int expo;
- int clock_divider;
+ int i, expo = 0;
/* Register 0x8309 controls exposure for the spca561,
the basic exposure setting goes from 1-2047, where 1 is completely
@@ -595,16 +594,22 @@ static void setexposure(struct gspca_dev *gspca_dev)
configure a divider for the base framerate which us used at the
exposure setting of 1-300. These bits configure the base framerate
according to the following formula: fps = 60 / (value + 2) */
- if (sd->exposure < 2048) {
- expo = sd->exposure;
- clock_divider = 0;
- } else {
- /* Add 900 to make the 0 setting of the second part of the
- exposure equal to the 2047 setting of the first part. */
- expo = (sd->exposure - 2048) + 900;
- clock_divider = 3;
+
+ /* We choose to use the high bits setting the fixed framerate divisor
+ asap, as setting high basic exposure setting without the fixed
+ divider in combination with high gains makes the cam stop */
+ int table[] = { 0, 450, 550, 625, EXPOSURE_MAX };
+
+ for (i = 0; i < ARRAY_SIZE(table) - 1; i++) {
+ if (sd->exposure <= table[i + 1]) {
+ expo = sd->exposure - table[i];
+ if (i)
+ expo += 300;
+ expo |= i << 11;
+ break;
+ }
}
- expo |= clock_divider << 11;
+
gspca_dev->usb_buf[0] = expo;
gspca_dev->usb_buf[1] = expo >> 8;
reg_w_buf(gspca_dev, 0x8309, 2);
@@ -615,7 +620,16 @@ static void setgain(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- gspca_dev->usb_buf[0] = sd->gain;
+ /* gain reg low 6 bits 0-63 gain, bit 6 and 7, both double the
+ sensitivity when set, so 31 + one of them set == 63, and 15
+ with both of them set == 63 */
+ if (sd->gain < 64)
+ gspca_dev->usb_buf[0] = sd->gain;
+ else if (sd->gain < 128)
+ gspca_dev->usb_buf[0] = (sd->gain / 2) | 0x40;
+ else
+ gspca_dev->usb_buf[0] = (sd->gain / 4) | 0xC0;
+
gspca_dev->usb_buf[1] = 0;
reg_w_buf(gspca_dev, 0x8335, 2);
}
@@ -660,8 +674,7 @@ static int sd_start_12a(struct gspca_dev *gspca_dev)
reg_w_buf(gspca_dev, 0x8391, 8);
reg_w_buf(gspca_dev, 0x8390, 8);
setwhite(gspca_dev);
- setautogain(gspca_dev);
-/* setgain(gspca_dev); */
+ setgain(gspca_dev);
setexposure(gspca_dev);
return 0;
}
@@ -793,18 +806,6 @@ static void do_autogain(struct gspca_dev *gspca_dev)
i2c_write(gspca_dev, expotimes | pixelclk, 0x09);
}
break;
- case Rev012A:
- reg_r(gspca_dev, 0x8330, 2);
- if (gspca_dev->usb_buf[1] > 0x08) {
- gspca_dev->usb_buf[0] = ++sd->expo12a;
- gspca_dev->usb_buf[1] = 0;
- reg_w_buf(gspca_dev, 0x8339, 2);
- } else if (gspca_dev->usb_buf[1] < 0x02) {
- gspca_dev->usb_buf[0] = --sd->expo12a;
- gspca_dev->usb_buf[1] = 0;
- reg_w_buf(gspca_dev, 0x8339, 2);
- }
- break;
}
}
@@ -959,13 +960,13 @@ static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
static struct ctrl sd_ctrls_12a[] = {
{
{
- .id = V4L2_CID_DO_WHITE_BALANCE,
+ .id = V4L2_CID_HUE,
.type = V4L2_CTRL_TYPE_INTEGER,
- .name = "White Balance",
- .minimum = WHITE_MIN,
- .maximum = WHITE_MAX,
+ .name = "Hue",
+ .minimum = HUE_MIN,
+ .maximum = HUE_MAX,
.step = 1,
- .default_value = WHITE_DEF,
+ .default_value = HUE_DEF,
},
.set = sd_setwhite,
.get = sd_getwhite,
@@ -985,19 +986,6 @@ static struct ctrl sd_ctrls_12a[] = {
},
{
{
- .id = V4L2_CID_AUTOGAIN,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Auto Gain",
- .minimum = AUTOGAIN_MIN,
- .maximum = AUTOGAIN_MAX,
- .step = 1,
- .default_value = AUTOGAIN_DEF,
- },
- .set = sd_setautogain,
- .get = sd_getautogain,
- },
- {
- {
.id = V4L2_CID_GAIN,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Gain",
@@ -1014,13 +1002,13 @@ static struct ctrl sd_ctrls_12a[] = {
static struct ctrl sd_ctrls_72a[] = {
{
{
- .id = V4L2_CID_DO_WHITE_BALANCE,
+ .id = V4L2_CID_HUE,
.type = V4L2_CTRL_TYPE_INTEGER,
- .name = "White Balance",
- .minimum = WHITE_MIN,
- .maximum = WHITE_MAX,
+ .name = "Hue",
+ .minimum = HUE_MIN,
+ .maximum = HUE_MAX,
.step = 1,
- .default_value = WHITE_DEF,
+ .default_value = HUE_DEF,
},
.set = sd_setwhite,
.get = sd_getwhite,
@@ -1077,7 +1065,6 @@ static const struct sd_desc sd_desc_12a = {
.stopN = sd_stopN,
.stop0 = sd_stop0,
.pkt_scan = sd_pkt_scan,
-/* .dq_callback = do_autogain, * fixme */
};
static const struct sd_desc sd_desc_72a = {
.name = MODULE_NAME,
diff --git a/linux/drivers/media/video/gspca/stv06xx/Makefile b/linux/drivers/media/video/gspca/stv06xx/Makefile
index feeaa94ab..2f3c3a606 100644
--- a/linux/drivers/media/video/gspca/stv06xx/Makefile
+++ b/linux/drivers/media/video/gspca/stv06xx/Makefile
@@ -3,7 +3,8 @@ obj-$(CONFIG_USB_STV06XX) += gspca_stv06xx.o
gspca_stv06xx-objs := stv06xx.o \
stv06xx_vv6410.o \
stv06xx_hdcs.o \
- stv06xx_pb0100.o
+ stv06xx_pb0100.o \
+ stv06xx_st6422.o
EXTRA_CFLAGS += -Idrivers/media/video/gspca
diff --git a/linux/drivers/media/video/gspca/stv06xx/stv06xx.c b/linux/drivers/media/video/gspca/stv06xx/stv06xx.c
index 9dff2e65b..0da8e0de0 100644
--- a/linux/drivers/media/video/gspca/stv06xx/stv06xx.c
+++ b/linux/drivers/media/video/gspca/stv06xx/stv06xx.c
@@ -92,11 +92,10 @@ static int stv06xx_write_sensor_finish(struct sd *sd)
{
int err = 0;
- if (IS_850(sd)) {
+ if (sd->bridge == BRIDGE_STV610) {
struct usb_device *udev = sd->gspca_dev.dev;
__u8 *buf = sd->gspca_dev.usb_buf;
- /* Quickam Web needs an extra packet */
buf[0] = 0;
err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
0x04, 0x40, 0x1704, 0, buf, 1,
@@ -253,7 +252,7 @@ static int stv06xx_init(struct gspca_dev *gspca_dev)
err = sd->sensor->init(sd);
- if (dump_sensor)
+ if (dump_sensor && sd->sensor->dump)
sd->sensor->dump(sd);
return (err < 0) ? err : 0;
@@ -293,8 +292,6 @@ static void stv06xx_stopN(struct gspca_dev *gspca_dev)
goto out;
err = sd->sensor->stop(sd);
- if (err < 0)
- goto out;
out:
if (err < 0)
@@ -320,6 +317,8 @@ static void stv06xx_pkt_scan(struct gspca_dev *gspca_dev,
__u8 *data, /* isoc packet */
int len) /* iso packet length */
{
+ struct sd *sd = (struct sd *) gspca_dev;
+
PDEBUG(D_PACK, "Packet of length %d arrived", len);
/* A packet may contain several frames
@@ -345,14 +344,29 @@ static void stv06xx_pkt_scan(struct gspca_dev *gspca_dev,
if (len < chunk_len) {
PDEBUG(D_ERR, "URB packet length is smaller"
" than the specified chunk length");
+ gspca_dev->last_packet_type = DISCARD_PACKET;
return;
}
+ /* First byte seem to be 02=data 2nd byte is unknown??? */
+ if (sd->bridge == BRIDGE_ST6422 && (id & 0xFF00) == 0x0200)
+ goto frame_data;
+
switch (id) {
case 0x0200:
case 0x4200:
+frame_data:
PDEBUG(D_PACK, "Frame data packet detected");
+ if (sd->to_skip) {
+ int skip = (sd->to_skip < chunk_len) ?
+ sd->to_skip : chunk_len;
+ data += skip;
+ len -= skip;
+ chunk_len -= skip;
+ sd->to_skip -= skip;
+ }
+
gspca_frame_add(gspca_dev, INTER_PACKET, frame,
data, chunk_len);
break;
@@ -367,6 +381,9 @@ static void stv06xx_pkt_scan(struct gspca_dev *gspca_dev,
gspca_frame_add(gspca_dev, FIRST_PACKET,
frame, data, 0);
+ if (sd->bridge == BRIDGE_ST6422)
+ sd->to_skip = gspca_dev->width * 4;
+
if (chunk_len)
PDEBUG(D_ERR, "Chunk length is "
"non-zero on a SOF");
@@ -397,8 +414,12 @@ static void stv06xx_pkt_scan(struct gspca_dev *gspca_dev,
/* Unknown chunk with 2 bytes of data,
occurs 2-3 times per USB interrupt */
break;
+ case 0x42ff:
+ PDEBUG(D_PACK, "Chunk 0x42ff detected");
+ /* Special chunk seen sometimes on the ST6422 */
+ break;
default:
- PDEBUG(D_PACK, "Unknown chunk %d detected", id);
+ PDEBUG(D_PACK, "Unknown chunk 0x%04x detected", id);
/* Unknown chunk */
}
data += chunk_len;
@@ -430,11 +451,16 @@ static int stv06xx_config(struct gspca_dev *gspca_dev,
cam = &gspca_dev->cam;
sd->desc = sd_desc;
+ sd->bridge = id->driver_info;
gspca_dev->sd_desc = &sd->desc;
if (dump_bridge)
stv06xx_dump_bridge(sd);
+ sd->sensor = &stv06xx_sensor_st6422;
+ if (!sd->sensor->probe(sd))
+ return 0;
+
sd->sensor = &stv06xx_sensor_vv6410;
if (!sd->sensor->probe(sd))
return 0;
@@ -459,9 +485,20 @@ static int stv06xx_config(struct gspca_dev *gspca_dev,
/* -- module initialisation -- */
static const __devinitdata struct usb_device_id device_table[] = {
- {USB_DEVICE(0x046d, 0x0840)}, /* QuickCam Express */
- {USB_DEVICE(0x046d, 0x0850)}, /* LEGO cam / QuickCam Web */
- {USB_DEVICE(0x046d, 0x0870)}, /* Dexxa WebCam USB */
+ /* QuickCam Express */
+ {USB_DEVICE(0x046d, 0x0840), .driver_info = BRIDGE_STV600 },
+ /* LEGO cam / QuickCam Web */
+ {USB_DEVICE(0x046d, 0x0850), .driver_info = BRIDGE_STV610 },
+ /* Dexxa WebCam USB */
+ {USB_DEVICE(0x046d, 0x0870), .driver_info = BRIDGE_STV602 },
+ /* QuickCam Messenger */
+ {USB_DEVICE(0x046D, 0x08F0), .driver_info = BRIDGE_ST6422 },
+ /* QuickCam Communicate */
+ {USB_DEVICE(0x046D, 0x08F5), .driver_info = BRIDGE_ST6422 },
+ /* QuickCam Messenger (new) */
+ {USB_DEVICE(0x046D, 0x08F6), .driver_info = BRIDGE_ST6422 },
+ /* QuickCam Messenger (new) */
+ {USB_DEVICE(0x046D, 0x08DA), .driver_info = BRIDGE_ST6422 },
{}
};
MODULE_DEVICE_TABLE(usb, device_table);
diff --git a/linux/drivers/media/video/gspca/stv06xx/stv06xx.h b/linux/drivers/media/video/gspca/stv06xx/stv06xx.h
index 1207e7d17..bb73c3288 100644
--- a/linux/drivers/media/video/gspca/stv06xx/stv06xx.h
+++ b/linux/drivers/media/video/gspca/stv06xx/stv06xx.h
@@ -31,6 +31,7 @@
#define STV06XX_H_
#include "gspca.h"
+#include "compat.h"
#define MODULE_NAME "STV06xx"
@@ -93,6 +94,17 @@ struct sd {
/* Sensor private data */
void *sensor_priv;
+
+ /* The first 4 lines produced by the stv6422 are no good, this keeps
+ track of how many bytes we still need to skip during a frame */
+ int to_skip;
+
+ /* Bridge / Camera type */
+ u8 bridge;
+ #define BRIDGE_STV600 0
+ #define BRIDGE_STV602 1
+ #define BRIDGE_STV610 2
+ #define BRIDGE_ST6422 3 /* With integrated sensor */
};
int stv06xx_write_bridge(struct sd *sd, u16 address, u16 i2c_data);
diff --git a/linux/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c b/linux/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c
index b16903814..3039ec208 100644
--- a/linux/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c
+++ b/linux/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c
@@ -434,7 +434,7 @@ static int hdcs_probe_1x00(struct sd *sd)
hdcs->exp.er = 100;
/*
- * Frame rate on HDCS-1000 0x46D:0x840 depends on PSMP:
+ * Frame rate on HDCS-1000 with STV600 depends on PSMP:
* 4 = doesn't work at all
* 5 = 7.8 fps,
* 6 = 6.9 fps,
@@ -443,7 +443,7 @@ static int hdcs_probe_1x00(struct sd *sd)
* 15 = 4.4 fps,
* 31 = 2.8 fps
*
- * Frame rate on HDCS-1000 0x46D:0x870 depends on PSMP:
+ * Frame rate on HDCS-1000 with STV602 depends on PSMP:
* 15 = doesn't work at all
* 18 = doesn't work at all
* 19 = 7.3 fps
@@ -453,7 +453,7 @@ static int hdcs_probe_1x00(struct sd *sd)
* 24 = 6.3 fps
* 30 = 5.4 fps
*/
- hdcs->psmp = IS_870(sd) ? 20 : 5;
+ hdcs->psmp = (sd->bridge == BRIDGE_STV602) ? 20 : 5;
sd->sensor_priv = hdcs;
@@ -530,7 +530,7 @@ static int hdcs_init(struct sd *sd)
int i, err = 0;
/* Set the STV0602AA in STV0600 emulation mode */
- if (IS_870(sd))
+ if (sd->bridge == BRIDGE_STV602)
stv06xx_write_bridge(sd, STV_STV0600_EMULATION, 1);
/* Execute the bridge init */
@@ -558,7 +558,7 @@ static int hdcs_init(struct sd *sd)
return err;
/* Set PGA sample duration
- (was 0x7E for IS_870, but caused slow framerate with HDCS-1020) */
+ (was 0x7E for the STV602, but caused slow framerate with HDCS-1020) */
if (IS_1020(sd))
err = stv06xx_write_sensor(sd, HDCS_TCTRL,
(HDCS_ADC_START_SIG_DUR << 6) | hdcs->psmp);
diff --git a/linux/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h b/linux/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h
index e88c42f7d..934b9cebc 100644
--- a/linux/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h
+++ b/linux/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h
@@ -32,14 +32,13 @@
#include "stv06xx.h"
-#define IS_850(sd) ((sd)->gspca_dev.dev->descriptor.idProduct == 0x850)
-#define IS_870(sd) ((sd)->gspca_dev.dev->descriptor.idProduct == 0x870)
#define IS_1020(sd) ((sd)->sensor == &stv06xx_sensor_hdcs1020)
extern const struct stv06xx_sensor stv06xx_sensor_vv6410;
extern const struct stv06xx_sensor stv06xx_sensor_hdcs1x00;
extern const struct stv06xx_sensor stv06xx_sensor_hdcs1020;
extern const struct stv06xx_sensor stv06xx_sensor_pb0100;
+extern const struct stv06xx_sensor stv06xx_sensor_st6422;
struct stv06xx_sensor {
/* Defines the name of a sensor */
diff --git a/linux/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c b/linux/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c
new file mode 100644
index 000000000..87cb5b9dd
--- /dev/null
+++ b/linux/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c
@@ -0,0 +1,453 @@
+/*
+ * Support for the sensor part which is integrated (I think) into the
+ * st6422 stv06xx alike bridge, as its integrated there are no i2c writes
+ * but instead direct bridge writes.
+ *
+ * Copyright (c) 2009 Hans de Goede <hdegoede@redhat.com>
+ *
+ * Strongly based on qc-usb-messenger, which is:
+ * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher
+ * Mark Cave-Ayland, Carlo E Prelz, Dick Streefland
+ * Copyright (c) 2002, 2003 Tuukka Toivonen
+ *
+ * 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
+ *
+ */
+
+#include "stv06xx_st6422.h"
+
+static struct v4l2_pix_format st6422_mode[] = {
+ /* Note we actually get 124 lines of data, of which we skip the 4st
+ 4 as they are garbage */
+ {
+ 162,
+ 120,
+ V4L2_PIX_FMT_SGRBG8,
+ V4L2_FIELD_NONE,
+ .sizeimage = 162 * 120,
+ .bytesperline = 162,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 1
+ },
+ /* Note we actually get 248 lines of data, of which we skip the 4st
+ 4 as they are garbage, and we tell the app it only gets the
+ first 240 of the 244 lines it actually gets, so that it ignores
+ the last 4. */
+ {
+ 324,
+ 240,
+ V4L2_PIX_FMT_SGRBG8,
+ V4L2_FIELD_NONE,
+ .sizeimage = 324 * 244,
+ .bytesperline = 324,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0
+ },
+};
+
+static const struct ctrl st6422_ctrl[] = {
+#define BRIGHTNESS_IDX 0
+ {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+ .maximum = 31,
+ .step = 1,
+ .default_value = 3
+ },
+ .set = st6422_set_brightness,
+ .get = st6422_get_brightness
+ },
+#define CONTRAST_IDX 1
+ {
+ {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = 0,
+ .maximum = 15,
+ .step = 1,
+ .default_value = 11
+ },
+ .set = st6422_set_contrast,
+ .get = st6422_get_contrast
+ },
+#define GAIN_IDX 2
+ {
+ {
+ .id = V4L2_CID_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Gain",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+ .default_value = 64
+ },
+ .set = st6422_set_gain,
+ .get = st6422_get_gain
+ },
+#define EXPOSURE_IDX 3
+ {
+ {
+ .id = V4L2_CID_EXPOSURE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Exposure",
+ .minimum = 0,
+ .maximum = 1023,
+ .step = 1,
+ .default_value = 256
+ },
+ .set = st6422_set_exposure,
+ .get = st6422_get_exposure
+ },
+};
+
+static int st6422_probe(struct sd *sd)
+{
+ int i;
+ s32 *sensor_settings;
+
+ if (sd->bridge != BRIDGE_ST6422)
+ return -ENODEV;
+
+ info("st6422 sensor detected");
+
+ sensor_settings = kmalloc(ARRAY_SIZE(st6422_ctrl) * sizeof(s32),
+ GFP_KERNEL);
+ if (!sensor_settings)
+ return -ENOMEM;
+
+ sd->gspca_dev.cam.cam_mode = st6422_mode;
+ sd->gspca_dev.cam.nmodes = ARRAY_SIZE(st6422_mode);
+ sd->desc.ctrls = st6422_ctrl;
+ sd->desc.nctrls = ARRAY_SIZE(st6422_ctrl);
+ sd->sensor_priv = sensor_settings;
+
+ for (i = 0; i < sd->desc.nctrls; i++)
+ sensor_settings[i] = st6422_ctrl[i].qctrl.default_value;
+
+ return 0;
+}
+
+static int st6422_init(struct sd *sd)
+{
+ int err = 0, i;
+
+ const u16 st6422_bridge_init[][2] = {
+ { STV_ISO_ENABLE, 0x00 }, /* disable capture */
+ { 0x1436, 0x00 },
+ { 0x1432, 0x03 }, /* 0x00-0x1F brightness */
+ { 0x143a, 0xF9 }, /* 0x00-0x0F contrast */
+ { 0x0509, 0x38 }, /* R */
+ { 0x050a, 0x38 }, /* G */
+ { 0x050b, 0x38 }, /* B */
+ { 0x050c, 0x2A },
+ { 0x050d, 0x01 },
+
+
+ { 0x1431, 0x00 }, /* 0x00-0x07 ??? */
+ { 0x1433, 0x34 }, /* 160x120, 0x00-0x01 night filter */
+ { 0x1438, 0x18 }, /* 640x480 */
+/* 18 bayes */
+/* 10 compressed? */
+
+ { 0x1439, 0x00 },
+/* antiflimmer?? 0xa2 ger perfekt bild mot monitor */
+
+ { 0x143b, 0x05 },
+ { 0x143c, 0x00 }, /* 0x00-0x01 - ??? */
+
+
+/* shutter time 0x0000-0x03FF */
+/* low value give good picures on moving objects (but requires much light) */
+/* high value gives good picures in darkness (but tends to be overexposed) */
+ { 0x143e, 0x01 },
+ { 0x143d, 0x00 },
+
+ { 0x1442, 0xe2 },
+/* write: 1x1x xxxx */
+/* read: 1x1x xxxx */
+/* bit 5 == button pressed and hold if 0 */
+/* write 0xe2,0xea */
+
+/* 0x144a */
+/* 0x00 init */
+/* bit 7 == button has been pressed, but not handled */
+
+/* interrupt */
+/* if(urb->iso_frame_desc[i].status == 0x80) { */
+/* if(urb->iso_frame_desc[i].status == 0x88) { */
+
+ { 0x1500, 0xd0 },
+ { 0x1500, 0xd0 },
+ { 0x1500, 0x50 }, /* 0x00 - 0xFF 0x80 == compr ? */
+
+ { 0x1501, 0xaf },
+/* high val-> ljus area blir morkare. */
+/* low val -> ljus area blir ljusare. */
+ { 0x1502, 0xc2 },
+/* high val-> ljus area blir morkare. */
+/* low val -> ljus area blir ljusare. */
+ { 0x1503, 0x45 },
+/* high val-> ljus area blir morkare. */
+/* low val -> ljus area blir ljusare. */
+
+ { 0x1505, 0x02 },
+/* 2 : 324x248 80352 bytes */
+/* 7 : 248x162 40176 bytes */
+/* c+f: 162*124 20088 bytes */
+
+ { 0x150e, 0x8e },
+ { 0x150f, 0x37 },
+ { 0x15c0, 0x00 },
+ { 0x15c1, 1023 }, /* 160x120, ISOC_PACKET_SIZE */
+ { 0x15c3, 0x08 }, /* 0x04/0x14 ... test pictures ??? */
+
+
+ { 0x143f, 0x01 }, /* commit settings */
+
+ };
+
+ for (i = 0; i < ARRAY_SIZE(st6422_bridge_init) && !err; i++) {
+ err = stv06xx_write_bridge(sd, st6422_bridge_init[i][0],
+ st6422_bridge_init[i][1]);
+ }
+
+ return err;
+}
+
+static void st6422_disconnect(struct sd *sd)
+{
+ sd->sensor = NULL;
+ kfree(sd->sensor_priv);
+}
+
+static int st6422_start(struct sd *sd)
+{
+ int err, packet_size;
+ struct cam *cam = &sd->gspca_dev.cam;
+ s32 *sensor_settings = sd->sensor_priv;
+ struct usb_host_interface *alt;
+ struct usb_interface *intf;
+
+ intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface);
+ alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt);
+ if (!alt) {
+ PDEBUG(D_ERR, "Couldn't get altsetting");
+ return -EIO;
+ }
+
+ packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
+ err = stv06xx_write_bridge(sd, 0x15c1, packet_size);
+ if (err < 0)
+ return err;
+
+ if (cam->cam_mode[sd->gspca_dev.curr_mode].priv)
+ err = stv06xx_write_bridge(sd, 0x1505, 0x0f);
+ else
+ err = stv06xx_write_bridge(sd, 0x1505, 0x02);
+ if (err < 0)
+ return err;
+
+ err = st6422_set_brightness(&sd->gspca_dev,
+ sensor_settings[BRIGHTNESS_IDX]);
+ if (err < 0)
+ return err;
+
+ err = st6422_set_contrast(&sd->gspca_dev,
+ sensor_settings[CONTRAST_IDX]);
+ if (err < 0)
+ return err;
+
+ err = st6422_set_exposure(&sd->gspca_dev,
+ sensor_settings[EXPOSURE_IDX]);
+ if (err < 0)
+ return err;
+
+ err = st6422_set_gain(&sd->gspca_dev,
+ sensor_settings[GAIN_IDX]);
+ if (err < 0)
+ return err;
+
+ PDEBUG(D_STREAM, "Starting stream");
+
+ return 0;
+}
+
+static int st6422_stop(struct sd *sd)
+{
+ PDEBUG(D_STREAM, "Halting stream");
+
+ return 0;
+}
+
+static int st6422_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
+
+ *val = sensor_settings[BRIGHTNESS_IDX];
+
+ PDEBUG(D_V4L2, "Read brightness %d", *val);
+
+ return 0;
+}
+
+static int st6422_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+ int err;
+ struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
+
+ sensor_settings[BRIGHTNESS_IDX] = val;
+
+ if (!gspca_dev->streaming)
+ return 0;
+
+ /* val goes from 0 -> 31 */
+ PDEBUG(D_V4L2, "Set brightness to %d", val);
+ err = stv06xx_write_bridge(sd, 0x1432, val);
+ if (err < 0)
+ return err;
+
+ /* commit settings */
+ err = stv06xx_write_bridge(sd, 0x143f, 0x01);
+ return (err < 0) ? err : 0;
+}
+
+static int st6422_get_contrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
+
+ *val = sensor_settings[CONTRAST_IDX];
+
+ PDEBUG(D_V4L2, "Read contrast %d", *val);
+
+ return 0;
+}
+
+static int st6422_set_contrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+ int err;
+ struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
+
+ sensor_settings[CONTRAST_IDX] = val;
+
+ if (!gspca_dev->streaming)
+ return 0;
+
+ /* Val goes from 0 -> 15 */
+ PDEBUG(D_V4L2, "Set contrast to %d\n", val);
+ err = stv06xx_write_bridge(sd, 0x143a, 0xf0 | val);
+ if (err < 0)
+ return err;
+
+ /* commit settings */
+ err = stv06xx_write_bridge(sd, 0x143f, 0x01);
+ return (err < 0) ? err : 0;
+}
+
+static int st6422_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
+
+ *val = sensor_settings[GAIN_IDX];
+
+ PDEBUG(D_V4L2, "Read gain %d", *val);
+
+ return 0;
+}
+
+static int st6422_set_gain(struct gspca_dev *gspca_dev, __s32 val)
+{
+ int err;
+ struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
+
+ sensor_settings[GAIN_IDX] = val;
+
+ if (!gspca_dev->streaming)
+ return 0;
+
+ PDEBUG(D_V4L2, "Set gain to %d", val);
+
+ /* Set red, green, blue, gain */
+ err = stv06xx_write_bridge(sd, 0x0509, val);
+ if (err < 0)
+ return err;
+
+ err = stv06xx_write_bridge(sd, 0x050a, val);
+ if (err < 0)
+ return err;
+
+ err = stv06xx_write_bridge(sd, 0x050b, val);
+ if (err < 0)
+ return err;
+
+ /* 2 mystery writes */
+ err = stv06xx_write_bridge(sd, 0x050c, 0x2a);
+ if (err < 0)
+ return err;
+
+ err = stv06xx_write_bridge(sd, 0x050d, 0x01);
+ if (err < 0)
+ return err;
+
+ /* commit settings */
+ err = stv06xx_write_bridge(sd, 0x143f, 0x01);
+ return (err < 0) ? err : 0;
+}
+
+static int st6422_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
+
+ *val = sensor_settings[EXPOSURE_IDX];
+
+ PDEBUG(D_V4L2, "Read exposure %d", *val);
+
+ return 0;
+}
+
+static int st6422_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
+{
+ int err;
+ struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
+
+ sensor_settings[EXPOSURE_IDX] = val;
+
+ if (!gspca_dev->streaming)
+ return 0;
+
+ PDEBUG(D_V4L2, "Set exposure to %d\n", val);
+ err = stv06xx_write_bridge(sd, 0x143d, val & 0xff);
+ if (err < 0)
+ return err;
+
+ err = stv06xx_write_bridge(sd, 0x143e, val >> 8);
+ if (err < 0)
+ return err;
+
+ /* commit settings */
+ err = stv06xx_write_bridge(sd, 0x143f, 0x01);
+ return (err < 0) ? err : 0;
+}
diff --git a/linux/drivers/media/video/gspca/stv06xx/stv06xx_st6422.h b/linux/drivers/media/video/gspca/stv06xx/stv06xx_st6422.h
new file mode 100644
index 000000000..b2d45fe50
--- /dev/null
+++ b/linux/drivers/media/video/gspca/stv06xx/stv06xx_st6422.h
@@ -0,0 +1,59 @@
+/*
+ * Support for the sensor part which is integrated (I think) into the
+ * st6422 stv06xx alike bridge, as its integrated there are no i2c writes
+ * but instead direct bridge writes.
+ *
+ * Copyright (c) 2009 Hans de Goede <hdegoede@redhat.com>
+ *
+ * Strongly based on qc-usb-messenger, which is:
+ * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher
+ * Mark Cave-Ayland, Carlo E Prelz, Dick Streefland
+ * Copyright (c) 2002, 2003 Tuukka Toivonen
+ *
+ * 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
+ *
+ */
+
+#ifndef STV06XX_ST6422_H_
+#define STV06XX_ST6422_H_
+
+#include "stv06xx_sensor.h"
+
+static int st6422_probe(struct sd *sd);
+static int st6422_start(struct sd *sd);
+static int st6422_init(struct sd *sd);
+static int st6422_stop(struct sd *sd);
+static void st6422_disconnect(struct sd *sd);
+
+/* V4L2 controls supported by the driver */
+static int st6422_get_brightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int st6422_set_brightness(struct gspca_dev *gspca_dev, __s32 val);
+static int st6422_get_contrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int st6422_set_contrast(struct gspca_dev *gspca_dev, __s32 val);
+static int st6422_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
+static int st6422_set_gain(struct gspca_dev *gspca_dev, __s32 val);
+static int st6422_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
+static int st6422_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
+
+const struct stv06xx_sensor stv06xx_sensor_st6422 = {
+ .name = "ST6422",
+ .init = st6422_init,
+ .probe = st6422_probe,
+ .start = st6422_start,
+ .stop = st6422_stop,
+ .disconnect = st6422_disconnect,
+};
+
+#endif
diff --git a/linux/drivers/media/video/hdpvr/hdpvr-video.c b/linux/drivers/media/video/hdpvr/hdpvr-video.c
index 3e6ffee8d..ccd47f57f 100644
--- a/linux/drivers/media/video/hdpvr/hdpvr-video.c
+++ b/linux/drivers/media/video/hdpvr/hdpvr-video.c
@@ -181,7 +181,7 @@ static int hdpvr_submit_buffers(struct hdpvr_device *dev)
buff_list);
if (buf->status != BUFSTAT_AVAILABLE) {
v4l2_err(&dev->v4l2_dev,
- "buffer not marked as availbale\n");
+ "buffer not marked as available\n");
ret = -EFAULT;
goto err;
}
diff --git a/linux/drivers/media/video/ir-kbd-i2c.c b/linux/drivers/media/video/ir-kbd-i2c.c
index 7bae57ad3..cdf369129 100644
--- a/linux/drivers/media/video/ir-kbd-i2c.c
+++ b/linux/drivers/media/video/ir-kbd-i2c.c
@@ -75,7 +75,11 @@ static int get_key_haup_common(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw,
int start, range, toggle, dev, code, ircode;
/* poll IR chip */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
if (size != i2c_master_recv(&ir->c,buf,size))
+#else
+ if (size != i2c_master_recv(ir->c, buf, size))
+#endif
return -EIO;
/* split rc5 data block ... */
@@ -138,7 +142,11 @@ static int get_key_pixelview(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
unsigned char b;
/* poll IR chip */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
if (1 != i2c_master_recv(&ir->c,&b,1)) {
+#else
+ if (1 != i2c_master_recv(ir->c, &b, 1)) {
+#endif
dprintk(1,"read error\n");
return -EIO;
}
@@ -152,7 +160,11 @@ static int get_key_pv951(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
unsigned char b;
/* poll IR chip */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
if (1 != i2c_master_recv(&ir->c,&b,1)) {
+#else
+ if (1 != i2c_master_recv(ir->c, &b, 1)) {
+#endif
dprintk(1,"read error\n");
return -EIO;
}
@@ -172,7 +184,11 @@ static int get_key_fusionhdtv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
unsigned char buf[4];
/* poll IR chip */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
if (4 != i2c_master_recv(&ir->c,buf,4)) {
+#else
+ if (4 != i2c_master_recv(ir->c, buf, 4)) {
+#endif
dprintk(1,"read error\n");
return -EIO;
}
@@ -196,7 +212,11 @@ static int get_key_knc1(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
unsigned char b;
/* poll IR chip */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
if (1 != i2c_master_recv(&ir->c,&b,1)) {
+#else
+ if (1 != i2c_master_recv(ir->c, &b, 1)) {
+#endif
dprintk(1,"read error\n");
return -EIO;
}
@@ -223,12 +243,24 @@ static int get_key_avermedia_cardbus(struct IR_i2c *ir,
u32 *ir_key, u32 *ir_raw)
{
unsigned char subaddr, key, keygroup;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
struct i2c_msg msg[] = { { .addr = ir->c.addr, .flags = 0,
+#else
+ struct i2c_msg msg[] = { { .addr = ir->c->addr, .flags = 0,
+#endif
.buf = &subaddr, .len = 1},
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
{ .addr = ir->c.addr, .flags = I2C_M_RD,
+#else
+ { .addr = ir->c->addr, .flags = I2C_M_RD,
+#endif
.buf = &key, .len = 1} };
subaddr = 0x0d;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
if (2 != i2c_transfer(ir->c.adapter, msg, 2)) {
+#else
+ if (2 != i2c_transfer(ir->c->adapter, msg, 2)) {
+#endif
dprintk(1, "read error\n");
return -EIO;
}
@@ -238,7 +270,11 @@ static int get_key_avermedia_cardbus(struct IR_i2c *ir,
subaddr = 0x0b;
msg[1].buf = &keygroup;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
if (2 != i2c_transfer(ir->c.adapter, msg, 2)) {
+#else
+ if (2 != i2c_transfer(ir->c->adapter, msg, 2)) {
+#endif
dprintk(1, "read error\n");
return -EIO;
}
@@ -295,7 +331,11 @@ static void ir_work(struct work_struct *work)
/* MSI TV@nywhere Plus requires more frequent polling
otherwise it will miss some keypresses */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
if (ir->c.adapter->id == I2C_HW_SAA7134 && ir->c.addr == 0x30)
+#else
+ if (ir->c->adapter->id == I2C_HW_SAA7134 && ir->c->addr == 0x30)
+#endif
polling_interval = 50;
ir_key_poll(ir);
@@ -304,8 +344,9 @@ static void ir_work(struct work_struct *work)
/* ----------------------------------------------------------------------- */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
static int ir_attach(struct i2c_adapter *adap, int addr,
- unsigned short flags, int kind);
+ unsigned short flags, int kind);
static int ir_detach(struct i2c_client *client);
static int ir_probe(struct i2c_adapter *adap);
@@ -313,25 +354,32 @@ static struct i2c_driver driver = {
.driver = {
.name = "ir-kbd-i2c",
},
- .id = I2C_DRIVERID_INFRARED,
- .attach_adapter = ir_probe,
- .detach_client = ir_detach,
+ .id = I2C_DRIVERID_INFRARED,
+ .attach_adapter = ir_probe,
+ .detach_client = ir_detach,
};
-
-static struct i2c_client client_template =
+
+static struct i2c_client client =
{
- .name = "unset",
- .driver = &driver
-};
+ .name = "unset",
+ .driver = &driver
+ };
static int ir_attach(struct i2c_adapter *adap, int addr,
- unsigned short flags, int kind)
+ unsigned short flags, int kind)
+#else
+static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
+#endif
{
IR_KEYTAB_TYPE *ir_codes = NULL;
- char *name;
+ const char *name = NULL;
int ir_type;
struct IR_i2c *ir;
struct input_dev *input_dev;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
+ struct i2c_adapter *adap = client->adapter;
+ unsigned short addr = client->addr;
+#endif
int err;
ir = kzalloc(sizeof(struct IR_i2c),GFP_KERNEL);
@@ -341,13 +389,18 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
goto err_out_free;
}
- ir->c = client_template;
+ ir->c = client;
ir->input = input_dev;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
ir->c.adapter = adap;
ir->c.addr = addr;
+ snprintf(ir->c.name, sizeof(ir->c.name), "ir-kbd");
i2c_set_clientdata(&ir->c, ir);
+#else
+ i2c_set_clientdata(client, ir);
+#endif
switch(addr) {
case 0x64:
@@ -412,16 +465,40 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
ir_codes = ir_codes_avermedia_cardbus;
break;
default:
- /* shouldn't happen */
- printk(DEVNAME ": Huh? unknown i2c address (0x%02x)?\n", addr);
+ dprintk(1, DEVNAME ": Unsupported i2c address 0x%02x\n", addr);
+ err = -ENODEV;
+ goto err_out_free;
+ }
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
+ /* Let the caller override settings */
+ if (client->dev.platform_data) {
+ const struct IR_i2c_init_data *init_data =
+ client->dev.platform_data;
+
+ ir_codes = init_data->ir_codes;
+ name = init_data->name;
+ ir->get_key = init_data->get_key;
+ }
+
+ /* Make sure we are all setup before going on */
+ if (!name || !ir->get_key || !ir_codes) {
+ dprintk(1, DEVNAME ": Unsupported device at address 0x%02x\n",
+ addr);
err = -ENODEV;
goto err_out_free;
}
+#endif
/* Sets name */
- snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (%s)", name);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
+ snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (%s)", name);
+#else
+ snprintf(ir->name, sizeof(ir->name), "i2c IR (%s)", name);
+#endif
ir->ir_codes = ir_codes;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
/* register i2c device
* At device register, IR codes may be changed to be
* board dependent.
@@ -437,19 +514,29 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
}
/* Phys addr can only be set after attaching (for ir->c.dev) */
+#endif
snprintf(ir->phys, sizeof(ir->phys), "%s/%s/ir0",
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
dev_name(&ir->c.adapter->dev),
dev_name(&ir->c.dev));
+#else
+ dev_name(&adap->dev),
+ dev_name(&client->dev));
+#endif
/* init + register input device */
ir_input_init(input_dev, &ir->ir, ir_type, ir->ir_codes);
input_dev->id.bustype = BUS_I2C;
- input_dev->name = ir->c.name;
+ input_dev->name = ir->name;
input_dev->phys = ir->phys;
err = input_register_device(ir->input);
if (err)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
goto err_out_detach;
+#else
+ goto err_out_free;
+#endif
printk(DEVNAME ": %s detected at %s [%s]\n",
ir->input->name, ir->input->phys, adap->name);
@@ -464,30 +551,43 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
return 0;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
err_out_detach:
i2c_detach_client(&ir->c);
+#endif
err_out_free:
input_free_device(input_dev);
kfree(ir);
return err;
}
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
static int ir_detach(struct i2c_client *client)
+#else
+static int ir_remove(struct i2c_client *client)
+#endif
{
struct IR_i2c *ir = i2c_get_clientdata(client);
/* kill outstanding polls */
cancel_delayed_work_sync(&ir->work);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
/* unregister devices */
+#else
+ /* unregister device */
+#endif
input_unregister_device(ir->input);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
i2c_detach_client(&ir->c);
+#endif
/* free memory */
kfree(ir);
return 0;
}
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
static int ir_probe(struct i2c_adapter *adap)
{
@@ -593,6 +693,23 @@ static int ir_probe(struct i2c_adapter *adap)
return 0;
}
+#else
+static const struct i2c_device_id ir_kbd_id[] = {
+ /* Generic entry for any IR receiver */
+ { "ir_video", 0 },
+ /* IR device specific entries could be added here */
+ { }
+};
+
+static struct i2c_driver driver = {
+ .driver = {
+ .name = "ir-kbd-i2c",
+ },
+ .probe = ir_probe,
+ .remove = ir_remove,
+ .id_table = ir_kbd_id,
+};
+#endif
/* ----------------------------------------------------------------------- */
diff --git a/linux/drivers/media/video/ivtv/ivtv-controls.c b/linux/drivers/media/video/ivtv/ivtv-controls.c
index 84995bcf4..a3b77ed3f 100644
--- a/linux/drivers/media/video/ivtv/ivtv-controls.c
+++ b/linux/drivers/media/video/ivtv/ivtv-controls.c
@@ -60,6 +60,8 @@ int ivtv_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qctrl)
switch (qctrl->id) {
/* Standard V4L2 controls */
+ case V4L2_CID_USER_CLASS:
+ return v4l2_ctrl_query_fill(qctrl, 0, 0, 0, 0);
case V4L2_CID_BRIGHTNESS:
case V4L2_CID_HUE:
case V4L2_CID_SATURATION:
diff --git a/linux/drivers/media/video/ivtv/ivtv-driver.c b/linux/drivers/media/video/ivtv/ivtv-driver.c
index edb81a948..9f91838d7 100644
--- a/linux/drivers/media/video/ivtv/ivtv-driver.c
+++ b/linux/drivers/media/video/ivtv/ivtv-driver.c
@@ -455,7 +455,7 @@ static void ivtv_process_eeprom(struct ivtv *itv)
break;
}
if (tv.tuner_type == TUNER_ABSENT)
- IVTV_ERR("tveeprom cannot autodetect tuner!");
+ IVTV_ERR("tveeprom cannot autodetect tuner!\n");
if (itv->options.tuner == -1)
itv->options.tuner = tv.tuner_type;
diff --git a/linux/drivers/media/video/ivtv/ivtv-i2c.c b/linux/drivers/media/video/ivtv/ivtv-i2c.c
index 984c73b5e..484a323f1 100644
--- a/linux/drivers/media/video/ivtv/ivtv-i2c.c
+++ b/linux/drivers/media/video/ivtv/ivtv-i2c.c
@@ -592,9 +592,11 @@ static struct i2c_client ivtv_i2c_client_template = {
.name = "ivtv internal",
};
-/* init + register i2c algo-bit adapter */
+/* init + register i2c adapter + instantiate IR receiver */
int init_ivtv_i2c(struct ivtv *itv)
{
+ int retval;
+
IVTV_DEBUG_I2C("i2c init\n");
/* Sanity checks for the I2C hardware arrays. They must be the
@@ -634,9 +636,39 @@ int init_ivtv_i2c(struct ivtv *itv)
ivtv_setsda(itv, 1);
if (itv->options.newi2c > 0)
- return i2c_add_adapter(&itv->i2c_adap);
+ retval = i2c_add_adapter(&itv->i2c_adap);
else
- return i2c_bit_add_bus(&itv->i2c_adap);
+ retval = i2c_bit_add_bus(&itv->i2c_adap);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
+ /* Instantiate the IR receiver device, if present */
+ if (retval == 0) {
+ struct i2c_board_info info;
+ /* The external IR receiver is at i2c address 0x34 (0x35 for
+ reads). Future Hauppauge cards will have an internal
+ receiver at 0x30 (0x31 for reads). In theory, both can be
+ fitted, and Hauppauge suggest an external overrides an
+ internal.
+
+ That's why we probe 0x1a (~0x34) first. CB
+ */
+ const unsigned short addr_list[] = {
+ 0x1a, /* Hauppauge IR external */
+ 0x18, /* Hauppauge IR internal */
+ 0x71, /* Hauppauge IR (PVR150) */
+ 0x64, /* Pixelview IR */
+ 0x30, /* KNC ONE IR */
+ 0x6b, /* Adaptec IR */
+ I2C_CLIENT_END
+ };
+
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
+ i2c_new_probed_device(&itv->i2c_adap, &info, addr_list);
+ }
+#endif
+
+ return retval;
}
void exit_ivtv_i2c(struct ivtv *itv)
diff --git a/linux/drivers/media/video/ivtv/ivtv-queue.c b/linux/drivers/media/video/ivtv/ivtv-queue.c
index ff7b7dede..7fde36e6d 100644
--- a/linux/drivers/media/video/ivtv/ivtv-queue.c
+++ b/linux/drivers/media/video/ivtv/ivtv-queue.c
@@ -230,7 +230,8 @@ int ivtv_stream_alloc(struct ivtv_stream *s)
return -ENOMEM;
}
if (ivtv_might_use_dma(s)) {
- s->sg_handle = pci_map_single(itv->pdev, s->sg_dma, sizeof(struct ivtv_sg_element), s->dma);
+ s->sg_handle = pci_map_single(itv->pdev, s->sg_dma,
+ sizeof(struct ivtv_sg_element), PCI_DMA_TODEVICE);
ivtv_stream_sync_for_cpu(s);
}
diff --git a/linux/drivers/media/video/mt9m001.c b/linux/drivers/media/video/mt9m001.c
index 8d61ad30a..e609d68c4 100644
--- a/linux/drivers/media/video/mt9m001.c
+++ b/linux/drivers/media/video/mt9m001.c
@@ -280,15 +280,9 @@ static int mt9m001_try_fmt(struct soc_camera_device *icd,
{
struct v4l2_pix_format *pix = &f->fmt.pix;
- if (pix->height < 32 + icd->y_skip_top)
- pix->height = 32 + icd->y_skip_top;
- if (pix->height > 1024 + icd->y_skip_top)
- pix->height = 1024 + icd->y_skip_top;
- if (pix->width < 48)
- pix->width = 48;
- if (pix->width > 1280)
- pix->width = 1280;
- pix->width &= ~0x01; /* has to be even, unsure why was ~3 */
+ v4l_bound_align_image(&pix->width, 48, 1280, 1,
+ &pix->height, 32 + icd->y_skip_top,
+ 1024 + icd->y_skip_top, 0, 0);
return 0;
}
diff --git a/linux/drivers/media/video/mt9t031.c b/linux/drivers/media/video/mt9t031.c
index 381dd0fbe..a57051522 100644
--- a/linux/drivers/media/video/mt9t031.c
+++ b/linux/drivers/media/video/mt9t031.c
@@ -385,17 +385,9 @@ static int mt9t031_try_fmt(struct soc_camera_device *icd,
{
struct v4l2_pix_format *pix = &f->fmt.pix;
- if (pix->height < MT9T031_MIN_HEIGHT)
- pix->height = MT9T031_MIN_HEIGHT;
- if (pix->height > MT9T031_MAX_HEIGHT)
- pix->height = MT9T031_MAX_HEIGHT;
- if (pix->width < MT9T031_MIN_WIDTH)
- pix->width = MT9T031_MIN_WIDTH;
- if (pix->width > MT9T031_MAX_WIDTH)
- pix->width = MT9T031_MAX_WIDTH;
-
- pix->width &= ~0x01; /* has to be even */
- pix->height &= ~0x01; /* has to be even */
+ v4l_bound_align_image(
+ &pix->width, MT9T031_MIN_WIDTH, MT9T031_MAX_WIDTH, 1,
+ &pix->height, MT9T031_MIN_HEIGHT, MT9T031_MAX_HEIGHT, 1, 0);
return 0;
}
diff --git a/linux/drivers/media/video/mt9v022.c b/linux/drivers/media/video/mt9v022.c
index 016bcdfcf..4841e6eea 100644
--- a/linux/drivers/media/video/mt9v022.c
+++ b/linux/drivers/media/video/mt9v022.c
@@ -364,15 +364,9 @@ static int mt9v022_try_fmt(struct soc_camera_device *icd,
{
struct v4l2_pix_format *pix = &f->fmt.pix;
- if (pix->height < 32 + icd->y_skip_top)
- pix->height = 32 + icd->y_skip_top;
- if (pix->height > 480 + icd->y_skip_top)
- pix->height = 480 + icd->y_skip_top;
- if (pix->width < 48)
- pix->width = 48;
- if (pix->width > 752)
- pix->width = 752;
- pix->width &= ~0x03; /* ? */
+ v4l_bound_align_image(&pix->width, 48, 752, 2 /* ? */,
+ &pix->height, 32 + icd->y_skip_top,
+ 480 + icd->y_skip_top, 0, 0);
return 0;
}
diff --git a/linux/drivers/media/video/mx3_camera.c b/linux/drivers/media/video/mx3_camera.c
index 4d47eeb14..e605c076e 100644
--- a/linux/drivers/media/video/mx3_camera.c
+++ b/linux/drivers/media/video/mx3_camera.c
@@ -1074,7 +1074,7 @@ static struct soc_camera_host_ops mx3_soc_camera_host_ops = {
.set_bus_param = mx3_camera_set_bus_param,
};
-static int mx3_camera_probe(struct platform_device *pdev)
+static int __devinit mx3_camera_probe(struct platform_device *pdev)
{
struct mx3_camera_dev *mx3_cam;
struct resource *res;
@@ -1194,11 +1194,11 @@ static struct platform_driver mx3_camera_driver = {
.name = MX3_CAM_DRV_NAME,
},
.probe = mx3_camera_probe,
- .remove = __exit_p(mx3_camera_remove),
+ .remove = __devexit_p(mx3_camera_remove),
};
-static int __devinit mx3_camera_init(void)
+static int __init mx3_camera_init(void)
{
return platform_driver_register(&mx3_camera_driver);
}
diff --git a/linux/drivers/media/video/ov511.c b/linux/drivers/media/video/ov511.c
index 12d109eaa..346eed722 100644
--- a/linux/drivers/media/video/ov511.c
+++ b/linux/drivers/media/video/ov511.c
@@ -112,6 +112,8 @@ static int framedrop = -1;
static int fastset;
static int force_palette;
static int backlight;
+/* Bitmask marking allocated devices from 0 to OV511_MAX_UNIT_VIDEO */
+static unsigned long ov511_devused;
static int unit_video[OV511_MAX_UNIT_VIDEO];
static int remove_zeros;
static int mirror;
@@ -209,8 +211,6 @@ static const int i2c_detect_tries = 5;
static struct usb_device_id device_table [] = {
{ USB_DEVICE(VEND_OMNIVISION, PROD_OV511) },
{ USB_DEVICE(VEND_OMNIVISION, PROD_OV511PLUS) },
- { USB_DEVICE(VEND_OMNIVISION, PROD_OV518) },
- { USB_DEVICE(VEND_OMNIVISION, PROD_OV518PLUS) },
{ USB_DEVICE(VEND_MATTEL, PROD_ME2CAM) },
{ } /* Terminating entry */
};
@@ -5724,7 +5724,7 @@ ov51x_probe(struct usb_interface *intf, const struct usb_device_id *id)
struct usb_device *dev = interface_to_usbdev(intf);
struct usb_interface_descriptor *idesc;
struct usb_ov511 *ov;
- int i;
+ int i, rc, nr;
PDEBUG(1, "probing for device...");
@@ -5849,33 +5849,41 @@ ov51x_probe(struct usb_interface *intf, const struct usb_device_id *id)
ov->vdev->parent = &intf->dev;
video_set_drvdata(ov->vdev, ov);
- for (i = 0; i < OV511_MAX_UNIT_VIDEO; i++) {
- /* Minor 0 cannot be specified; assume user wants autodetect */
- if (unit_video[i] == 0)
- break;
+ mutex_lock(&ov->lock);
- if (video_register_device(ov->vdev, VFL_TYPE_GRABBER,
- unit_video[i]) >= 0) {
- break;
- }
- }
+ /* Check to see next free device and mark as used */
+ nr = find_first_zero_bit(&ov511_devused, OV511_MAX_UNIT_VIDEO);
+
+ /* Registers device */
+ if (unit_video[nr] != 0)
+ rc = video_register_device(ov->vdev, VFL_TYPE_GRABBER,
+ unit_video[nr]);
+ else
+ rc = video_register_device(ov->vdev, VFL_TYPE_GRABBER, -1);
- /* Use the next available one */
- if ((ov->vdev->minor == -1) &&
- video_register_device(ov->vdev, VFL_TYPE_GRABBER, -1) < 0) {
+ if (rc < 0) {
err("video_register_device failed");
+ mutex_unlock(&ov->lock);
goto error;
}
+ /* Mark device as used */
+ ov511_devused |= 1 << nr;
+ ov->nr = nr;
+
dev_info(&intf->dev, "Device at %s registered to minor %d\n",
ov->usb_path, ov->vdev->minor);
usb_set_intfdata(intf, ov);
if (ov_create_sysfs(ov->vdev)) {
err("ov_create_sysfs failed");
+ ov511_devused &= ~(1 << nr);
+ mutex_unlock(&ov->lock);
goto error;
}
+ mutex_lock(&ov->lock);
+
return 0;
error:
@@ -5910,10 +5918,16 @@ ov51x_disconnect(struct usb_interface *intf)
PDEBUG(3, "");
+ mutex_lock(&ov->lock);
usb_set_intfdata (intf, NULL);
- if (!ov)
+ if (!ov) {
+ mutex_unlock(&ov->lock);
return;
+ }
+
+ /* Free device number */
+ ov511_devused &= ~(1 << ov->nr);
if (ov->vdev)
video_unregister_device(ov->vdev);
@@ -5931,6 +5945,7 @@ ov51x_disconnect(struct usb_interface *intf)
ov->streaming = 0;
ov51x_unlink_isoc(ov);
+ mutex_unlock(&ov->lock);
ov->dev = NULL;
diff --git a/linux/drivers/media/video/ov511.h b/linux/drivers/media/video/ov511.h
index c303ac5a8..c213d944e 100644
--- a/linux/drivers/media/video/ov511.h
+++ b/linux/drivers/media/video/ov511.h
@@ -495,6 +495,9 @@ struct usb_ov511 {
int has_decoder; /* Device has a video decoder */
int pal; /* Device is designed for PAL resolution */
+ /* ov511 device number ID */
+ int nr; /* Stores a device number */
+
/* I2C interface */
struct mutex i2c_lock; /* Protect I2C controller regs */
unsigned char primary_i2c_slave; /* I2C write id of sensor */
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
index 28463489a..24644fc96 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
@@ -43,7 +43,7 @@ static int ir_mode[PVR_NUM] = { [0 ... PVR_NUM-1] = 1 };
module_param_array(ir_mode, int, NULL, 0444);
MODULE_PARM_DESC(ir_mode,"specify: 0=disable IR reception, 1=normal IR");
-static int pvr2_disable_ir_video = 1;
+static int pvr2_disable_ir_video;
module_param_named(disable_autoload_ir_video, pvr2_disable_ir_video,
int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(disable_autoload_ir_video,
@@ -651,6 +651,7 @@ static void do_i2c_scan(struct pvr2_hdw *hdw)
static void pvr2_i2c_register_ir(struct pvr2_hdw *hdw)
{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
struct i2c_board_info info;
unsigned char addr = 0;
if (pvr2_disable_ir_video) {
@@ -672,6 +673,7 @@ static void pvr2_i2c_register_ir(struct pvr2_hdw *hdw)
strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
info.addr = addr;
i2c_new_device(&hdw->i2c_adap, &info);
+#endif
}
void pvr2_i2c_core_init(struct pvr2_hdw *hdw)
diff --git a/linux/drivers/media/video/pwc/pwc-if.c b/linux/drivers/media/video/pwc/pwc-if.c
index b3765e280..4087612ee 100644
--- a/linux/drivers/media/video/pwc/pwc-if.c
+++ b/linux/drivers/media/video/pwc/pwc-if.c
@@ -605,7 +605,7 @@ static void pwc_snapshot_button(struct pwc_device *pdev, int down)
#ifdef CONFIG_USB_PWC_INPUT_EVDEV
if (pdev->button_dev) {
- input_report_key(pdev->button_dev, BTN_0, down);
+ input_report_key(pdev->button_dev, KEY_CAMERA, down);
input_sync(pdev->button_dev);
}
#endif
@@ -1791,7 +1791,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
return -ENOMEM;
}
memcpy(pdev->vdev, &pwc_template, sizeof(pwc_template));
- pdev->vdev->parent = &(udev->dev);
+ pdev->vdev->parent = &intf->dev;
strcpy(pdev->vdev->name, name);
video_set_drvdata(pdev->vdev, pdev);
@@ -1859,7 +1859,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
pdev->button_dev->cdev.dev = &pdev->udev->dev;
#endif
pdev->button_dev->evbit[0] = BIT_MASK(EV_KEY);
- pdev->button_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0);
+ pdev->button_dev->keybit[BIT_WORD(KEY_CAMERA)] = BIT_MASK(KEY_CAMERA);
rc = input_register_device(pdev->button_dev);
if (rc) {
diff --git a/linux/drivers/media/video/pxa_camera.c b/linux/drivers/media/video/pxa_camera.c
index 35642c430..8964d60cd 100644
--- a/linux/drivers/media/video/pxa_camera.c
+++ b/linux/drivers/media/video/pxa_camera.c
@@ -175,13 +175,6 @@
CICR0_EOFM | CICR0_FOM)
/*
- * YUV422P picture size should be a multiple of 16, so the heuristic aligns
- * height, width on 4 byte boundaries to reach the 16 multiple for the size.
- */
-#define YUV422P_X_Y_ALIGN 4
-#define YUV422P_SIZE_ALIGN YUV422P_X_Y_ALIGN * YUV422P_X_Y_ALIGN
-
-/*
* Structures
*/
enum pxa_camera_active_dma {
@@ -1410,28 +1403,15 @@ static int pxa_camera_try_fmt(struct soc_camera_device *icd,
return -EINVAL;
}
- /* limit to pxa hardware capabilities */
- if (pix->height < 32)
- pix->height = 32;
- if (pix->height > 2048)
- pix->height = 2048;
- if (pix->width < 48)
- pix->width = 48;
- if (pix->width > 2048)
- pix->width = 2048;
- pix->width &= ~0x01;
-
/*
- * YUV422P planar format requires images size to be a 16 bytes
- * multiple. If not, zeros will be inserted between Y and U planes, and
- * U and V planes, and YUV422P standard would be violated.
+ * Limit to pxa hardware capabilities. YUV422P planar format requires
+ * images size to be a multiple of 16 bytes. If not, zeros will be
+ * inserted between Y and U planes, and U and V planes, which violates
+ * the YUV422P standard.
*/
- if (xlate->host_fmt->fourcc == V4L2_PIX_FMT_YUV422P) {
- if (!IS_ALIGNED(pix->width * pix->height, YUV422P_SIZE_ALIGN))
- pix->height = ALIGN(pix->height, YUV422P_X_Y_ALIGN);
- if (!IS_ALIGNED(pix->width * pix->height, YUV422P_SIZE_ALIGN))
- pix->width = ALIGN(pix->width, YUV422P_X_Y_ALIGN);
- }
+ v4l_bound_align_image(&pix->width, 48, 2048, 1,
+ &pix->height, 32, 2048, 0,
+ xlate->host_fmt->fourcc == V4L2_PIX_FMT_YUV422P ? 4 : 0);
pix->bytesperline = pix->width *
DIV_ROUND_UP(xlate->host_fmt->depth, 8);
@@ -1563,7 +1543,7 @@ static struct soc_camera_host_ops pxa_soc_camera_host_ops = {
.set_bus_param = pxa_camera_set_bus_param,
};
-static int pxa_camera_probe(struct platform_device *pdev)
+static int __devinit pxa_camera_probe(struct platform_device *pdev)
{
struct pxa_camera_dev *pcdev;
struct resource *res;
@@ -1738,11 +1718,11 @@ static struct platform_driver pxa_camera_driver = {
.name = PXA_CAM_DRV_NAME,
},
.probe = pxa_camera_probe,
- .remove = __exit_p(pxa_camera_remove),
+ .remove = __devexit_p(pxa_camera_remove),
};
-static int __devinit pxa_camera_init(void)
+static int __init pxa_camera_init(void)
{
return platform_driver_register(&pxa_camera_driver);
}
diff --git a/linux/drivers/media/video/s2255drv.c b/linux/drivers/media/video/s2255drv.c
index 8a939387a..203f6e3ff 100644
--- a/linux/drivers/media/video/s2255drv.c
+++ b/linux/drivers/media/video/s2255drv.c
@@ -110,6 +110,8 @@
#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) */
+/* SCALE_4CIFSI is the 2 fields interpolated into one */
+#define SCALE_4CIFSI 4 /* 640x480(NTSC) or 704x576(PAL) high quality */
#define COLOR_YUVPL 1 /* YUV planar */
#define COLOR_YUVPK 2 /* YUV packed */
@@ -239,6 +241,8 @@ struct s2255_dev {
struct s2255_mode mode[MAX_CHANNELS];
/* jpeg compression */
struct v4l2_jpegcompression jc[MAX_CHANNELS];
+ /* capture parameters (for high quality mode full size) */
+ struct v4l2_captureparm cap_parm[MAX_CHANNELS];
const struct s2255_fmt *cur_fmt[MAX_CHANNELS];
int cur_frame[MAX_CHANNELS];
int last_frame[MAX_CHANNELS];
@@ -1021,9 +1025,16 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
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
+ if (fh->height > norm_minh(fh->dev->vdev[fh->channel])) {
+ if (fh->dev->cap_parm[fh->channel].capturemode &
+ V4L2_MODE_HIGHQUALITY) {
+ fh->mode.scale = SCALE_4CIFSI;
+ dprintk(2, "scale 4CIFSI\n");
+ } else {
+ fh->mode.scale = SCALE_4CIFS;
+ dprintk(2, "scale 4CIFS\n");
+ }
+ } else
fh->mode.scale = SCALE_2CIFS;
} else {
@@ -1124,6 +1135,7 @@ static u32 get_transfer_size(struct s2255_mode *mode)
if (mode->format == FORMAT_NTSC) {
switch (mode->scale) {
case SCALE_4CIFS:
+ case SCALE_4CIFSI:
linesPerFrame = NUM_LINES_4CIFS_NTSC * 2;
pixelsPerLine = LINE_SZ_4CIFS_NTSC;
break;
@@ -1141,6 +1153,7 @@ static u32 get_transfer_size(struct s2255_mode *mode)
} else if (mode->format == FORMAT_PAL) {
switch (mode->scale) {
case SCALE_4CIFS:
+ case SCALE_4CIFSI:
linesPerFrame = NUM_LINES_4CIFS_PAL * 2;
pixelsPerLine = LINE_SZ_4CIFS_PAL;
break;
@@ -1496,6 +1509,33 @@ static int vidioc_s_jpegcomp(struct file *file, void *priv,
dprintk(2, "setting jpeg quality %d\n", jc->quality);
return 0;
}
+
+static int vidioc_g_parm(struct file *file, void *priv,
+ struct v4l2_streamparm *sp)
+{
+ struct s2255_fh *fh = priv;
+ struct s2255_dev *dev = fh->dev;
+ if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ sp->parm.capture.capturemode = dev->cap_parm[fh->channel].capturemode;
+ dprintk(2, "getting parm %d\n", sp->parm.capture.capturemode);
+ return 0;
+}
+
+static int vidioc_s_parm(struct file *file, void *priv,
+ struct v4l2_streamparm *sp)
+{
+ struct s2255_fh *fh = priv;
+ struct s2255_dev *dev = fh->dev;
+
+ if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ dev->cap_parm[fh->channel].capturemode = sp->parm.capture.capturemode;
+ dprintk(2, "setting param capture mode %d\n",
+ sp->parm.capture.capturemode);
+ return 0;
+}
static int s2255_open(struct file *file)
{
int minor = video_devdata(file)->minor;
@@ -1787,6 +1827,8 @@ static const struct v4l2_ioctl_ops s2255_ioctl_ops = {
#endif
.vidioc_s_jpegcomp = vidioc_s_jpegcomp,
.vidioc_g_jpegcomp = vidioc_g_jpegcomp,
+ .vidioc_s_parm = vidioc_s_parm,
+ .vidioc_g_parm = vidioc_g_parm,
};
static struct video_device template = {
diff --git a/linux/drivers/media/video/saa7134/Kconfig b/linux/drivers/media/video/saa7134/Kconfig
index 0ba68987b..5bcce092e 100644
--- a/linux/drivers/media/video/saa7134/Kconfig
+++ b/linux/drivers/media/video/saa7134/Kconfig
@@ -44,6 +44,7 @@ config VIDEO_SAA7134_DVB
select DVB_LNBP21 if !DVB_FE_CUSTOMISE
select DVB_ZL10353 if !DVB_FE_CUSTOMISE
select DVB_LGDT3305 if !DVB_FE_CUSTOMISE
+ select DVB_TDA10048 if !DVB_FE_CUSTOMISE
select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE
select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE
---help---
diff --git a/linux/drivers/media/video/saa7134/Makefile b/linux/drivers/media/video/saa7134/Makefile
index 3dbaa19a6..604158a8c 100644
--- a/linux/drivers/media/video/saa7134/Makefile
+++ b/linux/drivers/media/video/saa7134/Makefile
@@ -3,8 +3,7 @@ saa7134-objs := saa7134-cards.o saa7134-core.o saa7134-i2c.o \
saa7134-ts.o saa7134-tvaudio.o saa7134-vbi.o \
saa7134-video.o saa7134-input.o
-obj-$(CONFIG_VIDEO_SAA7134) += saa7134.o saa7134-empress.o \
- saa6752hs.o
+obj-$(CONFIG_VIDEO_SAA7134) += saa6752hs.o saa7134.o saa7134-empress.o
obj-$(CONFIG_VIDEO_SAA7134_ALSA) += saa7134-alsa.o
diff --git a/linux/drivers/media/video/saa7134/saa7134-cards.c b/linux/drivers/media/video/saa7134/saa7134-cards.c
index a4e3deac2..e2d98ff5c 100644
--- a/linux/drivers/media/video/saa7134/saa7134-cards.c
+++ b/linux/drivers/media/video/saa7134/saa7134-cards.c
@@ -3403,13 +3403,15 @@ struct saa7134_board saa7134_boards[] = {
},
},
[SAA7134_BOARD_HAUPPAUGE_HVR1110R3] = {
- .name = "Hauppauge WinTV-HVR1110r3",
+ .name = "Hauppauge WinTV-HVR1110r3 DVB-T/Hybrid",
.audio_clock = 0x00187de7,
.tuner_type = TUNER_PHILIPS_TDA8290,
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.tuner_config = 3,
+ .mpeg = SAA7134_MPEG_DVB,
+ .ts_type = SAA7134_MPEG_TS_SERIAL,
.gpiomask = 0x0800100, /* GPIO 21 is an INPUT */
.inputs = {{
.name = name_tv,
@@ -4495,6 +4497,7 @@ struct saa7134_board saa7134_boards[] = {
/* Igor Kuznetsov <igk@igk.ru> */
/* Andrey Melnikoff <temnota@kmv.ru> */
/* Beholder Intl. Ltd. Dmitry Belimov <d.belimov@gmail.com> */
+ /* Alexey Osipov <lion-simba@pridelands.ru> */
.name = "Beholder BeholdTV M6",
.audio_clock = 0x00187de7,
.tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
@@ -4569,6 +4572,7 @@ struct saa7134_board saa7134_boards[] = {
/* Igor Kuznetsov <igk@igk.ru> */
/* Andrey Melnikoff <temnota@kmv.ru> */
/* Beholder Intl. Ltd. Dmitry Belimov <d.belimov@gmail.com> */
+ /* Alexey Osipov <lion-simba@pridelands.ru> */
.name = "Beholder BeholdTV M6 Extra",
.audio_clock = 0x00187de7,
.tuner_type = TUNER_PHILIPS_FM1216ME_MK3, /* FIXME to MK5 */
@@ -6237,6 +6241,12 @@ struct pci_device_id saa7134_pci_tbl[] = {
}, {
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1461, /* Avermedia Technologies Inc */
+ .subdevice = 0xf736,
+ .driver_data = SAA7134_BOARD_AVERMEDIA_M103,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
.subvendor = 0x1043,
.subdevice = 0x4878, /* REV:1.02G */
.driver_data = SAA7134_BOARD_ASUSTeK_TIGER_3IN1,
diff --git a/linux/drivers/media/video/saa7134/saa7134-core.c b/linux/drivers/media/video/saa7134/saa7134-core.c
index 69a214417..da73430ad 100644
--- a/linux/drivers/media/video/saa7134/saa7134-core.c
+++ b/linux/drivers/media/video/saa7134/saa7134-core.c
@@ -380,6 +380,10 @@ void saa7134_buffer_next(struct saa7134_dev *dev,
dprintk("buffer_next %p\n",NULL);
saa7134_set_dmabits(dev);
del_timer(&q->timeout);
+
+ if (card_has_mpeg(dev))
+ if (dev->ts_started)
+ saa7134_ts_stop(dev);
}
}
@@ -465,6 +469,19 @@ int saa7134_set_dmabits(struct saa7134_dev *dev)
ctrl |= SAA7134_MAIN_CTRL_TE5;
irq |= SAA7134_IRQ1_INTE_RA2_1 |
SAA7134_IRQ1_INTE_RA2_0;
+
+ /* dma: setup channel 5 (= TS) */
+
+ saa_writeb(SAA7134_TS_DMA0, (dev->ts.nr_packets - 1) & 0xff);
+ saa_writeb(SAA7134_TS_DMA1,
+ ((dev->ts.nr_packets - 1) >> 8) & 0xff);
+ /* TSNOPIT=0, TSCOLAP=0 */
+ saa_writeb(SAA7134_TS_DMA2,
+ (((dev->ts.nr_packets - 1) >> 16) & 0x3f) | 0x00);
+ saa_writel(SAA7134_RS_PITCH(5), TS_PACKET_SIZE);
+ saa_writel(SAA7134_RS_CONTROL(5), SAA7134_RS_CONTROL_BURST_16 |
+ SAA7134_RS_CONTROL_ME |
+ (dev->ts.pt_ts.dma >> 12));
}
/* set task conditions + field handling */
@@ -836,7 +853,6 @@ static struct video_device *vdev_init(struct saa7134_dev *dev,
if (NULL == vfd)
return NULL;
*vfd = *template;
- vfd->minor = -1;
vfd->v4l2_dev = &dev->v4l2_dev;
vfd->release = video_device_release;
vfd->debug = video_debug;
diff --git a/linux/drivers/media/video/saa7134/saa7134-dvb.c b/linux/drivers/media/video/saa7134/saa7134-dvb.c
index 2e1344ecf..360fbdf19 100644
--- a/linux/drivers/media/video/saa7134/saa7134-dvb.c
+++ b/linux/drivers/media/video/saa7134/saa7134-dvb.c
@@ -48,6 +48,7 @@
#include "isl6405.h"
#include "lnbp21.h"
#include "tuner-simple.h"
+#include "tda10048.h"
#include "tda18271.h"
#include "lgdt3305.h"
#include "tda8290.h"
@@ -978,6 +979,18 @@ static struct lgdt3305_config hcw_lgdt3305_config = {
.vsb_if_khz = 3250,
};
+static struct tda10048_config hcw_tda10048_config = {
+ .demod_address = 0x10 >> 1,
+ .output_mode = TDA10048_SERIAL_OUTPUT,
+ .fwbulkwritelen = TDA10048_BULKWRITE_200,
+ .inversion = TDA10048_INVERSION_ON,
+ .dtv6_if_freq_khz = TDA10048_IF_3300,
+ .dtv7_if_freq_khz = TDA10048_IF_3500,
+ .dtv8_if_freq_khz = TDA10048_IF_4000,
+ .clk_freq_khz = TDA10048_CLK_16000,
+ .disable_gate_access = 1,
+};
+
static struct tda18271_std_map hauppauge_tda18271_std_map = {
.atsc_6 = { .if_freq = 3250, .agc_mode = 3, .std = 4,
.if_lvl = 1, .rfagc_top = 0x58, },
@@ -1106,6 +1119,19 @@ static int dvb_init(struct saa7134_dev *dev)
&tda827x_cfg_2) < 0)
goto dettach_frontend;
break;
+ case SAA7134_BOARD_HAUPPAUGE_HVR1110R3:
+ fe0->dvb.frontend = dvb_attach(tda10048_attach,
+ &hcw_tda10048_config,
+ &dev->i2c_adap);
+ if (fe0->dvb.frontend != NULL) {
+ dvb_attach(tda829x_attach, fe0->dvb.frontend,
+ &dev->i2c_adap, 0x4b,
+ &tda829x_no_probe);
+ dvb_attach(tda18271_attach, fe0->dvb.frontend,
+ 0x60, &dev->i2c_adap,
+ &hcw_tda18271_config);
+ }
+ break;
case SAA7134_BOARD_PHILIPS_TIGER:
if (configure_tda827x_fe(dev, &philips_tiger_config,
&tda827x_cfg_0) < 0)
diff --git a/linux/drivers/media/video/saa7134/saa7134-empress.c b/linux/drivers/media/video/saa7134/saa7134-empress.c
index dd22a5215..96334a20b 100644
--- a/linux/drivers/media/video/saa7134/saa7134-empress.c
+++ b/linux/drivers/media/video/saa7134/saa7134-empress.c
@@ -255,6 +255,16 @@ static int empress_s_fmt_vid_cap(struct file *file, void *priv,
return 0;
}
+static int empress_try_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct saa7134_dev *dev = file->private_data;
+
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
+ f->fmt.pix.sizeimage = TS_PACKET_SIZE * dev->ts.nr_packets;
+
+ return 0;
+}
static int empress_reqbufs(struct file *file, void *priv,
struct v4l2_requestbuffers *p)
@@ -450,6 +460,7 @@ static const struct v4l2_file_operations ts_fops =
static const struct v4l2_ioctl_ops ts_ioctl_ops = {
.vidioc_querycap = empress_querycap,
.vidioc_enum_fmt_vid_cap = empress_enum_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = empress_try_fmt_vid_cap,
.vidioc_s_fmt_vid_cap = empress_s_fmt_vid_cap,
.vidioc_g_fmt_vid_cap = empress_g_fmt_vid_cap,
.vidioc_reqbufs = empress_reqbufs,
diff --git a/linux/drivers/media/video/saa7134/saa7134-i2c.c b/linux/drivers/media/video/saa7134/saa7134-i2c.c
index 3eb60aabe..f6cf7c1be 100644
--- a/linux/drivers/media/video/saa7134/saa7134-i2c.c
+++ b/linux/drivers/media/video/saa7134/saa7134-i2c.c
@@ -264,7 +264,7 @@ static int saa7134_i2c_xfer(struct i2c_adapter *i2c_adap,
/* workaround for a saa7134 i2c bug
* needed to talk to the mt352 demux
* thanks to pinnacle for the hint */
- int quirk = 0xfd;
+ int quirk = 0xfe;
d1printk(" [%02x quirk]",quirk);
i2c_send_byte(dev,START,quirk);
i2c_recv_byte(dev);
@@ -326,33 +326,6 @@ static u32 functionality(struct i2c_adapter *adap)
return I2C_FUNC_SMBUS_EMUL;
}
-static int attach_inform(struct i2c_client *client)
-{
- struct saa7134_dev *dev = client->adapter->algo_data;
-
- d1printk( "%s i2c attach [addr=0x%x,client=%s]\n",
- client->driver->driver.name, client->addr, client->name);
-
- /* Am I an i2c remote control? */
-
- switch (client->addr) {
- case 0x7a:
- case 0x47:
- case 0x71:
- case 0x2d:
- case 0x30:
- {
- struct IR_i2c *ir = i2c_get_clientdata(client);
- d1printk("%s i2c IR detected (%s).\n",
- client->driver->driver.name, ir->phys);
- saa7134_set_i2c_ir(dev,ir);
- break;
- }
- }
-
- return 0;
-}
-
static struct i2c_algorithm saa7134_algo = {
.master_xfer = saa7134_i2c_xfer,
.functionality = functionality,
@@ -369,7 +342,6 @@ static struct i2c_adapter saa7134_adap_template = {
.name = "saa7134",
.id = I2C_HW_SAA7134,
.algo = &saa7134_algo,
- .client_register = attach_inform,
};
static struct i2c_client saa7134_client_template = {
@@ -444,6 +416,11 @@ int saa7134_i2c_register(struct saa7134_dev *dev)
saa7134_i2c_eeprom(dev,dev->eedata,sizeof(dev->eedata));
if (i2c_scan)
do_i2c_scan(dev->name,&dev->i2c_client);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
+
+ /* Instantiate the IR receiver device, if present */
+ saa7134_probe_i2c_ir(dev);
+#endif
return 0;
}
diff --git a/linux/drivers/media/video/saa7134/saa7134-input.c b/linux/drivers/media/video/saa7134/saa7134-input.c
index 80a4cc23d..b54bfd645 100644
--- a/linux/drivers/media/video/saa7134/saa7134-input.c
+++ b/linux/drivers/media/video/saa7134/saa7134-input.c
@@ -59,8 +59,13 @@ MODULE_PARM_DESC(disable_other_ir, "disable full codes of "
#define dprintk(fmt, arg...) if (ir_debug) \
printk(KERN_DEBUG "%s/ir: " fmt, dev->name , ## arg)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
#define i2cdprintk(fmt, arg...) if (ir_debug) \
printk(KERN_DEBUG "%s/ir: " fmt, ir->c.name , ## arg)
+#else
+#define i2cdprintk(fmt, arg...) if (ir_debug) \
+ printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg)
+#endif
/* Helper functions for RC5 and NEC decoding at GPIO16 or GPIO18 */
static int saa7134_rc5_irq(struct saa7134_dev *dev);
@@ -134,10 +139,18 @@ static int get_key_msi_tvanywhere_plus(struct IR_i2c *ir, u32 *ir_key,
int gpio;
/* <dev> is needed to access GPIO. Used by the saa_readl macro. */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
struct saa7134_dev *dev = ir->c.adapter->algo_data;
+#else
+ struct saa7134_dev *dev = ir->c->adapter->algo_data;
+#endif
if (dev == NULL) {
dprintk("get_key_msi_tvanywhere_plus: "
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
"gir->c.adapter->algo_data is NULL!\n");
+#else
+ "gir->c->adapter->algo_data is NULL!\n");
+#endif
return -EIO;
}
@@ -156,7 +169,11 @@ static int get_key_msi_tvanywhere_plus(struct IR_i2c *ir, u32 *ir_key,
/* GPIO says there is a button press. Get it. */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
if (1 != i2c_master_recv(&ir->c, &b, 1)) {
+#else
+ if (1 != i2c_master_recv(ir->c, &b, 1)) {
+#endif
i2cdprintk("read error\n");
return -EIO;
}
@@ -179,7 +196,11 @@ static int get_key_purpletv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
unsigned char b;
/* poll IR chip */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
if (1 != i2c_master_recv(&ir->c,&b,1)) {
+#else
+ if (1 != i2c_master_recv(ir->c, &b, 1)) {
+#endif
i2cdprintk("read error\n");
return -EIO;
}
@@ -202,7 +223,11 @@ static int get_key_hvr1110(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
unsigned char buf[5], cod4, code3, code4;
/* poll IR chip */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
if (5 != i2c_master_recv(&ir->c,buf,5))
+#else
+ if (5 != i2c_master_recv(ir->c, buf, 5))
+#endif
return -EIO;
cod4 = buf[4];
@@ -224,7 +249,11 @@ static int get_key_beholdm6xx(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
unsigned char data[12];
u32 gpio;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
struct saa7134_dev *dev = ir->c.adapter->algo_data;
+#else
+ struct saa7134_dev *dev = ir->c->adapter->algo_data;
+#endif
/* rising SAA7134_GPIO_GPRESCAN reads the status */
saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
@@ -235,9 +264,17 @@ static int get_key_beholdm6xx(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
if (0x400000 & ~gpio)
return 0; /* No button press */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
ir->c.addr = 0x5a >> 1;
+#else
+ ir->c->addr = 0x5a >> 1;
+#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
if (12 != i2c_master_recv(&ir->c, data, 12)) {
+#else
+ if (12 != i2c_master_recv(ir->c, data, 12)) {
+#endif
i2cdprintk("read error\n");
return -EIO;
}
@@ -267,7 +304,11 @@ static int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw,
unsigned int start = 0,parity = 0,code = 0;
/* poll IR chip */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
if (4 != i2c_master_recv(&ir->c, b, 4)) {
+#else
+ if (4 != i2c_master_recv(ir->c, b, 4)) {
+#endif
i2cdprintk("read error\n");
return -EIO;
}
@@ -686,40 +727,113 @@ void saa7134_input_fini(struct saa7134_dev *dev)
dev->remote = NULL;
}
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir)
+#else
+void saa7134_probe_i2c_ir(struct saa7134_dev *dev)
+#endif
{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
+ struct i2c_board_info info;
+ struct IR_i2c_init_data init_data;
+ const unsigned short addr_list[] = {
+ 0x7a, 0x47, 0x71, 0x2d,
+ I2C_CLIENT_END
+ };
+
+ struct i2c_msg msg_msi = {
+ .addr = 0x50,
+ .flags = I2C_M_RD,
+ .len = 0,
+ .buf = NULL,
+ };
+
+ int rc;
+
+#endif
if (disable_ir) {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
dprintk("Found supported i2c remote, but IR has been disabled\n");
ir->get_key=NULL;
+#else
+ dprintk("IR has been disabled, not probing for i2c remote\n");
+#endif
return;
}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ memset(&init_data, 0, sizeof(struct IR_i2c_init_data));
+ strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
+
+#endif
switch (dev->board) {
case SAA7134_BOARD_PINNACLE_PCTV_110i:
case SAA7134_BOARD_PINNACLE_PCTV_310i:
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
snprintf(ir->c.name, sizeof(ir->c.name), "Pinnacle PCTV");
+#else
+ init_data.name = "Pinnacle PCTV";
+#endif
if (pinnacle_remote == 0) {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
ir->get_key = get_key_pinnacle_color;
ir->ir_codes = ir_codes_pinnacle_color;
+#else
+ init_data.get_key = get_key_pinnacle_color;
+ init_data.ir_codes = ir_codes_pinnacle_color;
+#endif
} else {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
ir->get_key = get_key_pinnacle_grey;
ir->ir_codes = ir_codes_pinnacle_grey;
+#else
+ init_data.get_key = get_key_pinnacle_grey;
+ init_data.ir_codes = ir_codes_pinnacle_grey;
+#endif
}
break;
case SAA7134_BOARD_UPMOST_PURPLE_TV:
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
snprintf(ir->c.name, sizeof(ir->c.name), "Purple TV");
ir->get_key = get_key_purpletv;
ir->ir_codes = ir_codes_purpletv;
+#else
+ init_data.name = "Purple TV";
+ init_data.get_key = get_key_purpletv;
+ init_data.ir_codes = ir_codes_purpletv;
+#endif
break;
case SAA7134_BOARD_MSI_TVATANYWHERE_PLUS:
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
snprintf(ir->c.name, sizeof(ir->c.name), "MSI TV@nywhere Plus");
ir->get_key = get_key_msi_tvanywhere_plus;
ir->ir_codes = ir_codes_msi_tvanywhere_plus;
+#else
+ init_data.name = "MSI TV@nywhere Plus";
+ init_data.get_key = get_key_msi_tvanywhere_plus;
+ init_data.ir_codes = ir_codes_msi_tvanywhere_plus;
+ info.addr = 0x30;
+ /* MSI TV@nywhere Plus controller doesn't seem to
+ respond to probes unless we read something from
+ an existing device. Weird...
+ REVISIT: might no longer be needed */
+ rc = i2c_transfer(&dev->i2c_adap, &msg_msi, 1);
+ dprintk(KERN_DEBUG "probe 0x%02x @ %s: %s\n",
+ msg_msi.addr, dev->i2c_adap.name,
+ (1 == rc) ? "yes" : "no");
+#endif
break;
case SAA7134_BOARD_HAUPPAUGE_HVR1110:
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
snprintf(ir->c.name, sizeof(ir->c.name), "HVR 1110");
ir->get_key = get_key_hvr1110;
ir->ir_codes = ir_codes_hauppauge_new;
+#else
+ init_data.name = "HVR 1110";
+ init_data.get_key = get_key_hvr1110;
+ init_data.ir_codes = ir_codes_hauppauge_new;
+#endif
break;
case SAA7134_BOARD_BEHOLD_607FM_MK3:
case SAA7134_BOARD_BEHOLD_607FM_MK5:
@@ -733,15 +847,39 @@ void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir)
case SAA7134_BOARD_BEHOLD_M63:
case SAA7134_BOARD_BEHOLD_M6_EXTRA:
case SAA7134_BOARD_BEHOLD_H6:
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
snprintf(ir->c.name, sizeof(ir->c.name), "BeholdTV");
ir->get_key = get_key_beholdm6xx;
ir->ir_codes = ir_codes_behold;
+#else
+ init_data.name = "BeholdTV";
+ init_data.get_key = get_key_beholdm6xx;
+ init_data.ir_codes = ir_codes_behold;
+#endif
break;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
default:
dprintk("Shouldn't get here: Unknown board %x for I2C IR?\n",dev->board);
+#else
+ case SAA7134_BOARD_AVERMEDIA_CARDBUS_501:
+ case SAA7134_BOARD_AVERMEDIA_CARDBUS_506:
+ info.addr = 0x40;
+#endif
break;
}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
+ if (init_data.name)
+ info.platform_data = &init_data;
+ /* No need to probe if address is known */
+ if (info.addr) {
+ i2c_new_device(&dev->i2c_adap, &info);
+ return;
+ }
+
+ /* Address not known, fallback to probing */
+ i2c_new_probed_device(&dev->i2c_adap, &info, addr_list);
+#endif
}
static int saa7134_rc5_irq(struct saa7134_dev *dev)
diff --git a/linux/drivers/media/video/saa7134/saa7134-ts.c b/linux/drivers/media/video/saa7134/saa7134-ts.c
index b8ff459d0..3fa652279 100644
--- a/linux/drivers/media/video/saa7134/saa7134-ts.c
+++ b/linux/drivers/media/video/saa7134/saa7134-ts.c
@@ -67,33 +67,8 @@ static int buffer_activate(struct saa7134_dev *dev,
mod_timer(&dev->ts_q.timeout, jiffies+TS_BUFFER_TIMEOUT);
- if (dev->ts_state == SAA7134_TS_BUFF_DONE) {
- /* Clear TS cache */
- dev->buff_cnt = 0;
- saa_writeb(SAA7134_TS_SERIAL1, 0x00);
- saa_writeb(SAA7134_TS_SERIAL1, 0x03);
- saa_writeb(SAA7134_TS_SERIAL1, 0x00);
- saa_writeb(SAA7134_TS_SERIAL1, 0x01);
-
- /* TS clock non-inverted */
- saa_writeb(SAA7134_TS_SERIAL1, 0x00);
-
- /* Start TS stream */
- switch (saa7134_boards[dev->board].ts_type) {
- case SAA7134_MPEG_TS_PARALLEL:
- saa_writeb(SAA7134_TS_SERIAL0, 0x40);
- saa_writeb(SAA7134_TS_PARALLEL, 0xec);
- break;
- case SAA7134_MPEG_TS_SERIAL:
- saa_writeb(SAA7134_TS_SERIAL0, 0xd8);
- saa_writeb(SAA7134_TS_PARALLEL, 0x6c);
- saa_writeb(SAA7134_TS_PARALLEL_SERIAL, 0xbc);
- saa_writeb(SAA7134_TS_SERIAL1, 0x02);
- break;
- }
-
- dev->ts_state = SAA7134_TS_STARTED;
- }
+ if (!dev->ts_started)
+ saa7134_ts_start(dev);
return 0;
}
@@ -104,7 +79,6 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
struct saa7134_dev *dev = q->priv_data;
struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
unsigned int lines, llength, size;
- u32 control;
int err;
dprintk("buffer_prepare [%p,%s]\n",buf,v4l2_field_names[field]);
@@ -121,8 +95,11 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
}
if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+
struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
+ dprintk("buffer_prepare: needs_init\n");
+
buf->vb.width = llength;
buf->vb.height = lines;
buf->vb.size = size;
@@ -139,23 +116,6 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
goto oops;
}
- dev->buff_cnt++;
-
- if (dev->buff_cnt == dev->ts.nr_bufs) {
- dev->ts_state = SAA7134_TS_BUFF_DONE;
- /* dma: setup channel 5 (= TS) */
- control = SAA7134_RS_CONTROL_BURST_16 |
- SAA7134_RS_CONTROL_ME |
- (buf->pt->dma >> 12);
-
- saa_writeb(SAA7134_TS_DMA0, (lines - 1) & 0xff);
- saa_writeb(SAA7134_TS_DMA1, ((lines - 1) >> 8) & 0xff);
- /* TSNOPIT=0, TSCOLAP=0 */
- saa_writeb(SAA7134_TS_DMA2, (((lines - 1) >> 16) & 0x3f) | 0x00);
- saa_writel(SAA7134_RS_PITCH(5), TS_PACKET_SIZE);
- saa_writel(SAA7134_RS_CONTROL(5), control);
- }
-
buf->vb.state = VIDEOBUF_PREPARED;
buf->activate = buffer_activate;
buf->vb.field = field;
@@ -175,8 +135,7 @@ buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
if (0 == *count)
*count = dev->ts.nr_bufs;
*count = saa7134_buffer_count(*size,*count);
- dev->buff_cnt = 0;
- dev->ts_state = SAA7134_TS_STOPPED;
+
return 0;
}
@@ -193,11 +152,9 @@ static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
struct saa7134_dev *dev = q->priv_data;
- if (dev->ts_state == SAA7134_TS_STARTED) {
- /* Stop TS transport */
- saa_writeb(SAA7134_TS_PARALLEL, 0x6c);
- dev->ts_state = SAA7134_TS_STOPPED;
- }
+ if (dev->ts_started)
+ saa7134_ts_stop(dev);
+
saa7134_dma_free(q,buf);
}
@@ -214,7 +171,7 @@ EXPORT_SYMBOL_GPL(saa7134_ts_qops);
static unsigned int tsbufs = 8;
module_param(tsbufs, int, 0444);
-MODULE_PARM_DESC(tsbufs,"number of ts buffers, range 2-32");
+MODULE_PARM_DESC(tsbufs, "number of ts buffers for read/write IO, range 2-32");
static unsigned int ts_nr_packets = 64;
module_param(ts_nr_packets, int, 0444);
@@ -256,6 +213,7 @@ int saa7134_ts_init1(struct saa7134_dev *dev)
dev->ts_q.timeout.data = (unsigned long)(&dev->ts_q);
dev->ts_q.dev = dev;
dev->ts_q.need_two = 1;
+ dev->ts_started = 0;
saa7134_pgtable_alloc(dev->pci,&dev->ts.pt_ts);
/* init TS hw */
@@ -264,13 +222,67 @@ int saa7134_ts_init1(struct saa7134_dev *dev)
return 0;
}
+/* Function for stop TS */
+int saa7134_ts_stop(struct saa7134_dev *dev)
+{
+ dprintk("TS stop\n");
+
+ BUG_ON(!dev->ts_started);
+
+ /* Stop TS stream */
+ switch (saa7134_boards[dev->board].ts_type) {
+ case SAA7134_MPEG_TS_PARALLEL:
+ saa_writeb(SAA7134_TS_PARALLEL, 0x6c);
+ dev->ts_started = 0;
+ break;
+ case SAA7134_MPEG_TS_SERIAL:
+ saa_writeb(SAA7134_TS_SERIAL0, 0x40);
+ dev->ts_started = 0;
+ break;
+ }
+ return 0;
+}
+
+/* Function for start TS */
+int saa7134_ts_start(struct saa7134_dev *dev)
+{
+ dprintk("TS start\n");
+
+ BUG_ON(dev->ts_started);
+
+ saa_writeb(SAA7134_TS_SERIAL1, 0x00);
+ saa_writeb(SAA7134_TS_SERIAL1, 0x03);
+ saa_writeb(SAA7134_TS_SERIAL1, 0x00);
+ saa_writeb(SAA7134_TS_SERIAL1, 0x01);
+
+ /* TS clock non-inverted */
+ saa_writeb(SAA7134_TS_SERIAL1, 0x00);
+
+ /* Start TS stream */
+ switch (saa7134_boards[dev->board].ts_type) {
+ case SAA7134_MPEG_TS_PARALLEL:
+ saa_writeb(SAA7134_TS_SERIAL0, 0x40);
+ saa_writeb(SAA7134_TS_PARALLEL, 0xec);
+ break;
+ case SAA7134_MPEG_TS_SERIAL:
+ saa_writeb(SAA7134_TS_SERIAL0, 0xd8);
+ saa_writeb(SAA7134_TS_PARALLEL, 0x6c);
+ saa_writeb(SAA7134_TS_PARALLEL_SERIAL, 0xbc);
+ saa_writeb(SAA7134_TS_SERIAL1, 0x02);
+ break;
+ }
+
+ dev->ts_started = 1;
+
+ return 0;
+}
+
int saa7134_ts_fini(struct saa7134_dev *dev)
{
saa7134_pgtable_free(dev->pci,&dev->ts.pt_ts);
return 0;
}
-
void saa7134_irq_ts_done(struct saa7134_dev *dev, unsigned long status)
{
enum v4l2_field field;
diff --git a/linux/drivers/media/video/saa7134/saa7134-video.c b/linux/drivers/media/video/saa7134/saa7134-video.c
index 5f68bed54..4212c4ec8 100644
--- a/linux/drivers/media/video/saa7134/saa7134-video.c
+++ b/linux/drivers/media/video/saa7134/saa7134-video.c
@@ -1057,6 +1057,7 @@ static int buffer_prepare(struct videobuf_queue *q,
buf->vb.field = field;
buf->fmt = fh->fmt;
buf->pt = &fh->pt_cap;
+ dev->video_q.curr = NULL;
err = videobuf_iolock(q,&buf->vb,&dev->ovbuf);
if (err)
@@ -1423,11 +1424,13 @@ video_poll(struct file *file, struct poll_table_struct *wait)
{
struct saa7134_fh *fh = file->private_data;
struct videobuf_buffer *buf = NULL;
+ unsigned int rc = 0;
if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type)
return videobuf_poll_stream(file, &fh->vbi, wait);
if (res_check(fh,RESOURCE_VIDEO)) {
+ mutex_lock(&fh->cap.vb_lock);
if (!list_empty(&fh->cap.stream))
buf = list_entry(fh->cap.stream.next, struct videobuf_buffer, stream);
} else {
@@ -1446,13 +1449,14 @@ video_poll(struct file *file, struct poll_table_struct *wait)
}
if (!buf)
- return POLLERR;
+ goto err;
poll_wait(file, &buf->done, wait);
if (buf->state == VIDEOBUF_DONE ||
buf->state == VIDEOBUF_ERROR)
- return POLLIN|POLLRDNORM;
- return 0;
+ rc = POLLIN|POLLRDNORM;
+ mutex_unlock(&fh->cap.vb_lock);
+ return rc;
err:
mutex_unlock(&fh->cap.vb_lock);
@@ -1643,15 +1647,8 @@ static int saa7134_try_fmt_vid_cap(struct file *file, void *priv,
}
f->fmt.pix.field = field;
- if (f->fmt.pix.width < 48)
- f->fmt.pix.width = 48;
- if (f->fmt.pix.height < 32)
- f->fmt.pix.height = 32;
- if (f->fmt.pix.width > maxw)
- f->fmt.pix.width = maxw;
- if (f->fmt.pix.height > maxh)
- f->fmt.pix.height = maxh;
- f->fmt.pix.width &= ~0x03;
+ v4l_bound_align_image(&f->fmt.pix.width, 48, maxw, 2,
+ &f->fmt.pix.height, 32, maxh, 0, 0);
f->fmt.pix.bytesperline =
(f->fmt.pix.width * fmt->depth) >> 3;
f->fmt.pix.sizeimage =
diff --git a/linux/drivers/media/video/saa7134/saa7134.h b/linux/drivers/media/video/saa7134/saa7134.h
index ae7ba8923..454802e73 100644
--- a/linux/drivers/media/video/saa7134/saa7134.h
+++ b/linux/drivers/media/video/saa7134/saa7134.h
@@ -498,12 +498,6 @@ struct saa7134_mpeg_ops {
void (*signal_change)(struct saa7134_dev *dev);
};
-enum saa7134_ts_status {
- SAA7134_TS_STOPPED,
- SAA7134_TS_BUFF_DONE,
- SAA7134_TS_STARTED,
-};
-
/* global device status */
struct saa7134_dev {
struct list_head devlist;
@@ -598,8 +592,7 @@ struct saa7134_dev {
/* SAA7134_MPEG_* */
struct saa7134_ts ts;
struct saa7134_dmaqueue ts_q;
- enum saa7134_ts_status ts_state;
- unsigned int buff_cnt;
+ int ts_started;
struct saa7134_mpeg_ops *mops;
/* SAA7134_MPEG_EMPRESS only */
@@ -757,6 +750,9 @@ void saa7134_ts_unregister(struct saa7134_mpeg_ops *ops);
int saa7134_ts_init_hw(struct saa7134_dev *dev);
+int saa7134_ts_start(struct saa7134_dev *dev);
+int saa7134_ts_stop(struct saa7134_dev *dev);
+
/* ----------------------------------------------------------- */
/* saa7134-vbi.c */
@@ -804,7 +800,11 @@ void saa7134_irq_oss_done(struct saa7134_dev *dev, unsigned long status);
int saa7134_input_init1(struct saa7134_dev *dev);
void saa7134_input_fini(struct saa7134_dev *dev);
void saa7134_input_irq(struct saa7134_dev *dev);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir);
+#else
+void saa7134_probe_i2c_ir(struct saa7134_dev *dev);
+#endif
void saa7134_ir_start(struct saa7134_dev *dev, struct card_ir *ir);
void saa7134_ir_stop(struct saa7134_dev *dev);
diff --git a/linux/drivers/media/video/se401.c b/linux/drivers/media/video/se401.c
index cca1cb0c4..1274a5966 100644
--- a/linux/drivers/media/video/se401.c
+++ b/linux/drivers/media/video/se401.c
@@ -38,7 +38,7 @@ static const char version[] = "0.24";
static int flickerless;
static int video_nr = -1;
-static struct usb_device_id device_table [] = {
+static struct usb_device_id device_table[] = {
{ USB_DEVICE(0x03e8, 0x0004) },/* Endpoints/Aox SE401 */
{ USB_DEVICE(0x0471, 0x030b) },/* Philips PCVC665K */
{ USB_DEVICE(0x047d, 0x5001) },/* Kensington 67014 */
@@ -53,7 +53,8 @@ MODULE_AUTHOR("Jeroen Vreeken <pe1rxq@amsat.org>");
MODULE_DESCRIPTION("SE401 USB Camera Driver");
MODULE_LICENSE("GPL");
module_param(flickerless, int, 0);
-MODULE_PARM_DESC(flickerless, "Net frequency to adjust exposure time to (0/50/60)");
+MODULE_PARM_DESC(flickerless,
+ "Net frequency to adjust exposure time to (0/50/60)");
module_param(video_nr, int, 0);
static struct usb_driver se401_driver;
@@ -78,8 +79,8 @@ static void *rvmalloc(unsigned long size)
adr = (unsigned long) mem;
while (size > 0) {
SetPageReserved(vmalloc_to_page((void *)adr));
- adr += PAGE_SIZE;
- size -= PAGE_SIZE;
+ adr += PAGE_SIZE;
+ size -= PAGE_SIZE;
}
return mem;
@@ -95,8 +96,8 @@ static void rvfree(void *mem, unsigned long size)
adr = (unsigned long) mem;
while ((long) size > 0) {
ClearPageReserved(vmalloc_to_page((void *)adr));
- adr += PAGE_SIZE;
- size -= PAGE_SIZE;
+ adr += PAGE_SIZE;
+ size -= PAGE_SIZE;
}
vfree(mem);
}
@@ -112,7 +113,7 @@ static void rvfree(void *mem, unsigned long size)
static int se401_sndctrl(int set, struct usb_se401 *se401, unsigned short req,
unsigned short value, unsigned char *cp, int size)
{
- return usb_control_msg (
+ return usb_control_msg(
se401->dev,
set ? usb_sndctrlpipe(se401->dev, 0) : usb_rcvctrlpipe(se401->dev, 0),
req,
@@ -132,7 +133,7 @@ static int se401_set_feature(struct usb_se401 *se401, unsigned short selector,
and the param in index, but in the logs of the windows driver they do
this the other way around...
*/
- return usb_control_msg (
+ return usb_control_msg(
se401->dev,
usb_sndctrlpipe(se401->dev, 0),
SE401_REQ_SET_EXT_FEATURE,
@@ -152,7 +153,7 @@ static unsigned short se401_get_feature(struct usb_se401 *se401,
wrong here to....
*/
unsigned char cp[2];
- usb_control_msg (
+ usb_control_msg(
se401->dev,
usb_rcvctrlpipe(se401->dev, 0),
SE401_REQ_GET_EXT_FEATURE,
@@ -175,46 +176,51 @@ static unsigned short se401_get_feature(struct usb_se401 *se401,
static int se401_send_pict(struct usb_se401 *se401)
{
- se401_set_feature(se401, HV7131_REG_TITL, se401->expose_l);/* integration time low */
- se401_set_feature(se401, HV7131_REG_TITM, se401->expose_m);/* integration time mid */
- se401_set_feature(se401, HV7131_REG_TITU, se401->expose_h);/* integration time mid */
- se401_set_feature(se401, HV7131_REG_ARLV, se401->resetlevel);/* reset level value */
- se401_set_feature(se401, HV7131_REG_ARCG, se401->rgain);/* red color gain */
- se401_set_feature(se401, HV7131_REG_AGCG, se401->ggain);/* green color gain */
- se401_set_feature(se401, HV7131_REG_ABCG, se401->bgain);/* blue color gain */
+ /* integration time low */
+ se401_set_feature(se401, HV7131_REG_TITL, se401->expose_l);
+ /* integration time mid */
+ se401_set_feature(se401, HV7131_REG_TITM, se401->expose_m);
+ /* integration time mid */
+ se401_set_feature(se401, HV7131_REG_TITU, se401->expose_h);
+ /* reset level value */
+ se401_set_feature(se401, HV7131_REG_ARLV, se401->resetlevel);
+ /* red color gain */
+ se401_set_feature(se401, HV7131_REG_ARCG, se401->rgain);
+ /* green color gain */
+ se401_set_feature(se401, HV7131_REG_AGCG, se401->ggain);
+ /* blue color gain */
+ se401_set_feature(se401, HV7131_REG_ABCG, se401->bgain);
return 0;
}
static void se401_set_exposure(struct usb_se401 *se401, int brightness)
{
- int integration=brightness<<5;
-
- if (flickerless==50) {
- integration=integration-integration%106667;
- }
- if (flickerless==60) {
- integration=integration-integration%88889;
- }
- se401->brightness=integration>>5;
- se401->expose_h=(integration>>16)&0xff;
- se401->expose_m=(integration>>8)&0xff;
- se401->expose_l=integration&0xff;
+ int integration = brightness << 5;
+
+ if (flickerless == 50)
+ integration = integration-integration % 106667;
+ if (flickerless == 60)
+ integration = integration-integration % 88889;
+ se401->brightness = integration >> 5;
+ se401->expose_h = (integration >> 16) & 0xff;
+ se401->expose_m = (integration >> 8) & 0xff;
+ se401->expose_l = integration & 0xff;
}
static int se401_get_pict(struct usb_se401 *se401, struct video_picture *p)
{
- p->brightness=se401->brightness;
- if (se401->enhance) {
- p->whiteness=32768;
- } else {
- p->whiteness=0;
- }
- p->colour=65535;
- p->contrast=65535;
- p->hue=se401->rgain<<10;
- p->palette=se401->palette;
- p->depth=3; /* rgb24 */
+ p->brightness = se401->brightness;
+ if (se401->enhance)
+ p->whiteness = 32768;
+ else
+ p->whiteness = 0;
+
+ p->colour = 65535;
+ p->contrast = 65535;
+ p->hue = se401->rgain << 10;
+ p->palette = se401->palette;
+ p->depth = 3; /* rgb24 */
return 0;
}
@@ -223,20 +229,19 @@ static int se401_set_pict(struct usb_se401 *se401, struct video_picture *p)
{
if (p->palette != VIDEO_PALETTE_RGB24)
return 1;
- se401->palette=p->palette;
- if (p->hue!=se401->hue) {
- se401->rgain= p->hue>>10;
- se401->bgain= 0x40-(p->hue>>10);
- se401->hue=p->hue;
+ se401->palette = p->palette;
+ if (p->hue != se401->hue) {
+ se401->rgain = p->hue >> 10;
+ se401->bgain = 0x40-(p->hue >> 10);
+ se401->hue = p->hue;
}
- if (p->brightness!=se401->brightness) {
+ if (p->brightness != se401->brightness)
se401_set_exposure(se401, p->brightness);
- }
- if (p->whiteness>=32768) {
- se401->enhance=1;
- } else {
- se401->enhance=0;
- }
+
+ if (p->whiteness >= 32768)
+ se401->enhance = 1;
+ else
+ se401->enhance = 0;
se401_send_pict(se401);
se401_send_pict(se401);
return 0;
@@ -249,7 +254,7 @@ static int se401_set_pict(struct usb_se401 *se401, struct video_picture *p)
static void se401_auto_resetlevel(struct usb_se401 *se401)
{
unsigned int ahrc, alrc;
- int oldreset=se401->resetlevel;
+ int oldreset = se401->resetlevel;
/* For some reason this normally read-only register doesn't get reset
to zero after reading them just once...
@@ -258,24 +263,24 @@ static void se401_auto_resetlevel(struct usb_se401 *se401)
se401_get_feature(se401, HV7131_REG_HIREFNOL);
se401_get_feature(se401, HV7131_REG_LOREFNOH);
se401_get_feature(se401, HV7131_REG_LOREFNOL);
- ahrc=256*se401_get_feature(se401, HV7131_REG_HIREFNOH) +
+ ahrc = 256*se401_get_feature(se401, HV7131_REG_HIREFNOH) +
se401_get_feature(se401, HV7131_REG_HIREFNOL);
- alrc=256*se401_get_feature(se401, HV7131_REG_LOREFNOH) +
+ alrc = 256*se401_get_feature(se401, HV7131_REG_LOREFNOH) +
se401_get_feature(se401, HV7131_REG_LOREFNOL);
/* Not an exact science, but it seems to work pretty well... */
if (alrc > 10) {
- while (alrc>=10 && se401->resetlevel < 63) {
+ while (alrc >= 10 && se401->resetlevel < 63) {
se401->resetlevel++;
- alrc /=2;
+ alrc /= 2;
}
} else if (ahrc > 20) {
- while (ahrc>=20 && se401->resetlevel > 0) {
+ while (ahrc >= 20 && se401->resetlevel > 0) {
se401->resetlevel--;
- ahrc /=2;
+ ahrc /= 2;
}
}
- if (se401->resetlevel!=oldreset)
+ if (se401->resetlevel != oldreset)
se401_set_feature(se401, HV7131_REG_ARLV, se401->resetlevel);
return;
@@ -304,21 +309,22 @@ static void se401_button_irq(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __func__, urb->status);
+ dbg("%s - urb shutting down with status: %d",
+ __func__, urb->status);
return;
default:
- dbg("%s - nonzero urb status received: %d", __func__, urb->status);
+ dbg("%s - nonzero urb status received: %d",
+ __func__, urb->status);
goto exit;
}
- if (urb->actual_length >=2) {
+ if (urb->actual_length >= 2)
if (se401->button)
- se401->buttonpressed=1;
- }
+ se401->buttonpressed = 1;
exit:
- status = usb_submit_urb (urb, GFP_ATOMIC);
+ status = usb_submit_urb(urb, GFP_ATOMIC);
if (status)
- err ("%s - usb_submit_urb failed with result %d",
+ err("%s - usb_submit_urb failed with result %d",
__func__, status);
}
@@ -344,55 +350,52 @@ static void se401_video_irq(struct urb *urb)
keeps sending them forever...
*/
if (length && !urb->status) {
- se401->nullpackets=0;
- switch(se401->scratch[se401->scratch_next].state) {
- case BUFFER_READY:
- case BUFFER_BUSY: {
- se401->dropped++;
- break;
- }
- case BUFFER_UNUSED: {
- memcpy(se401->scratch[se401->scratch_next].data, (unsigned char *)urb->transfer_buffer, length);
- se401->scratch[se401->scratch_next].state=BUFFER_READY;
- se401->scratch[se401->scratch_next].offset=se401->bayeroffset;
- se401->scratch[se401->scratch_next].length=length;
- if (waitqueue_active(&se401->wq)) {
- wake_up_interruptible(&se401->wq);
- }
- se401->scratch_overflow=0;
- se401->scratch_next++;
- if (se401->scratch_next>=SE401_NUMSCRATCH)
- se401->scratch_next=0;
- break;
- }
- }
- se401->bayeroffset+=length;
- if (se401->bayeroffset>=se401->cheight*se401->cwidth) {
- se401->bayeroffset=0;
+ se401->nullpackets = 0;
+ switch (se401->scratch[se401->scratch_next].state) {
+ case BUFFER_READY:
+ case BUFFER_BUSY:
+ se401->dropped++;
+ break;
+ case BUFFER_UNUSED:
+ memcpy(se401->scratch[se401->scratch_next].data,
+ (unsigned char *)urb->transfer_buffer, length);
+ se401->scratch[se401->scratch_next].state
+ = BUFFER_READY;
+ se401->scratch[se401->scratch_next].offset
+ = se401->bayeroffset;
+ se401->scratch[se401->scratch_next].length = length;
+ if (waitqueue_active(&se401->wq))
+ wake_up_interruptible(&se401->wq);
+ se401->scratch_overflow = 0;
+ se401->scratch_next++;
+ if (se401->scratch_next >= SE401_NUMSCRATCH)
+ se401->scratch_next = 0;
+ break;
}
+ se401->bayeroffset += length;
+ if (se401->bayeroffset >= se401->cheight * se401->cwidth)
+ se401->bayeroffset = 0;
} else {
se401->nullpackets++;
- if (se401->nullpackets > SE401_MAX_NULLPACKETS) {
- if (waitqueue_active(&se401->wq)) {
+ if (se401->nullpackets > SE401_MAX_NULLPACKETS)
+ if (waitqueue_active(&se401->wq))
wake_up_interruptible(&se401->wq);
- }
- }
}
/* Resubmit urb for new data */
- urb->status=0;
- urb->dev=se401->dev;
- if(usb_submit_urb(urb, GFP_KERNEL))
+ urb->status = 0;
+ urb->dev = se401->dev;
+ if (usb_submit_urb(urb, GFP_KERNEL))
dev_info(&urb->dev->dev, "urb burned down\n");
return;
}
static void se401_send_size(struct usb_se401 *se401, int width, int height)
{
- int i=0;
- int mode=0x03; /* No compression */
- int sendheight=height;
- int sendwidth=width;
+ int i = 0;
+ int mode = 0x03; /* No compression */
+ int sendheight = height;
+ int sendwidth = width;
/* JangGu compression can only be used with the camera supported sizes,
but bayer seems to work with any size that fits on the sensor.
@@ -400,18 +403,21 @@ static void se401_send_size(struct usb_se401 *se401, int width, int height)
4 or 16 times subcapturing, if not we use uncompressed bayer data
but this will result in cutouts of the maximum size....
*/
- while (i<se401->sizes && !(se401->width[i]==width && se401->height[i]==height))
+ while (i < se401->sizes && !(se401->width[i] == width &&
+ se401->height[i] == height))
i++;
- while (i<se401->sizes) {
- if (se401->width[i]==width*2 && se401->height[i]==height*2) {
- sendheight=se401->height[i];
- sendwidth=se401->width[i];
- mode=0x40;
+ while (i < se401->sizes) {
+ if (se401->width[i] == width * 2 &&
+ se401->height[i] == height * 2) {
+ sendheight = se401->height[i];
+ sendwidth = se401->width[i];
+ mode = 0x40;
}
- if (se401->width[i]==width*4 && se401->height[i]==height*4) {
- sendheight=se401->height[i];
- sendwidth=se401->width[i];
- mode=0x42;
+ if (se401->width[i] == width * 4 &&
+ se401->height[i] == height * 4) {
+ sendheight = se401->height[i];
+ sendwidth = se401->width[i];
+ mode = 0x42;
}
i++;
}
@@ -420,13 +426,10 @@ static void se401_send_size(struct usb_se401 *se401, int width, int height)
se401_sndctrl(1, se401, SE401_REQ_SET_HEIGHT, sendheight, NULL, 0);
se401_set_feature(se401, SE401_OPERATINGMODE, mode);
- if (mode==0x03) {
- se401->format=FMT_BAYER;
- } else {
- se401->format=FMT_JANGGU;
- }
-
- return;
+ if (mode == 0x03)
+ se401->format = FMT_BAYER;
+ else
+ se401->format = FMT_JANGGU;
}
/*
@@ -437,29 +440,31 @@ static void se401_send_size(struct usb_se401 *se401, int width, int height)
static int se401_start_stream(struct usb_se401 *se401)
{
struct urb *urb;
- int err=0, i;
- se401->streaming=1;
+ int err = 0, i;
+ se401->streaming = 1;
se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 1, NULL, 0);
se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 1, NULL, 0);
/* Set picture settings */
- se401_set_feature(se401, HV7131_REG_MODE_B, 0x05);/*windowed + pix intg */
+ /* windowed + pix intg */
+ se401_set_feature(se401, HV7131_REG_MODE_B, 0x05);
se401_send_pict(se401);
se401_send_size(se401, se401->cwidth, se401->cheight);
- se401_sndctrl(1, se401, SE401_REQ_START_CONTINUOUS_CAPTURE, 0, NULL, 0);
+ se401_sndctrl(1, se401, SE401_REQ_START_CONTINUOUS_CAPTURE,
+ 0, NULL, 0);
/* Do some memory allocation */
- for (i=0; i<SE401_NUMFRAMES; i++) {
- se401->frame[i].data=se401->fbuf + i * se401->maxframesize;
- se401->frame[i].curpix=0;
+ for (i = 0; i < SE401_NUMFRAMES; i++) {
+ se401->frame[i].data = se401->fbuf + i * se401->maxframesize;
+ se401->frame[i].curpix = 0;
}
- for (i=0; i<SE401_NUMSBUF; i++) {
- se401->sbuf[i].data=kmalloc(SE401_PACKETSIZE, GFP_KERNEL);
+ for (i = 0; i < SE401_NUMSBUF; i++) {
+ se401->sbuf[i].data = kmalloc(SE401_PACKETSIZE, GFP_KERNEL);
if (!se401->sbuf[i].data) {
- for(i = i - 1; i >= 0; i--) {
+ for (i = i - 1; i >= 0; i--) {
kfree(se401->sbuf[i].data);
se401->sbuf[i].data = NULL;
}
@@ -467,26 +472,26 @@ static int se401_start_stream(struct usb_se401 *se401)
}
}
- se401->bayeroffset=0;
- se401->scratch_next=0;
- se401->scratch_use=0;
- se401->scratch_overflow=0;
- for (i=0; i<SE401_NUMSCRATCH; i++) {
- se401->scratch[i].data=kmalloc(SE401_PACKETSIZE, GFP_KERNEL);
+ se401->bayeroffset = 0;
+ se401->scratch_next = 0;
+ se401->scratch_use = 0;
+ se401->scratch_overflow = 0;
+ for (i = 0; i < SE401_NUMSCRATCH; i++) {
+ se401->scratch[i].data = kmalloc(SE401_PACKETSIZE, GFP_KERNEL);
if (!se401->scratch[i].data) {
- for(i = i - 1; i >= 0; i--) {
+ for (i = i - 1; i >= 0; i--) {
kfree(se401->scratch[i].data);
se401->scratch[i].data = NULL;
}
goto nomem_sbuf;
}
- se401->scratch[i].state=BUFFER_UNUSED;
+ se401->scratch[i].state = BUFFER_UNUSED;
}
- for (i=0; i<SE401_NUMSBUF; i++) {
- urb=usb_alloc_urb(0, GFP_KERNEL);
- if(!urb) {
- for(i = i - 1; i >= 0; i--) {
+ for (i = 0; i < SE401_NUMSBUF; i++) {
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb) {
+ for (i = i - 1; i >= 0; i--) {
usb_kill_urb(se401->urb[i]);
usb_free_urb(se401->urb[i]);
se401->urb[i] = NULL;
@@ -500,24 +505,24 @@ static int se401_start_stream(struct usb_se401 *se401)
se401_video_irq,
se401);
- se401->urb[i]=urb;
+ se401->urb[i] = urb;
- err=usb_submit_urb(se401->urb[i], GFP_KERNEL);
- if(err)
+ err = usb_submit_urb(se401->urb[i], GFP_KERNEL);
+ if (err)
err("urb burned down");
}
- se401->framecount=0;
+ se401->framecount = 0;
return 0;
nomem_scratch:
- for (i=0; i<SE401_NUMSCRATCH; i++) {
+ for (i = 0; i < SE401_NUMSCRATCH; i++) {
kfree(se401->scratch[i].data);
se401->scratch[i].data = NULL;
}
nomem_sbuf:
- for (i=0; i<SE401_NUMSBUF; i++) {
+ for (i = 0; i < SE401_NUMSBUF; i++) {
kfree(se401->sbuf[i].data);
se401->sbuf[i].data = NULL;
}
@@ -531,22 +536,23 @@ static int se401_stop_stream(struct usb_se401 *se401)
if (!se401->streaming || !se401->dev)
return 1;
- se401->streaming=0;
+ se401->streaming = 0;
se401_sndctrl(1, se401, SE401_REQ_STOP_CONTINUOUS_CAPTURE, 0, NULL, 0);
se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 0, NULL, 0);
se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 0, NULL, 0);
- for (i=0; i<SE401_NUMSBUF; i++) if (se401->urb[i]) {
- usb_kill_urb(se401->urb[i]);
- usb_free_urb(se401->urb[i]);
- se401->urb[i]=NULL;
- kfree(se401->sbuf[i].data);
- }
- for (i=0; i<SE401_NUMSCRATCH; i++) {
+ for (i = 0; i < SE401_NUMSBUF; i++)
+ if (se401->urb[i]) {
+ usb_kill_urb(se401->urb[i]);
+ usb_free_urb(se401->urb[i]);
+ se401->urb[i] = NULL;
+ kfree(se401->sbuf[i].data);
+ }
+ for (i = 0; i < SE401_NUMSCRATCH; i++) {
kfree(se401->scratch[i].data);
- se401->scratch[i].data=NULL;
+ se401->scratch[i].data = NULL;
}
return 0;
@@ -554,9 +560,9 @@ static int se401_stop_stream(struct usb_se401 *se401)
static int se401_set_size(struct usb_se401 *se401, int width, int height)
{
- int wasstreaming=se401->streaming;
+ int wasstreaming = se401->streaming;
/* Check to see if we need to change */
- if (se401->cwidth==width && se401->cheight==height)
+ if (se401->cwidth == width && se401->cheight == height)
return 0;
/* Check for a valid mode */
@@ -564,16 +570,16 @@ static int se401_set_size(struct usb_se401 *se401, int width, int height)
return 1;
if ((width & 1) || (height & 1))
return 1;
- if (width>se401->width[se401->sizes-1])
+ if (width > se401->width[se401->sizes-1])
return 1;
- if (height>se401->height[se401->sizes-1])
+ if (height > se401->height[se401->sizes-1])
return 1;
/* Stop a current stream and start it again at the new size */
if (wasstreaming)
se401_stop_stream(se401);
- se401->cwidth=width;
- se401->cheight=height;
+ se401->cwidth = width;
+ se401->cheight = height;
if (wasstreaming)
se401_start_stream(se401);
return 0;
@@ -594,68 +600,68 @@ static int se401_set_size(struct usb_se401 *se401, int width, int height)
static inline void enhance_picture(unsigned char *frame, int len)
{
while (len--) {
- *frame=(((*frame^255)*(*frame^255))/255)^255;
+ *frame = (((*frame^255)*(*frame^255))/255)^255;
frame++;
}
}
static inline void decode_JangGu_integrate(struct usb_se401 *se401, int data)
{
- struct se401_frame *frame=&se401->frame[se401->curframe];
- int linelength=se401->cwidth*3;
+ struct se401_frame *frame = &se401->frame[se401->curframe];
+ int linelength = se401->cwidth * 3;
if (frame->curlinepix >= linelength) {
- frame->curlinepix=0;
- frame->curline+=linelength;
+ frame->curlinepix = 0;
+ frame->curline += linelength;
}
/* First three are absolute, all others relative.
* Format is rgb from right to left (mirrorred image),
* we flip it to get bgr from left to right. */
- if (frame->curlinepix < 3) {
- *(frame->curline-frame->curlinepix)=1+data*4;
- } else {
- *(frame->curline-frame->curlinepix)=
- *(frame->curline-frame->curlinepix+3)+data*4;
- }
+ if (frame->curlinepix < 3)
+ *(frame->curline-frame->curlinepix) = 1 + data * 4;
+ else
+ *(frame->curline-frame->curlinepix) =
+ *(frame->curline-frame->curlinepix + 3) + data * 4;
frame->curlinepix++;
}
-static inline void decode_JangGu_vlc (struct usb_se401 *se401, unsigned char *data, int bit_exp, int packetlength)
+static inline void decode_JangGu_vlc(struct usb_se401 *se401,
+ unsigned char *data, int bit_exp, int packetlength)
{
- int pos=0;
- int vlc_cod=0;
- int vlc_size=0;
- int vlc_data=0;
+ int pos = 0;
+ int vlc_cod = 0;
+ int vlc_size = 0;
+ int vlc_data = 0;
int bit_cur;
int bit;
- data+=4;
+ data += 4;
while (pos < packetlength) {
- bit_cur=8;
+ bit_cur = 8;
while (bit_cur && bit_exp) {
- bit=((*data)>>(bit_cur-1))&1;
+ bit = ((*data) >> (bit_cur-1))&1;
if (!vlc_cod) {
if (bit) {
vlc_size++;
} else {
- if (!vlc_size) {
+ if (!vlc_size)
decode_JangGu_integrate(se401, 0);
- } else {
- vlc_cod=2;
- vlc_data=0;
+ else {
+ vlc_cod = 2;
+ vlc_data = 0;
}
}
} else {
- if (vlc_cod==2) {
+ if (vlc_cod == 2) {
if (!bit)
- vlc_data = -(1<<vlc_size) + 1;
+ vlc_data = -(1 << vlc_size) + 1;
vlc_cod--;
}
vlc_size--;
- vlc_data+=bit<<vlc_size;
+ vlc_data += bit << vlc_size;
if (!vlc_size) {
decode_JangGu_integrate(se401, vlc_data);
- vlc_cod=0;
+ vlc_cod = 0;
}
}
bit_cur--;
@@ -666,186 +672,188 @@ static inline void decode_JangGu_vlc (struct usb_se401 *se401, unsigned char *da
}
}
-static inline void decode_JangGu (struct usb_se401 *se401, struct se401_scratch *buffer)
+static inline void decode_JangGu(struct usb_se401 *se401,
+ struct se401_scratch *buffer)
{
- unsigned char *data=buffer->data;
- int len=buffer->length;
- int bit_exp=0, pix_exp=0, frameinfo=0, packetlength=0, size;
- int datapos=0;
+ unsigned char *data = buffer->data;
+ int len = buffer->length;
+ int bit_exp = 0, pix_exp = 0, frameinfo = 0, packetlength = 0, size;
+ int datapos = 0;
/* New image? */
if (!se401->frame[se401->curframe].curpix) {
- se401->frame[se401->curframe].curlinepix=0;
- se401->frame[se401->curframe].curline=
+ se401->frame[se401->curframe].curlinepix = 0;
+ se401->frame[se401->curframe].curline =
se401->frame[se401->curframe].data+
- se401->cwidth*3-1;
- if (se401->frame[se401->curframe].grabstate==FRAME_READY)
- se401->frame[se401->curframe].grabstate=FRAME_GRABBING;
- se401->vlcdatapos=0;
+ se401->cwidth * 3 - 1;
+ if (se401->frame[se401->curframe].grabstate == FRAME_READY)
+ se401->frame[se401->curframe].grabstate = FRAME_GRABBING;
+ se401->vlcdatapos = 0;
}
while (datapos < len) {
- size=1024-se401->vlcdatapos;
+ size = 1024 - se401->vlcdatapos;
if (size+datapos > len)
- size=len-datapos;
+ size = len-datapos;
memcpy(se401->vlcdata+se401->vlcdatapos, data+datapos, size);
- se401->vlcdatapos+=size;
- packetlength=0;
+ se401->vlcdatapos += size;
+ packetlength = 0;
if (se401->vlcdatapos >= 4) {
- bit_exp=se401->vlcdata[3]+(se401->vlcdata[2]<<8);
- pix_exp=se401->vlcdata[1]+((se401->vlcdata[0]&0x3f)<<8);
- frameinfo=se401->vlcdata[0]&0xc0;
- packetlength=((bit_exp+47)>>4)<<1;
+ bit_exp = se401->vlcdata[3] + (se401->vlcdata[2] << 8);
+ pix_exp = se401->vlcdata[1] +
+ ((se401->vlcdata[0] & 0x3f) << 8);
+ frameinfo = se401->vlcdata[0] & 0xc0;
+ packetlength = ((bit_exp + 47) >> 4) << 1;
if (packetlength > 1024) {
- se401->vlcdatapos=0;
- datapos=len;
- packetlength=0;
+ se401->vlcdatapos = 0;
+ datapos = len;
+ packetlength = 0;
se401->error++;
- se401->frame[se401->curframe].curpix=0;
+ se401->frame[se401->curframe].curpix = 0;
}
}
if (packetlength && se401->vlcdatapos >= packetlength) {
- decode_JangGu_vlc(se401, se401->vlcdata, bit_exp, packetlength);
- se401->frame[se401->curframe].curpix+=pix_exp*3;
- datapos+=size-(se401->vlcdatapos-packetlength);
- se401->vlcdatapos=0;
- if (se401->frame[se401->curframe].curpix>=se401->cwidth*se401->cheight*3) {
- if (se401->frame[se401->curframe].curpix==se401->cwidth*se401->cheight*3) {
- if (se401->frame[se401->curframe].grabstate==FRAME_GRABBING) {
- se401->frame[se401->curframe].grabstate=FRAME_DONE;
+ decode_JangGu_vlc(se401, se401->vlcdata, bit_exp,
+ packetlength);
+ se401->frame[se401->curframe].curpix += pix_exp * 3;
+ datapos += size-(se401->vlcdatapos-packetlength);
+ se401->vlcdatapos = 0;
+ if (se401->frame[se401->curframe].curpix >= se401->cwidth * se401->cheight * 3) {
+ if (se401->frame[se401->curframe].curpix == se401->cwidth * se401->cheight * 3) {
+ if (se401->frame[se401->curframe].grabstate == FRAME_GRABBING) {
+ se401->frame[se401->curframe].grabstate = FRAME_DONE;
se401->framecount++;
se401->readcount++;
}
- if (se401->frame[(se401->curframe+1)&(SE401_NUMFRAMES-1)].grabstate==FRAME_READY) {
- se401->curframe=(se401->curframe+1) & (SE401_NUMFRAMES-1);
- }
- } else {
+ if (se401->frame[(se401->curframe + 1) & (SE401_NUMFRAMES - 1)].grabstate == FRAME_READY)
+ se401->curframe = (se401->curframe + 1) & (SE401_NUMFRAMES - 1);
+ } else
se401->error++;
- }
- se401->frame[se401->curframe].curpix=0;
- datapos=len;
+ se401->frame[se401->curframe].curpix = 0;
+ datapos = len;
}
- } else {
- datapos+=size;
- }
+ } else
+ datapos += size;
}
}
-static inline void decode_bayer (struct usb_se401 *se401, struct se401_scratch *buffer)
+static inline void decode_bayer(struct usb_se401 *se401,
+ struct se401_scratch *buffer)
{
- unsigned char *data=buffer->data;
- int len=buffer->length;
- int offset=buffer->offset;
- int datasize=se401->cwidth*se401->cheight;
- struct se401_frame *frame=&se401->frame[se401->curframe];
+ unsigned char *data = buffer->data;
+ int len = buffer->length;
+ int offset = buffer->offset;
+ int datasize = se401->cwidth * se401->cheight;
+ struct se401_frame *frame = &se401->frame[se401->curframe];
+ unsigned char *framedata = frame->data, *curline, *nextline;
+ int width = se401->cwidth;
+ int blineoffset = 0, bline;
+ int linelength = width * 3, i;
- unsigned char *framedata=frame->data, *curline, *nextline;
- int width=se401->cwidth;
- int blineoffset=0, bline;
- int linelength=width*3, i;
+ if (frame->curpix == 0) {
+ if (frame->grabstate == FRAME_READY)
+ frame->grabstate = FRAME_GRABBING;
- if (frame->curpix==0) {
- if (frame->grabstate==FRAME_READY) {
- frame->grabstate=FRAME_GRABBING;
- }
- frame->curline=framedata+linelength;
- frame->curlinepix=0;
+ frame->curline = framedata + linelength;
+ frame->curlinepix = 0;
}
- if (offset!=frame->curpix) {
+ if (offset != frame->curpix) {
/* Regard frame as lost :( */
- frame->curpix=0;
+ frame->curpix = 0;
se401->error++;
return;
}
/* Check if we have to much data */
- if (frame->curpix+len > datasize) {
- len=datasize-frame->curpix;
- }
- if (se401->cheight%4)
- blineoffset=1;
- bline=frame->curpix/se401->cwidth+blineoffset;
-
- curline=frame->curline;
- nextline=curline+linelength;
- if (nextline >= framedata+datasize*3)
- nextline=curline;
+ if (frame->curpix + len > datasize)
+ len = datasize-frame->curpix;
+
+ if (se401->cheight % 4)
+ blineoffset = 1;
+ bline = frame->curpix / se401->cwidth+blineoffset;
+
+ curline = frame->curline;
+ nextline = curline + linelength;
+ if (nextline >= framedata+datasize * 3)
+ nextline = curline;
while (len) {
- if (frame->curlinepix>=width) {
- frame->curlinepix-=width;
- bline=frame->curpix/width+blineoffset;
- curline+=linelength*2;
- nextline+=linelength*2;
- if (curline >= framedata+datasize*3) {
+ if (frame->curlinepix >= width) {
+ frame->curlinepix -= width;
+ bline = frame->curpix / width + blineoffset;
+ curline += linelength*2;
+ nextline += linelength*2;
+ if (curline >= framedata+datasize * 3) {
frame->curlinepix++;
- curline-=3;
- nextline-=3;
+ curline -= 3;
+ nextline -= 3;
len--;
data++;
frame->curpix++;
}
if (nextline >= framedata+datasize*3)
- nextline=curline;
+ nextline = curline;
}
- if ((bline&1)) {
- if ((frame->curlinepix&1)) {
- *(curline+2)=*data;
- *(curline-1)=*data;
- *(nextline+2)=*data;
- *(nextline-1)=*data;
+ if (bline & 1) {
+ if (frame->curlinepix & 1) {
+ *(curline + 2) = *data;
+ *(curline - 1) = *data;
+ *(nextline + 2) = *data;
+ *(nextline - 1) = *data;
} else {
- *(curline+1)=
- (*(curline+1)+*data)/2;
- *(curline-2)=
- (*(curline-2)+*data)/2;
- *(nextline+1)=*data;
- *(nextline-2)=*data;
+ *(curline + 1) =
+ (*(curline + 1) + *data) / 2;
+ *(curline-2) =
+ (*(curline - 2) + *data) / 2;
+ *(nextline + 1) = *data;
+ *(nextline - 2) = *data;
}
} else {
- if ((frame->curlinepix&1)) {
- *(curline+1)=
- (*(curline+1)+*data)/2;
- *(curline-2)=
- (*(curline-2)+*data)/2;
- *(nextline+1)=*data;
- *(nextline-2)=*data;
+ if (frame->curlinepix & 1) {
+ *(curline + 1) =
+ (*(curline + 1) + *data) / 2;
+ *(curline - 2) =
+ (*(curline - 2) + *data) / 2;
+ *(nextline + 1) = *data;
+ *(nextline - 2) = *data;
} else {
- *curline=*data;
- *(curline-3)=*data;
- *nextline=*data;
- *(nextline-3)=*data;
+ *curline = *data;
+ *(curline - 3) = *data;
+ *nextline = *data;
+ *(nextline - 3) = *data;
}
}
frame->curlinepix++;
- curline-=3;
- nextline-=3;
+ curline -= 3;
+ nextline -= 3;
len--;
data++;
frame->curpix++;
}
- frame->curline=curline;
+ frame->curline = curline;
- if (frame->curpix>=datasize) {
+ if (frame->curpix >= datasize) {
/* Fix the top line */
- framedata+=linelength;
- for (i=0; i<linelength; i++) {
+ framedata += linelength;
+ for (i = 0; i < linelength; i++) {
framedata--;
- *framedata=*(framedata+linelength);
+ *framedata = *(framedata + linelength);
}
/* Fix the left side (green is already present) */
- for (i=0; i<se401->cheight; i++) {
- *framedata=*(framedata+3);
- *(framedata+1)=*(framedata+4);
- *(framedata+2)=*(framedata+5);
- framedata+=linelength;
+ for (i = 0; i < se401->cheight; i++) {
+ *framedata = *(framedata + 3);
+ *(framedata + 1) = *(framedata + 4);
+ *(framedata + 2) = *(framedata + 5);
+ framedata += linelength;
}
- frame->curpix=0;
- frame->grabstate=FRAME_DONE;
+ frame->curpix = 0;
+ frame->grabstate = FRAME_DONE;
se401->framecount++;
se401->readcount++;
- if (se401->frame[(se401->curframe+1)&(SE401_NUMFRAMES-1)].grabstate==FRAME_READY) {
- se401->curframe=(se401->curframe+1) & (SE401_NUMFRAMES-1);
+ if (se401->frame[(se401->curframe + 1) &
+ (SE401_NUMFRAMES - 1)].grabstate == FRAME_READY) {
+ se401->curframe = (se401->curframe+1) &
+ (SE401_NUMFRAMES-1);
}
}
}
@@ -853,72 +861,76 @@ static inline void decode_bayer (struct usb_se401 *se401, struct se401_scratch *
static int se401_newframe(struct usb_se401 *se401, int framenr)
{
DECLARE_WAITQUEUE(wait, current);
- int errors=0;
+ int errors = 0;
while (se401->streaming &&
- (se401->frame[framenr].grabstate==FRAME_READY ||
- se401->frame[framenr].grabstate==FRAME_GRABBING) ) {
- if(!se401->frame[framenr].curpix) {
+ (se401->frame[framenr].grabstate == FRAME_READY ||
+ se401->frame[framenr].grabstate == FRAME_GRABBING)) {
+ if (!se401->frame[framenr].curpix)
errors++;
- }
+
wait_interruptible(
- se401->scratch[se401->scratch_use].state!=BUFFER_READY,
- &se401->wq,
- &wait
- );
+ se401->scratch[se401->scratch_use].state != BUFFER_READY,
+ &se401->wq, &wait);
if (se401->nullpackets > SE401_MAX_NULLPACKETS) {
- se401->nullpackets=0;
+ se401->nullpackets = 0;
dev_info(&se401->dev->dev,
- "too many null length packets, restarting capture\n");
+ "too many null length packets, restarting capture\n");
se401_stop_stream(se401);
se401_start_stream(se401);
} else {
- if (se401->scratch[se401->scratch_use].state!=BUFFER_READY) {
- se401->frame[framenr].grabstate=FRAME_ERROR;
+ if (se401->scratch[se401->scratch_use].state !=
+ BUFFER_READY) {
+ se401->frame[framenr].grabstate = FRAME_ERROR;
return -EIO;
}
- se401->scratch[se401->scratch_use].state=BUFFER_BUSY;
- if (se401->format==FMT_JANGGU) {
- decode_JangGu(se401, &se401->scratch[se401->scratch_use]);
- } else {
- decode_bayer(se401, &se401->scratch[se401->scratch_use]);
- }
- se401->scratch[se401->scratch_use].state=BUFFER_UNUSED;
+ se401->scratch[se401->scratch_use].state = BUFFER_BUSY;
+ if (se401->format == FMT_JANGGU)
+ decode_JangGu(se401,
+ &se401->scratch[se401->scratch_use]);
+ else
+ decode_bayer(se401,
+ &se401->scratch[se401->scratch_use]);
+
+ se401->scratch[se401->scratch_use].state =
+ BUFFER_UNUSED;
se401->scratch_use++;
- if (se401->scratch_use>=SE401_NUMSCRATCH)
- se401->scratch_use=0;
+ if (se401->scratch_use >= SE401_NUMSCRATCH)
+ se401->scratch_use = 0;
if (errors > SE401_MAX_ERRORS) {
- errors=0;
+ errors = 0;
dev_info(&se401->dev->dev,
- "too many errors, restarting capture\n");
+ "too many errors, restarting capture\n");
se401_stop_stream(se401);
se401_start_stream(se401);
}
}
}
- if (se401->frame[framenr].grabstate==FRAME_DONE)
+ if (se401->frame[framenr].grabstate == FRAME_DONE)
if (se401->enhance)
- enhance_picture(se401->frame[framenr].data, se401->cheight*se401->cwidth*3);
+ enhance_picture(se401->frame[framenr].data,
+ se401->cheight * se401->cwidth * 3);
return 0;
}
-static void usb_se401_remove_disconnected (struct usb_se401 *se401)
+static void usb_se401_remove_disconnected(struct usb_se401 *se401)
{
int i;
se401->dev = NULL;
- for (i=0; i<SE401_NUMSBUF; i++)
+ for (i = 0; i < SE401_NUMSBUF; i++)
if (se401->urb[i]) {
usb_kill_urb(se401->urb[i]);
usb_free_urb(se401->urb[i]);
se401->urb[i] = NULL;
kfree(se401->sbuf[i].data);
}
- for (i=0; i<SE401_NUMSCRATCH; i++) {
+
+ for (i = 0; i < SE401_NUMSCRATCH; i++)
kfree(se401->scratch[i].data);
- }
+
if (se401->inturb) {
usb_kill_urb(se401->inturb);
usb_free_urb(se401->inturb);
@@ -973,11 +985,11 @@ static int se401_close(struct file *file)
dev_info(&se401->dev->dev, "device unregistered\n");
usb_se401_remove_disconnected(se401);
} else {
- for (i=0; i<SE401_NUMFRAMES; i++)
- se401->frame[i].grabstate=FRAME_UNUSED;
+ for (i = 0; i < SE401_NUMFRAMES; i++)
+ se401->frame[i].grabstate = FRAME_UNUSED;
if (se401->streaming)
se401_stop_stream(se401);
- se401->user=0;
+ se401->user = 0;
}
file->private_data = NULL;
return 0;
@@ -1073,7 +1085,7 @@ static long se401_do_ioctl(struct file *file, unsigned int cmd, void *arg)
memset(vm, 0, sizeof(*vm));
vm->size = SE401_NUMFRAMES * se401->maxframesize;
vm->frames = SE401_NUMFRAMES;
- for (i=0; i<SE401_NUMFRAMES; i++)
+ for (i = 0; i < SE401_NUMFRAMES; i++)
vm->offsets[i] = se401->maxframesize * i;
return 0;
}
@@ -1091,16 +1103,16 @@ static long se401_do_ioctl(struct file *file, unsigned int cmd, void *arg)
/* Is this according to the v4l spec??? */
if (se401_set_size(se401, vm->width, vm->height))
return -EINVAL;
- se401->frame[vm->frame].grabstate=FRAME_READY;
+ se401->frame[vm->frame].grabstate = FRAME_READY;
if (!se401->streaming)
se401_start_stream(se401);
/* Set the picture properties */
- if (se401->framecount==0)
+ if (se401->framecount == 0)
se401_send_pict(se401);
/* Calibrate the reset level after a few frames. */
- if (se401->framecount%20==1)
+ if (se401->framecount % 20 == 1)
se401_auto_resetlevel(se401);
return 0;
@@ -1108,13 +1120,13 @@ static long se401_do_ioctl(struct file *file, unsigned int cmd, void *arg)
case VIDIOCSYNC:
{
int *frame = arg;
- int ret=0;
+ int ret = 0;
- if(*frame <0 || *frame >= SE401_NUMFRAMES)
+ if (*frame < 0 || *frame >= SE401_NUMFRAMES)
return -EINVAL;
- ret=se401_newframe(se401, *frame);
- se401->frame[*frame].grabstate=FRAME_UNUSED;
+ ret = se401_newframe(se401, *frame);
+ se401->frame[*frame].grabstate = FRAME_UNUSED;
return ret;
}
case VIDIOCGFBUF:
@@ -1155,36 +1167,36 @@ static long se401_ioctl(struct file *file,
static ssize_t se401_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
- int realcount=count, ret=0;
+ int realcount = count, ret = 0;
struct video_device *dev = file->private_data;
struct usb_se401 *se401 = (struct usb_se401 *)dev;
- if (se401->dev == NULL)
+ if (se401->dev == NULL)
return -EIO;
if (realcount > se401->cwidth*se401->cheight*3)
- realcount=se401->cwidth*se401->cheight*3;
+ realcount = se401->cwidth*se401->cheight*3;
/* Shouldn't happen: */
- if (se401->frame[0].grabstate==FRAME_GRABBING)
+ if (se401->frame[0].grabstate == FRAME_GRABBING)
return -EBUSY;
- se401->frame[0].grabstate=FRAME_READY;
- se401->frame[1].grabstate=FRAME_UNUSED;
- se401->curframe=0;
+ se401->frame[0].grabstate = FRAME_READY;
+ se401->frame[1].grabstate = FRAME_UNUSED;
+ se401->curframe = 0;
if (!se401->streaming)
se401_start_stream(se401);
/* Set the picture properties */
- if (se401->framecount==0)
+ if (se401->framecount == 0)
se401_send_pict(se401);
/* Calibrate the reset level after a few frames. */
- if (se401->framecount%20==1)
+ if (se401->framecount%20 == 1)
se401_auto_resetlevel(se401);
- ret=se401_newframe(se401, 0);
+ ret = se401_newframe(se401, 0);
- se401->frame[0].grabstate=FRAME_UNUSED;
+ se401->frame[0].grabstate = FRAME_UNUSED;
if (ret)
return ret;
if (copy_to_user(buf, se401->frame[0].data, realcount))
@@ -1203,11 +1215,12 @@ static int se401_mmap(struct file *file, struct vm_area_struct *vma)
mutex_lock(&se401->lock);
- if (se401->dev == NULL) {
+ if (se401->dev == NULL) {
mutex_unlock(&se401->lock);
return -EIO;
}
- if (size > (((SE401_NUMFRAMES * se401->maxframesize) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) {
+ if (size > (((SE401_NUMFRAMES * se401->maxframesize) + PAGE_SIZE - 1)
+ & ~(PAGE_SIZE - 1))) {
mutex_unlock(&se401->lock);
return -EINVAL;
}
@@ -1218,10 +1231,10 @@ static int se401_mmap(struct file *file, struct vm_area_struct *vma)
mutex_unlock(&se401->lock);
return -EAGAIN;
}
- start += PAGE_SIZE;
- pos += PAGE_SIZE;
+ start += PAGE_SIZE;
+ pos += PAGE_SIZE;
if (size > PAGE_SIZE)
- size -= PAGE_SIZE;
+ size -= PAGE_SIZE;
else
size = 0;
}
@@ -1231,7 +1244,7 @@ static int se401_mmap(struct file *file, struct vm_area_struct *vma)
}
static const struct v4l2_file_operations se401_fops = {
- .owner = THIS_MODULE,
+ .owner = THIS_MODULE,
.open = se401_open,
.release = se401_close,
.read = se401_read,
@@ -1249,71 +1262,76 @@ static struct video_device se401_template = {
/***************************/
static int se401_init(struct usb_se401 *se401, int button)
{
- int i=0, rc;
+ int i = 0, rc;
unsigned char cp[0x40];
char temp[200];
+ int slen;
/* led on */
se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 1, NULL, 0);
/* get camera descriptor */
- rc=se401_sndctrl(0, se401, SE401_REQ_GET_CAMERA_DESCRIPTOR, 0, cp, sizeof(cp));
- if (cp[1]!=0x41) {
+ rc = se401_sndctrl(0, se401, SE401_REQ_GET_CAMERA_DESCRIPTOR, 0,
+ cp, sizeof(cp));
+ if (cp[1] != 0x41) {
err("Wrong descriptor type");
return 1;
}
- sprintf (temp, "ExtraFeatures: %d", cp[3]);
+ slen = snprintf(temp, 200, "ExtraFeatures: %d", cp[3]);
- se401->sizes=cp[4]+cp[5]*256;
- se401->width=kmalloc(se401->sizes*sizeof(int), GFP_KERNEL);
+ se401->sizes = cp[4] + cp[5] * 256;
+ se401->width = kmalloc(se401->sizes*sizeof(int), GFP_KERNEL);
if (!se401->width)
return 1;
- se401->height=kmalloc(se401->sizes*sizeof(int), GFP_KERNEL);
+ se401->height = kmalloc(se401->sizes*sizeof(int), GFP_KERNEL);
if (!se401->height) {
kfree(se401->width);
return 1;
}
- for (i=0; i<se401->sizes; i++) {
- se401->width[i]=cp[6+i*4+0]+cp[6+i*4+1]*256;
- se401->height[i]=cp[6+i*4+2]+cp[6+i*4+3]*256;
+ for (i = 0; i < se401->sizes; i++) {
+ se401->width[i] = cp[6 + i * 4 + 0] + cp[6 + i*4 + 1] * 256;
+ se401->height[i] = cp[6 + i * 4 + 2] + cp[6 + i * 4 + 3] * 256;
}
- sprintf (temp, "%s Sizes:", temp);
- for (i=0; i<se401->sizes; i++) {
- sprintf(temp, "%s %dx%d", temp, se401->width[i], se401->height[i]);
+ slen += snprintf(temp + slen, 200 - slen, " Sizes:");
+ for (i = 0; i < se401->sizes; i++) {
+ slen += snprintf(temp + slen, 200 - slen,
+ " %dx%d", se401->width[i], se401->height[i]);
}
dev_info(&se401->dev->dev, "%s\n", temp);
- se401->maxframesize=se401->width[se401->sizes-1]*se401->height[se401->sizes-1]*3;
+ se401->maxframesize = se401->width[se401->sizes-1] *
+ se401->height[se401->sizes - 1] * 3;
- rc=se401_sndctrl(0, se401, SE401_REQ_GET_WIDTH, 0, cp, sizeof(cp));
- se401->cwidth=cp[0]+cp[1]*256;
- rc=se401_sndctrl(0, se401, SE401_REQ_GET_HEIGHT, 0, cp, sizeof(cp));
- se401->cheight=cp[0]+cp[1]*256;
+ rc = se401_sndctrl(0, se401, SE401_REQ_GET_WIDTH, 0, cp, sizeof(cp));
+ se401->cwidth = cp[0]+cp[1]*256;
+ rc = se401_sndctrl(0, se401, SE401_REQ_GET_HEIGHT, 0, cp, sizeof(cp));
+ se401->cheight = cp[0]+cp[1]*256;
if (!(cp[2] & SE401_FORMAT_BAYER)) {
err("Bayer format not supported!");
return 1;
}
/* set output mode (BAYER) */
- se401_sndctrl(1, se401, SE401_REQ_SET_OUTPUT_MODE, SE401_FORMAT_BAYER, NULL, 0);
+ se401_sndctrl(1, se401, SE401_REQ_SET_OUTPUT_MODE,
+ SE401_FORMAT_BAYER, NULL, 0);
- rc=se401_sndctrl(0, se401, SE401_REQ_GET_BRT, 0, cp, sizeof(cp));
- se401->brightness=cp[0]+cp[1]*256;
+ rc = se401_sndctrl(0, se401, SE401_REQ_GET_BRT, 0, cp, sizeof(cp));
+ se401->brightness = cp[0]+cp[1]*256;
/* some default values */
- se401->resetlevel=0x2d;
- se401->rgain=0x20;
- se401->ggain=0x20;
- se401->bgain=0x20;
+ se401->resetlevel = 0x2d;
+ se401->rgain = 0x20;
+ se401->ggain = 0x20;
+ se401->bgain = 0x20;
se401_set_exposure(se401, 20000);
- se401->palette=VIDEO_PALETTE_RGB24;
- se401->enhance=1;
- se401->dropped=0;
- se401->error=0;
- se401->framecount=0;
- se401->readcount=0;
+ se401->palette = VIDEO_PALETTE_RGB24;
+ se401->enhance = 1;
+ se401->dropped = 0;
+ se401->error = 0;
+ se401->framecount = 0;
+ se401->readcount = 0;
/* Start interrupt transfers for snapshot button */
if (button) {
- se401->inturb=usb_alloc_urb(0, GFP_KERNEL);
+ se401->inturb = usb_alloc_urb(0, GFP_KERNEL);
if (!se401->inturb) {
dev_info(&se401->dev->dev,
"Allocation of inturb failed\n");
@@ -1331,7 +1349,7 @@ static int se401_init(struct usb_se401 *se401, int button)
return 1;
}
} else
- se401->inturb=NULL;
+ se401->inturb = NULL;
/* Flash the led */
se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 1, NULL, 0);
@@ -1348,8 +1366,8 @@ static int se401_probe(struct usb_interface *intf,
struct usb_device *dev = interface_to_usbdev(intf);
struct usb_interface_descriptor *interface;
struct usb_se401 *se401;
- char *camera_name=NULL;
- int button=1;
+ char *camera_name = NULL;
+ int button = 1;
/* We don't handle multi-config cameras */
if (dev->descriptor.bNumConfigurations != 1)
@@ -1358,22 +1376,22 @@ static int se401_probe(struct usb_interface *intf,
interface = &intf->cur_altsetting->desc;
/* Is it an se401? */
- if (le16_to_cpu(dev->descriptor.idVendor) == 0x03e8 &&
- le16_to_cpu(dev->descriptor.idProduct) == 0x0004) {
- camera_name="Endpoints/Aox SE401";
- } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x0471 &&
- le16_to_cpu(dev->descriptor.idProduct) == 0x030b) {
- camera_name="Philips PCVC665K";
- } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x047d &&
- le16_to_cpu(dev->descriptor.idProduct) == 0x5001) {
- camera_name="Kensington VideoCAM 67014";
- } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x047d &&
- le16_to_cpu(dev->descriptor.idProduct) == 0x5002) {
- camera_name="Kensington VideoCAM 6701(5/7)";
- } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x047d &&
- le16_to_cpu(dev->descriptor.idProduct) == 0x5003) {
- camera_name="Kensington VideoCAM 67016";
- button=0;
+ if (le16_to_cpu(dev->descriptor.idVendor) == 0x03e8 &&
+ le16_to_cpu(dev->descriptor.idProduct) == 0x0004) {
+ camera_name = "Endpoints/Aox SE401";
+ } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x0471 &&
+ le16_to_cpu(dev->descriptor.idProduct) == 0x030b) {
+ camera_name = "Philips PCVC665K";
+ } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x047d &&
+ le16_to_cpu(dev->descriptor.idProduct) == 0x5001) {
+ camera_name = "Kensington VideoCAM 67014";
+ } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x047d &&
+ le16_to_cpu(dev->descriptor.idProduct) == 0x5002) {
+ camera_name = "Kensington VideoCAM 6701(5/7)";
+ } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x047d &&
+ le16_to_cpu(dev->descriptor.idProduct) == 0x5003) {
+ camera_name = "Kensington VideoCAM 67016";
+ button = 0;
} else
return -ENODEV;
@@ -1386,7 +1404,8 @@ static int se401_probe(struct usb_interface *intf,
/* We found one */
dev_info(&intf->dev, "SE401 camera found: %s\n", camera_name);
- if ((se401 = kzalloc(sizeof(*se401), GFP_KERNEL)) == NULL) {
+ se401 = kzalloc(sizeof(*se401), GFP_KERNEL);
+ if (se401 == NULL) {
err("couldn't kmalloc se401 struct");
return -ENOMEM;
}
@@ -1404,12 +1423,14 @@ static int se401_probe(struct usb_interface *intf,
}
memcpy(&se401->vdev, &se401_template, sizeof(se401_template));
- memcpy(se401->vdev.name, se401->camera_name, strlen(se401->camera_name));
+ memcpy(se401->vdev.name, se401->camera_name,
+ strlen(se401->camera_name));
init_waitqueue_head(&se401->wq);
mutex_init(&se401->lock);
wmb();
- if (video_register_device(&se401->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
+ if (video_register_device(&se401->vdev,
+ VFL_TYPE_GRABBER, video_nr) < 0) {
kfree(se401);
err("video_register_device failed");
return -EIO;
@@ -1417,20 +1438,20 @@ static int se401_probe(struct usb_interface *intf,
dev_info(&intf->dev, "registered new video device: video%d\n",
se401->vdev.num);
- usb_set_intfdata (intf, se401);
+ usb_set_intfdata(intf, se401);
return 0;
}
static void se401_disconnect(struct usb_interface *intf)
{
- struct usb_se401 *se401 = usb_get_intfdata (intf);
+ struct usb_se401 *se401 = usb_get_intfdata(intf);
- usb_set_intfdata (intf, NULL);
+ usb_set_intfdata(intf, NULL);
if (se401) {
video_unregister_device(&se401->vdev);
- if (!se401->user){
+ if (!se401->user)
usb_se401_remove_disconnected(se401);
- } else {
+ else {
se401->frame[0].grabstate = FRAME_ERROR;
se401->frame[0].grabstate = FRAME_ERROR;
@@ -1443,10 +1464,10 @@ static void se401_disconnect(struct usb_interface *intf)
}
static struct usb_driver se401_driver = {
- .name = "se401",
- .id_table = device_table,
- .probe = se401_probe,
- .disconnect = se401_disconnect,
+ .name = "se401",
+ .id_table = device_table,
+ .probe = se401_probe,
+ .disconnect = se401_disconnect,
};
@@ -1459,9 +1480,10 @@ static struct usb_driver se401_driver = {
static int __init usb_se401_init(void)
{
- printk(KERN_INFO "SE401 usb camera driver version %s registering\n", version);
+ printk(KERN_INFO "SE401 usb camera driver version %s registering\n",
+ version);
if (flickerless)
- if (flickerless!=50 && flickerless!=60) {
+ if (flickerless != 50 && flickerless != 60) {
printk(KERN_ERR "Invallid flickerless value, use 0, 50 or 60.\n");
return -1;
}
diff --git a/linux/drivers/media/video/se401.h b/linux/drivers/media/video/se401.h
index 0be02c48b..00f0ddbf4 100644
--- a/linux/drivers/media/video/se401.h
+++ b/linux/drivers/media/video/se401.h
@@ -2,7 +2,7 @@
#ifndef __LINUX_se401_H
#define __LINUX_se401_H
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include "compat.h"
#include <linux/videodev.h>
#include <media/v4l2-common.h>
@@ -13,9 +13,10 @@
#ifdef se401_DEBUG
# define PDEBUG(level, fmt, args...) \
-if (debug >= level) info("[" __PRETTY_FUNCTION__ ":%d] " fmt, __LINE__ , ## args)
+if (debug >= level) \
+ info("[" __PRETTY_FUNCTION__ ":%d] " fmt, __LINE__ , ## args)
#else
-# define PDEBUG(level, fmt, args...) do {} while(0)
+# define PDEBUG(level, fmt, args...) do {} while (0)
#endif
/* An almost drop-in replacement for sleep_on_interruptible */
diff --git a/linux/drivers/media/video/sh_mobile_ceu_camera.c b/linux/drivers/media/video/sh_mobile_ceu_camera.c
index bf0b176f9..7ea2a0edf 100644
--- a/linux/drivers/media/video/sh_mobile_ceu_camera.c
+++ b/linux/drivers/media/video/sh_mobile_ceu_camera.c
@@ -690,16 +690,8 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
/* FIXME: calculate using depth and bus width */
- if (f->fmt.pix.height < 4)
- f->fmt.pix.height = 4;
- if (f->fmt.pix.height > 1920)
- f->fmt.pix.height = 1920;
- if (f->fmt.pix.width < 2)
- f->fmt.pix.width = 2;
- if (f->fmt.pix.width > 2560)
- f->fmt.pix.width = 2560;
- f->fmt.pix.width &= ~0x01;
- f->fmt.pix.height &= ~0x03;
+ v4l_bound_align_image(&f->fmt.pix.width, 2, 2560, 1,
+ &f->fmt.pix.height, 4, 1920, 2, 0);
f->fmt.pix.bytesperline = f->fmt.pix.width *
DIV_ROUND_UP(xlate->host_fmt->depth, 8);
diff --git a/linux/drivers/media/video/soc_camera.c b/linux/drivers/media/video/soc_camera.c
index 822052b25..e4056a9c2 100644
--- a/linux/drivers/media/video/soc_camera.c
+++ b/linux/drivers/media/video/soc_camera.c
@@ -1206,7 +1206,7 @@ static int __devexit soc_camera_pdrv_remove(struct platform_device *pdev)
static struct platform_driver __refdata soc_camera_pdrv = {
.probe = soc_camera_pdrv_probe,
- .remove = __exit_p(soc_camera_pdrv_remove),
+ .remove = __devexit_p(soc_camera_pdrv_remove),
.driver = {
.name = "soc-camera-pdrv",
.owner = THIS_MODULE,
diff --git a/linux/drivers/media/video/tcm825x.c b/linux/drivers/media/video/tcm825x.c
index 559ade821..d778c41ef 100644
--- a/linux/drivers/media/video/tcm825x.c
+++ b/linux/drivers/media/video/tcm825x.c
@@ -882,7 +882,7 @@ static int tcm825x_probe(struct i2c_client *client,
return rval;
}
-static int __exit tcm825x_remove(struct i2c_client *client)
+static int tcm825x_remove(struct i2c_client *client)
{
struct tcm825x_sensor *sensor = i2c_get_clientdata(client);
@@ -908,7 +908,7 @@ static struct i2c_driver tcm825x_i2c_driver = {
.name = TCM825X_NAME,
},
.probe = tcm825x_probe,
- .remove = __exit_p(tcm825x_remove),
+ .remove = tcm825x_remove,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
.id_table = tcm825x_id,
#endif
diff --git a/linux/drivers/media/video/tuner-core.c b/linux/drivers/media/video/tuner-core.c
index bb60c910e..85b133df4 100644
--- a/linux/drivers/media/video/tuner-core.c
+++ b/linux/drivers/media/video/tuner-core.c
@@ -426,18 +426,12 @@ static void set_type(struct i2c_client *c, unsigned int type,
break;
case TUNER_XC5000:
{
- struct dvb_tuner_ops *xc_tuner_ops;
-
xc5000_cfg.i2c_address = t->i2c->addr;
/* if_khz will be set when the digital dvb_attach() occurs */
xc5000_cfg.if_khz = 0;
if (!dvb_attach(xc5000_attach,
&t->fe, t->i2c->adapter, &xc5000_cfg))
goto attach_failed;
-
- xc_tuner_ops = &t->fe.ops.tuner_ops;
- if (xc_tuner_ops->init)
- xc_tuner_ops->init(&t->fe);
break;
}
default:
diff --git a/linux/drivers/media/video/tveeprom.c b/linux/drivers/media/video/tveeprom.c
index 7d6459dd2..5e3c9f4e2 100644
--- a/linux/drivers/media/video/tveeprom.c
+++ b/linux/drivers/media/video/tveeprom.c
@@ -185,7 +185,7 @@ hauppauge_tuner[] =
{ TUNER_ABSENT, "Silicon TDA8275C1 8290 FM"},
{ TUNER_ABSENT, "Thompson DTT757"},
/* 80-89 */
- { TUNER_PHILIPS_FM1216ME_MK3, "Philips FQ1216LME MK3"},
+ { TUNER_PHILIPS_FQ1216LME_MK3, "Philips FQ1216LME MK3"},
{ TUNER_LG_PAL_NEW_TAPC, "LG TAPC G701D"},
{ TUNER_LG_NTSC_NEW_TAPC, "LG TAPC H791F"},
{ TUNER_LG_PAL_NEW_TAPC, "TCL 2002MB 3"},
@@ -230,7 +230,7 @@ hauppauge_tuner[] =
{ TUNER_ABSENT, "Samsung THPD5222FG30A"},
/* 120-129 */
{ TUNER_XC2028, "Xceive XC3028"},
- { TUNER_ABSENT, "Philips FQ1216LME MK5"},
+ { TUNER_PHILIPS_FQ1216LME_MK3, "Philips FQ1216LME MK5"},
{ TUNER_ABSENT, "Philips FQD1216LME"},
{ TUNER_ABSENT, "Conexant CX24118A"},
{ TUNER_ABSENT, "TCL DMF11WIP"},
diff --git a/linux/drivers/media/video/tvp514x.c b/linux/drivers/media/video/tvp514x.c
index 4262e60b8..3750f7fad 100644
--- a/linux/drivers/media/video/tvp514x.c
+++ b/linux/drivers/media/video/tvp514x.c
@@ -692,7 +692,7 @@ static int ioctl_s_routing(struct v4l2_int_device *s,
break; /* Input detected */
}
- if ((current_std == STD_INVALID) || (try_count <= 0))
+ if ((current_std == STD_INVALID) || (try_count < 0))
return -EINVAL;
decoder->current_std = current_std;
diff --git a/linux/drivers/media/video/usbvideo/Kconfig b/linux/drivers/media/video/usbvideo/Kconfig
index e4cb99c1f..adb1c044a 100644
--- a/linux/drivers/media/video/usbvideo/Kconfig
+++ b/linux/drivers/media/video/usbvideo/Kconfig
@@ -38,10 +38,13 @@ config USB_KONICAWC
module will be called konicawc.
config USB_QUICKCAM_MESSENGER
- tristate "USB Logitech Quickcam Messenger"
+ tristate "USB Logitech Quickcam Messenger (DEPRECATED)"
depends on VIDEO_V4L1
select VIDEO_USBVIDEO
---help---
+ This driver is DEPRECATED please use the gspca stv06xx module
+ instead.
+
Say Y or M here to enable support for the USB Logitech Quickcam
Messenger webcam.
diff --git a/linux/drivers/media/video/usbvideo/konicawc.c b/linux/drivers/media/video/usbvideo/konicawc.c
index 75485168e..07bc85761 100644
--- a/linux/drivers/media/video/usbvideo/konicawc.c
+++ b/linux/drivers/media/video/usbvideo/konicawc.c
@@ -249,7 +249,7 @@ static void konicawc_register_input(struct konicawc *cam, struct usb_device *dev
#endif
input_dev->evbit[0] = BIT_MASK(EV_KEY);
- input_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0);
+ input_dev->keybit[BIT_WORD(KEY_CAMERA)] = BIT_MASK(KEY_CAMERA);
error = input_register_device(cam->input);
if (error) {
@@ -272,7 +272,7 @@ static void konicawc_unregister_input(struct konicawc *cam)
static void konicawc_report_buttonstat(struct konicawc *cam)
{
if (cam->input) {
- input_report_key(cam->input, BTN_0, cam->buttonsts);
+ input_report_key(cam->input, KEY_CAMERA, cam->buttonsts);
input_sync(cam->input);
}
}
diff --git a/linux/drivers/media/video/usbvideo/quickcam_messenger.c b/linux/drivers/media/video/usbvideo/quickcam_messenger.c
index f129bea11..ab30ef54a 100644
--- a/linux/drivers/media/video/usbvideo/quickcam_messenger.c
+++ b/linux/drivers/media/video/usbvideo/quickcam_messenger.c
@@ -112,7 +112,7 @@ static void qcm_register_input(struct qcm *cam, struct usb_device *dev)
#endif
input_dev->evbit[0] = BIT_MASK(EV_KEY);
- input_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0);
+ input_dev->keybit[BIT_WORD(KEY_CAMERA)] = BIT_MASK(KEY_CAMERA);
error = input_register_device(cam->input);
if (error) {
@@ -135,7 +135,7 @@ static void qcm_unregister_input(struct qcm *cam)
static void qcm_report_buttonstat(struct qcm *cam)
{
if (cam->input) {
- input_report_key(cam->input, BTN_0, cam->button_sts);
+ input_report_key(cam->input, KEY_CAMERA, cam->button_sts);
input_sync(cam->input);
}
}
diff --git a/linux/drivers/media/video/usbvision/usbvision-core.c b/linux/drivers/media/video/usbvision/usbvision-core.c
index 9253ec6dd..baf2e5621 100644
--- a/linux/drivers/media/video/usbvision/usbvision-core.c
+++ b/linux/drivers/media/video/usbvision/usbvision-core.c
@@ -390,10 +390,9 @@ int usbvision_scratch_alloc(struct usb_usbvision *usbvision)
void usbvision_scratch_free(struct usb_usbvision *usbvision)
{
- if (usbvision->scratch != NULL) {
- vfree(usbvision->scratch);
- usbvision->scratch = NULL;
- }
+ vfree(usbvision->scratch);
+ usbvision->scratch = NULL;
+
}
/*
@@ -506,10 +505,9 @@ int usbvision_decompress_alloc(struct usb_usbvision *usbvision)
*/
void usbvision_decompress_free(struct usb_usbvision *usbvision)
{
- if (usbvision->IntraFrameBuffer != NULL) {
- vfree(usbvision->IntraFrameBuffer);
- usbvision->IntraFrameBuffer = NULL;
- }
+ vfree(usbvision->IntraFrameBuffer);
+ usbvision->IntraFrameBuffer = NULL;
+
}
/************************************************************
diff --git a/linux/drivers/media/video/usbvision/usbvision-video.c b/linux/drivers/media/video/usbvision/usbvision-video.c
index d03e5922d..90b58914f 100644
--- a/linux/drivers/media/video/usbvision/usbvision-video.c
+++ b/linux/drivers/media/video/usbvision/usbvision-video.c
@@ -1794,7 +1794,7 @@ static struct usb_driver usbvision_driver = {
.name = "usbvision",
.id_table = usbvision_table,
.probe = usbvision_probe,
- .disconnect = usbvision_disconnect
+ .disconnect = __devexit_p(usbvision_disconnect),
};
/*
diff --git a/linux/drivers/media/video/uvc/uvc_ctrl.c b/linux/drivers/media/video/uvc/uvc_ctrl.c
index 7774ce6b5..ef55bc35a 100644
--- a/linux/drivers/media/video/uvc/uvc_ctrl.c
+++ b/linux/drivers/media/video/uvc/uvc_ctrl.c
@@ -1374,21 +1374,19 @@ end:
}
/*
- * Prune an entity of its bogus controls. This currently includes processing
- * unit auto controls for which no corresponding manual control is available.
- * Such auto controls make little sense if any, and are known to crash at
- * least the SiGma Micro webcam.
+ * Prune an entity of its bogus controls using a blacklist. Bogus controls
+ * are currently the ones that crash the camera or unconditionally return an
+ * error when queried.
*/
static void
-uvc_ctrl_prune_entity(struct uvc_entity *entity)
+uvc_ctrl_prune_entity(struct uvc_device *dev, struct uvc_entity *entity)
{
static const struct {
- u8 idx_manual;
- u8 idx_auto;
+ struct usb_device_id id;
+ u8 index;
} blacklist[] = {
- { 2, 11 }, /* Hue */
- { 6, 12 }, /* White Balance Temperature */
- { 7, 13 }, /* White Balance Component */
+ { { USB_DEVICE(0x1c4f, 0x3000) }, 6 }, /* WB Temperature */
+ { { USB_DEVICE(0x5986, 0x0241) }, 2 }, /* Hue */
};
u8 *controls;
@@ -1402,19 +1400,17 @@ uvc_ctrl_prune_entity(struct uvc_entity *entity)
size = entity->processing.bControlSize;
for (i = 0; i < ARRAY_SIZE(blacklist); ++i) {
- if (blacklist[i].idx_auto >= 8 * size ||
- blacklist[i].idx_manual >= 8 * size)
+ if (!usb_match_id(dev->intf, &blacklist[i].id))
continue;
- if (!uvc_test_bit(controls, blacklist[i].idx_auto) ||
- uvc_test_bit(controls, blacklist[i].idx_manual))
+ if (blacklist[i].index >= 8 * size ||
+ !uvc_test_bit(controls, blacklist[i].index))
continue;
- uvc_trace(UVC_TRACE_CONTROL, "Auto control %u/%u has no "
- "matching manual control, removing it.\n", entity->id,
- blacklist[i].idx_auto);
+ uvc_trace(UVC_TRACE_CONTROL, "%u/%u control is black listed, "
+ "removing it.\n", entity->id, blacklist[i].index);
- uvc_clear_bit(controls, blacklist[i].idx_auto);
+ uvc_clear_bit(controls, blacklist[i].index);
}
}
@@ -1444,8 +1440,7 @@ int uvc_ctrl_init_device(struct uvc_device *dev)
bControlSize = entity->camera.bControlSize;
}
- if (dev->quirks & UVC_QUIRK_PRUNE_CONTROLS)
- uvc_ctrl_prune_entity(entity);
+ uvc_ctrl_prune_entity(dev, entity);
for (i = 0; i < bControlSize; ++i)
ncontrols += hweight8(bmControls[i]);
diff --git a/linux/drivers/media/video/uvc/uvc_driver.c b/linux/drivers/media/video/uvc/uvc_driver.c
index 4a69a3af6..40df6828f 100644
--- a/linux/drivers/media/video/uvc/uvc_driver.c
+++ b/linux/drivers/media/video/uvc/uvc_driver.c
@@ -289,10 +289,8 @@ static int uvc_parse_format(struct uvc_device *dev,
struct uvc_format_desc *fmtdesc;
struct uvc_frame *frame;
const unsigned char *start = buffer;
- unsigned char *_buffer;
unsigned int interval;
unsigned int i, n;
- int _buflen;
__u8 ftype;
format->type = buffer[2];
@@ -303,7 +301,7 @@ static int uvc_parse_format(struct uvc_device *dev,
case VS_FORMAT_FRAME_BASED:
n = buffer[2] == VS_FORMAT_UNCOMPRESSED ? 27 : 28;
if (buflen < n) {
- uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+ uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
"interface %d FORMAT error\n",
dev->udev->devnum,
alts->desc.bInterfaceNumber);
@@ -338,7 +336,7 @@ static int uvc_parse_format(struct uvc_device *dev,
case VS_FORMAT_MJPEG:
if (buflen < 11) {
- uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+ uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
"interface %d FORMAT error\n",
dev->udev->devnum,
alts->desc.bInterfaceNumber);
@@ -354,7 +352,7 @@ static int uvc_parse_format(struct uvc_device *dev,
case VS_FORMAT_DV:
if (buflen < 9) {
- uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+ uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
"interface %d FORMAT error\n",
dev->udev->devnum,
alts->desc.bInterfaceNumber);
@@ -372,7 +370,7 @@ static int uvc_parse_format(struct uvc_device *dev,
strlcpy(format->name, "HD-DV", sizeof format->name);
break;
default:
- uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+ uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
"interface %d: unknown DV format %u\n",
dev->udev->devnum,
alts->desc.bInterfaceNumber, buffer[8]);
@@ -401,7 +399,7 @@ static int uvc_parse_format(struct uvc_device *dev,
case VS_FORMAT_STREAM_BASED:
/* Not supported yet. */
default:
- uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+ uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
"interface %d unsupported format %u\n",
dev->udev->devnum, alts->desc.bInterfaceNumber,
buffer[2]);
@@ -413,20 +411,11 @@ static int uvc_parse_format(struct uvc_device *dev,
buflen -= buffer[0];
buffer += buffer[0];
- /* Count the number of frame descriptors to test the bFrameIndex
- * field when parsing the descriptors. We can't rely on the
- * bNumFrameDescriptors field as some cameras don't initialize it
- * properly.
- */
- for (_buflen = buflen, _buffer = buffer;
- _buflen > 2 && _buffer[2] == ftype;
- _buflen -= _buffer[0], _buffer += _buffer[0])
- format->nframes++;
-
/* 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
@@ -435,22 +424,12 @@ static int uvc_parse_format(struct uvc_device *dev,
n = n ? n : 3;
if (buflen < 26 + 4*n) {
- uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+ uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
"interface %d FRAME error\n", dev->udev->devnum,
alts->desc.bInterfaceNumber);
return -EINVAL;
}
- if (buffer[3] - 1 >= format->nframes) {
- uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
- "interface %d frame index %u out of range\n",
- dev->udev->devnum, alts->desc.bInterfaceNumber,
- buffer[3]);
- return -EINVAL;
- }
-
- frame = &format->frame[buffer[3] - 1];
-
frame->bFrameIndex = buffer[3];
frame->bmCapabilities = buffer[4];
frame->wWidth = get_unaligned_le16(&buffer[5]);
@@ -507,6 +486,7 @@ static int uvc_parse_format(struct uvc_device *dev,
10000000/frame->dwDefaultFrameInterval,
(100000000/frame->dwDefaultFrameInterval)%10);
+ format->nframes++;
buflen -= buffer[0];
buffer += buffer[0];
}
@@ -518,7 +498,7 @@ static int uvc_parse_format(struct uvc_device *dev,
if (buflen > 2 && buffer[2] == VS_COLORFORMAT) {
if (buflen < 6) {
- uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+ uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
"interface %d COLORFORMAT error\n",
dev->udev->devnum,
alts->desc.bInterfaceNumber);
@@ -664,7 +644,7 @@ static int uvc_parse_streaming(struct uvc_device *dev,
_buflen = buflen;
/* Count the format and frame descriptors. */
- while (_buflen > 2) {
+ while (_buflen > 2 && _buffer[1] == CS_INTERFACE) {
switch (_buffer[2]) {
case VS_FORMAT_UNCOMPRESSED:
case VS_FORMAT_MJPEG:
@@ -729,7 +709,7 @@ static int uvc_parse_streaming(struct uvc_device *dev,
streaming->nformats = nformats;
/* Parse the format descriptors. */
- while (buflen > 2) {
+ while (buflen > 2 && buffer[1] == CS_INTERFACE) {
switch (buffer[2]) {
case VS_FORMAT_UNCOMPRESSED:
case VS_FORMAT_MJPEG:
@@ -1316,7 +1296,7 @@ static int uvc_scan_chain_forward(struct uvc_video_device *video,
continue;
if (forward->extension.bNrInPins != 1) {
- uvc_trace(UVC_TRACE_DESCR, "Extension unit %d has"
+ uvc_trace(UVC_TRACE_DESCR, "Extension unit %d has "
"more than 1 input pin.\n", entity->id);
return -1;
}
@@ -1614,6 +1594,7 @@ static int uvc_probe(struct usb_interface *intf,
INIT_LIST_HEAD(&dev->entities);
INIT_LIST_HEAD(&dev->streaming);
kref_init(&dev->kref);
+ atomic_set(&dev->users, 0);
dev->udev = usb_get_dev(udev);
dev->intf = usb_get_intf(intf);
@@ -1929,7 +1910,7 @@ static struct usb_device_id uvc_ids[] = {
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
.driver_info = UVC_QUIRK_STREAM_NO_FID },
- /* Lenovo Thinkpad SL500 */
+ /* Lenovo Thinkpad SL400/SL500 */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
.idVendor = 0x17ef,
@@ -1938,6 +1919,15 @@ static struct usb_device_id uvc_ids[] = {
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
.driver_info = UVC_QUIRK_STREAM_NO_FID },
+ /* Aveo Technology USB 2.0 Camera */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x1871,
+ .idProduct = 0x0306,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_PROBE_EXTRAFIELDS },
/* Ecamm Pico iMage */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
@@ -1947,6 +1937,15 @@ static struct usb_device_id uvc_ids[] = {
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
.driver_info = UVC_QUIRK_PROBE_EXTRAFIELDS },
+ /* FSC WebCam V30S */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x18ec,
+ .idProduct = 0x3288,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_PROBE_MINMAX },
/* Bodelin ProScopeHR */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_DEV_HI
@@ -1967,8 +1966,7 @@ static struct usb_device_id uvc_ids[] = {
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
.driver_info = UVC_QUIRK_PROBE_MINMAX
- | UVC_QUIRK_IGNORE_SELECTOR_UNIT
- | UVC_QUIRK_PRUNE_CONTROLS },
+ | UVC_QUIRK_IGNORE_SELECTOR_UNIT },
/* Generic USB Video Class */
{ USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, 0) },
{}
diff --git a/linux/drivers/media/video/uvc/uvc_queue.c b/linux/drivers/media/video/uvc/uvc_queue.c
index 0155752e4..f854698c4 100644
--- a/linux/drivers/media/video/uvc/uvc_queue.c
+++ b/linux/drivers/media/video/uvc/uvc_queue.c
@@ -172,6 +172,20 @@ int uvc_free_buffers(struct uvc_video_queue *queue)
return 0;
}
+/*
+ * Check if buffers have been allocated.
+ */
+int uvc_queue_allocated(struct uvc_video_queue *queue)
+{
+ int allocated;
+
+ mutex_lock(&queue->mutex);
+ allocated = queue->count != 0;
+ mutex_unlock(&queue->mutex);
+
+ return allocated;
+}
+
static void __uvc_query_buffer(struct uvc_buffer *buf,
struct v4l2_buffer *v4l2_buf)
{
diff --git a/linux/drivers/media/video/uvc/uvc_status.c b/linux/drivers/media/video/uvc/uvc_status.c
index 1e1bda413..b05df63b4 100644
--- a/linux/drivers/media/video/uvc/uvc_status.c
+++ b/linux/drivers/media/video/uvc/uvc_status.c
@@ -206,7 +206,7 @@ int uvc_status_init(struct uvc_device *dev)
dev->status, UVC_MAX_STATUS_SIZE, uvc_status_complete,
dev, interval);
- return usb_submit_urb(dev->int_urb, GFP_KERNEL);
+ return 0;
}
void uvc_status_cleanup(struct uvc_device *dev)
@@ -217,15 +217,30 @@ void uvc_status_cleanup(struct uvc_device *dev)
uvc_input_cleanup(dev);
}
-int uvc_status_suspend(struct uvc_device *dev)
+int uvc_status_start(struct uvc_device *dev)
+{
+ if (dev->int_urb == NULL)
+ return 0;
+
+ return usb_submit_urb(dev->int_urb, GFP_KERNEL);
+}
+
+void uvc_status_stop(struct uvc_device *dev)
{
usb_kill_urb(dev->int_urb);
+}
+
+int uvc_status_suspend(struct uvc_device *dev)
+{
+ if (atomic_read(&dev->users))
+ usb_kill_urb(dev->int_urb);
+
return 0;
}
int uvc_status_resume(struct uvc_device *dev)
{
- if (dev->int_urb == NULL)
+ if (dev->int_urb == NULL || atomic_read(&dev->users) == 0)
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
index bc13dbf05..0be85adf3 100644
--- a/linux/drivers/media/video/uvc/uvc_v4l2.c
+++ b/linux/drivers/media/video/uvc/uvc_v4l2.c
@@ -251,7 +251,7 @@ static int uvc_v4l2_set_format(struct uvc_video_device *video,
if (fmt->type != video->streaming->type)
return -EINVAL;
- if (uvc_queue_streaming(&video->queue))
+ if (uvc_queue_allocated(&video->queue))
return -EBUSY;
ret = uvc_v4l2_try_format(video, fmt, &probe, &format, &frame);
@@ -443,6 +443,17 @@ static int uvc_v4l2_open(struct file *file)
goto done;
}
+ if (atomic_inc_return(&video->dev->users) == 1) {
+ if ((ret = uvc_status_start(video->dev)) < 0) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
+ usb_autopm_put_interface(video->dev->intf);
+#endif
+ atomic_dec(&video->dev->users);
+ kfree(handle);
+ goto done;
+ }
+ }
+
handle->device = video;
handle->state = UVC_HANDLE_PASSIVE;
file->private_data = handle;
@@ -477,6 +488,9 @@ static int uvc_v4l2_release(struct file *file)
kfree(handle);
file->private_data = NULL;
+ if (atomic_dec_return(&video->dev->users) == 0)
+ uvc_status_stop(video->dev);
+
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
usb_autopm_put_interface(video->dev->intf);
#endif
@@ -524,7 +538,10 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
memset(&xctrl, 0, sizeof xctrl);
xctrl.id = ctrl->id;
- uvc_ctrl_begin(video);
+ ret = uvc_ctrl_begin(video);
+ if (ret < 0)
+ return ret;
+
ret = uvc_ctrl_get(video, &xctrl);
uvc_ctrl_rollback(video);
if (ret >= 0)
@@ -541,7 +558,10 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
xctrl.id = ctrl->id;
xctrl.value = ctrl->value;
- uvc_ctrl_begin(video);
+ ret = uvc_ctrl_begin(video);
+ if (ret < 0)
+ return ret;
+
ret = uvc_ctrl_set(video, &xctrl);
if (ret < 0) {
uvc_ctrl_rollback(video);
@@ -560,7 +580,10 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
struct v4l2_ext_control *ctrl = ctrls->controls;
unsigned int i;
- uvc_ctrl_begin(video);
+ ret = uvc_ctrl_begin(video);
+ if (ret < 0)
+ return ret;
+
for (i = 0; i < ctrls->count; ++ctrl, ++i) {
ret = uvc_ctrl_get(video, ctrl);
if (ret < 0) {
diff --git a/linux/drivers/media/video/uvc/uvc_video.c b/linux/drivers/media/video/uvc/uvc_video.c
index c5df33de9..07e755ba7 100644
--- a/linux/drivers/media/video/uvc/uvc_video.c
+++ b/linux/drivers/media/video/uvc/uvc_video.c
@@ -65,7 +65,8 @@ static void uvc_fixup_video_ctrl(struct uvc_video_device *video,
struct uvc_streaming_control *ctrl)
{
struct uvc_format *format;
- struct uvc_frame *frame;
+ struct uvc_frame *frame = NULL;
+ unsigned int i;
if (ctrl->bFormatIndex <= 0 ||
ctrl->bFormatIndex > video->streaming->nformats)
@@ -73,11 +74,15 @@ static void uvc_fixup_video_ctrl(struct uvc_video_device *video,
format = &video->streaming->format[ctrl->bFormatIndex - 1];
- if (ctrl->bFrameIndex <= 0 ||
- ctrl->bFrameIndex > format->nframes)
- return;
+ for (i = 0; i < format->nframes; ++i) {
+ if (format->frame[i].bFrameIndex == ctrl->bFrameIndex) {
+ frame = &format->frame[i];
+ break;
+ }
+ }
- frame = &format->frame[ctrl->bFrameIndex - 1];
+ if (frame == NULL)
+ return;
if (!(format->flags & UVC_FMT_FLAG_COMPRESSED) ||
(ctrl->dwMaxVideoFrameSize == 0 &&
@@ -1093,7 +1098,7 @@ int uvc_video_init(struct uvc_video_device *video)
/* 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.
+ * descriptor is not found, use the first available frame.
*/
for (i = format->nframes; i > 0; --i) {
frame = &format->frame[i-1];
diff --git a/linux/drivers/media/video/uvc/uvcvideo.h b/linux/drivers/media/video/uvc/uvcvideo.h
index 53d5c9e0c..de13c86f2 100644
--- a/linux/drivers/media/video/uvc/uvcvideo.h
+++ b/linux/drivers/media/video/uvc/uvcvideo.h
@@ -314,7 +314,6 @@ struct uvc_xu_control {
#define UVC_QUIRK_BUILTIN_ISIGHT 0x00000008
#define UVC_QUIRK_STREAM_NO_FID 0x00000010
#define UVC_QUIRK_IGNORE_SELECTOR_UNIT 0x00000020
-#define UVC_QUIRK_PRUNE_CONTROLS 0x00000040
#define UVC_QUIRK_FIX_BANDWIDTH 0x00000080
/* Format flags */
@@ -635,6 +634,7 @@ struct uvc_device {
enum uvc_device_state state;
struct kref kref;
struct list_head list;
+ atomic_t users;
/* Video control interface */
__u16 uvc_version;
@@ -748,6 +748,7 @@ 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);
+extern int uvc_queue_allocated(struct uvc_video_queue *queue);
static inline int uvc_queue_streaming(struct uvc_video_queue *queue)
{
return queue->flags & UVC_QUEUE_STREAMING;
@@ -771,6 +772,8 @@ extern int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
/* Status */
extern int uvc_status_init(struct uvc_device *dev);
extern void uvc_status_cleanup(struct uvc_device *dev);
+extern int uvc_status_start(struct uvc_device *dev);
+extern void uvc_status_stop(struct uvc_device *dev);
extern int uvc_status_suspend(struct uvc_device *dev);
extern int uvc_status_resume(struct uvc_device *dev);
diff --git a/linux/drivers/media/video/v4l2-common.c b/linux/drivers/media/video/v4l2-common.c
index 8f2db1250..f94b5d92a 100644
--- a/linux/drivers/media/video/v4l2-common.c
+++ b/linux/drivers/media/video/v4l2-common.c
@@ -997,4 +997,78 @@ const unsigned short *v4l2_i2c_tuner_addrs(enum v4l2_i2c_tuner_type type)
}
EXPORT_SYMBOL_GPL(v4l2_i2c_tuner_addrs);
-#endif
+#endif /* defined(CONFIG_I2C) */
+
+/* Clamp x to be between min and max, aligned to a multiple of 2^align. min
+ * and max don't have to be aligned, but there must be at least one valid
+ * value. E.g., min=17,max=31,align=4 is not allowed as there are no multiples
+ * of 16 between 17 and 31. */
+static unsigned int clamp_align(unsigned int x, unsigned int min,
+ unsigned int max, unsigned int align)
+{
+ /* Bits that must be zero to be aligned */
+ unsigned int mask = ~((1 << align) - 1);
+
+ /* Round to nearest aligned value */
+ if (align)
+ x = (x + (1 << (align - 1))) & mask;
+
+ /* Clamp to aligned value of min and max */
+ if (x < min)
+ x = (min + ~mask) & mask;
+ else if (x > max)
+ x = max & mask;
+
+ return x;
+}
+
+/* Bound an image to have a width between wmin and wmax, and height between
+ * hmin and hmax, inclusive. Additionally, the width will be a multiple of
+ * 2^walign, the height will be a multiple of 2^halign, and the overall size
+ * (width*height) will be a multiple of 2^salign. The image may be shrunk
+ * or enlarged to fit the alignment constraints.
+ *
+ * The width or height maximum must not be smaller than the corresponding
+ * minimum. The alignments must not be so high there are no possible image
+ * sizes within the allowed bounds. wmin and hmin must be at least 1
+ * (don't use 0). If you don't care about a certain alignment, specify 0,
+ * as 2^0 is 1 and one byte alignment is equivalent to no alignment. If
+ * you only want to adjust downward, specify a maximum that's the same as
+ * the initial value.
+ */
+void v4l_bound_align_image(u32 *w, unsigned int wmin, unsigned int wmax,
+ unsigned int walign,
+ u32 *h, unsigned int hmin, unsigned int hmax,
+ unsigned int halign, unsigned int salign)
+{
+ *w = clamp_align(*w, wmin, wmax, walign);
+ *h = clamp_align(*h, hmin, hmax, halign);
+
+ /* Usually we don't need to align the size and are done now. */
+ if (!salign)
+ return;
+
+ /* How much alignment do we have? */
+ walign = __ffs(*w);
+ halign = __ffs(*h);
+ /* Enough to satisfy the image alignment? */
+ if (walign + halign < salign) {
+ /* Max walign where there is still a valid width */
+ unsigned int wmaxa = __fls(wmax ^ (wmin - 1));
+ /* Max halign where there is still a valid height */
+ unsigned int hmaxa = __fls(hmax ^ (hmin - 1));
+
+ /* up the smaller alignment until we have enough */
+ do {
+ if (halign >= hmaxa ||
+ (walign <= halign && walign < wmaxa)) {
+ *w = clamp_align(*w, wmin, wmax, walign + 1);
+ walign = __ffs(*w);
+ } else {
+ *h = clamp_align(*h, hmin, hmax, halign + 1);
+ halign = __ffs(*h);
+ }
+ } while (halign + walign < salign);
+ }
+}
+EXPORT_SYMBOL_GPL(v4l_bound_align_image);
diff --git a/linux/drivers/media/video/v4l2-device.c b/linux/drivers/media/video/v4l2-device.c
index b962862fe..4fa93189d 100644
--- a/linux/drivers/media/video/v4l2-device.c
+++ b/linux/drivers/media/video/v4l2-device.c
@@ -86,7 +86,8 @@ void v4l2_device_unregister(struct v4l2_device *v4l2_dev)
/* Unregister subdevs */
list_for_each_entry_safe(sd, next, &v4l2_dev->subdevs, list) {
v4l2_device_unregister_subdev(sd);
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
if (sd->flags & V4L2_SUBDEV_FL_IS_I2C) {
struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -98,6 +99,7 @@ void v4l2_device_unregister(struct v4l2_device *v4l2_dev)
i2c_unregister_device(client);
}
#endif
+#endif
}
}
EXPORT_SYMBOL_GPL(v4l2_device_unregister);
diff --git a/linux/drivers/media/video/videobuf-core.c b/linux/drivers/media/video/videobuf-core.c
index e9696385d..faf912403 100644
--- a/linux/drivers/media/video/videobuf-core.c
+++ b/linux/drivers/media/video/videobuf-core.c
@@ -119,6 +119,7 @@ void videobuf_queue_core_init(struct videobuf_queue *q,
void *priv,
struct videobuf_qtype_ops *int_ops)
{
+ BUG_ON(!q);
memset(q, 0, sizeof(*q));
q->irqlock = irqlock;
q->dev = dev;
diff --git a/linux/drivers/media/video/videobuf-dma-sg.c b/linux/drivers/media/video/videobuf-dma-sg.c
index ed38145e1..da83ac706 100644
--- a/linux/drivers/media/video/videobuf-dma-sg.c
+++ b/linux/drivers/media/video/videobuf-dma-sg.c
@@ -59,9 +59,10 @@ videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages)
struct page *pg;
int i;
- sglist = kcalloc(nr_pages, sizeof(struct scatterlist), GFP_KERNEL);
+ sglist = vmalloc(nr_pages * sizeof(*sglist));
if (NULL == sglist)
return NULL;
+ memset(sglist, 0, nr_pages * sizeof(*sglist));
sg_init_table(sglist, nr_pages);
for (i = 0; i < nr_pages; i++, virt += PAGE_SIZE) {
pg = vmalloc_to_page(virt);
@@ -73,7 +74,7 @@ videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages)
return sglist;
err:
- kfree(sglist);
+ vfree(sglist);
return NULL;
}
@@ -85,7 +86,7 @@ videobuf_pages_to_sg(struct page **pages, int nr_pages, int offset)
if (NULL == pages[0])
return NULL;
- sglist = kmalloc(nr_pages * sizeof(*sglist), GFP_KERNEL);
+ sglist = vmalloc(nr_pages * sizeof(*sglist));
if (NULL == sglist)
return NULL;
sg_init_table(sglist, nr_pages);
@@ -105,12 +106,12 @@ videobuf_pages_to_sg(struct page **pages, int nr_pages, int offset)
nopage:
dprintk(2,"sgl: oops - no page\n");
- kfree(sglist);
+ vfree(sglist);
return NULL;
highmem:
dprintk(2,"sgl: oops - highmem page\n");
- kfree(sglist);
+ vfree(sglist);
return NULL;
}
@@ -231,7 +232,7 @@ int videobuf_dma_map(struct videobuf_queue* q, struct videobuf_dmabuf *dma)
(dma->vmalloc,dma->nr_pages);
}
if (dma->bus_addr) {
- dma->sglist = kmalloc(sizeof(struct scatterlist), GFP_KERNEL);
+ dma->sglist = vmalloc(sizeof(*dma->sglist));
if (NULL != dma->sglist) {
dma->sglen = 1;
sg_dma_address(&dma->sglist[0]) = dma->bus_addr & PAGE_MASK;
@@ -249,10 +250,10 @@ int videobuf_dma_map(struct videobuf_queue* q, struct videobuf_dmabuf *dma)
if (0 == dma->sglen) {
printk(KERN_WARNING
"%s: videobuf_map_sg failed\n",__func__);
- kfree(dma->sglist);
+ vfree(dma->sglist);
dma->sglist = NULL;
dma->sglen = 0;
- return -EIO;
+ return -ENOMEM;
}
}
return 0;
@@ -275,7 +276,7 @@ int videobuf_dma_unmap(struct videobuf_queue* q,struct videobuf_dmabuf *dma)
dma_unmap_sg(q->dev, dma->sglist, dma->nr_pages, dma->direction);
- kfree(dma->sglist);
+ vfree(dma->sglist);
dma->sglist = NULL;
dma->sglen = 0;
return 0;
diff --git a/linux/drivers/media/video/vino.c b/linux/drivers/media/video/vino.c
index 808d9434d..7c39b43ee 100644
--- a/linux/drivers/media/video/vino.c
+++ b/linux/drivers/media/video/vino.c
@@ -868,9 +868,9 @@ static void vino_sync_buffer(struct vino_framebuffer *fb)
dprintk("vino_sync_buffer():\n");
for (i = 0; i < fb->desc_table.page_count; i++)
- dma_sync_single(NULL,
- fb->desc_table.dma_cpu[VINO_PAGE_RATIO * i],
- PAGE_SIZE, DMA_FROM_DEVICE);
+ dma_sync_single_for_cpu(NULL,
+ fb->desc_table.dma_cpu[VINO_PAGE_RATIO * i],
+ PAGE_SIZE, DMA_FROM_DEVICE);
}
/* Framebuffer fifo functions (need to be locked externally) */
diff --git a/linux/drivers/media/video/vivi.c b/linux/drivers/media/video/vivi.c
index e3bc2b0a3..fe39b7326 100644
--- a/linux/drivers/media/video/vivi.c
+++ b/linux/drivers/media/video/vivi.c
@@ -886,15 +886,8 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
maxh = norm_maxh();
f->fmt.pix.field = field;
- if (f->fmt.pix.height < 32)
- f->fmt.pix.height = 32;
- if (f->fmt.pix.height > maxh)
- f->fmt.pix.height = maxh;
- if (f->fmt.pix.width < 48)
- f->fmt.pix.width = 48;
- if (f->fmt.pix.width > maxw)
- f->fmt.pix.width = maxw;
- f->fmt.pix.width &= ~0x03;
+ v4l_bound_align_image(&f->fmt.pix.width, 48, maxw, 2,
+ &f->fmt.pix.height, 32, maxh, 0, 0);
f->fmt.pix.bytesperline =
(f->fmt.pix.width * fmt->depth) >> 3;
f->fmt.pix.sizeimage =
diff --git a/linux/drivers/media/video/w9968cf.c b/linux/drivers/media/video/w9968cf.c
index d51566ddc..86738d186 100644
--- a/linux/drivers/media/video/w9968cf.c
+++ b/linux/drivers/media/video/w9968cf.c
@@ -464,7 +464,7 @@ static int w9968cf_set_picture(struct w9968cf_device*, struct video_picture);
static int w9968cf_set_window(struct w9968cf_device*, struct video_window);
static int w9968cf_postprocess_frame(struct w9968cf_device*,
struct w9968cf_frame_t*);
-static int w9968cf_adjust_window_size(struct w9968cf_device*, u16* w, u16* h);
+static int w9968cf_adjust_window_size(struct w9968cf_device*, u32 *w, u32 *h);
static void w9968cf_init_framelist(struct w9968cf_device*);
static void w9968cf_push_frame(struct w9968cf_device*, u8 f_num);
static void w9968cf_pop_frame(struct w9968cf_device*,struct w9968cf_frame_t**);
@@ -1777,8 +1777,7 @@ w9968cf_set_window(struct w9968cf_device* cam, struct video_window win)
#define UNSC(x) ((x) >> 10)
/* Make sure we are using a supported resolution */
- if ((err = w9968cf_adjust_window_size(cam, (u16*)&win.width,
- (u16*)&win.height)))
+ if ((err = w9968cf_adjust_window_size(cam, &win.width, &win.height)))
goto error;
/* Scaling factors */
@@ -1928,12 +1927,9 @@ error:
Return 0 on success, -1 otherwise.
--------------------------------------------------------------------------*/
static int
-w9968cf_adjust_window_size(struct w9968cf_device* cam, u16* width, u16* height)
+w9968cf_adjust_window_size(struct w9968cf_device *cam, u32 *width, u32 *height)
{
- u16 maxw, maxh;
-
- if ((*width < cam->minwidth) || (*height < cam->minheight))
- return -ERANGE;
+ unsigned int maxw, maxh, align;
maxw = cam->upscaling && !(cam->vpp_flag & VPP_DECOMPRESSION) &&
w9968cf_vpp ? max((u16)W9968CF_MAX_WIDTH, cam->maxwidth)
@@ -1941,16 +1937,10 @@ w9968cf_adjust_window_size(struct w9968cf_device* cam, u16* width, u16* height)
maxh = cam->upscaling && !(cam->vpp_flag & VPP_DECOMPRESSION) &&
w9968cf_vpp ? max((u16)W9968CF_MAX_HEIGHT, cam->maxheight)
: cam->maxheight;
+ align = (cam->vpp_flag & VPP_DECOMPRESSION) ? 4 : 0;
- if (*width > maxw)
- *width = maxw;
- if (*height > maxh)
- *height = maxh;
-
- if (cam->vpp_flag & VPP_DECOMPRESSION) {
- *width &= ~15L; /* multiple of 16 */
- *height &= ~15L;
- }
+ v4l_bound_align_image(width, cam->minwidth, maxw, align,
+ height, cam->minheight, maxh, align, 0);
PDBGG("Window size adjusted w=%u, h=%u ", *width, *height)
@@ -3057,8 +3047,8 @@ static long w9968cf_v4l_ioctl(struct file *filp,
if (win.clipcount != 0 || win.flags != 0)
return -EINVAL;
- if ((err = w9968cf_adjust_window_size(cam, (u16*)&win.width,
- (u16*)&win.height))) {
+ if ((err = w9968cf_adjust_window_size(cam, &win.width,
+ &win.height))) {
DBG(4, "Resolution not supported (%ux%u). "
"VIDIOCSWIN failed", win.width, win.height)
return err;
@@ -3130,6 +3120,7 @@ static long w9968cf_v4l_ioctl(struct file *filp,
{
struct video_mmap mmap;
struct w9968cf_frame_t* fr;
+ u32 w, h;
int err = 0;
if (copy_from_user(&mmap, arg, sizeof(mmap)))
@@ -3178,8 +3169,10 @@ static long w9968cf_v4l_ioctl(struct file *filp,
}
}
- if ((err = w9968cf_adjust_window_size(cam, (u16*)&mmap.width,
- (u16*)&mmap.height))) {
+ w = mmap.width; h = mmap.height;
+ err = w9968cf_adjust_window_size(cam, &w, &h);
+ mmap.width = w; mmap.height = h;
+ if (err) {
DBG(4, "Resolution not supported (%dx%d). "
"VIDIOCMCAPTURE failed",
mmap.width, mmap.height)
diff --git a/linux/drivers/media/video/zoran/zoran_card.c b/linux/drivers/media/video/zoran/zoran_card.c
index 67ab10878..85f63116d 100644
--- a/linux/drivers/media/video/zoran/zoran_card.c
+++ b/linux/drivers/media/video/zoran/zoran_card.c
@@ -1478,7 +1478,7 @@ static struct pci_driver zoran_driver = {
.name = "zr36067",
.id_table = zr36067_pci_tbl,
.probe = zoran_probe,
- .remove = zoran_remove,
+ .remove = __devexit_p(zoran_remove),
};
static int __init zoran_init(void)
diff --git a/linux/drivers/media/video/zoran/zoran_driver.c b/linux/drivers/media/video/zoran/zoran_driver.c
index 793395074..8c17d47b3 100644
--- a/linux/drivers/media/video/zoran/zoran_driver.c
+++ b/linux/drivers/media/video/zoran/zoran_driver.c
@@ -2096,16 +2096,10 @@ static int zoran_try_fmt_vid_cap(struct file *file, void *__fh,
return -EINVAL;
}
- bpp = (zoran_formats[i].depth + 7) / 8;
- fmt->fmt.pix.width &= ~((bpp == 2) ? 1 : 3);
- if (fmt->fmt.pix.width > BUZ_MAX_WIDTH)
- fmt->fmt.pix.width = BUZ_MAX_WIDTH;
- if (fmt->fmt.pix.width < BUZ_MIN_WIDTH)
- fmt->fmt.pix.width = BUZ_MIN_WIDTH;
- if (fmt->fmt.pix.height > BUZ_MAX_HEIGHT)
- fmt->fmt.pix.height = BUZ_MAX_HEIGHT;
- if (fmt->fmt.pix.height < BUZ_MIN_HEIGHT)
- fmt->fmt.pix.height = BUZ_MIN_HEIGHT;
+ bpp = DIV_ROUND_UP(zoran_formats[i].depth, 8);
+ v4l_bound_align_image(
+ &fmt->fmt.pix.width, BUZ_MIN_WIDTH, BUZ_MAX_WIDTH, bpp == 2 ? 1 : 2,
+ &fmt->fmt.pix.height, BUZ_MIN_HEIGHT, BUZ_MAX_HEIGHT, 0, 0);
mutex_unlock(&zr->resource_lock);
return 0;
diff --git a/linux/drivers/media/video/zr364xx.c b/linux/drivers/media/video/zr364xx.c
index b8f47acab..8746f067d 100644
--- a/linux/drivers/media/video/zr364xx.c
+++ b/linux/drivers/media/video/zr364xx.c
@@ -883,9 +883,11 @@ static void zr364xx_disconnect(struct usb_interface *intf)
video_unregister_device(cam->vdev);
cam->vdev = NULL;
kfree(cam->buffer);
- if (cam->framebuf)
- vfree(cam->framebuf);
+ cam->buffer = NULL;
+ vfree(cam->framebuf);
+ cam->framebuf = NULL;
kfree(cam);
+ cam = NULL;
}
diff --git a/linux/include/linux/mmc/sdio_ids.h b/linux/include/linux/mmc/sdio_ids.h
index 3d7533d1e..39751c8cd 100644
--- a/linux/include/linux/mmc/sdio_ids.h
+++ b/linux/include/linux/mmc/sdio_ids.h
@@ -24,14 +24,16 @@
*/
#define SDIO_VENDOR_ID_MARVELL 0x02df
-#define SDIO_VENDOR_ID_SIANO 0x039a
-
#define SDIO_DEVICE_ID_MARVELL_LIBERTAS 0x9103
-#define SDIO_DEVICE_ID_SIANO_STELLAR 0x5347
-#define SDIO_DEVICE_ID_SIANO_NOVA_A0 0x1100
+#define SDIO_DEVICE_ID_MARVELL_8688WLAN 0x9104
+#define SDIO_DEVICE_ID_MARVELL_8688BT 0x9105
+
+#define SDIO_VENDOR_ID_SIANO 0x039a
#define SDIO_DEVICE_ID_SIANO_NOVA_B0 0x0201
#define SDIO_DEVICE_ID_SIANO_NICE 0x0202
#define SDIO_DEVICE_ID_SIANO_VEGA_A0 0x0300
#define SDIO_DEVICE_ID_SIANO_VENICE 0x0301
+#define SDIO_DEVICE_ID_SIANO_NOVA_A0 0x1100
+#define SDIO_DEVICE_ID_SIANO_STELLAR 0x5347
#endif
diff --git a/linux/include/linux/videodev2.h b/linux/include/linux/videodev2.h
index 82f9e723e..699ea62a7 100644
--- a/linux/include/linux/videodev2.h
+++ b/linux/include/linux/videodev2.h
@@ -347,7 +347,9 @@ struct v4l2_pix_format {
#define V4L2_PIX_FMT_MR97310A v4l2_fourcc('M', '3', '1', '0') /* compressed BGGR bayer */
#define V4L2_PIX_FMT_SQ905C v4l2_fourcc('9', '0', '5', 'C') /* compressed RGGB bayer */
#define V4L2_PIX_FMT_PJPG v4l2_fourcc('P', 'J', 'P', 'G') /* Pixart 73xx JPEG */
-#define V4L2_PIX_FMT_YVYU v4l2_fourcc('Y', 'V', 'Y', 'U') /* 16 YVU 4:2:2 */
+#define V4L2_PIX_FMT_YVYU v4l2_fourcc('Y', 'V', 'Y', 'U') /* 16 YVU 4:2:2 */
+#define V4L2_PIX_FMT_OV511 v4l2_fourcc('O', '5', '1', '1') /* ov511 JPEG */
+#define V4L2_PIX_FMT_OV518 v4l2_fourcc('O', '5', '1', '8') /* ov518 JPEG */
/*
* F O R M A T E N U M E R A T I O N
@@ -893,9 +895,10 @@ enum v4l2_colorfx {
V4L2_COLORFX_BW = 1,
V4L2_COLORFX_SEPIA = 2,
};
+#define V4L2_CID_AUTOBRIGHTNESS (V4L2_CID_BASE+32)
/* last CID + 1 */
-#define V4L2_CID_LASTP1 (V4L2_CID_BASE+32)
+#define V4L2_CID_LASTP1 (V4L2_CID_BASE+33)
/* MPEG-class control IDs defined by V4L2 */
#define V4L2_CID_MPEG_BASE (V4L2_CTRL_CLASS_MPEG | 0x900)
diff --git a/linux/include/media/ir-common.h b/linux/include/media/ir-common.h
index 7b5b91f60..9dcb632f6 100644
--- a/linux/include/media/ir-common.h
+++ b/linux/include/media/ir-common.h
@@ -162,6 +162,8 @@ extern IR_KEYTAB_TYPE ir_codes_ati_tv_wonder_hd_600[IR_KEYTAB_SIZE];
extern IR_KEYTAB_TYPE ir_codes_kworld_plus_tv_analog[IR_KEYTAB_SIZE];
extern IR_KEYTAB_TYPE ir_codes_kaiomy[IR_KEYTAB_SIZE];
extern IR_KEYTAB_TYPE ir_codes_dm1105_nec[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_evga_indtube[IR_KEYTAB_SIZE];
+
#endif
/*
diff --git a/linux/include/media/ir-kbd-i2c.h b/linux/include/media/ir-kbd-i2c.h
index 07963d705..93a6c933b 100644
--- a/linux/include/media/ir-kbd-i2c.h
+++ b/linux/include/media/ir-kbd-i2c.h
@@ -7,7 +7,11 @@ struct IR_i2c;
struct IR_i2c {
IR_KEYTAB_TYPE *ir_codes;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
struct i2c_client c;
+#else
+ struct i2c_client *c;
+#endif
struct input_dev *input;
struct ir_input_state ir;
@@ -15,7 +19,15 @@ struct IR_i2c {
unsigned char old;
struct delayed_work work;
+ char name[32];
char phys[32];
int (*get_key)(struct IR_i2c*, u32*, u32*);
};
+
+/* Can be passed when instantiating an ir_video i2c device */
+struct IR_i2c_init_data {
+ IR_KEYTAB_TYPE *ir_codes;
+ const char *name;
+ int (*get_key)(struct IR_i2c*, u32*, u32*);
+};
#endif
diff --git a/linux/include/media/tuner.h b/linux/include/media/tuner.h
index 735a2a941..cbf97f45f 100644
--- a/linux/include/media/tuner.h
+++ b/linux/include/media/tuner.h
@@ -125,6 +125,7 @@
#define TUNER_TCL_MF02GIP_5N 77 /* TCL MF02GIP_5N */
#define TUNER_PHILIPS_FMD1216MEX_MK3 78
#define TUNER_PHILIPS_FM1216MK5 79
+#define TUNER_PHILIPS_FQ1216LME_MK3 80 /* Active loopthrough, no FM */
/* tv card specific */
#define TDA9887_PRESENT (1<<0)
diff --git a/linux/include/media/v4l2-common.h b/linux/include/media/v4l2-common.h
index 2e1e3a293..54728d4c0 100644
--- a/linux/include/media/v4l2-common.h
+++ b/linux/include/media/v4l2-common.h
@@ -198,4 +198,14 @@ struct v4l2_routing {
u32 output;
};
+/* ------------------------------------------------------------------------- */
+
+/* Miscellaneous helper functions */
+
+void v4l_bound_align_image(unsigned int *w, unsigned int wmin,
+ unsigned int wmax, unsigned int walign,
+ unsigned int *h, unsigned int hmin,
+ unsigned int hmax, unsigned int halign,
+ unsigned int salign);
+
#endif /* V4L2_COMMON_H_ */
diff --git a/linux/include/media/v4l2-i2c-drv.h b/linux/include/media/v4l2-i2c-drv.h
index 121f0ada0..f5e4ffe27 100644
--- a/linux/include/media/v4l2-i2c-drv.h
+++ b/linux/include/media/v4l2-i2c-drv.h
@@ -22,7 +22,7 @@
*/
/* NOTE: the full version of this header is in the v4l-dvb repository
- * and allows v4l i2c drivers to be compiled on older kernels as well.
+ * and allows v4l i2c drivers to be compiled on pre-2.6.26 kernels.
* The version of this header as it appears in the kernel is a stripped
* version (without all the backwards compatibility stuff) and so it
* looks a bit odd.
@@ -30,6 +30,9 @@
* If you look at the full version then you will understand the reason
* for introducing this header since you really don't want to have all
* the tricky backwards compatibility code in each and every i2c driver.
+ *
+ * If the i2c driver will never be compiled for pre-2.6.26 kernels, then
+ * DO NOT USE this header! Just write it as a regular i2c driver.
*/
#ifndef __V4L2_I2C_DRV_H__
diff --git a/linux/sound/pci/bt87x.c b/linux/sound/pci/bt87x.c
index 11b10d70e..59e73e2b0 100644
--- a/linux/sound/pci/bt87x.c
+++ b/linux/sound/pci/bt87x.c
@@ -375,7 +375,8 @@ static struct snd_pcm_hardware snd_bt87x_digital_hw = {
.info = SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
- SNDRV_PCM_INFO_MMAP_VALID,
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_BATCH,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.rates = 0, /* set at runtime */
.channels_min = 2,
@@ -391,7 +392,8 @@ static struct snd_pcm_hardware snd_bt87x_analog_hw = {
.info = SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
- SNDRV_PCM_INFO_MMAP_VALID,
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_BATCH,
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8,
.rates = SNDRV_PCM_RATE_KNOT,
.rate_min = ANALOG_CLOCK / CLOCK_DIV_MAX,
@@ -834,6 +836,8 @@ static struct pci_device_id snd_bt87x_ids[] = {
BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x107d, 0x6606, GENERIC),
/* Voodoo TV 200 */
BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x121a, 0x3000, GENERIC),
+ /* Askey Computer Corp. MagicTView'99 */
+ BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x144f, 0x3000, GENERIC),
/* AVerMedia Studio No. 103, 203, ...? */
BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x1461, 0x0003, AVPHONE98),
/* Prolink PixelView PV-M4900 */
diff --git a/mailimport b/mailimport
index 0050a1ded..2ff60d1d8 100755
--- a/mailimport
+++ b/mailimport
@@ -186,7 +186,7 @@ proccess_patch ()
exit
fi
- cat $i| git-mailinfo $DIR/msg $DIR/patch >$DIR/author
+ cat $i| git mailinfo $DIR/msg $DIR/patch >$DIR/author
cat $DIR/msg|grep -vi ^CC: >$DIR/msg2
cat $DIR/author|perl -ne "if (m/Author[:]\\s*(.*)\\n/) { \$auth=\$1; } else \
@@ -292,9 +292,9 @@ else
^Content-Transfer-Encoding: 8bit
EOF
- echo git-mailsplit -b $DIR/tmpbox $DIR
+ echo git mailsplit -b $DIR/tmpbox $DIR
echo -n "Number of patches at file: "
- git-mailsplit -b $DIR/tmpbox $DIR
+ git mailsplit -b $DIR/tmpbox $DIR
echo
for i in $DIR/0*; do
diff --git a/v4l/compat.h b/v4l/compat.h
index 6a40e2a33..6b3504706 100644
--- a/v4l/compat.h
+++ b/v4l/compat.h
@@ -283,10 +283,14 @@ static inline int dummy_algo_control(struct i2c_adapter *adapter,
})
#endif
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 28)
+#ifdef NEED_SND_BUG_ON
#define snd_BUG_ON(cond) WARN((cond), "BUG? (%s)\n", __stringify(cond))
#endif
+#ifdef NEED_BITOPS
+#define BIT(x) (1UL<<((x)%BITS_PER_LONG))
+#endif
+
#ifndef PCI_DEVICE_ID_MARVELL_88ALP01_CCIC
#define PCI_DEVICE_ID_MARVELL_88ALP01_CCIC 0x4102
#endif
@@ -454,4 +458,20 @@ static inline int snd_card_create(int idx, const char *id,
#define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : ((1ULL<<(n))-1))
#endif
+/* __fls() was added for generic code in 2.6.29, existed for just 64-bit arches
+ * since 2.6.26 (v2.6.25-5228-g56a6b1e), and was x86-64 only before then. We
+ * only want this compat code when __fls doesn't exist, which 2.6.29 or later,
+ * non x86-64, and non 64-bit that's 2.6.26 or later. */
+#if !(LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) || \
+ defined(__x86_64__) || \
+ (BITS_PER_LONG == 64 && LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)))
+/* This define will prevent breakage if __fls was already defined. */
+#undef __fls
+#define __fls v4l_compat_fls
+static inline unsigned long v4l_compat_fls(unsigned long x)
+{
+ return fls(x) - 1;
+}
+#endif
+
#endif /* _COMPAT_H */
diff --git a/v4l/scripts/gentree.pl b/v4l/scripts/gentree.pl
index 1968bb334..b9053f464 100755..100644
--- a/v4l/scripts/gentree.pl
+++ b/v4l/scripts/gentree.pl
@@ -22,8 +22,8 @@
# If gentree knows the result of an expression, that directive will be
# "processed", otherwise it will be an "other". gentree knows the value
# of LINUX_VERSION_CODE, BTTV_VERSION_CODE, the KERNEL_VERSION(x,y,z)
-# macro, numeric constants like 0 and 1, and a few defines like MM_KERNEL
-# and STV0297_CS2.
+# macro, numeric constants like 0 and 1, and a few defines like
+# I2C_CLASS_TV_DIGITAL
#
# An exception is if the comment "/*KEEP*/" appears after the expression,
# in which case that directive will be considered an "other" and not
@@ -55,22 +55,10 @@ my %defs = (
'LINUX_VERSION_CODE' => $LINUXCODE,
'BTTV_VERSION_CODE' => $BTTVCODE,
'_COMPAT_H' => 0,
- 'MM_KERNEL' => ($extra =~ /-mm/)?1:0,
- 'BROKEN_XAWTV' => 0,
- 'STV0297_CS2' => 0,
- 'HAVE_VIDEO_BUF_DVB' => 1,
- 'I2C_PEC' => 1,
- 'I2C_DF_DUMMY' => 0,
- 'CONFIG_XC3028' => 0,
- 'HAVE_XC2028'=> 0,
- 'HAVE_XC3028' => 0,
'I2C_CLASS_TV_ANALOG' => 1,
'I2C_CLASS_TV_DIGITAL' => 1,
'OLD_XMIT_LOCK' => 0,
'COMPAT_SND_CTL_BOOLEAN_MONO' => 0,
- 'CONFIG_VIVI_SCATTER' => 0,
- 'CONFIG_BIGPHYS_AREA' => 0,
- 'BUZ_USE_HIMEM' => 1,
'NEED_SOUND_DRIVER_H' => 0,
'TTUSB_KERNEL' => 1,
'NO_PCM_LOCK' => 0,
diff --git a/v4l/scripts/make_config_compat.pl b/v4l/scripts/make_config_compat.pl
index 3c2b623ca..7c7841459 100755
--- a/v4l/scripts/make_config_compat.pl
+++ b/v4l/scripts/make_config_compat.pl
@@ -280,9 +280,7 @@ sub check_snd_card_create()
sub check_poll_schedule()
{
-
-
- my @files = ( "$kdir//include/linux/poll.h" );
+ my @files = ( "$kdir/include/linux/poll.h" );
foreach my $file ( @files ) {
open IN, "<$file" or die "File not found: $file";
@@ -300,6 +298,46 @@ sub check_poll_schedule()
$out.= "\n#define NEED_POLL_SCHEDULE 1\n";
}
+sub check_snd_BUG_ON()
+{
+ my @files = ( "$kdir/include/sound/core.h" );
+
+ foreach my $file ( @files ) {
+ open IN, "<$file" or die "File not found: $file";
+ while (<IN>) {
+ if (m/snd_BUG_ON/) {
+ close IN;
+ # definition found. No need for compat
+ return;
+ }
+ }
+ close IN;
+ }
+
+ # definition not found. This means that we need compat
+ $out.= "\n#define NEED_SND_BUG_ON 1\n";
+}
+
+sub check_bitops()
+{
+ my @files = ( "$kdir/include/linux/bitops.h" );
+
+ foreach my $file ( @files ) {
+ open IN, "<$file" or next;
+ while (<IN>) {
+ if (m/#define\s+BIT\(/) {
+ close IN;
+ # definition found. No need for compat
+ return;
+ }
+ }
+ close IN;
+ }
+
+ # definition not found. This means that we need compat
+ $out.= "\n#define NEED_BITOPS 1\n";
+}
+
sub check_other_dependencies()
{
check_spin_lock();
@@ -317,6 +355,8 @@ sub check_other_dependencies()
check_pci_ioremap_bar();
check_snd_card_create();
check_poll_schedule();
+ check_snd_BUG_ON();
+ check_bitops();
}
# Do the basic rules
diff --git a/v4l/versions.txt b/v4l/versions.txt
index eb206b520..7e8e2fa6e 100644
--- a/v4l/versions.txt
+++ b/v4l/versions.txt
@@ -5,14 +5,13 @@
# Needs defines that are only available from 2.6.29
VIDEO_PXA27x
-[2.6.28]
-USB_STV06XX
-
[2.6.26]
# Requires struct i2c_device_id
VIDEO_TVP514X
# requires id_table and new i2c stuff
RADIO_TEA5764
+VIDEO_THS7303
+VIDEO_ADV7343
[2.6.25]
# Requires gpiolib
diff --git a/v4l2-apps/libv4l/ChangeLog b/v4l2-apps/libv4l/ChangeLog
index 11f6ca2fd..e69a8c8f4 100644
--- a/v4l2-apps/libv4l/ChangeLog
+++ b/v4l2-apps/libv4l/ChangeLog
@@ -1,3 +1,73 @@
+libv4l-0.6.0
+------------
+* Recognize disabled controls and replace with fake equivalents where
+ available
+* Add support for decompressing ov511 and ov518 "JPEG", by piping data through
+ an external helper as I've failed to contact Mark W. McClelland to get
+ permission to relicense the code. If you know a working email address for
+ Mark W. McClelland, please let me know.
+* Fix a bug in the always report widths which are a multiple of 8 code added
+ in 0.5.97
+
+libv4l-0.5.99
+-------------
+* Link libv4lconvert with -lm for powf by Gregor Jasny
+* Fix black screen on devices with hardware gamma control
+* Fix crash with devices on which we do not emulate fake controls
+* Add a patch by Hans Petter Selasky <hselasky@freebsd.org>, which should
+ lead to allowing use of libv4l (and the Linux webcam drivers ported
+ to userspace usb drivers) on FreeBSD, this is a work in progress
+
+libv4l-0.5.98
+-------------
+* Add software gamma correction
+* Add software auto gain / exposure
+* Add support for separate vflipping and hflipping
+* Add fake controls controlling the software h- and v-flipping
+* Add ability to determine upside down cams based on DMI info
+* Add the capability to provide 320x240 to apps if the cam can only
+ do 320x232 (some zc3xx cams) by adding black borders
+* Rewrite video processing code to make it easier to add more video filters
+ (and with little extra processing cost). As part of this the normalize
+ filter has been removed as it wasn't functioning satisfactory anyways
+* Support V4L2_CTRL_FLAG_NEXT_CTRL for fake controls by Adam Baker
+* Some makefile improvements by Gregor Jasny
+* Various small bugfixes and tweaks
+* The V4L2_ENABLE_ENUM_FMT_EMULATION v4l2_fd_open flag is obsolete, libv4l2
+ now *always* reports emulated formats through the ENUM_FMT ioctl
+
+libv4l-0.5.97
+-------------
+* As the version number shows this is a beta release of the 0.6.x series,
+ the big change here is the addition of video processing to libv4l
+ currently this only does whitebalance and normalizing (which turns out
+ to be useless for most cams) but the basic framework for doing video
+ processing, and being able to control it through fake v4l2 controls using
+ for example v4l2ucp is there.
+ The initial version of this code was written by 3 of my computer science
+ students: Elmar Kleijn, Sjoerd Piepenbrink and Radjnies Bhansingh
+* Currently whitebalancing gets enabled based on USB-ID's and it only gets
+ enabled for Pixart webcam's. You can force it being enabled with other
+ webcams by setting the environment variable LIBV4LCONTROL_CONTROLS, this
+ sets a bitmask enabling certain v4l2 controls which control the video
+ processing set it to 15 to enable both whitebalancing and normalize. You
+ can then change the settings using a v4l2 control panel like v4l2ucp
+* Only report / allow supported destination formats in enum_fmt / try_fmt /
+ g_fmt / s_fmt when processing, rotating or flipping.
+* Some applications / libs (*cough* gstreamer *cough*) will not work
+ correctly with planar YUV formats when the width is not a multiple of 8,
+ so crop widths which are not a multiple of 8 to the nearest multiple of 8
+ when converting to planar YUV
+* Add dependency generation to libv4l by: Gilles Gigan <gilles.gigan@gmail.com>
+* Add support to use orientation from VIDIOC_ENUMINPUT by:
+ Adam Baker <linux@baker-net.org.uk>
+* sn9c20x cams have occasional bad jpeg frames, drop these to avoid the
+ flickering effect they cause, by: Brian Johnson <brijohn@gmail.com>
+* adjust libv4l's upside down cam detection to also work with devices
+ which have the usb interface as parent instead of the usb device
+* fix libv4l upside down detection for the new v4l minor numbering scheme
+* fix reading outside of the source memory when doing yuv420->rgb conversion
+
libv4l-0.5.9
------------
* Add support for MR97310A decompression by Kyle Guinn <elyk03@gmail.com>
diff --git a/v4l2-apps/libv4l/Makefile b/v4l2-apps/libv4l/Makefile
index 703f3298f..acec5c540 100644
--- a/v4l2-apps/libv4l/Makefile
+++ b/v4l2-apps/libv4l/Makefile
@@ -1,5 +1,5 @@
LIB_RELEASE=0
-V4L2_LIB_VERSION=$(LIB_RELEASE).5.9
+V4L2_LIB_VERSION=$(LIB_RELEASE).5.99
all install:
$(MAKE) -C libv4lconvert V4L2_LIB_VERSION=$(V4L2_LIB_VERSION) $@
@@ -7,7 +7,7 @@ all install:
$(MAKE) -C libv4l1 V4L2_LIB_VERSION=$(V4L2_LIB_VERSION) $@
clean:
- rm -f *~ include/*~
+ rm -f *~ include/*~ DEADJOE include/DEADJOE
$(MAKE) -C libv4lconvert V4L2_LIB_VERSION=$(V4L2_LIB_VERSION) $@
$(MAKE) -C libv4l2 V4L2_LIB_VERSION=$(V4L2_LIB_VERSION) $@
$(MAKE) -C libv4l1 V4L2_LIB_VERSION=$(V4L2_LIB_VERSION) $@
diff --git a/v4l2-apps/libv4l/README b/v4l2-apps/libv4l/README
index 3a2059224..481d5b92e 100644
--- a/v4l2-apps/libv4l/README
+++ b/v4l2-apps/libv4l/README
@@ -15,14 +15,26 @@ libv4l consists of 3 different libraries:
libv4lconvert
-------------
-libv4lconvert offers functions to convert from any (known) pixelformat
-to V4l2_PIX_FMT_BGR24 or V4l2_PIX_FMT_YUV420.
-
-Currently the following source formats are supported:
-jpeg, mjpeg, bayer (all 4 variants: bggr, rggb, gbrg, grbg),
-spca501 (chip specific yuv 420 with interlaced components),
-spca561 (chip specific compressed gbrg bayer)
-For more details on the v4lconvert_ functions see libv4lconvert.h .
+libv4lconvert started as a library to convert from any (known) pixelformat to
+V4l2_PIX_FMT_BGR24, RGB24, YUV420 or YVU420.
+
+The list of know source formats is large and continually growing, so instead
+of keeping an (almost always outdated) list here in the README, I refer you
+to the source, see the list of defines at the top of
+libv4lconvert/libv4lconvert.c for the full list.
+For more details on the v4lconvert_ functions see libv4lconvert.h.
+
+Later on libv4lconvert was expanded to also be able to do various video
+processing functions improve webcam video quality on a software basis. So
+the name no longer 100% covers the functionality. The video processing is
+split in to 2 parts, libv4lconvert/control and libv4lconvert/processing.
+
+The control part is used to offer video controls which can be used to control
+the video processing functions made available by libv4lconvert/processing.
+These controls are stored application wide (untill reboot) by using a
+persistent shared memory object.
+
+libv4lconvert/processing offers the actual video processing functionality.
libv4l1
diff --git a/v4l2-apps/libv4l/TODO b/v4l2-apps/libv4l/TODO
index debb9c78c..8f7744337 100644
--- a/v4l2-apps/libv4l/TODO
+++ b/v4l2-apps/libv4l/TODO
@@ -8,3 +8,8 @@
necessary to implement CGMBUF in the kernel for each driver.
-take the possibility of pitch != width into account everywhere
+
+-make updating of parameters happen based on time elapsed rather then
+ frames
+
+-get standardized CID for AUTOGAIN_TARGET upstream and switch to that
diff --git a/v4l2-apps/libv4l/include/libv4l1.h b/v4l2-apps/libv4l/include/libv4l1.h
index c878cc198..4ddf8efdb 100644
--- a/v4l2-apps/libv4l/include/libv4l1.h
+++ b/v4l2-apps/libv4l/include/libv4l1.h
@@ -63,7 +63,7 @@ LIBV4L_PUBLIC int v4l1_dup(int fd);
LIBV4L_PUBLIC int v4l1_ioctl (int fd, unsigned long int request, ...);
LIBV4L_PUBLIC ssize_t v4l1_read (int fd, void* buffer, size_t n);
LIBV4L_PUBLIC void *v4l1_mmap(void *start, size_t length, int prot, int flags, int fd,
- __off64_t offset);
+ int64_t offset);
LIBV4L_PUBLIC int v4l1_munmap(void *_start, size_t length);
#ifdef __cplusplus
diff --git a/v4l2-apps/libv4l/include/libv4l2.h b/v4l2-apps/libv4l/include/libv4l2.h
index b05b57cb6..7ecbb2cee 100644
--- a/v4l2-apps/libv4l/include/libv4l2.h
+++ b/v4l2-apps/libv4l/include/libv4l2.h
@@ -21,6 +21,7 @@
#include <stdio.h>
#include <unistd.h>
+#include <stdint.h>
#ifdef __cplusplus
extern "C" {
@@ -41,18 +42,12 @@ LIBV4L_PUBLIC extern FILE *v4l2_log_file;
format which is not supported by the cam, but is supported by libv4lconvert,
then the try_fmt / set_fmt will succeed as if the cam supports the format
and on dqbuf / read the data will be converted for you and returned in
- the request format.
+ the request format. enum_fmt will also report support for the formats to
+ which conversion is possible.
Another difference is that you can make v4l2_read() calls even on devices
which do not support the regular read() method.
- Note that libv4l2 normally does not interfere with enum_fmt, so enum_fmt
- will still return the actual formats the hardware supports, and not any
- formats which may be emulated on top of that. If you pass the
- V4L2_ENABLE_ENUM_FMT_EMULATION flag to v4l2_fd_open (as the v4l2convert.so
- wrapper does) then enum_fmt will also report support for the formats to
- which conversion is possible.
-
Note the device name passed to v4l2_open must be of a video4linux2 device,
if it is anything else (including a video4linux1 device), v4l2_open will
fail.
@@ -64,7 +59,7 @@ LIBV4L_PUBLIC int v4l2_dup(int fd);
LIBV4L_PUBLIC int v4l2_ioctl (int fd, unsigned long int request, ...);
LIBV4L_PUBLIC ssize_t v4l2_read (int fd, void* buffer, size_t n);
LIBV4L_PUBLIC void *v4l2_mmap(void *start, size_t length, int prot, int flags, int fd,
- __off64_t offset);
+ int64_t offset);
LIBV4L_PUBLIC int v4l2_munmap(void *_start, size_t length);
@@ -89,11 +84,14 @@ LIBV4L_PUBLIC int v4l2_get_control(int fd, int cid);
/* Flags for v4l2_fd_open's v4l2_flags argument */
-/* Disable all format conversion done by libv4l2 (reduces libv4l2 functionality
- to offering v4l2_read() even on devices which don't implement read()) */
+/* Disable all format conversion done by libv4l2, this includes the software
+ whitebalance, gamma correction, flipping, etc. libv4lconvert does. Use this
+ if you want raw frame data, but still want the additional error checks and
+ the read() emulation libv4l2 offers. */
#define V4L2_DISABLE_CONVERSION 0x01
-/* Report not only real but also emulated formats with the ENUM_FMT ioctl */
-#define V4L2_ENABLE_ENUM_FMT_EMULATION 02
+/* This flag is *OBSOLETE*, since version 0.5.98 libv4l *always* reports
+ emulated formats to ENUM_FMT, except when conversion is disabled. */
+#define V4L2_ENABLE_ENUM_FMT_EMULATION 0x02
/* v4l2_fd_open: open an already opened fd for further use through
v4l2lib and possibly modify libv4l2's default behavior through the
diff --git a/v4l2-apps/libv4l/include/libv4lconvert.h b/v4l2-apps/libv4l/include/libv4lconvert.h
index 626c43473..b274c938b 100644
--- a/v4l2-apps/libv4l/include/libv4lconvert.h
+++ b/v4l2-apps/libv4l/include/libv4lconvert.h
@@ -21,10 +21,21 @@
/* These headers are not needed by us, but by linux/videodev2.h,
which is broken on some systems and doesn't include them itself :( */
+
+#ifdef linux
#include <sys/time.h>
#include <linux/types.h>
#include <linux/ioctl.h>
+#endif
+
+#ifdef __FreeBSD__
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#endif
+
/* end broken header workaround includes */
+
#include <linux/videodev2.h>
#ifdef __cplusplus
@@ -42,18 +53,30 @@ struct v4lconvert_data;
LIBV4L_PUBLIC struct v4lconvert_data *v4lconvert_create(int fd);
LIBV4L_PUBLIC void v4lconvert_destroy(struct v4lconvert_data *data);
+/* When doing flipping / rotating / video-processing, only supported
+ destination formats can be used (as flipping / rotating / video-processing
+ is not supported on other formats). This function can be used to query
+ if that is the case. */
+LIBV4L_PUBLIC int v4lconvert_supported_dst_fmt_only(
+ struct v4lconvert_data *data);
+
/* With regards to dest_fmt just like VIDIOC_TRY_FMT, except that the try
format will succeed and return the requested V4L2_PIX_FMT_foo in dest_fmt if
the cam has a format from which v4lconvert can convert to dest_fmt.
The real format to which the cam should be set is returned through src_fmt
- when not NULL. */
+ when not NULL.
+ Note that just like the real VIDIOC_TRY_FMT this function will change the
+ dest_fmt when not supported. This includes changing it to a supported
+ destination format when trying a native format of the camera and
+ v4lconvert_supported_dst_fmt_only() returns true. */
LIBV4L_PUBLIC int v4lconvert_try_format(struct v4lconvert_data *data,
struct v4l2_format *dest_fmt, /* in / out */
struct v4l2_format *src_fmt /* out */
);
-/* Just like VIDIOC_ENUM_FMT, except that the emulated formats are added at
- the end of the list */
+/* Like VIDIOC_ENUM_FMT, but the emulated formats are added at the end of the
+ list, except if flipping / processing is active for the device, then only
+ supported destination formats are listed */
LIBV4L_PUBLIC int v4lconvert_enum_fmt(struct v4lconvert_data *data, struct v4l2_fmtdesc *fmt);
/* Is conversion necessary or can the app use the data directly? */
@@ -81,6 +104,17 @@ LIBV4L_PUBLIC int v4lconvert_enum_framesizes(struct v4lconvert_data *data,
LIBV4L_PUBLIC int v4lconvert_enum_frameintervals(struct v4lconvert_data *data,
struct v4l2_frmivalenum *frmival);
+/* Pass calls to query, get and set video controls to the libv4lcontrol class */
+LIBV4L_PUBLIC int v4lconvert_vidioc_queryctrl(struct v4lconvert_data *data,
+ void *arg);
+LIBV4L_PUBLIC int v4lconvert_vidioc_g_ctrl(struct v4lconvert_data *data,
+ void *arg);
+LIBV4L_PUBLIC int v4lconvert_vidioc_s_ctrl(struct v4lconvert_data *data,
+ void *arg);
+
+/* Is the passed in pixelformat supported as destination format ? */
+LIBV4L_PUBLIC int v4lconvert_supported_dst_format(unsigned int pixelformat);
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
diff --git a/v4l2-apps/libv4l/libv4l1/Makefile b/v4l2-apps/libv4l/libv4l1/Makefile
index 9f30cbb0f..e6d306055 100644
--- a/v4l2-apps/libv4l/libv4l1/Makefile
+++ b/v4l2-apps/libv4l/libv4l1/Makefile
@@ -13,9 +13,10 @@ INCLUDES = ../include/libv4l1.h
ifeq ($(LINKTYPE),static)
V4L1_LIB = libv4l1.a
+V4L1_DEPS = $(V4L1_OBJS)
else
V4L1_LIB = libv4l1.so
-V4L1_OBJS += ../libv4l2/libv4l2.so
+V4L1_DEPS += $(V4L1_OBJS) ../libv4l2/libv4l2.so
TARGETS += $(V4L1COMPAT)
override CPPFLAGS += -fPIC
endif
@@ -34,8 +35,9 @@ endif
all: $(TARGETS)
+-include $(V4L1_OBJS:.o=.d)
-$(V4L1_LIB): $(V4L1_OBJS)
+$(V4L1_LIB): $(V4L1_DEPS)
$(V4L1COMPAT): $(V4L1COMPAT_O) $(V4L1_LIB)
@@ -69,10 +71,10 @@ endif
install -m 644 libv4l1.pc $(DESTDIR)$(LIBDIR)/pkgconfig
clean::
- rm -f *.a *.so* *.o *.d libv4l1.pc log *~ *.orig *.rej
+ rm -f *.a *.so* *.o *.d libv4l1.pc log *~ *.orig *.rej DEADJOE
%.o: %.c
- $(CC) -c -MMD $(CPPFLAGS) $(CFLAGS) -o $@ $<
+ $(CC) -Wp,-MMD,"$*.d",-MQ,"$@",-MP -c $(CPPFLAGS) $(CFLAGS) -o $@ $<
%.so:
$(CC) -shared $(LDFLAGS) -Wl,-soname,$@.$(LIB_RELEASE) -o $@.$(LIB_RELEASE) $^ $(LIBS_$*)
diff --git a/v4l2-apps/libv4l/libv4l1/libv4l1-priv.h b/v4l2-apps/libv4l/libv4l1/libv4l1-priv.h
index 651599255..370686b3a 100644
--- a/v4l2-apps/libv4l/libv4l1/libv4l1-priv.h
+++ b/v4l2-apps/libv4l/libv4l1/libv4l1-priv.h
@@ -22,14 +22,7 @@
#include <stdio.h>
#include <pthread.h>
-/* On 32 bits archs we always use mmap2, on 64 bits archs there is no mmap2 */
-#ifdef __NR_mmap2
-#define SYS_mmap2 __NR_mmap2
-#define MMAP2_PAGE_SHIFT 12
-#else
-#define SYS_mmap2 SYS_mmap
-#define MMAP2_PAGE_SHIFT 0
-#endif
+#include "../libv4lconvert/libv4lsyscall-priv.h"
#define V4L1_MAX_DEVICES 16
#define V4L1_NO_FRAMES 4
diff --git a/v4l2-apps/libv4l/libv4l1/libv4l1.c b/v4l2-apps/libv4l/libv4l1/libv4l1.c
index 797c8768a..9b23926be 100644
--- a/v4l2-apps/libv4l/libv4l1/libv4l1.c
+++ b/v4l2-apps/libv4l/libv4l1/libv4l1.c
@@ -44,18 +44,12 @@
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
-#include <syscall.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/mman.h>
-/* These headers are not needed by us, but by linux/videodev2.h,
- which is broken on some systems and doesn't include them itself :( */
-#include <sys/time.h>
-#include <asm/types.h>
-#include <linux/ioctl.h>
-/* end broken header workaround includes */
+#include "../libv4lconvert/libv4lsyscall-priv.h"
#include <linux/videodev.h>
#include <linux/videodev2.h>
#include <libv4l2.h>
@@ -155,8 +149,10 @@ static int v4l1_set_format(int index, unsigned int width,
/* Do we need to change the resolution / format ? */
if (width == devices[index].width && height == devices[index].height &&
- v4l2_pixfmt == devices[index].v4l2_pixfmt)
+ v4l2_pixfmt == devices[index].v4l2_pixfmt) {
+ devices[index].v4l1_pal = v4l1_pal;
return 0;
+ }
/* Get current settings, apply our changes and try the new setting */
if ((result = v4l2_ioctl(devices[index].fd, VIDIOC_G_FMT, &fmt2))) {
@@ -223,14 +219,14 @@ static void v4l1_find_min_and_max_size(int index, struct v4l2_format *fmt2)
for (i = 0; ; i++) {
fmtdesc2.index = i;
- if (syscall(SYS_ioctl, devices[index].fd, VIDIOC_ENUM_FMT, &fmtdesc2))
+ if (v4l2_ioctl(devices[index].fd, VIDIOC_ENUM_FMT, &fmtdesc2))
break;
fmt2->fmt.pix.pixelformat = fmtdesc2.pixelformat;
fmt2->fmt.pix.width = 48;
fmt2->fmt.pix.height = 32;
- if (syscall(SYS_ioctl, devices[index].fd, VIDIOC_TRY_FMT, fmt2) == 0) {
+ if (v4l2_ioctl(devices[index].fd, VIDIOC_TRY_FMT, fmt2) == 0) {
if (fmt2->fmt.pix.width < devices[index].min_width)
devices[index].min_width = fmt2->fmt.pix.width;
if (fmt2->fmt.pix.height < devices[index].min_height)
@@ -241,7 +237,7 @@ static void v4l1_find_min_and_max_size(int index, struct v4l2_format *fmt2)
fmt2->fmt.pix.width = 100000;
fmt2->fmt.pix.height = 100000;
- if (syscall(SYS_ioctl, devices[index].fd, VIDIOC_TRY_FMT, fmt2) == 0) {
+ if (v4l2_ioctl(devices[index].fd, VIDIOC_TRY_FMT, fmt2) == 0) {
if (fmt2->fmt.pix.width > devices[index].max_width)
devices[index].max_width = fmt2->fmt.pix.width;
if (fmt2->fmt.pix.height > devices[index].max_height)
@@ -278,11 +274,12 @@ int v4l1_open (const char *file, int oflag, ...)
va_start (ap, oflag);
mode = va_arg (ap, mode_t);
- fd = syscall(SYS_open, file, oflag, mode);
+ fd = SYS_OPEN(file, oflag, mode);
va_end(ap);
} else
- fd = syscall(SYS_open, file, oflag);
+ fd = SYS_OPEN(file, oflag, 0);
+
/* end of original open code */
if (fd == -1 || !v4l_device)
@@ -290,7 +287,7 @@ int v4l1_open (const char *file, int oflag, ...)
/* check that this is an v4l2 device, no need to emulate v4l1 on
a v4l1 device */
- if (syscall(SYS_ioctl, fd, VIDIOC_QUERYCAP, &cap2))
+ if (SYS_IOCTL(fd, VIDIOC_QUERYCAP, &cap2))
return fd;
/* IMPROVEME */
@@ -308,21 +305,20 @@ int v4l1_open (const char *file, int oflag, ...)
if (!v4l2_log_file)
v4l2_log_file = v4l1_log_file;
- /* Get initial width, height and pixelformat */
- fmt2.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- if (syscall(SYS_ioctl, fd, VIDIOC_G_FMT, &fmt2)) {
+ /* Register with libv4l2, as we use that todo format conversion and read()
+ emulation for us */
+ if (v4l2_fd_open(fd, 0) == -1) {
int saved_err = errno;
- V4L1_LOG_ERR("getting pixformat: %s\n", strerror(errno));
- syscall(SYS_close, fd);
+ SYS_CLOSE(fd);
errno = saved_err;
return -1;
}
- /* Register with libv4l2, as we use that todo format conversion and read()
- emulation for us */
- if (v4l2_fd_open(fd, V4L2_ENABLE_ENUM_FMT_EMULATION) == -1) {
+ /* Get initial width, height and pixelformat */
+ fmt2.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ if (v4l2_ioctl(fd, VIDIOC_G_FMT, &fmt2)) {
int saved_err = errno;
- syscall(SYS_close, fd);
+ SYS_CLOSE(fd);
errno = saved_err;
return -1;
}
@@ -399,7 +395,7 @@ int v4l1_close(int fd) {
int index, result;
if ((index = v4l1_get_index(fd)) == -1)
- return syscall(SYS_close, fd);
+ return SYS_CLOSE(fd);
/* Abuse stream_lock to stop 2 closes from racing and trying to free the
resources twice */
@@ -417,7 +413,7 @@ int v4l1_close(int fd) {
V4L1_LOG("v4l1 capture buffer still mapped: %d times on close()\n",
devices[index].v4l1_frame_buf_map_count);
else
- syscall(SYS_munmap, devices[index].v4l1_frame_pointer,
+ SYS_MUNMAP(devices[index].v4l1_frame_pointer,
V4L1_NO_FRAMES * V4L1_FRAME_BUF_SIZE);
devices[index].v4l1_frame_pointer = MAP_FAILED;
}
@@ -446,7 +442,6 @@ int v4l1_dup(int fd)
return v4l2_dup(fd);
}
-
int v4l1_ioctl (int fd, unsigned long int request, ...)
{
void *arg;
@@ -458,7 +453,7 @@ int v4l1_ioctl (int fd, unsigned long int request, ...)
va_end (ap);
if ((index = v4l1_get_index(fd)) == -1)
- return syscall(SYS_ioctl, fd, request, arg);
+ return SYS_IOCTL(fd, request, arg);
/* Appearantly the kernel and / or glibc ignore the 32 most significant bits
when long = 64 bits, and some applications pass an int holding the req to
@@ -485,7 +480,7 @@ int v4l1_ioctl (int fd, unsigned long int request, ...)
{
struct video_capability *cap = arg;
- result = syscall(SYS_ioctl, fd, request, arg);
+ result = SYS_IOCTL(fd, request, arg);
/* override kernel v4l1 compat min / max size with our own more
accurate values */
@@ -547,24 +542,27 @@ int v4l1_ioctl (int fd, unsigned long int request, ...)
break;
case VIDIOCSWIN:
+ case VIDIOCGWIN:
{
struct video_window *win = arg;
devices[index].flags |= V4L1_PIX_SIZE_TOUCHED;
- result = v4l1_set_format(index, win->width, win->height, -1, 1);
+ if (request == VIDIOCSWIN)
+ result = v4l1_set_format(index, win->width, win->height, -1, 1);
+ else
+ result = 0;
+
if (result == 0) {
+ win->x = 0;
+ win->y = 0;
win->width = devices[index].width;
win->height = devices[index].height;
+ win->flags = 0;
}
}
break;
- case VIDIOCGWIN:
- devices[index].flags |= V4L1_PIX_SIZE_TOUCHED;
- result = syscall(SYS_ioctl, fd, request, arg);
- break;
-
case VIDIOCGCHAN:
{
struct v4l2_input input2;
@@ -572,7 +570,7 @@ int v4l1_ioctl (int fd, unsigned long int request, ...)
if ((devices[index].flags & V4L1_SUPPORTS_ENUMINPUT) &&
(devices[index].flags & V4L1_SUPPORTS_ENUMSTD)) {
- result = syscall(SYS_ioctl, fd, request, arg);
+ result = SYS_IOCTL(fd, request, arg);
break;
}
@@ -614,7 +612,7 @@ int v4l1_ioctl (int fd, unsigned long int request, ...)
struct video_channel *chan = arg;
if ((devices[index].flags & V4L1_SUPPORTS_ENUMINPUT) &&
(devices[index].flags & V4L1_SUPPORTS_ENUMSTD)) {
- result = syscall(SYS_ioctl, fd, request, arg);
+ result = SYS_IOCTL(fd, request, arg);
break;
}
/* In case of no ENUMSTD support, ignore the norm member of the
@@ -650,7 +648,7 @@ int v4l1_ioctl (int fd, unsigned long int request, ...)
}
if (devices[index].v4l1_frame_pointer == MAP_FAILED) {
- devices[index].v4l1_frame_pointer = (void *)syscall(SYS_mmap2, NULL,
+ devices[index].v4l1_frame_pointer = (void *)SYS_MMAP(NULL,
(size_t)mbuf->size,
PROT_READ|PROT_WRITE,
MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
@@ -747,7 +745,7 @@ ssize_t v4l1_read(int fd, void* buffer, size_t n)
ssize_t result;
if ((index = v4l1_get_index(fd)) == -1)
- return syscall(SYS_read, fd, buffer, n);
+ return SYS_READ(fd, buffer, n);
pthread_mutex_lock(&devices[index].stream_lock);
result = v4l2_read(fd, buffer, n);
@@ -758,7 +756,7 @@ ssize_t v4l1_read(int fd, void* buffer, size_t n)
void *v4l1_mmap(void *start, size_t length, int prot, int flags, int fd,
- __off64_t offset)
+ int64_t offset)
{
int index;
void *result;
diff --git a/v4l2-apps/libv4l/libv4l1/log.c b/v4l2-apps/libv4l/libv4l1/log.c
index 9ff0cea46..fd095817f 100644
--- a/v4l2-apps/libv4l/libv4l1/log.c
+++ b/v4l2-apps/libv4l/libv4l1/log.c
@@ -18,12 +18,7 @@
#include <stdio.h>
#include <stdlib.h>
-#include <linux/ioctl.h>
-/* These headers are not needed by us, but by linux/videodev2.h,
- which is broken on some systems and doesn't include them itself :( */
-#include <sys/time.h>
-#include <asm/types.h>
-/* end broken header workaround includes */
+#include "../libv4lconvert/libv4lsyscall-priv.h"
#include <linux/videodev.h>
#include "libv4l1-priv.h"
diff --git a/v4l2-apps/libv4l/libv4l1/v4l1compat.c b/v4l2-apps/libv4l/libv4l1/v4l1compat.c
index e4293d2f9..704ec22dd 100644
--- a/v4l2-apps/libv4l/libv4l1/v4l1compat.c
+++ b/v4l2-apps/libv4l/libv4l1/v4l1compat.c
@@ -25,6 +25,7 @@
#include <stdarg.h>
#include <fcntl.h>
#include <libv4l1.h>
+#include "../libv4lconvert/libv4lsyscall-priv.h" /* for __off_t */
#include <sys/ioctl.h>
#include <sys/mman.h>
@@ -61,6 +62,7 @@ LIBV4L_PUBLIC int open (const char *file, int oflag, ...)
return fd;
}
+#ifdef linux
LIBV4L_PUBLIC int open64 (const char *file, int oflag, ...)
{
int fd;
@@ -81,6 +83,7 @@ LIBV4L_PUBLIC int open64 (const char *file, int oflag, ...)
return fd;
}
+#endif
LIBV4L_PUBLIC int close(int fd) {
return v4l1_close(fd);
@@ -114,11 +117,13 @@ LIBV4L_PUBLIC void *mmap(void *start, size_t length, int prot, int flags, int fd
return v4l1_mmap(start, length, prot, flags, fd, offset);
}
+#ifdef linux
LIBV4L_PUBLIC void *mmap64(void *start, size_t length, int prot, int flags, int fd,
__off64_t offset)
{
return v4l1_mmap(start, length, prot, flags, fd, offset);
}
+#endif
LIBV4L_PUBLIC int munmap(void *start, size_t length)
{
diff --git a/v4l2-apps/libv4l/libv4l2/Makefile b/v4l2-apps/libv4l/libv4l2/Makefile
index 614b36cf8..06c010f3c 100644
--- a/v4l2-apps/libv4l/libv4l2/Makefile
+++ b/v4l2-apps/libv4l/libv4l2/Makefile
@@ -13,9 +13,10 @@ INCLUDES = ../include/libv4l2.h
ifeq ($(LINKTYPE),static)
V4L2_LIB = libv4l2.a
+V4L2_DEPS = $(V4L2_OBJS)
else
V4L2_LIB = libv4l2.so
-V4L2_OBJS += ../libv4lconvert/libv4lconvert.so
+V4L2_DEPS += $(V4L2_OBJS) ../libv4lconvert/libv4lconvert.so
TARGETS += $(V4L2CONVERT)
override CPPFLAGS += -fPIC
endif
@@ -34,7 +35,9 @@ endif
all: $(TARGETS)
-$(V4L2_LIB): $(V4L2_OBJS)
+-include $(V4L2_OBJS:.o=.d)
+
+$(V4L2_LIB): $(V4L2_DEPS)
$(V4L2CONVERT): $(V4L2CONVERT_O) $(V4L2_LIB)
@@ -68,10 +71,10 @@ endif
install -m 644 libv4l2.pc $(DESTDIR)$(LIBDIR)/pkgconfig
clean::
- rm -f *.a *.so* *.o *.d libv4l2.pc log *~ *.orig *.rej
+ rm -f *.a *.so* *.o *.d libv4l2.pc log *~ *.orig *.rej DEADJOE
%.o: %.c
- $(CC) -c -MMD $(CPPFLAGS) $(CFLAGS) -o $@ $<
+ $(CC) -Wp,-MMD,"$*.d",-MQ,"$@",-MP -c $(CPPFLAGS) $(CFLAGS) -o $@ $<
%.so:
$(CC) -shared $(LDFLAGS) -Wl,-soname,$@.$(LIB_RELEASE) -o $@.$(LIB_RELEASE) $^ $(LIBS_$*)
@@ -79,4 +82,3 @@ clean::
%.a:
$(AR) cqs $@ $^
-
diff --git a/v4l2-apps/libv4l/libv4l2/libv4l2-priv.h b/v4l2-apps/libv4l/libv4l2/libv4l2-priv.h
index 8724832e1..0bfd53e2a 100644
--- a/v4l2-apps/libv4l/libv4l2/libv4l2-priv.h
+++ b/v4l2-apps/libv4l/libv4l2/libv4l2-priv.h
@@ -23,14 +23,7 @@
#include <pthread.h>
#include <libv4lconvert.h> /* includes videodev2.h for us */
-/* On 32 bits archs we always use mmap2, on 64 bits archs there is no mmap2 */
-#ifdef __NR_mmap2
-#define SYS_mmap2 __NR_mmap2
-#define MMAP2_PAGE_SHIFT 12
-#else
-#define SYS_mmap2 SYS_mmap
-#define MMAP2_PAGE_SHIFT 0
-#endif
+#include "../libv4lconvert/libv4lsyscall-priv.h"
#define V4L2_MAX_DEVICES 16
/* Warning when making this larger the frame_queued and frame_mapped members of
diff --git a/v4l2-apps/libv4l/libv4l2/libv4l2.c b/v4l2-apps/libv4l/libv4l2/libv4l2.c
index b6ddef6e8..b71c9b4c6 100644
--- a/v4l2-apps/libv4l/libv4l2/libv4l2.c
+++ b/v4l2-apps/libv4l/libv4l2/libv4l2.c
@@ -59,7 +59,6 @@
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
-#include <syscall.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
@@ -77,6 +76,7 @@
#define V4L2_STREAM_CONTROLLED_BY_READ 0x0400
#define V4L2_SUPPORTS_READ 0x0800
#define V4L2_IS_UVC 0x1000
+#define V4L2_STREAM_TOUCHED 0x2000
#define V4L2_MMAP_OFFSET_MAGIC 0xABCDEF00u
@@ -99,7 +99,7 @@ static int v4l2_request_read_buffers(int index)
devices[index].nreadbuffers;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
- if ((result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_REQBUFS, &req)) < 0){
+ if ((result = SYS_IOCTL(devices[index].fd, VIDIOC_REQBUFS, &req)) < 0){
int saved_err = errno;
V4L2_LOG_ERR("requesting %u buffers: %s\n", req.count, strerror(errno));
errno = saved_err;
@@ -126,7 +126,7 @@ static void v4l2_unrequest_read_buffers(int index)
req.count = 0;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
- if(syscall(SYS_ioctl, devices[index].fd, VIDIOC_REQBUFS, &req) < 0)
+ if(SYS_IOCTL(devices[index].fd, VIDIOC_REQBUFS, &req) < 0)
return;
devices[index].no_frames = MIN(req.count, V4L2_MAX_NO_FRAMES);
@@ -147,7 +147,7 @@ static int v4l2_map_buffers(int index)
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = i;
- result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_QUERYBUF, &buf);
+ result = SYS_IOCTL(devices[index].fd, VIDIOC_QUERYBUF, &buf);
if (result) {
int saved_err = errno;
V4L2_LOG_ERR("querying buffer %u: %s\n", i, strerror(errno));
@@ -155,9 +155,9 @@ static int v4l2_map_buffers(int index)
break;
}
- devices[index].frame_pointers[i] = (void *)syscall(SYS_mmap2, NULL,
+ devices[index].frame_pointers[i] = (void *)SYS_MMAP(NULL,
(size_t)buf.length, PROT_READ|PROT_WRITE, MAP_SHARED, devices[index].fd,
- (__off_t)(buf.m.offset >> MMAP2_PAGE_SHIFT));
+ buf.m.offset);
if (devices[index].frame_pointers[i] == MAP_FAILED) {
int saved_err = errno;
V4L2_LOG_ERR("mmapping buffer %u: %s\n", i, strerror(errno));
@@ -181,7 +181,7 @@ static void v4l2_unmap_buffers(int index)
/* unmap the buffers */
for (i = 0; i < devices[index].no_frames; i++) {
if (devices[index].frame_pointers[i] != MAP_FAILED) {
- syscall(SYS_munmap, devices[index].frame_pointers[i],
+ SYS_MUNMAP(devices[index].frame_pointers[i],
devices[index].frame_sizes[i]);
devices[index].frame_pointers[i] = MAP_FAILED;
V4L2_LOG("unmapped buffer %u\n", i);
@@ -195,7 +195,7 @@ static int v4l2_streamon(int index)
enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (!(devices[index].flags & V4L2_STREAMON)) {
- if ((result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_STREAMON,
+ if ((result = SYS_IOCTL(devices[index].fd, VIDIOC_STREAMON,
&type))) {
int saved_err = errno;
V4L2_LOG_ERR("turning on stream: %s\n", strerror(errno));
@@ -214,7 +214,7 @@ static int v4l2_streamoff(int index)
enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (devices[index].flags & V4L2_STREAMON) {
- if ((result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_STREAMOFF,
+ if ((result = SYS_IOCTL(devices[index].fd, VIDIOC_STREAMOFF,
&type))) {
int saved_err = errno;
V4L2_LOG_ERR("turning off stream: %s\n", strerror(errno));
@@ -242,7 +242,7 @@ static int v4l2_queue_read_buffer(int index, int buffer_index)
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = buffer_index;
- if ((result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_QBUF, &buf))) {
+ if ((result = SYS_IOCTL(devices[index].fd, VIDIOC_QBUF, &buf))) {
int saved_err = errno;
V4L2_LOG_ERR("queuing buf %d: %s\n", buffer_index, strerror(errno));
errno = saved_err;
@@ -264,7 +264,7 @@ static int v4l2_dequeue_and_convert(int index, struct v4l2_buffer *buf,
return result;
do {
- if ((result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_DQBUF, buf))) {
+ if ((result = SYS_IOCTL(devices[index].fd, VIDIOC_DQBUF, buf))) {
if (errno != EAGAIN) {
int saved_err = errno;
V4L2_LOG_ERR("dequeuing buf: %s\n", strerror(errno));
@@ -364,12 +364,20 @@ static int v4l2_deactivate_read_stream(int index)
return 0;
}
+static int v4l2_needs_conversion(int index)
+{
+ if (!(devices[index].flags & V4L2_DISABLE_CONVERSION))
+ return v4lconvert_needs_conversion(devices[index].convert,
+ &devices[index].src_fmt, &devices[index].dest_fmt);
+
+ return 0;
+}
+
static int v4l2_buffers_mapped(int index)
{
unsigned int i;
- if (devices[index].src_fmt.fmt.pix.pixelformat ==
- devices[index].dest_fmt.fmt.pix.pixelformat) {
+ if (!v4l2_needs_conversion(index)) {
/* Normal (no conversion) mode */
struct v4l2_buffer buf;
@@ -377,7 +385,7 @@ static int v4l2_buffers_mapped(int index)
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = i;
- if (syscall(SYS_ioctl, devices[index].fd, VIDIOC_QUERYBUF, &buf)) {
+ if (SYS_IOCTL(devices[index].fd, VIDIOC_QUERYBUF, &buf)) {
int saved_err = errno;
V4L2_LOG_ERR("querying buffer %u: %s\n", i, strerror(errno));
errno = saved_err;
@@ -413,12 +421,12 @@ int v4l2_open (const char *file, int oflag, ...)
va_start (ap, oflag);
mode = va_arg (ap, mode_t);
- fd = syscall(SYS_open, file, oflag, mode);
+ fd = SYS_OPEN(file, oflag, mode);
va_end(ap);
}
else
- fd = syscall(SYS_open, file, oflag);
+ fd = SYS_OPEN(file, oflag, 0);
/* end of original open code */
if (fd == -1)
@@ -426,7 +434,7 @@ int v4l2_open (const char *file, int oflag, ...)
if (v4l2_fd_open(fd, 0) == -1) {
int saved_err = errno;
- syscall(SYS_close, fd);
+ SYS_CLOSE(fd);
errno = saved_err;
return -1;
}
@@ -448,7 +456,7 @@ int v4l2_fd_open(int fd, int v4l2_flags)
v4l2_log_file = fopen(lfname, "w");
/* check that this is an v4l2 device */
- if (syscall(SYS_ioctl, fd, VIDIOC_QUERYCAP, &cap)) {
+ if (SYS_IOCTL(fd, VIDIOC_QUERYCAP, &cap)) {
int saved_err = errno;
V4L2_LOG_ERR("getting capabilities: %s\n", strerror(errno));
errno = saved_err;
@@ -463,7 +471,7 @@ int v4l2_fd_open(int fd, int v4l2_flags)
/* Get current cam format */
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- if (syscall(SYS_ioctl, fd, VIDIOC_G_FMT, &fmt)) {
+ if (SYS_IOCTL(fd, VIDIOC_G_FMT, &fmt)) {
int saved_err = errno;
V4L2_LOG_ERR("getting pixformat: %s\n", strerror(errno));
errno = saved_err;
@@ -499,6 +507,16 @@ int v4l2_fd_open(int fd, int v4l2_flags)
devices[index].src_fmt = fmt;
devices[index].dest_fmt = fmt;
+ /* When a user does a try_fmt with the current dest_fmt and the dest_fmt
+ is a supported one we will align the resulution (see try_fmt for why).
+ Do the same here now, so that a try_fmt on the result of a get_fmt done
+ immediately after open leaves the fmt unchanged. */
+ if (v4lconvert_supported_dst_format(
+ devices[index].dest_fmt.fmt.pix.pixelformat)) {
+ devices[index].dest_fmt.fmt.pix.width &= ~7;
+ devices[index].dest_fmt.fmt.pix.height &= ~1;
+ }
+
pthread_mutex_init(&devices[index].stream_lock, NULL);
devices[index].no_frames = 0;
@@ -544,7 +562,7 @@ int v4l2_close(int fd)
int index, result;
if ((index = v4l2_get_index(fd)) == -1)
- return syscall(SYS_close, fd);
+ return SYS_CLOSE(fd);
/* Abuse stream_lock to stop 2 closes from racing and trying to free the
resources twice */
@@ -558,15 +576,15 @@ int v4l2_close(int fd)
/* Free resources */
v4l2_unmap_buffers(index);
- v4lconvert_destroy(devices[index].convert);
if (devices[index].convert_mmap_buf != MAP_FAILED) {
if (v4l2_buffers_mapped(index))
V4L2_LOG_WARN("v4l2 mmap buffers still mapped on close()\n");
else
- syscall(SYS_munmap, devices[index].convert_mmap_buf,
+ SYS_MUNMAP(devices[index].convert_mmap_buf,
devices[index].no_frames * V4L2_FRAME_BUF_SIZE);
devices[index].convert_mmap_buf = MAP_FAILED;
}
+ v4lconvert_destroy(devices[index].convert);
/* Remove the fd from our list of managed fds before closing it, because as
soon as we've done the actual close the fd maybe returned by an open in
@@ -576,7 +594,7 @@ int v4l2_close(int fd)
/* Since we've marked the fd as no longer used, and freed the resources,
redo the close in case it was interrupted */
do {
- result = syscall(SYS_close, fd);
+ result = SYS_CLOSE(fd);
} while (result == -1 && errno == EINTR);
V4L2_LOG("close: %d\n", fd);
@@ -613,7 +631,7 @@ static int v4l2_check_buffer_change_ok(int index)
/* We may change from convert to non conversion mode and
v4l2_unrequest_read_buffers may change the no_frames, so free the
convert mmap buffer */
- syscall(SYS_munmap, devices[index].convert_mmap_buf,
+ SYS_MUNMAP(devices[index].convert_mmap_buf,
devices[index].no_frames * V4L2_FRAME_BUF_SIZE);
devices[index].convert_mmap_buf = MAP_FAILED;
@@ -659,7 +677,7 @@ int v4l2_ioctl (int fd, unsigned long int request, ...)
{
void *arg;
va_list ap;
- int result, converting, index, saved_err;
+ int result, index, saved_err;
int is_capture_request = 0, stream_needs_locking = 0;
va_start (ap, request);
@@ -667,7 +685,7 @@ int v4l2_ioctl (int fd, unsigned long int request, ...)
va_end (ap);
if ((index = v4l2_get_index(fd)) == -1)
- return syscall(SYS_ioctl, fd, request, arg);
+ return SYS_IOCTL(fd, request, arg);
/* Appearantly the kernel and / or glibc ignore the 32 most significant bits
when long = 64 bits, and some applications pass an int holding the req to
@@ -676,21 +694,28 @@ int v4l2_ioctl (int fd, unsigned long int request, ...)
/* Is this a capture request and do we need to take the stream lock? */
switch (request) {
+ case VIDIOC_QUERYCTRL:
+ case VIDIOC_G_CTRL:
+ case VIDIOC_S_CTRL:
+ if (!(devices[index].flags & V4L2_DISABLE_CONVERSION))
+ is_capture_request = 1;
+ break;
case VIDIOC_QUERYCAP:
is_capture_request = 1;
break;
case VIDIOC_ENUM_FMT:
if (((struct v4l2_fmtdesc *)arg)->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
- (devices[index].flags & V4L2_ENABLE_ENUM_FMT_EMULATION))
+ !(devices[index].flags & V4L2_DISABLE_CONVERSION))
is_capture_request = 1;
break;
case VIDIOC_ENUM_FRAMESIZES:
case VIDIOC_ENUM_FRAMEINTERVALS:
- if (devices[index].flags & V4L2_ENABLE_ENUM_FMT_EMULATION)
+ if (!(devices[index].flags & V4L2_DISABLE_CONVERSION))
is_capture_request = 1;
break;
case VIDIOC_TRY_FMT:
- if (((struct v4l2_format *)arg)->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ if (((struct v4l2_format *)arg)->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+ !(devices[index].flags & V4L2_DISABLE_CONVERSION))
is_capture_request = 1;
break;
case VIDIOC_S_FMT:
@@ -724,7 +749,7 @@ int v4l2_ioctl (int fd, unsigned long int request, ...)
}
if (!is_capture_request) {
- result = syscall(SYS_ioctl, fd, request, arg);
+ result = SYS_IOCTL(fd, request, arg);
saved_err = errno;
v4l2_log_ioctl(request, arg, result);
errno = saved_err;
@@ -732,18 +757,48 @@ int v4l2_ioctl (int fd, unsigned long int request, ...)
}
- if (stream_needs_locking)
+ if (stream_needs_locking) {
pthread_mutex_lock(&devices[index].stream_lock);
-
- converting = v4lconvert_needs_conversion(devices[index].convert,
- &devices[index].src_fmt, &devices[index].dest_fmt);
+ /* If this is the first stream related ioctl, and we should only allow
+ libv4lconvert supported destination formats (so that it can do flipping,
+ processing, etc.) and the current destination format is not supported,
+ try setting the format to RGB24 (which is a supported dest. format). */
+ if (!(devices[index].flags & V4L2_STREAM_TOUCHED) &&
+ !(devices[index].flags & V4L2_DISABLE_CONVERSION) &&
+ v4lconvert_supported_dst_fmt_only(devices[index].convert) &&
+ !v4lconvert_supported_dst_format(
+ devices[index].dest_fmt.fmt.pix.pixelformat)) {
+ struct v4l2_format fmt = devices[index].dest_fmt;
+
+ V4L2_LOG("Setting pixelformat to RGB24 (supported_dst_fmt_only)");
+ devices[index].flags |= V4L2_STREAM_TOUCHED;
+ fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24;
+ pthread_mutex_unlock(&devices[index].stream_lock);
+ v4l2_ioctl(fd, VIDIOC_S_FMT, &fmt);
+ pthread_mutex_lock(&devices[index].stream_lock);
+ V4L2_LOG("Done setting pixelformat (supported_dst_fmt_only)");
+ }
+ devices[index].flags |= V4L2_STREAM_TOUCHED;
+ }
switch (request) {
+ case VIDIOC_QUERYCTRL:
+ result = v4lconvert_vidioc_queryctrl(devices[index].convert, arg);
+ break;
+
+ case VIDIOC_G_CTRL:
+ result = v4lconvert_vidioc_g_ctrl(devices[index].convert, arg);
+ break;
+
+ case VIDIOC_S_CTRL:
+ result = v4lconvert_vidioc_s_ctrl(devices[index].convert, arg);
+ break;
+
case VIDIOC_QUERYCAP:
{
struct v4l2_capability *cap = arg;
- result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_QUERYCAP, cap);
+ result = SYS_IOCTL(devices[index].fd, VIDIOC_QUERYCAP, cap);
if (result == 0)
/* We always support read() as we fake it using mmap mode */
cap->capabilities |= V4L2_CAP_READWRITE;
@@ -794,7 +849,7 @@ int v4l2_ioctl (int fd, unsigned long int request, ...)
}
if (devices[index].flags & V4L2_DISABLE_CONVERSION) {
- result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_TRY_FMT,
+ result = SYS_IOCTL(devices[index].fd, VIDIOC_TRY_FMT,
dest_fmt);
src_fmt = *dest_fmt;
} else {
@@ -834,7 +889,7 @@ int v4l2_ioctl (int fd, unsigned long int request, ...)
break;
req_pix_fmt = src_fmt.fmt.pix;
- result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_S_FMT, &src_fmt);
+ result = SYS_IOCTL(devices[index].fd, VIDIOC_S_FMT, &src_fmt);
if (result) {
saved_err = errno;
V4L2_LOG_ERR("setting pixformat: %s\n", strerror(errno));
@@ -884,7 +939,7 @@ int v4l2_ioctl (int fd, unsigned long int request, ...)
if (req->count > V4L2_MAX_NO_FRAMES)
req->count = V4L2_MAX_NO_FRAMES;
- result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_REQBUFS, req);
+ result = SYS_IOCTL(devices[index].fd, VIDIOC_REQBUFS, req);
if (result < 0)
break;
result = 0; /* some drivers return the number of buffers on success */
@@ -904,8 +959,8 @@ int v4l2_ioctl (int fd, unsigned long int request, ...)
/* Do a real query even when converting to let the driver fill in
things like buf->field */
- result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_QUERYBUF, buf);
- if (result || !converting)
+ result = SYS_IOCTL(devices[index].fd, VIDIOC_QUERYBUF, buf);
+ if (result || !v4l2_needs_conversion(index))
break;
buf->m.offset = V4L2_MMAP_OFFSET_MAGIC | buf->index;
@@ -923,11 +978,11 @@ int v4l2_ioctl (int fd, unsigned long int request, ...)
break;
/* With some drivers the buffers must be mapped before queuing */
- if (converting)
+ if (v4l2_needs_conversion(index))
if ((result = v4l2_map_buffers(index)))
break;
- result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_QBUF, arg);
+ result = SYS_IOCTL(devices[index].fd, VIDIOC_QBUF, arg);
break;
case VIDIOC_DQBUF:
@@ -938,8 +993,8 @@ int v4l2_ioctl (int fd, unsigned long int request, ...)
if ((result = v4l2_deactivate_read_stream(index)))
break;
- if (!converting) {
- result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_DQBUF, buf);
+ if (!v4l2_needs_conversion(index)) {
+ result = SYS_IOCTL(devices[index].fd, VIDIOC_DQBUF, buf);
if (result) {
int saved_err = errno;
V4L2_LOG_ERR("dequeuing buf: %s\n", strerror(errno));
@@ -952,7 +1007,7 @@ int v4l2_ioctl (int fd, unsigned long int request, ...)
but we need the buffer _now_ to write our converted data
to it! */
if (devices[index].convert_mmap_buf == MAP_FAILED) {
- devices[index].convert_mmap_buf = (void *)syscall(SYS_mmap2, NULL,
+ devices[index].convert_mmap_buf = (void *)SYS_MMAP(NULL,
(size_t)(
devices[index].no_frames *
V4L2_FRAME_BUF_SIZE),
@@ -997,7 +1052,7 @@ int v4l2_ioctl (int fd, unsigned long int request, ...)
break;
default:
- result = syscall(SYS_ioctl, fd, request, arg);
+ result = SYS_IOCTL(fd, request, arg);
}
if (stream_needs_locking)
@@ -1018,16 +1073,15 @@ ssize_t v4l2_read (int fd, void* dest, size_t n)
struct v4l2_buffer buf;
if ((index = v4l2_get_index(fd)) == -1)
- return syscall(SYS_read, fd, dest, n);
+ return SYS_READ(fd, dest, n);
pthread_mutex_lock(&devices[index].stream_lock);
/* When not converting and the device supports read let the kernel handle
it */
if ((devices[index].flags & V4L2_SUPPORTS_READ) &&
- !v4lconvert_needs_conversion(devices[index].convert,
- &devices[index].src_fmt, &devices[index].dest_fmt)) {
- result = syscall(SYS_read, fd, dest, n);
+ !v4l2_needs_conversion(index)) {
+ result = SYS_READ(fd, dest, n);
goto leave;
}
@@ -1056,7 +1110,7 @@ leave:
}
void *v4l2_mmap(void *start, size_t length, int prot, int flags, int fd,
- __off64_t offset)
+ int64_t offset)
{
int index;
unsigned int buffer_index;
@@ -1076,8 +1130,7 @@ void *v4l2_mmap(void *start, size_t length, int prot, int flags, int fd,
return MAP_FAILED;
}
- return (void *)syscall(SYS_mmap2, start, length, prot, flags, fd,
- (__off_t)(offset >> MMAP2_PAGE_SHIFT));
+ return (void *)SYS_MMAP(start, length, prot, flags, fd, offset);
}
pthread_mutex_lock(&devices[index].stream_lock);
@@ -1085,15 +1138,14 @@ void *v4l2_mmap(void *start, size_t length, int prot, int flags, int fd,
buffer_index = offset & 0xff;
if (buffer_index >= devices[index].no_frames ||
/* Got magic offset and not converting ?? */
- !v4lconvert_needs_conversion(devices[index].convert,
- &devices[index].src_fmt, &devices[index].dest_fmt)) {
+ !v4l2_needs_conversion(index)) {
errno = EINVAL;
result = MAP_FAILED;
goto leave;
}
if (devices[index].convert_mmap_buf == MAP_FAILED) {
- devices[index].convert_mmap_buf = (void *)syscall(SYS_mmap2, NULL,
+ devices[index].convert_mmap_buf = (void *)SYS_MMAP(NULL,
(size_t)(
devices[index].no_frames *
V4L2_FRAME_BUF_SIZE),
@@ -1166,7 +1218,7 @@ int v4l2_munmap(void *_start, size_t length)
V4L2_LOG("v4l2 unknown munmap %p, %d\n", start, (int)length);
- return syscall(SYS_munmap, _start, length);
+ return SYS_MUNMAP(_start, length);
}
/* Misc utility functions */
@@ -1176,7 +1228,7 @@ int v4l2_set_control(int fd, int cid, int value)
struct v4l2_control ctrl = { .id = cid };
int result;
- if ((result = syscall(SYS_ioctl, fd, VIDIOC_QUERYCTRL, &qctrl)))
+ if ((result = SYS_IOCTL(fd, VIDIOC_QUERYCTRL, &qctrl)))
return result;
if (!(qctrl.flags & V4L2_CTRL_FLAG_DISABLED) &&
@@ -1187,7 +1239,7 @@ int v4l2_set_control(int fd, int cid, int value)
ctrl.value = (value * (qctrl.maximum - qctrl.minimum) + 32767) / 65535 +
qctrl.minimum;
- result = syscall(SYS_ioctl, fd, VIDIOC_S_CTRL, &ctrl);
+ result = SYS_IOCTL(fd, VIDIOC_S_CTRL, &ctrl);
}
return result;
@@ -1198,13 +1250,13 @@ int v4l2_get_control(int fd, int cid)
struct v4l2_queryctrl qctrl = { .id = cid };
struct v4l2_control ctrl = { .id = cid };
- if (syscall(SYS_ioctl, fd, VIDIOC_QUERYCTRL, &qctrl))
+ if (SYS_IOCTL(fd, VIDIOC_QUERYCTRL, &qctrl))
return 0;
if (qctrl.flags & V4L2_CTRL_FLAG_DISABLED)
return 0;
- if (syscall(SYS_ioctl, fd, VIDIOC_G_CTRL, &ctrl))
+ if (SYS_IOCTL(fd, VIDIOC_G_CTRL, &ctrl))
return 0;
return ((ctrl.value - qctrl.minimum) * 65535 +
diff --git a/v4l2-apps/libv4l/libv4l2/log.c b/v4l2-apps/libv4l/libv4l2/log.c
index c29086ff4..86d71b64e 100644
--- a/v4l2-apps/libv4l/libv4l2/log.c
+++ b/v4l2-apps/libv4l/libv4l2/log.c
@@ -1,5 +1,7 @@
/*
-# (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl>
+# (C) 2008 Elmar Kleijn <elmar_kleijn@hotmail.com>
+# (C) 2008 Sjoerd Piepenbrink <need4weed@gmail.com>
+# (C) 2008 Hans de Goede <hdegoede@redhat.com>
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
@@ -20,12 +22,7 @@
#include <stdlib.h>
#include <string.h>
#include <errno.h>
-#include <linux/ioctl.h>
-/* These headers are not needed by us, but by linux/videodev2.h,
- which is broken on some systems and doesn't include them itself :( */
-#include <sys/time.h>
-#include <asm/types.h>
-/* end broken header workaround includes */
+#include "../libv4lconvert/libv4lsyscall-priv.h"
#include <linux/videodev2.h>
#include "libv4l2.h"
#include "libv4l2-priv.h"
@@ -161,7 +158,7 @@ void v4l2_log_ioctl(unsigned long int request, void *arg, int result)
struct v4l2_frmsizeenum *frmsize = arg;
int pixfmt = frmsize->pixel_format;
- fprintf(v4l2_log_file, " index: %u pixelformat: %c%c%c%c",
+ fprintf(v4l2_log_file, " index: %u pixelformat: %c%c%c%c\n",
frmsize->index,
pixfmt & 0xff,
(pixfmt >> 8) & 0xff,
@@ -169,12 +166,12 @@ void v4l2_log_ioctl(unsigned long int request, void *arg, int result)
pixfmt >> 24);
switch (frmsize->type) {
case V4L2_FRMSIZE_TYPE_DISCRETE:
- fprintf(v4l2_log_file, " %ux%u\n", frmsize->discrete.width,
+ fprintf(v4l2_log_file, " %ux%u\n", frmsize->discrete.width,
frmsize->discrete.height);
break;
case V4L2_FRMSIZE_TYPE_CONTINUOUS:
case V4L2_FRMSIZE_TYPE_STEPWISE:
- fprintf(v4l2_log_file, " %ux%u -> %ux%u\n",
+ fprintf(v4l2_log_file, " %ux%u -> %ux%u\n",
frmsize->stepwise.min_width, frmsize->stepwise.min_height,
frmsize->stepwise.max_width, frmsize->stepwise.max_height);
break;
@@ -186,7 +183,7 @@ void v4l2_log_ioctl(unsigned long int request, void *arg, int result)
struct v4l2_frmivalenum *frmival = arg;
int pixfmt = frmival->pixel_format;
- fprintf(v4l2_log_file, " index: %u pixelformat: %c%c%c%c %ux%u: ",
+ fprintf(v4l2_log_file, " index: %u pixelformat: %c%c%c%c %ux%u:\n",
frmival->index,
pixfmt & 0xff,
(pixfmt >> 8) & 0xff,
@@ -196,12 +193,12 @@ void v4l2_log_ioctl(unsigned long int request, void *arg, int result)
frmival->height);
switch (frmival->type) {
case V4L2_FRMIVAL_TYPE_DISCRETE:
- fprintf(v4l2_log_file, "%u/%u\n", frmival->discrete.numerator,
+ fprintf(v4l2_log_file, " %u/%u\n", frmival->discrete.numerator,
frmival->discrete.denominator);
break;
case V4L2_FRMIVAL_TYPE_CONTINUOUS:
case V4L2_FRMIVAL_TYPE_STEPWISE:
- fprintf(v4l2_log_file, "%u/%u -> %u/%u\n",
+ fprintf(v4l2_log_file, " %u/%u -> %u/%u\n",
frmival->stepwise.min.numerator,
frmival->stepwise.min.denominator,
frmival->stepwise.max.numerator,
diff --git a/v4l2-apps/libv4l/libv4l2/v4l2convert.c b/v4l2-apps/libv4l/libv4l2/v4l2convert.c
index 307a03ce5..4b75a5ebf 100644
--- a/v4l2-apps/libv4l/libv4l2/v4l2convert.c
+++ b/v4l2-apps/libv4l/libv4l2/v4l2convert.c
@@ -24,17 +24,11 @@
#include <stdarg.h>
#include <stdlib.h>
-#include <syscall.h>
#include <fcntl.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
-/* These headers are not needed by us, but by linux/videodev2.h,
- which is broken on some systems and doesn't include them itself :( */
-#include <sys/time.h>
-#include <asm/types.h>
-#include <linux/ioctl.h>
-/* end broken header workaround includes */
+#include "../libv4lconvert/libv4lsyscall-priv.h"
#include <linux/videodev2.h>
#include <libv4l2.h>
@@ -72,18 +66,18 @@ LIBV4L_PUBLIC int open (const char *file, int oflag, ...)
va_start (ap, oflag);
mode = va_arg (ap, mode_t);
- fd = syscall(SYS_open, file, oflag, mode);
+ fd = SYS_OPEN(file, oflag, mode);
va_end(ap);
} else
- fd = syscall(SYS_open, file, oflag);
+ fd = SYS_OPEN(file, oflag, 0);
/* end of original open code */
if (fd == -1 || !v4l_device)
return fd;
/* check that this is an v4l2 device, libv4l2 only supports v4l2 devices */
- if (syscall(SYS_ioctl, fd, VIDIOC_QUERYCAP, &cap))
+ if (SYS_IOCTL(fd, VIDIOC_QUERYCAP, &cap))
return fd;
/* libv4l2 only adds functionality to capture capable devices */
@@ -92,11 +86,12 @@ LIBV4L_PUBLIC int open (const char *file, int oflag, ...)
/* Try to Register with libv4l2 (in case of failure pass the fd to the
application as is) */
- v4l2_fd_open(fd, V4L2_ENABLE_ENUM_FMT_EMULATION);
+ v4l2_fd_open(fd, 0);
return fd;
}
+#ifdef linux
LIBV4L_PUBLIC int open64(const char *file, int oflag, ...)
{
int fd;
@@ -119,6 +114,7 @@ LIBV4L_PUBLIC int open64(const char *file, int oflag, ...)
return fd;
}
+#endif
LIBV4L_PUBLIC int close(int fd)
{
@@ -153,11 +149,13 @@ LIBV4L_PUBLIC void *mmap(void *start, size_t length, int prot, int flags, int fd
return v4l2_mmap(start, length, prot, flags, fd, offset);
}
+#ifdef linux
LIBV4L_PUBLIC void *mmap64(void *start, size_t length, int prot, int flags, int fd,
__off64_t offset)
{
return v4l2_mmap(start, length, prot, flags, fd, offset);
}
+#endif
LIBV4L_PUBLIC int munmap(void *start, size_t length)
{
diff --git a/v4l2-apps/libv4l/libv4lconvert/Makefile b/v4l2-apps/libv4l/libv4lconvert/Makefile
index f779011b4..036649e86 100644
--- a/v4l2-apps/libv4l/libv4lconvert/Makefile
+++ b/v4l2-apps/libv4l/libv4lconvert/Makefile
@@ -3,6 +3,8 @@ override CPPFLAGS += -I../include -I../../../include -fvisibility=hidden
CFLAGS := -g -O1
CFLAGS += -Wall -Wno-unused -Wpointer-arith -Wstrict-prototypes -Wmissing-prototypes
+LIBS_libv4lconvert = -lrt -lm
+
ifeq ($(LINKTYPE),static)
CONVERT_LIB = libv4lconvert.a
else
@@ -12,8 +14,11 @@ endif
CONVERT_OBJS = libv4lconvert.o tinyjpeg.o sn9c10x.o sn9c20x.o pac207.o \
mr97310a.o flip.o crop.o jidctflt.o spca561-decompress.o \
- rgbyuv.o spca501.o sq905c.o bayer.o hm12.o
-TARGETS = $(CONVERT_LIB) libv4lconvert.pc
+ rgbyuv.o spca501.o sq905c.o bayer.o hm12.o helper.o \
+ control/libv4lcontrol.o processing/libv4lprocessing.o \
+ processing/whitebalance.o processing/autogain.o \
+ processing/gamma.o
+TARGETS = $(CONVERT_LIB) libv4lconvert.pc ov511-decomp ov518-decomp
INCLUDES = ../include/libv4lconvert.h
ifeq ($(LIB_RELEASE),)
@@ -28,8 +33,12 @@ ifeq ($(LIBDIR),)
LIBDIR = $(PREFIX)/lib
endif
+override CPPFLAGS += -DLIBDIR=\"$(LIBDIR)\"
+
all: $(TARGETS)
+-include $(CONVERT_OBJS:.o=.d)
+
$(CONVERT_LIB): $(CONVERT_OBJS)
libv4lconvert.pc:
@@ -40,32 +49,37 @@ libv4lconvert.pc:
@echo 'Description: v4l format conversion library' >> libv4lconvert.pc
@echo 'Version: '$(V4L2_LIB_VERSION) >> libv4lconvert.pc
@echo 'Libs: -L$${libdir} -lv4lconvert' >> libv4lconvert.pc
+ @echo 'Libs.private: -lrt -lm' >> libv4lconvert.pc
@echo 'Cflags: -I$${prefix}/include' >> libv4lconvert.pc
install: all
mkdir -p $(DESTDIR)$(PREFIX)/include
install -p -m 644 $(INCLUDES) $(DESTDIR)$(PREFIX)/include
- mkdir -p $(DESTDIR)$(LIBDIR)
+ mkdir -p $(DESTDIR)$(LIBDIR)/libv4l
ifeq ($(LINKTYPE),static)
- mkdir -p $(DESTDIR)$(LIBDIR)
install -m 644 $(CONVERT_LIB) $(DESTDIR)$(LIBDIR)
else
install -m 755 $(CONVERT_LIB).$(LIB_RELEASE) $(DESTDIR)$(LIBDIR)
cd $(DESTDIR)$(LIBDIR) && \
ln -f -s $(CONVERT_LIB).$(LIB_RELEASE) $(CONVERT_LIB)
endif
+ install -m 755 *-decomp $(DESTDIR)$(LIBDIR)/libv4l
mkdir -p $(DESTDIR)$(LIBDIR)/pkgconfig
install -m 644 libv4lconvert.pc $(DESTDIR)$(LIBDIR)/pkgconfig
clean::
- rm -f *.a *.so* *.o *.d libv4lconvert.pc log *~ *.orig *.rej
+ rm -f *.a *.so* *.o *.d */*.o */*.d libv4lconvert.pc log *~ */*~
+ rm -f *.orig *.rej */*.orig */*.rej DEADJOE */DEADJOE *-decomp
%.o: %.c
- $(CC) -c -MMD $(CPPFLAGS) $(CFLAGS) -o $@ $<
+ $(CC) -Wp,-MMD,"$*.d",-MQ,"$@",-MP -c $(CPPFLAGS) $(CFLAGS) -o $@ $<
%.so:
- $(CC) -shared $(LDFLAGS) -Wl,-soname,$@.$(LIB_RELEASE) -o $@.$(LIB_RELEASE) $^
+ $(CC) -shared $(LDFLAGS) -Wl,-soname,$@.$(LIB_RELEASE) -o $@.$(LIB_RELEASE) $^ $(LIBS_$*)
ln -f -s $@.$(LIB_RELEASE) $@
%.a:
$(AR) cqs $@ $^
+
+ov511-decomp: ov511-decomp.o
+ov518-decomp: ov518-decomp.o
diff --git a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol-priv.h b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol-priv.h
new file mode 100644
index 000000000..6211ee22a
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol-priv.h
@@ -0,0 +1,54 @@
+/*
+# (C) 2008-2009 Elmar Kleijn <elmar_kleijn@hotmail.com>
+# (C) 2008-2009 Sjoerd Piepenbrink <need4weed@gmail.com>
+# (C) 2008-2009 Radjnies Bhansingh <radjnies@gmail.com>
+# (C) 2008-2009 Hans de Goede <hdegoede@redhat.com>
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser 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
+*/
+
+#ifndef __LIBV4LCONTROL_PRIV_H
+#define __LIBV4LCONTROL_PRIV_H
+
+#define V4LCONTROL_SHM_SIZE 4096
+
+#define V4LCONTROL_SUPPORTS_NEXT_CTRL 0x01
+
+struct v4lcontrol_flags_info;
+
+struct v4lcontrol_data {
+ int fd; /* Device fd */
+ int flags; /* Flags for this device */
+ int priv_flags; /* Internal use only flags */
+ int controls; /* Which controls to use for this device */
+ unsigned int *shm_values; /* shared memory control value store */
+ unsigned int old_values[V4LCONTROL_COUNT]; /* for controls_changed() */
+ const struct v4lcontrol_flags_info *flags_info;
+};
+
+struct v4lcontrol_flags_info {
+ unsigned short vendor_id;
+ unsigned short product_id;
+ unsigned short product_mask;
+ const char *dmi_board_vendor;
+ const char *dmi_board_name;
+/* We could also use the USB manufacturer and product strings some devices have
+ const char *manufacturer;
+ const char *product; */
+ int flags;
+ int default_gamma;
+};
+
+#endif
diff --git a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c
new file mode 100644
index 000000000..4e600351b
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c
@@ -0,0 +1,504 @@
+/*
+# (C) 2008-2009 Elmar Kleijn <elmar_kleijn@hotmail.com>
+# (C) 2008-2009 Sjoerd Piepenbrink <need4weed@gmail.com>
+# (C) 2008-2009 Radjnies Bhansingh <radjnies@gmail.com>
+# (C) 2008-2009 Hans de Goede <hdegoede@redhat.com>
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser 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
+*/
+
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include "libv4lcontrol.h"
+#include "libv4lcontrol-priv.h"
+#include "../libv4lsyscall-priv.h"
+#include <linux/videodev2.h>
+
+#define ARRAY_SIZE(x) ((int)sizeof(x)/(int)sizeof((x)[0]))
+
+/* Workaround these potentially missing from videodev2.h */
+#ifndef V4L2_IN_ST_HFLIP
+#define V4L2_IN_ST_HFLIP 0x00000010 /* Frames are flipped horizontally */
+#endif
+
+#ifndef V4L2_IN_ST_VFLIP
+#define V4L2_IN_ST_VFLIP 0x00000020 /* Frames are flipped vertically */
+#endif
+
+
+/* List of cams which need special flags */
+static const struct v4lcontrol_flags_info v4lcontrol_flags[] = {
+/* First: Upside down devices */
+ /* Philips SPC200NC */
+ { 0x0471, 0x0325, 0, NULL, NULL, V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ /* Philips SPC300NC */
+ { 0x0471, 0x0326, 0, NULL, NULL, V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ /* Philips SPC210NC */
+ { 0x0471, 0x032d, 0, NULL, NULL, V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ /* Genius E-M 112 (also want whitebalance by default) */
+ { 0x093a, 0x2476, 0, NULL, NULL,
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED|V4LCONTROL_WANTS_WB, 1500 },
+ /* Asus N50Vn laptop */
+ { 0x04f2, 0xb106, 0, "ASUSTeK Computer Inc. ", "N50Vn ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+/* Second: devices which should use some software processing by default */
+ /* Pac207 based devices */
+ { 0x041e, 0x4028, 0, NULL, NULL, V4LCONTROL_WANTS_WB, 1500 },
+ { 0x093a, 0x2460, 0x1f, NULL, NULL, V4LCONTROL_WANTS_WB, 1500 },
+ { 0x145f, 0x013a, 0, NULL, NULL, V4LCONTROL_WANTS_WB, 1500 },
+ { 0x2001, 0xf115, 0, NULL, NULL, V4LCONTROL_WANTS_WB, 1500 },
+ /* Pac7302 based devices */
+ { 0x093a, 0x2620, 0x0f, NULL, NULL,
+ V4LCONTROL_ROTATED_90_JPEG|V4LCONTROL_WANTS_WB },
+ /* Pac7311 based devices */
+ { 0x093a, 0x2600, 0x0f, NULL, NULL, V4LCONTROL_WANTS_WB },
+ /* sq905 devices */
+ { 0x2770, 0x9120, 0, NULL, NULL, V4LCONTROL_WANTS_WB },
+ /* spca561 revison 12a devices */
+ { 0x041e, 0x403b, 0, NULL, NULL, V4LCONTROL_WANTS_WB_AUTOGAIN },
+ { 0x046d, 0x0928, 7, NULL, NULL, V4LCONTROL_WANTS_WB_AUTOGAIN },
+ /* logitech quickcam express stv06xx + pb0100 */
+ { 0x046d, 0x0840, 0, NULL, NULL, V4LCONTROL_WANTS_WB },
+ /* logitech quickcam messenger variants, st6422 */
+ { 0x046d, 0x08f0, 0, NULL, NULL, V4LCONTROL_WANTS_AUTOGAIN },
+ { 0x046d, 0x08f5, 0, NULL, NULL, V4LCONTROL_WANTS_AUTOGAIN },
+ { 0x046d, 0x08f6, 0, NULL, NULL, V4LCONTROL_WANTS_AUTOGAIN },
+ { 0x046d, 0x08da, 0, NULL, NULL, V4LCONTROL_WANTS_AUTOGAIN },
+};
+
+static const struct v4l2_queryctrl fake_controls[];
+
+static void v4lcontrol_init_flags(struct v4lcontrol_data *data)
+{
+ struct stat st;
+ FILE *f;
+ char sysfs_name[512];
+ unsigned short vendor_id = 0;
+ unsigned short product_id = 0;
+ char dmi_board_vendor[512] = "";
+ char dmi_board_name[512]= "";
+ int i, minor;
+ char c, *s, buf[32];
+ struct v4l2_input input;
+
+ if ((SYS_IOCTL(data->fd, VIDIOC_G_INPUT, &input.index) == 0) &&
+ (SYS_IOCTL(data->fd, VIDIOC_ENUMINPUT, &input) == 0)) {
+ if (input.status & V4L2_IN_ST_HFLIP)
+ data->flags |= V4LCONTROL_HFLIPPED;
+ if (input.status & V4L2_IN_ST_VFLIP)
+ data->flags |= V4LCONTROL_VFLIPPED;
+ }
+
+ if (fstat(data->fd, &st) || !S_ISCHR(st.st_mode)) {
+ return; /* Should never happen */
+ }
+
+ /* <Sigh> find ourselve in sysfs */
+ for (i = 0; i < 256; i++) {
+ snprintf(sysfs_name, sizeof(sysfs_name),
+ "/sys/class/video4linux/video%d/dev", i);
+ f = fopen(sysfs_name, "r");
+ if (!f)
+ continue;
+
+ s = fgets(buf, sizeof(buf), f);
+ fclose(f);
+
+ if (s && sscanf(buf, "%*d:%d%c", &minor, &c) == 2 && c == '\n' &&
+ minor == minor(st.st_rdev))
+ break;
+ }
+ if (i == 256)
+ return; /* Not found, sysfs not mounted? */
+
+ /* Get vendor and product ID */
+ snprintf(sysfs_name, sizeof(sysfs_name),
+ "/sys/class/video4linux/video%d/device/modalias", i);
+ f = fopen(sysfs_name, "r");
+ if (f) {
+ s = fgets(buf, sizeof(buf), f);
+ fclose(f);
+
+ if (!s ||
+ sscanf(s, "usb:v%4hxp%4hx%c", &vendor_id, &product_id, &c) != 3 ||
+ c != 'd')
+ return; /* Not an USB device */
+ } else {
+ /* Try again assuming the device link points to the usb
+ device instead of the usb interface (bug in older versions
+ of gspca) */
+
+ /* Get product ID */
+ snprintf(sysfs_name, sizeof(sysfs_name),
+ "/sys/class/video4linux/video%d/device/idVendor", i);
+ f = fopen(sysfs_name, "r");
+ if (!f)
+ return; /* Not an USB device (or no sysfs) */
+
+ s = fgets(buf, sizeof(buf), f);
+ fclose(f);
+
+ if (!s || sscanf(s, "%04hx%c", &vendor_id, &c) != 2 || c != '\n')
+ return; /* Should never happen */
+
+ /* Get product ID */
+ snprintf(sysfs_name, sizeof(sysfs_name),
+ "/sys/class/video4linux/video%d/device/idProduct", i);
+ f = fopen(sysfs_name, "r");
+ if (!f)
+ return; /* Should never happen */
+
+ s = fgets(buf, sizeof(buf), f);
+ fclose(f);
+
+ if (!s || sscanf(s, "%04hx%c", &product_id, &c) != 2 || c != '\n')
+ return; /* Should never happen */
+ }
+
+ /* Get DMI board vendor and name */
+ f = fopen("/sys/devices/virtual/dmi/id/board_vendor", "r");
+ if (f) {
+ s = fgets(dmi_board_vendor, sizeof(dmi_board_vendor), f);
+ if (s)
+ s[strlen(s) - 1] = 0;
+ fclose(f);
+ }
+
+ f = fopen("/sys/devices/virtual/dmi/id/board_name", "r");
+ if (f) {
+ s = fgets(dmi_board_name, sizeof(dmi_board_name), f);
+ if (s)
+ s[strlen(s) - 1] = 0;
+ fclose(f);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(v4lcontrol_flags); i++)
+ if (v4lcontrol_flags[i].vendor_id == vendor_id &&
+ v4lcontrol_flags[i].product_id ==
+ (product_id & ~v4lcontrol_flags[i].product_mask) &&
+ (v4lcontrol_flags[i].dmi_board_vendor == NULL ||
+ !strcmp(v4lcontrol_flags[i].dmi_board_vendor, dmi_board_vendor)) &&
+ (v4lcontrol_flags[i].dmi_board_name == NULL ||
+ !strcmp(v4lcontrol_flags[i].dmi_board_name, dmi_board_name))) {
+ data->flags |= v4lcontrol_flags[i].flags;
+ data->flags_info = &v4lcontrol_flags[i];
+ break;
+ }
+}
+
+struct v4lcontrol_data *v4lcontrol_create(int fd, int always_needs_conversion)
+{
+ int shm_fd;
+ int i, rc, init = 0;
+ char *s, shm_name[256];
+ struct v4l2_capability cap;
+ struct v4l2_queryctrl ctrl;
+
+ struct v4lcontrol_data *data = calloc(1, sizeof(struct v4lcontrol_data));
+
+ if (!data)
+ return NULL;
+
+ data->fd = fd;
+
+ v4lcontrol_init_flags(data);
+
+ /* Allow overriding through environment */
+ if ((s = getenv("LIBV4LCONTROL_FLAGS")))
+ data->flags = strtol(s, NULL, 0);
+
+ ctrl.id = V4L2_CTRL_FLAG_NEXT_CTRL;
+ if (SYS_IOCTL(data->fd, VIDIOC_QUERYCTRL, &ctrl) == 0)
+ data->priv_flags |= V4LCONTROL_SUPPORTS_NEXT_CTRL;
+
+ /* If the device always needs conversion, we can add fake controls at no cost
+ (no cost when not activated by the user that is) */
+ if (always_needs_conversion || v4lcontrol_needs_conversion(data)) {
+ for (i = 0; i < V4LCONTROL_AUTO_ENABLE_COUNT; i++) {
+ ctrl.id = fake_controls[i].id;
+ rc = SYS_IOCTL(data->fd, VIDIOC_QUERYCTRL, &ctrl);
+ if (rc == -1 || (rc == 0 && (ctrl.flags & V4L2_CTRL_FLAG_DISABLED)))
+ data->controls |= 1 << i;
+ }
+ }
+
+ if (data->flags & V4LCONTROL_WANTS_AUTOGAIN)
+ data->controls |= 1 << V4LCONTROL_AUTOGAIN |
+ 1 << V4LCONTROL_AUTOGAIN_TARGET;
+
+ /* Allow overriding through environment */
+ if ((s = getenv("LIBV4LCONTROL_CONTROLS")))
+ data->controls = strtol(s, NULL, 0);
+
+ if (data->controls == 0)
+ return data; /* No need to create a shared memory segment */
+
+ SYS_IOCTL(fd, VIDIOC_QUERYCAP, &cap);
+ snprintf(shm_name, 256, "/%s:%s", cap.bus_info, cap.card);
+
+ /* / is not allowed inside shm names */
+ for (i = 1; shm_name[i]; i++)
+ if (shm_name[i] == '/')
+ shm_name[i] = '-';
+
+ /* Open the shared memory object identified by shm_name */
+ if ((shm_fd = shm_open(shm_name, (O_CREAT | O_EXCL | O_RDWR),
+ (S_IREAD | S_IWRITE))) >= 0)
+ init = 1;
+ else if ((shm_fd = shm_open(shm_name, O_RDWR, (S_IREAD | S_IWRITE))) < 0)
+ goto error;
+
+ /* Set the shared memory size */
+ ftruncate(shm_fd, V4LCONTROL_SHM_SIZE);
+
+ /* Retreive a pointer to the shm object */
+ data->shm_values = mmap(NULL, V4LCONTROL_SHM_SIZE, (PROT_READ | PROT_WRITE),
+ MAP_SHARED, shm_fd, 0);
+ close(shm_fd);
+
+ if (data->shm_values == MAP_FAILED)
+ goto error;
+
+ if (init) {
+ /* Initialize the new shm object we created */
+ memset(data->shm_values, 0, sizeof(V4LCONTROL_SHM_SIZE));
+
+ for (i = 0; i < V4LCONTROL_COUNT; i++)
+ data->shm_values[i] = fake_controls[i].default_value;
+
+ if (data->flags & V4LCONTROL_WANTS_WB)
+ data->shm_values[V4LCONTROL_WHITEBALANCE] = 1;
+
+ if (data->flags_info && data->flags_info->default_gamma)
+ data->shm_values[V4LCONTROL_GAMMA] = data->flags_info->default_gamma;
+ }
+
+ return data;
+
+error:
+ free(data);
+ return NULL;
+}
+
+void v4lcontrol_destroy(struct v4lcontrol_data *data)
+{
+ if (data->controls)
+ munmap(data->shm_values, V4LCONTROL_SHM_SIZE);
+ free(data);
+}
+
+/* FIXME get better CID's for normalize */
+static const struct v4l2_queryctrl fake_controls[V4LCONTROL_COUNT] = {
+{
+ .id = V4L2_CID_AUTO_WHITE_BALANCE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Whitebalance (software)",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ .flags = 0
+},
+{
+ .id = V4L2_CID_HFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Horizontal flip (sw)",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ .flags = 0
+},
+{
+ .id = V4L2_CID_VFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Vertical flip (sw)",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ .flags = 0
+},
+{
+ .id = V4L2_CID_GAMMA,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Gamma (software)",
+ .minimum = 500, /* == 0.5 */
+ .maximum = 3000, /* == 3.0 */
+ .step = 1,
+ .default_value = 1000, /* == 1.0 */
+ .flags = 0
+},
+{}, /* Dummy place holder for V4LCONTROL_AUTO_ENABLE_COUNT */
+{
+ .id = V4L2_CID_AUTOGAIN,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Auto Gain (software)",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 1,
+ .flags = 0
+},
+{
+ .id = V4L2_CTRL_CLASS_USER + 0x2000, /* FIXME */
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Auto Gain target",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+ .default_value = 100,
+ .flags = 0
+},
+};
+
+static void v4lcontrol_copy_queryctrl(struct v4lcontrol_data *data,
+ struct v4l2_queryctrl *ctrl, int i)
+{
+ memcpy(ctrl, &fake_controls[i], sizeof(struct v4l2_queryctrl));
+
+ /* Hmm, not pretty */
+ if (ctrl->id == V4L2_CID_AUTO_WHITE_BALANCE &&
+ (data->flags & V4LCONTROL_WANTS_WB))
+ ctrl->default_value = 1;
+
+ if (ctrl->id == V4L2_CID_GAMMA && data->flags_info &&
+ data->flags_info->default_gamma)
+ ctrl->default_value = data->flags_info->default_gamma;
+}
+
+int v4lcontrol_vidioc_queryctrl(struct v4lcontrol_data *data, void *arg)
+{
+ int i;
+ struct v4l2_queryctrl *ctrl = arg;
+ int retval;
+ __u32 orig_id=ctrl->id;
+
+ /* if we have an exact match return it */
+ for (i = 0; i < V4LCONTROL_COUNT; i++)
+ if ((data->controls & (1 << i)) &&
+ ctrl->id == fake_controls[i].id) {
+ v4lcontrol_copy_queryctrl(data, ctrl, i);
+ return 0;
+ }
+
+ /* find out what the kernel driver would respond. */
+ retval = SYS_IOCTL(data->fd, VIDIOC_QUERYCTRL, arg);
+
+ if ((data->priv_flags & V4LCONTROL_SUPPORTS_NEXT_CTRL) &&
+ (orig_id & V4L2_CTRL_FLAG_NEXT_CTRL)) {
+ /* If the hardware has no more controls check if we still have any
+ fake controls with a higher id then the hardware's highest */
+ if (retval)
+ ctrl->id = V4L2_CTRL_FLAG_NEXT_CTRL;
+
+ /* If any of our controls have an id > orig_id but less than
+ ctrl->id then return that control instead. Note we do not
+ break when we have a match, but keep iterating, so that
+ we end up with the fake ctrl with the lowest CID > orig_id. */
+ for (i = 0; i < V4LCONTROL_COUNT; i++)
+ if ((data->controls & (1 << i)) &&
+ (fake_controls[i].id > (orig_id & ~V4L2_CTRL_FLAG_NEXT_CTRL)) &&
+ (fake_controls[i].id <= ctrl->id)) {
+ v4lcontrol_copy_queryctrl(data, ctrl, i);
+ retval = 0;
+ }
+ }
+
+ return retval;
+}
+
+int v4lcontrol_vidioc_g_ctrl(struct v4lcontrol_data *data, void *arg)
+{
+ int i;
+ struct v4l2_control *ctrl = arg;
+
+ for (i = 0; i < V4LCONTROL_COUNT; i++)
+ if ((data->controls & (1 << i)) &&
+ ctrl->id == fake_controls[i].id) {
+ ctrl->value = data->shm_values[i];
+ return 0;
+ }
+
+ return SYS_IOCTL(data->fd, VIDIOC_G_CTRL, arg);
+}
+
+int v4lcontrol_vidioc_s_ctrl(struct v4lcontrol_data *data, void *arg)
+{
+ int i;
+ struct v4l2_control *ctrl = arg;
+
+ for (i = 0; i < V4LCONTROL_COUNT; i++)
+ if ((data->controls & (1 << i)) &&
+ ctrl->id == fake_controls[i].id) {
+ if (ctrl->value > fake_controls[i].maximum ||
+ ctrl->value < fake_controls[i].minimum) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ data->shm_values[i] = ctrl->value;
+ return 0;
+ }
+
+ return SYS_IOCTL(data->fd, VIDIOC_S_CTRL, arg);
+}
+
+int v4lcontrol_get_flags(struct v4lcontrol_data *data)
+{
+ return data->flags;
+}
+
+int v4lcontrol_get_ctrl(struct v4lcontrol_data *data, int ctrl)
+{
+ if (data->controls & (1 << ctrl)) {
+ /* Special case for devices with flipped input */
+ if ((ctrl == V4LCONTROL_HFLIP && (data->flags & V4LCONTROL_HFLIPPED)) ||
+ (ctrl == V4LCONTROL_VFLIP && (data->flags & V4LCONTROL_VFLIPPED)))
+ return !data->shm_values[ctrl];
+
+ return data->shm_values[ctrl];
+ }
+
+ return 0;
+}
+
+int v4lcontrol_controls_changed(struct v4lcontrol_data *data)
+{
+ int res;
+
+ if (!data->controls)
+ return 0;
+
+ res = memcmp(data->shm_values, data->old_values,
+ V4LCONTROL_COUNT * sizeof(unsigned int));
+
+ memcpy(data->old_values, data->shm_values,
+ V4LCONTROL_COUNT * sizeof(unsigned int));
+
+ return res;
+}
+
+/* See the comment about this in libv4lconvert.h */
+int v4lcontrol_needs_conversion(struct v4lcontrol_data *data) {
+ return data->flags || data->controls;
+}
diff --git a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.h b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.h
new file mode 100644
index 000000000..e29fde3d4
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.h
@@ -0,0 +1,70 @@
+/*
+# (C) 2008-2009 Elmar Kleijn <elmar_kleijn@hotmail.com>
+# (C) 2008-2009 Sjoerd Piepenbrink <need4weed@gmail.com>
+# (C) 2008-2009 Radjnies Bhansingh <radjnies@gmail.com>
+# (C) 2008-2009 Hans de Goede <hdegoede@redhat.com>
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser 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
+*/
+
+#ifndef __LIBV4LCONTROL_H
+#define __LIBV4LCONTROL_H
+
+/* Flags */
+#define V4LCONTROL_HFLIPPED 0x01
+#define V4LCONTROL_VFLIPPED 0x02
+#define V4LCONTROL_ROTATED_90_JPEG 0x04
+#define V4LCONTROL_WANTS_WB 0x08
+#define V4LCONTROL_WANTS_AUTOGAIN 0x10
+
+/* Masks */
+#define V4LCONTROL_WANTS_WB_AUTOGAIN (V4LCONTROL_WANTS_WB | V4LCONTROL_WANTS_AUTOGAIN)
+
+/* Controls */
+enum {
+ V4LCONTROL_WHITEBALANCE,
+ V4LCONTROL_HFLIP,
+ V4LCONTROL_VFLIP,
+ V4LCONTROL_GAMMA,
+ /* All fake controls above here are auto enabled when not present in hw */
+ V4LCONTROL_AUTO_ENABLE_COUNT,
+ V4LCONTROL_AUTOGAIN,
+ V4LCONTROL_AUTOGAIN_TARGET,
+ V4LCONTROL_COUNT
+ };
+
+struct v4lcontrol_data;
+
+struct v4lcontrol_data* v4lcontrol_create(int fd, int always_needs_conversion);
+void v4lcontrol_destroy(struct v4lcontrol_data *data);
+
+/* Functions used by v4lprocessing to get the control state */
+int v4lcontrol_get_flags(struct v4lcontrol_data *data);
+int v4lcontrol_get_ctrl(struct v4lcontrol_data *data, int ctrl);
+/* Check if the controls have changed since the last time this function
+ was called */
+int v4lcontrol_controls_changed(struct v4lcontrol_data *data);
+/* Check if we must go through the conversion path (and thus alloc conversion
+ buffers, etc. in libv4l2). Note this always return 1 if we *may* need
+ rotate90 / flipping / processing, as if we actually need this may change
+ on the fly while the stream is active. */
+int v4lcontrol_needs_conversion(struct v4lcontrol_data *data);
+
+/* Functions used by v4lconvert to pass vidioc calls from libv4l2 */
+int v4lcontrol_vidioc_queryctrl(struct v4lcontrol_data *data, void *arg);
+int v4lcontrol_vidioc_g_ctrl(struct v4lcontrol_data *data, void *arg);
+int v4lcontrol_vidioc_s_ctrl(struct v4lcontrol_data *data, void *arg);
+
+#endif
diff --git a/v4l2-apps/libv4l/libv4lconvert/crop.c b/v4l2-apps/libv4l/libv4lconvert/crop.c
index 4294fbeaf..46c87f0ce 100644
--- a/v4l2-apps/libv4l/libv4lconvert/crop.c
+++ b/v4l2-apps/libv4l/libv4lconvert/crop.c
@@ -69,8 +69,8 @@ static void v4lconvert_reduceandcrop_yuv420(
int x,y;
int dest_height_half = dest_fmt->fmt.pix.height / 2;
int dest_width_half = dest_fmt->fmt.pix.width / 2;
- int startx = src_fmt->fmt.pix.width / 2 - dest_fmt->fmt.pix.width;
- int starty = src_fmt->fmt.pix.height / 2 - dest_fmt->fmt.pix.height;
+ int startx = (src_fmt->fmt.pix.width / 2 - dest_fmt->fmt.pix.width) & ~1;
+ int starty = (src_fmt->fmt.pix.height / 2 - dest_fmt->fmt.pix.height) & ~1;
unsigned char *mysrc, *mysrc2;
/* Y */
@@ -113,8 +113,8 @@ static void v4lconvert_crop_yuv420(unsigned char *src, unsigned char *dest,
const struct v4l2_format *src_fmt, const struct v4l2_format *dest_fmt)
{
int x;
- int startx = (src_fmt->fmt.pix.width - dest_fmt->fmt.pix.width) / 2;
- int starty = (src_fmt->fmt.pix.height - dest_fmt->fmt.pix.height) / 2;
+ int startx = ((src_fmt->fmt.pix.width - dest_fmt->fmt.pix.width) / 2) & ~1;
+ int starty = ((src_fmt->fmt.pix.height - dest_fmt->fmt.pix.height) / 2) & ~1;
unsigned char *mysrc = src + starty * src_fmt->fmt.pix.bytesperline + startx;
/* Y */
@@ -143,26 +143,146 @@ static void v4lconvert_crop_yuv420(unsigned char *src, unsigned char *dest,
}
}
+/* Ok, so this is not really cropping, but more the reverse, whatever */
+static void v4lconvert_add_border_rgbbgr24(
+ unsigned char *src, unsigned char *dest,
+ const struct v4l2_format *src_fmt, const struct v4l2_format *dest_fmt)
+{
+ int y;
+ int borderx = (dest_fmt->fmt.pix.width - src_fmt->fmt.pix.width) / 2;
+ int bordery = (dest_fmt->fmt.pix.height - src_fmt->fmt.pix.height) / 2;
+
+ for (y = 0; y < bordery; y++) {
+ memset(dest, 0, dest_fmt->fmt.pix.width * 3);
+ dest += dest_fmt->fmt.pix.bytesperline;
+ }
+
+ for (y = 0; y < src_fmt->fmt.pix.height; y++) {
+ memset(dest, 0, borderx * 3);
+ dest += borderx * 3;
+
+ memcpy(dest, src, src_fmt->fmt.pix.width * 3);
+ src += src_fmt->fmt.pix.bytesperline;
+ dest += src_fmt->fmt.pix.width * 3;
+
+ memset(dest, 0, borderx * 3);
+ dest += dest_fmt->fmt.pix.bytesperline -
+ (borderx + src_fmt->fmt.pix.width) * 3;
+ }
+
+ for (y = 0; y < bordery; y++) {
+ memset(dest, 0, dest_fmt->fmt.pix.width * 3);
+ dest += dest_fmt->fmt.pix.bytesperline;
+ }
+}
+
+static void v4lconvert_add_border_yuv420(
+ unsigned char *src, unsigned char *dest,
+ const struct v4l2_format *src_fmt, const struct v4l2_format *dest_fmt)
+{
+ int y;
+ int borderx = ((dest_fmt->fmt.pix.width - src_fmt->fmt.pix.width) / 2) & ~1;
+ int bordery = ((dest_fmt->fmt.pix.height - src_fmt->fmt.pix.height) / 2) & ~1;
+
+ /* Y */
+ for (y = 0; y < bordery; y++) {
+ memset(dest, 16, dest_fmt->fmt.pix.width);
+ dest += dest_fmt->fmt.pix.bytesperline;
+ }
+
+ for (y = 0; y < src_fmt->fmt.pix.height; y++) {
+ memset(dest, 16, borderx);
+ dest += borderx;
+
+ memcpy(dest, src, src_fmt->fmt.pix.width);
+ src += src_fmt->fmt.pix.bytesperline;
+ dest += src_fmt->fmt.pix.width;
+
+ memset(dest, 16, borderx);
+ dest += dest_fmt->fmt.pix.bytesperline -
+ (borderx + src_fmt->fmt.pix.width);
+ }
+
+ for (y = 0; y < bordery; y++) {
+ memset(dest, 16, dest_fmt->fmt.pix.width);
+ dest += dest_fmt->fmt.pix.bytesperline;
+ }
+
+ /* U */
+ for (y = 0; y < bordery / 2; y++) {
+ memset(dest, 128, dest_fmt->fmt.pix.width / 2);
+ dest += dest_fmt->fmt.pix.bytesperline / 2;
+ }
+
+ for (y = 0; y < src_fmt->fmt.pix.height / 2; y++) {
+ memset(dest, 128, borderx / 2);
+ dest += borderx / 2;
+
+ memcpy(dest, src, src_fmt->fmt.pix.width / 2);
+ src += src_fmt->fmt.pix.bytesperline / 2;
+ dest += src_fmt->fmt.pix.width / 2;
+
+ memset(dest, 128, borderx / 2);
+ dest += (dest_fmt->fmt.pix.bytesperline -
+ (borderx + src_fmt->fmt.pix.width)) / 2;
+ }
+
+ for (y = 0; y < bordery / 2; y++) {
+ memset(dest, 128, dest_fmt->fmt.pix.width / 2);
+ dest += dest_fmt->fmt.pix.bytesperline / 2;
+ }
+
+ /* V */
+ for (y = 0; y < bordery / 2; y++) {
+ memset(dest, 128, dest_fmt->fmt.pix.width / 2);
+ dest += dest_fmt->fmt.pix.bytesperline / 2;
+ }
+
+ for (y = 0; y < src_fmt->fmt.pix.height / 2; y++) {
+ memset(dest, 128, borderx / 2);
+ dest += borderx / 2;
+
+ memcpy(dest, src, src_fmt->fmt.pix.width / 2);
+ src += src_fmt->fmt.pix.bytesperline / 2;
+ dest += src_fmt->fmt.pix.width / 2;
+
+ memset(dest, 128, borderx / 2);
+ dest += (dest_fmt->fmt.pix.bytesperline -
+ (borderx + src_fmt->fmt.pix.width)) / 2;
+ }
+
+ for (y = 0; y < bordery / 2; y++) {
+ memset(dest, 128, dest_fmt->fmt.pix.width / 2);
+ dest += dest_fmt->fmt.pix.bytesperline / 2;
+ }
+}
+
void v4lconvert_crop(unsigned char *src, unsigned char *dest,
const struct v4l2_format *src_fmt, const struct v4l2_format *dest_fmt)
{
switch (dest_fmt->fmt.pix.pixelformat) {
case V4L2_PIX_FMT_RGB24:
case V4L2_PIX_FMT_BGR24:
- if (src_fmt->fmt.pix.width >= 2 * dest_fmt->fmt.pix.width &&
- src_fmt->fmt.pix.height >= 2 * dest_fmt->fmt.pix.height)
+ if (src_fmt->fmt.pix.width <= dest_fmt->fmt.pix.width &&
+ src_fmt->fmt.pix.height <= dest_fmt->fmt.pix.height)
+ v4lconvert_add_border_rgbbgr24(src, dest, src_fmt, dest_fmt);
+ else if (src_fmt->fmt.pix.width >= 2 * dest_fmt->fmt.pix.width &&
+ src_fmt->fmt.pix.height >= 2 * dest_fmt->fmt.pix.height)
v4lconvert_reduceandcrop_rgbbgr24(src, dest, src_fmt, dest_fmt);
else
v4lconvert_crop_rgbbgr24(src, dest, src_fmt, dest_fmt);
break;
+
case V4L2_PIX_FMT_YUV420:
case V4L2_PIX_FMT_YVU420:
- if (src_fmt->fmt.pix.width >= 2 * dest_fmt->fmt.pix.width &&
- src_fmt->fmt.pix.height >= 2 * dest_fmt->fmt.pix.height)
+ if (src_fmt->fmt.pix.width <= dest_fmt->fmt.pix.width &&
+ src_fmt->fmt.pix.height <= dest_fmt->fmt.pix.height)
+ v4lconvert_add_border_yuv420(src, dest, src_fmt, dest_fmt);
+ else if (src_fmt->fmt.pix.width >= 2 * dest_fmt->fmt.pix.width &&
+ src_fmt->fmt.pix.height >= 2 * dest_fmt->fmt.pix.height)
v4lconvert_reduceandcrop_yuv420(src, dest, src_fmt, dest_fmt);
else
v4lconvert_crop_yuv420(src, dest, src_fmt, dest_fmt);
-
break;
}
}
diff --git a/v4l2-apps/libv4l/libv4lconvert/flip.c b/v4l2-apps/libv4l/libv4lconvert/flip.c
index f47afde72..8c4d8233c 100644
--- a/v4l2-apps/libv4l/libv4lconvert/flip.c
+++ b/v4l2-apps/libv4l/libv4lconvert/flip.c
@@ -20,8 +20,100 @@
*/
+#include <string.h>
#include "libv4lconvert-priv.h"
+static void v4lconvert_vflip_rgbbgr24(unsigned char *src, unsigned char *dest,
+ struct v4l2_format *fmt)
+{
+ int y;
+
+ src += fmt->fmt.pix.height * fmt->fmt.pix.bytesperline;
+ for (y = 0; y < fmt->fmt.pix.height; y++) {
+ src -= fmt->fmt.pix.bytesperline;
+ memcpy(dest, src, fmt->fmt.pix.width * 3);
+ dest += fmt->fmt.pix.width * 3;
+ }
+}
+
+static void v4lconvert_vflip_yuv420(unsigned char *src, unsigned char *dest,
+ struct v4l2_format *fmt)
+{
+ int y;
+
+ /* First flip the Y plane */
+ src += fmt->fmt.pix.height * fmt->fmt.pix.bytesperline;
+ for (y = 0; y < fmt->fmt.pix.height; y++) {
+ src -= fmt->fmt.pix.bytesperline;
+ memcpy(dest, src, fmt->fmt.pix.width);
+ dest += fmt->fmt.pix.width;
+ }
+
+ /* Now flip the U plane */
+ src += fmt->fmt.pix.height * fmt->fmt.pix.bytesperline * 5 / 4;
+ for (y = 0; y < fmt->fmt.pix.height / 2; y++) {
+ src -= fmt->fmt.pix.bytesperline / 2;
+ memcpy(dest, src, fmt->fmt.pix.width / 2);
+ dest += fmt->fmt.pix.width / 2;
+ }
+
+ /* Last flip the V plane */
+ src += fmt->fmt.pix.height * fmt->fmt.pix.bytesperline / 2;
+ for (y = 0; y < fmt->fmt.pix.height / 2; y++) {
+ src -= fmt->fmt.pix.bytesperline / 2;
+ memcpy(dest, src, fmt->fmt.pix.width / 2);
+ dest += fmt->fmt.pix.width / 2;
+ }
+}
+
+static void v4lconvert_hflip_rgbbgr24(unsigned char *src, unsigned char *dest,
+ struct v4l2_format *fmt)
+{
+ int x, y;
+
+ for (y = 0; y < fmt->fmt.pix.height; y++) {
+ src += fmt->fmt.pix.width * 3;
+ for (x = 0; x < fmt->fmt.pix.width; x++) {
+ src -= 3;
+ dest[0] = src[0];
+ dest[1] = src[1];
+ dest[2] = src[2];
+ dest += 3;
+ }
+ src += fmt->fmt.pix.bytesperline;
+ }
+}
+
+static void v4lconvert_hflip_yuv420(unsigned char *src, unsigned char *dest,
+ struct v4l2_format *fmt)
+{
+ int x, y;
+
+ /* First flip the Y plane */
+ for (y = 0; y < fmt->fmt.pix.height; y++) {
+ src += fmt->fmt.pix.width;
+ for (x = 0; x < fmt->fmt.pix.width; x++)
+ *dest++ = *--src;
+ src += fmt->fmt.pix.bytesperline;
+ }
+
+ /* Now flip the U plane */
+ for (y = 0; y < fmt->fmt.pix.height / 2; y++) {
+ src += fmt->fmt.pix.width / 2;
+ for (x = 0; x < fmt->fmt.pix.width / 2; x++)
+ *dest++ = *--src;
+ src += fmt->fmt.pix.bytesperline / 2;
+ }
+
+ /* Last flip the V plane */
+ for (y = 0; y < fmt->fmt.pix.height / 2; y++) {
+ src += fmt->fmt.pix.width / 2;
+ for (x = 0; x < fmt->fmt.pix.width / 2; x++)
+ *dest++ = *--src;
+ src += fmt->fmt.pix.bytesperline / 2;
+ }
+}
+
static void v4lconvert_rotate180_rgbbgr24(const unsigned char *src,
unsigned char *dst, int width, int height)
{
@@ -106,37 +198,69 @@ static void v4lconvert_rotate90_yuv420(const unsigned char *src,
}
}
-void v4lconvert_rotate(unsigned char *src, unsigned char *dest,
- int width, int height, unsigned int pix_fmt, int rotate)
+void v4lconvert_rotate90(unsigned char *src, unsigned char *dest,
+ struct v4l2_format *fmt)
+{
+ int tmp;
+
+ tmp = fmt->fmt.pix.width;
+ fmt->fmt.pix.width = fmt->fmt.pix.height;
+ fmt->fmt.pix.height = tmp;
+
+ switch (fmt->fmt.pix.pixelformat) {
+ case V4L2_PIX_FMT_RGB24:
+ case V4L2_PIX_FMT_BGR24:
+ v4lconvert_rotate90_rgbbgr24(src, dest, fmt->fmt.pix.width,
+ fmt->fmt.pix.height);
+ break;
+ case V4L2_PIX_FMT_YUV420:
+ case V4L2_PIX_FMT_YVU420:
+ v4lconvert_rotate90_yuv420(src, dest, fmt->fmt.pix.width,
+ fmt->fmt.pix.height);
+ break;
+ }
+}
+
+void v4lconvert_flip(unsigned char *src, unsigned char *dest,
+ struct v4l2_format *fmt, int hflip, int vflip)
{
- switch (rotate) {
- case 0:
- break;
- case 90:
- switch (pix_fmt) {
+ if (vflip && hflip) {
+ switch (fmt->fmt.pix.pixelformat) {
+ case V4L2_PIX_FMT_RGB24:
+ case V4L2_PIX_FMT_BGR24:
+ v4lconvert_rotate180_rgbbgr24(src, dest, fmt->fmt.pix.width,
+ fmt->fmt.pix.height);
+ break;
+ case V4L2_PIX_FMT_YUV420:
+ case V4L2_PIX_FMT_YVU420:
+ v4lconvert_rotate180_yuv420(src, dest, fmt->fmt.pix.width,
+ fmt->fmt.pix.height);
+ break;
+ }
+ } else if (hflip) {
+ switch (fmt->fmt.pix.pixelformat) {
case V4L2_PIX_FMT_RGB24:
case V4L2_PIX_FMT_BGR24:
- v4lconvert_rotate90_rgbbgr24(src, dest, width, height);
+ v4lconvert_hflip_rgbbgr24(src, dest, fmt);
break;
case V4L2_PIX_FMT_YUV420:
case V4L2_PIX_FMT_YVU420:
- v4lconvert_rotate90_yuv420(src, dest, width, height);
+ v4lconvert_hflip_yuv420(src, dest, fmt);
break;
}
- break;
- case 180:
- switch (pix_fmt) {
+ } else if (vflip) {
+ switch (fmt->fmt.pix.pixelformat) {
case V4L2_PIX_FMT_RGB24:
case V4L2_PIX_FMT_BGR24:
- v4lconvert_rotate180_rgbbgr24(src, dest, width, height);
+ v4lconvert_vflip_rgbbgr24(src, dest, fmt);
break;
case V4L2_PIX_FMT_YUV420:
case V4L2_PIX_FMT_YVU420:
- v4lconvert_rotate180_yuv420(src, dest, width, height);
+ v4lconvert_vflip_yuv420(src, dest, fmt);
break;
}
- break;
- default:
- printf("FIXME add %d degrees rotation\n", rotate);
}
+
+ /* Our newly written data has no padding */
+ v4lconvert_fixup_fmt(fmt);
}
diff --git a/v4l2-apps/libv4l/libv4lconvert/helper-funcs.h b/v4l2-apps/libv4l/libv4lconvert/helper-funcs.h
new file mode 100644
index 000000000..8ce12343c
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4lconvert/helper-funcs.h
@@ -0,0 +1,79 @@
+/* Utility functions for decompression helpers
+ *
+ * Copyright (c) 2009 Hans de Goede <hdegoede@redhat.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+
+static int v4lconvert_helper_write(int fd, const void *b, size_t count,
+ char *progname)
+{
+ const unsigned char *buf = b;
+ size_t ret, written = 0;
+
+ while (written < count) {
+ ret = write(fd, buf + written, count - written);
+ if (ret == -1) {
+ if (errno == EINTR)
+ continue;
+
+ if (errno == EPIPE) /* Main program has quited */
+ exit(0);
+
+ fprintf(stderr, "%s: error writing: %s\n", progname, strerror(errno));
+ return -1;
+ }
+ written += ret;
+ }
+
+ return 0;
+}
+
+static int v4lconvert_helper_read(int fd, void *b, size_t count,
+ char *progname)
+{
+ unsigned char *buf = b;
+ size_t ret, r = 0;
+
+ while (r < count) {
+ ret = read(fd, buf + r, count - r);
+ if (ret == -1) {
+ if (errno == EINTR)
+ continue;
+
+ fprintf(stderr, "%s: error reading: %s\n", progname, strerror(errno));
+ return -1;
+ }
+ if (ret == 0) /* EOF */
+ exit(0);
+
+ r += ret;
+ }
+
+ return 0;
+}
diff --git a/v4l2-apps/libv4l/libv4lconvert/helper.c b/v4l2-apps/libv4l/libv4lconvert/helper.c
new file mode 100644
index 000000000..c1d55c2e5
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4lconvert/helper.c
@@ -0,0 +1,224 @@
+/*
+# (C) 2009 Hans de Goede <hdegoede@redhat.com>
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser 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
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include "libv4lconvert-priv.h"
+
+#define READ_END 0
+#define WRITE_END 1
+
+/* <sigh> Unfortunately I've failed in contact some Authors of decompression
+ code of out of tree drivers. So I've no permission to relicense their code
+ their code from GPL to LGPL. To work around this, these decompression
+ algorithms are put in separate executables and we pipe data through these
+ to decompress.
+
+ The "protocol" is very simple:
+
+ From libv4l to the helper the following is send:
+ int width
+ int height
+ int flags
+ int data length
+ unsigned char[] data (data length long)
+
+ From the helper to libv4l the following is send:
+ int data length (-1 in case of a decompression error)
+ unsigned char[] data (not present when a decompression error happened)
+*/
+
+static int v4lconvert_helper_start(struct v4lconvert_data *data,
+ const char *helper)
+{
+ if (pipe(data->decompress_in_pipe)) {
+ V4LCONVERT_ERR("with helper pipe: %s\n", strerror(errno));
+ goto error;
+ }
+
+ if (pipe(data->decompress_out_pipe)) {
+ V4LCONVERT_ERR("with helper pipe: %s\n", strerror(errno));
+ goto error_close_in_pipe;
+ }
+
+ data->decompress_pid = fork();
+ if (data->decompress_pid == -1) {
+ V4LCONVERT_ERR("with helper fork: %s\n", strerror(errno));
+ goto error_close_out_pipe;
+ }
+
+ if (data->decompress_pid == 0) {
+ /* We are the child */
+
+ /* Closed unused read / write end of the pipes */
+ close(data->decompress_out_pipe[WRITE_END]);
+ close(data->decompress_in_pipe[READ_END]);
+
+ /* Connect stdin / out to the pipes */
+ if (dup2(data->decompress_out_pipe[READ_END], STDIN_FILENO) == -1) {
+ perror("libv4lconvert: error with helper dup2");
+ exit(1);
+ }
+ if (dup2(data->decompress_in_pipe[WRITE_END], STDOUT_FILENO) == -1) {
+ perror("libv4lconvert: error with helper dup2");
+ exit(1);
+ }
+
+ /* And execute the helper */
+ execl(helper, helper, NULL);
+
+ /* We should never get here */
+ perror("libv4lconvert: error starting helper");
+ exit(1);
+ } else {
+ /* Closed unused read / write end of the pipes */
+ close(data->decompress_out_pipe[READ_END]);
+ close(data->decompress_in_pipe[WRITE_END]);
+ }
+
+ return 0;
+
+error_close_out_pipe:
+ close(data->decompress_out_pipe[READ_END]);
+ close(data->decompress_out_pipe[WRITE_END]);
+error_close_in_pipe:
+ close(data->decompress_in_pipe[READ_END]);
+ close(data->decompress_in_pipe[WRITE_END]);
+error:
+ return -1;
+}
+
+/* IMPROVE ME: we could block SIGPIPE here using pthread_sigmask()
+ and then in case of EPIPE consume the signal using
+ sigtimedwait (we need to check if a blocked signal wasn't present
+ before the write, otherwise we will consume that) and
+ after consuming the signal try to restart the helper.
+
+ Note we currently do not do this, as SIGPIPE only happens if the
+ decompressor crashes, which in case of an embedded decompressor
+ would mean end of program, so by not handling SIGPIPE we treat
+ external decompressors identical. */
+static int v4lconvert_helper_write(struct v4lconvert_data *data,
+ const void *b, size_t count)
+{
+ const unsigned char *buf = b;
+ const int *i = b;
+ size_t ret, written = 0;
+
+ while (written < count) {
+ ret = write(data->decompress_out_pipe[WRITE_END], buf + written,
+ count - written);
+ if (ret == -1) {
+ if (errno == EINTR)
+ continue;
+
+ V4LCONVERT_ERR("writing to helper: %s\n", strerror(errno));
+ return -1;
+ }
+ written += ret;
+ }
+
+ return 0;
+}
+
+static int v4lconvert_helper_read(struct v4lconvert_data *data, void *b,
+ size_t count)
+{
+ unsigned char *buf = b;
+ size_t ret, r = 0;
+
+ while (r < count) {
+ ret = read(data->decompress_in_pipe[READ_END], buf + r, count - r);
+ if (ret == -1) {
+ if (errno == EINTR)
+ continue;
+
+ V4LCONVERT_ERR("reading from helper: %s\n", strerror(errno));
+ return -1;
+ }
+ if (ret == 0) {
+ V4LCONVERT_ERR("reading from helper: unexpected EOF\n");
+ return -1;
+ }
+ r += ret;
+ }
+
+ return 0;
+}
+
+int v4lconvert_helper_decompress(struct v4lconvert_data *data,
+ const char *helper, const unsigned char *src, int src_size,
+ unsigned char *dest, int dest_size, int width, int height, int flags)
+{
+ int r;
+
+ if (data->decompress_pid == -1) {
+ if (v4lconvert_helper_start(data, helper))
+ return -1;
+ }
+
+ if (v4lconvert_helper_write(data, &width, sizeof(int)))
+ return -1;
+
+ if (v4lconvert_helper_write(data, &height, sizeof(int)))
+ return -1;
+
+ if (v4lconvert_helper_write(data, &flags, sizeof(int)))
+ return -1;
+
+ if (v4lconvert_helper_write(data, &src_size, sizeof(int)))
+ return -1;
+
+ if (v4lconvert_helper_write(data, src, src_size))
+ return -1;
+
+ if (v4lconvert_helper_read(data, &r, sizeof(int)))
+ return -1;
+
+ if (r < 0) {
+ V4LCONVERT_ERR("decompressing frame data\n");
+ return -1;
+ }
+
+ if (dest_size < r) {
+ V4LCONVERT_ERR("destination buffer to small\n");
+ return -1;
+ }
+
+ return v4lconvert_helper_read(data, dest, r);
+}
+
+void v4lconvert_helper_cleanup(struct v4lconvert_data *data)
+{
+ int status;
+
+ if (data->decompress_pid != -1) {
+ kill(data->decompress_pid, SIGTERM);
+ waitpid(data->decompress_pid, &status, 0);
+
+ close(data->decompress_out_pipe[WRITE_END]);
+ close(data->decompress_in_pipe[READ_END]);
+
+ data->decompress_pid = -1;
+ }
+}
diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h
index 5ce7bde3b..2cf8f6ba4 100644
--- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h
+++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h
@@ -20,9 +20,14 @@
#define __LIBV4LCONVERT_PRIV_H
#include <stdio.h>
+#include <sys/types.h>
#include "libv4lconvert.h"
+#include "control/libv4lcontrol.h"
+#include "processing/libv4lprocessing.h"
#include "tinyjpeg.h"
+/* Workaround these potentially missing from videodev2.h */
+
#ifndef V4L2_PIX_FMT_SPCA501
#define V4L2_PIX_FMT_SPCA501 v4l2_fourcc('S','5','0','1') /* YUYV per line */
#endif
@@ -79,6 +84,16 @@
#define V4L2_PIX_FMT_SN9C20X_I420 v4l2_fourcc('S', '9', '2', '0')
#endif
+#ifndef V4L2_PIX_FMT_OV511
+#define V4L2_PIX_FMT_OV511 v4l2_fourcc('O', '5', '1', '1')
+#endif
+
+#ifndef V4L2_PIX_FMT_OV518
+#define V4L2_PIX_FMT_OV518 v4l2_fourcc('O', '5', '1', '8') /* ov518 JPEG */
+#endif
+
+#define ARRAY_SIZE(x) ((int)sizeof(x)/(int)sizeof((x)[0]))
+
#define V4LCONVERT_ERROR_MSG_SIZE 256
#define V4LCONVERT_MAX_FRAMESIZES 16
@@ -87,37 +102,40 @@
"v4l-convert: error " __VA_ARGS__)
/* Card flags */
-#define V4LCONVERT_ROTATE_90 0x01
-#define V4LCONVERT_ROTATE_180 0x02
-#define V4LCONVERT_IS_UVC 0x04
+#define V4LCONVERT_IS_UVC 0x01
+#define V4LCONVERT_IS_SN9C20X 0x02
/* Pixformat flags */
-#define V4LCONVERT_COMPRESSED 0x01
+#define V4LCONVERT_COMPRESSED 0x01 /* Compressed format */
+#define V4LCONVERT_NEEDS_CONVERSION 0x02 /* Apps likely wont know this */
struct v4lconvert_data {
int fd;
int flags; /* bitfield */
+ int control_flags; /* bitfield */
int supported_src_formats; /* bitfield */
unsigned int no_formats;
char error_msg[V4LCONVERT_ERROR_MSG_SIZE];
struct jdec_private *jdec;
struct v4l2_frmsizeenum framesizes[V4LCONVERT_MAX_FRAMESIZES];
unsigned int no_framesizes;
- int convert_buf_size;
- int rotate_buf_size;
+ int convert1_buf_size;
+ int convert2_buf_size;
+ int rotate90_buf_size;
+ int flip_buf_size;
int convert_pixfmt_buf_size;
- unsigned char *convert_buf;
- unsigned char *rotate_buf;
+ unsigned char *convert1_buf;
+ unsigned char *convert2_buf;
+ unsigned char *rotate90_buf;
+ unsigned char *flip_buf;
unsigned char *convert_pixfmt_buf;
-};
+ struct v4lcontrol_data *control;
+ struct v4lprocessing_data *processing;
-struct v4lconvert_flags_info {
- unsigned short vendor_id;
- unsigned short product_id;
-/* We could also use the USB manufacturer and product strings some devices have
- const char *manufacturer;
- const char *product; */
- int flags;
+ /* Data for external decompression helpers code */
+ pid_t decompress_pid;
+ int decompress_in_pipe[2]; /* Data from helper to us */
+ int decompress_out_pipe[2]; /* Data from us to helper */
};
struct v4lconvert_pixfmt {
@@ -125,6 +143,8 @@ struct v4lconvert_pixfmt {
int flags;
};
+void v4lconvert_fixup_fmt(struct v4l2_format *fmt);
+
void v4lconvert_rgb24_to_yuv420(const unsigned char *src, unsigned char *dest,
const struct v4l2_format *src_fmt, int bgr, int yvu);
@@ -209,10 +229,19 @@ void v4lconvert_hm12_to_bgr24(const unsigned char *src,
void v4lconvert_hm12_to_yuv420(const unsigned char *src,
unsigned char *dst, int width, int height, int yvu);
-void v4lconvert_rotate(unsigned char *src, unsigned char *dest,
- int width, int height, unsigned int pix_fmt, int rotate);
+void v4lconvert_rotate90(unsigned char *src, unsigned char *dest,
+ struct v4l2_format *fmt);
+
+void v4lconvert_flip(unsigned char *src, unsigned char *dest,
+ struct v4l2_format *fmt, int hflip, int vflip);
void v4lconvert_crop(unsigned char *src, unsigned char *dest,
const struct v4l2_format *src_fmt, const struct v4l2_format *dest_fmt);
+int v4lconvert_helper_decompress(struct v4lconvert_data *data,
+ const char *helper, const unsigned char *src, int src_size,
+ unsigned char *dest, int dest_size, int width, int height, int command);
+
+void v4lconvert_helper_cleanup(struct v4lconvert_data *data);
+
#endif
diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c
index 1204e8ef2..1389c58bc 100644
--- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c
+++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c
@@ -19,15 +19,14 @@
#include <errno.h>
#include <string.h>
#include <stdlib.h>
-#include <syscall.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "libv4lconvert.h"
#include "libv4lconvert-priv.h"
+#include "libv4lsyscall-priv.h"
#define MIN(a,b) (((a)<(b))?(a):(b))
-#define ARRAY_SIZE(x) ((int)sizeof(x)/(int)sizeof((x)[0]))
/* Note for proper functioning of v4lconvert_enum_fmt the first entries in
supported_src_pixfmts must match with the entries in supported_dst_pixfmts */
@@ -47,15 +46,15 @@ static const struct v4lconvert_pixfmt supported_src_pixfmts[] = {
{ V4L2_PIX_FMT_YUYV, 0 },
{ V4L2_PIX_FMT_YVYU, 0 },
{ V4L2_PIX_FMT_UYVY, 0 },
- { V4L2_PIX_FMT_SN9C20X_I420, 0 },
- { V4L2_PIX_FMT_SBGGR8, 0 },
- { V4L2_PIX_FMT_SGBRG8, 0 },
- { V4L2_PIX_FMT_SGRBG8, 0 },
- { V4L2_PIX_FMT_SRGGB8, 0 },
- { V4L2_PIX_FMT_SPCA501, 0 },
- { V4L2_PIX_FMT_SPCA505, 0 },
- { V4L2_PIX_FMT_SPCA508, 0 },
- { V4L2_PIX_FMT_HM12, 0 },
+ { V4L2_PIX_FMT_SN9C20X_I420, V4LCONVERT_NEEDS_CONVERSION },
+ { V4L2_PIX_FMT_SBGGR8, V4LCONVERT_NEEDS_CONVERSION },
+ { V4L2_PIX_FMT_SGBRG8, V4LCONVERT_NEEDS_CONVERSION },
+ { V4L2_PIX_FMT_SGRBG8, V4LCONVERT_NEEDS_CONVERSION },
+ { V4L2_PIX_FMT_SRGGB8, V4LCONVERT_NEEDS_CONVERSION },
+ { V4L2_PIX_FMT_SPCA501, V4LCONVERT_NEEDS_CONVERSION },
+ { V4L2_PIX_FMT_SPCA505, V4LCONVERT_NEEDS_CONVERSION },
+ { V4L2_PIX_FMT_SPCA508, V4LCONVERT_NEEDS_CONVERSION },
+ { V4L2_PIX_FMT_HM12, V4LCONVERT_NEEDS_CONVERSION },
{ V4L2_PIX_FMT_MJPEG, V4LCONVERT_COMPRESSED },
{ V4L2_PIX_FMT_JPEG, V4LCONVERT_COMPRESSED },
{ V4L2_PIX_FMT_SPCA561, V4LCONVERT_COMPRESSED },
@@ -64,20 +63,14 @@ static const struct v4lconvert_pixfmt supported_src_pixfmts[] = {
{ V4L2_PIX_FMT_MR97310A, V4LCONVERT_COMPRESSED },
{ V4L2_PIX_FMT_SQ905C, V4LCONVERT_COMPRESSED },
{ V4L2_PIX_FMT_PJPG, V4LCONVERT_COMPRESSED },
+ { V4L2_PIX_FMT_OV511, V4LCONVERT_COMPRESSED },
+ { V4L2_PIX_FMT_OV518, V4LCONVERT_COMPRESSED },
};
static const struct v4lconvert_pixfmt supported_dst_pixfmts[] = {
SUPPORTED_DST_PIXFMTS
};
-/* List of cams which need special flags */
-static const struct v4lconvert_flags_info v4lconvert_flags[] = {
- { 0x0471, 0x0325, V4LCONVERT_ROTATE_180 }, /* Philips SPC200NC */
- { 0x0471, 0x0326, V4LCONVERT_ROTATE_180 }, /* Philips SPC300NC */
- { 0x0471, 0x032d, V4LCONVERT_ROTATE_180 }, /* Philips SPC210NC */
- { 0x093a, 0x2476, V4LCONVERT_ROTATE_180 }, /* Genius E-M 112 */
-};
-
/* List of well known resolutions which we can get by cropping somewhat larger
resolutions */
static const int v4lconvert_crop_res[][2] = {
@@ -91,56 +84,21 @@ static const int v4lconvert_crop_res[][2] = {
{ 176, 144 },
};
-static int v4lconvert_get_flags(int fd)
-{
- struct stat st;
- FILE *f;
- char sysfs_name[512];
- unsigned short vendor_id = 0;
- unsigned short product_id = 0;
- int i;
-
- if (fstat(fd, &st) || !S_ISCHR(st.st_mode))
- return 0; /* Should never happen */
-
- /* Get product ID */
- snprintf(sysfs_name, sizeof(sysfs_name),
- "/sys/class/video4linux/video%d/device/idVendor",
- minor(st.st_rdev));
- f = fopen(sysfs_name, "r");
- if (!f)
- return 0; /* Not an USB device (or no sysfs) */
- i = fscanf(f, "%hx", &vendor_id);
- fclose(f);
-
- /* Get product ID */
- snprintf(sysfs_name, sizeof(sysfs_name),
- "/sys/class/video4linux/video%d/device/idProduct",
- minor(st.st_rdev));
- f = fopen(sysfs_name, "r");
- if (!f)
- return 0; /* Should never happen */
- i = fscanf(f, "%hx", &product_id);
- fclose(f);
-
- for (i = 0; i < ARRAY_SIZE(v4lconvert_flags); i++)
- if (v4lconvert_flags[i].vendor_id == vendor_id &&
- v4lconvert_flags[i].product_id == product_id)
- return v4lconvert_flags[i].flags;
-
- return 0;
-}
-
struct v4lconvert_data *v4lconvert_create(int fd)
{
int i, j;
struct v4lconvert_data *data = calloc(1, sizeof(struct v4lconvert_data));
struct v4l2_capability cap;
+ /* This keeps tracks of devices which have only formats for which apps
+ most likely will need conversion and we can thus safely add software
+ processing controls without a performance impact. */
+ int always_needs_conversion = 1;
if (!data)
return NULL;
data->fd = fd;
+ data->decompress_pid = -1;
/* Check supported formats */
for (i = 0; ; i++) {
@@ -148,24 +106,47 @@ struct v4lconvert_data *v4lconvert_create(int fd)
fmt.index = i;
- if (syscall(SYS_ioctl, fd, VIDIOC_ENUM_FMT, &fmt))
+ if (SYS_IOCTL(data->fd, VIDIOC_ENUM_FMT, &fmt))
break;
for (j = 0; j < ARRAY_SIZE(supported_src_pixfmts); j++)
if (fmt.pixelformat == supported_src_pixfmts[j].fmt) {
data->supported_src_formats |= 1 << j;
v4lconvert_get_framesizes(data, fmt.pixelformat, j);
+ if (!supported_src_pixfmts[j].flags)
+ always_needs_conversion = 0;
break;
}
+
+ if (j == ARRAY_SIZE(supported_src_pixfmts))
+ always_needs_conversion = 0;
}
data->no_formats = i;
/* Check if this cam has any special flags */
- data->flags = v4lconvert_get_flags(data->fd);
- if (syscall(SYS_ioctl, fd, VIDIOC_QUERYCAP, &cap) == 0) {
+ if (SYS_IOCTL(data->fd, VIDIOC_QUERYCAP, &cap) == 0) {
if (!strcmp((char *)cap.driver, "uvcvideo"))
data->flags |= V4LCONVERT_IS_UVC;
+ else if (!strcmp((char *)cap.driver, "sn9c20x"))
+ data->flags |= V4LCONVERT_IS_SN9C20X;
+
+ if ((cap.capabilities & 0xff) & ~V4L2_CAP_VIDEO_CAPTURE)
+ always_needs_conversion = 0;
+ }
+
+ data->control = v4lcontrol_create(fd, always_needs_conversion);
+ if (!data->control) {
+ free(data);
+ return NULL;
+ }
+ data->control_flags = v4lcontrol_get_flags(data->control);
+
+ data->processing = v4lprocessing_create(fd, data->control);
+ if (!data->processing) {
+ v4lcontrol_destroy(data->control);
+ free(data);
+ return NULL;
}
return data;
@@ -173,18 +154,23 @@ struct v4lconvert_data *v4lconvert_create(int fd)
void v4lconvert_destroy(struct v4lconvert_data *data)
{
+ v4lprocessing_destroy(data->processing);
+ v4lcontrol_destroy(data->control);
if (data->jdec) {
unsigned char *comps[3] = { NULL, NULL, NULL };
tinyjpeg_set_components(data->jdec, comps, 3);
tinyjpeg_free(data->jdec);
}
- free(data->convert_buf);
- free(data->rotate_buf);
+ v4lconvert_helper_cleanup(data);
+ free(data->convert1_buf);
+ free(data->convert2_buf);
+ free(data->rotate90_buf);
+ free(data->flip_buf);
free(data->convert_pixfmt_buf);
free(data);
}
-static int v4lconvert_supported_dst_format(unsigned int pixelformat)
+int v4lconvert_supported_dst_format(unsigned int pixelformat)
{
int i;
@@ -195,6 +181,12 @@ static int v4lconvert_supported_dst_format(unsigned int pixelformat)
return i != ARRAY_SIZE(supported_dst_pixfmts);
}
+int v4lconvert_supported_dst_fmt_only(struct v4lconvert_data *data)
+{
+ return v4lcontrol_needs_conversion(data->control) &&
+ data->supported_src_formats;
+}
+
/* See libv4lconvert.h for description of in / out parameters */
int v4lconvert_enum_fmt(struct v4lconvert_data *data, struct v4l2_fmtdesc *fmt)
{
@@ -202,17 +194,22 @@ int v4lconvert_enum_fmt(struct v4lconvert_data *data, struct v4l2_fmtdesc *fmt)
unsigned int faked_fmts[ARRAY_SIZE(supported_dst_pixfmts)];
if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
- fmt->index < data->no_formats ||
- !data->supported_src_formats)
- return syscall(SYS_ioctl, data->fd, VIDIOC_ENUM_FMT, fmt);
+ (!v4lconvert_supported_dst_fmt_only(data) &&
+ fmt->index < data->no_formats))
+ return SYS_IOCTL(data->fd, VIDIOC_ENUM_FMT, fmt);
for (i = 0; i < ARRAY_SIZE(supported_dst_pixfmts); i++)
- if (!(data->supported_src_formats & (1 << i))) {
+ if (v4lconvert_supported_dst_fmt_only(data) ||
+ !(data->supported_src_formats & (1 << i))) {
faked_fmts[no_faked_fmts] = supported_dst_pixfmts[i].fmt;
no_faked_fmts++;
}
- i = fmt->index - data->no_formats;
+ if (!v4lconvert_supported_dst_fmt_only(data))
+ i = fmt->index - data->no_formats;
+ else
+ i = fmt->index;
+
if (i >= no_faked_fmts) {
errno = EINVAL;
return -1;
@@ -307,7 +304,7 @@ static int v4lconvert_do_try_format(struct v4lconvert_data *data,
try_fmt = *dest_fmt;
try_fmt.fmt.pix.pixelformat = supported_src_pixfmts[i].fmt;
- if (!syscall(SYS_ioctl, data->fd, VIDIOC_TRY_FMT, &try_fmt))
+ if (!SYS_IOCTL(data->fd, VIDIOC_TRY_FMT, &try_fmt))
{
if (try_fmt.fmt.pix.pixelformat == supported_src_pixfmts[i].fmt) {
int size_x_diff = abs((int)try_fmt.fmt.pix.width -
@@ -339,7 +336,7 @@ static int v4lconvert_do_try_format(struct v4lconvert_data *data,
return 0;
}
-static void v4lconvert_fixup_fmt(struct v4l2_format *fmt)
+void v4lconvert_fixup_fmt(struct v4l2_format *fmt)
{
switch (fmt->fmt.pix.pixelformat) {
case V4L2_PIX_FMT_RGB24:
@@ -362,27 +359,58 @@ int v4lconvert_try_format(struct v4lconvert_data *data,
int i, result;
unsigned int desired_width = dest_fmt->fmt.pix.width;
unsigned int desired_height = dest_fmt->fmt.pix.height;
- struct v4l2_format try_src, try_dest = *dest_fmt;
+ struct v4l2_format try_src, try_dest, try2_src, try2_dest;
+
+ if (dest_fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+ v4lconvert_supported_dst_fmt_only(data) &&
+ !v4lconvert_supported_dst_format(dest_fmt->fmt.pix.pixelformat))
+ dest_fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24;
+
+ try_dest = *dest_fmt;
/* Can we do conversion to the requested format & type? */
if (!v4lconvert_supported_dst_format(dest_fmt->fmt.pix.pixelformat) ||
dest_fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
v4lconvert_do_try_format(data, &try_dest, &try_src)) {
- result = syscall(SYS_ioctl, data->fd, VIDIOC_TRY_FMT, dest_fmt);
+ result = SYS_IOCTL(data->fd, VIDIOC_TRY_FMT, dest_fmt);
if (src_fmt)
*src_fmt = *dest_fmt;
return result;
}
+ /* In case of a non exact resolution match, try again with a slightly larger
+ resolution as some weird devices are not able to crop of the number of
+ extra (border) pixels most sensors have compared to standard resolutions,
+ which we will then just crop of in software */
+ if (try_dest.fmt.pix.width != desired_width ||
+ try_dest.fmt.pix.height != desired_height) {
+ try2_dest = *dest_fmt;
+ try2_dest.fmt.pix.width = desired_width + 7;
+ try2_dest.fmt.pix.height = desired_height + 1;
+ result = v4lconvert_do_try_format(data, &try2_dest, &try2_src);
+ if (result == 0 &&
+ try2_dest.fmt.pix.width >= desired_width &&
+ try2_dest.fmt.pix.width <= desired_width + 7 &&
+ try2_dest.fmt.pix.height >= desired_height &&
+ try2_dest.fmt.pix.height <= desired_height + 1) {
+ /* Success! */
+ try2_dest.fmt.pix.width = desired_width;
+ try2_dest.fmt.pix.height = desired_height;
+ try_dest = try2_dest;
+ try_src = try2_src;
+ }
+ }
+
/* In case of a non exact resolution match, see if this is a well known
resolution some apps are hardcoded too and try to give the app what it
- asked for by cropping a slightly larger resolution */
+ asked for by cropping a slightly larger resolution or adding a small
+ black border to a slightly smaller resolution */
if (try_dest.fmt.pix.width != desired_width ||
try_dest.fmt.pix.height != desired_height) {
for (i = 0; i < ARRAY_SIZE(v4lconvert_crop_res); i++) {
if (v4lconvert_crop_res[i][0] == desired_width &&
v4lconvert_crop_res[i][1] == desired_height) {
- struct v4l2_format try2_src, try2_dest = *dest_fmt;
+ try2_dest = *dest_fmt;
/* Note these are chosen so that cropping to vga res just works for
vv6410 sensor cams, which have 356x292 and 180x148 */
@@ -390,13 +418,20 @@ int v4lconvert_try_format(struct v4lconvert_data *data,
try2_dest.fmt.pix.height = desired_height * 124 / 100;
result = v4lconvert_do_try_format(data, &try2_dest, &try2_src);
if (result == 0 &&
- ((try2_dest.fmt.pix.width >= desired_width &&
+ (/* Add a small black border of max 16 pixels */
+ (try2_dest.fmt.pix.width >= desired_width - 16 &&
+ try2_dest.fmt.pix.width <= desired_width &&
+ try2_dest.fmt.pix.height >= desired_height - 16 &&
+ try2_dest.fmt.pix.height <= desired_height) ||
+ /* Standard cropping to max 80% of actual width / height */
+ (try2_dest.fmt.pix.width >= desired_width &&
try2_dest.fmt.pix.width <= desired_width * 5 / 4 &&
try2_dest.fmt.pix.height >= desired_height &&
try2_dest.fmt.pix.height <= desired_height * 5 / 4) ||
+ /* Downscale 2x + cropping to max 80% of actual width / height */
(try2_dest.fmt.pix.width >= desired_width * 2 &&
try2_dest.fmt.pix.width <= desired_width * 5 / 2 &&
- try2_dest.fmt.pix.height >= desired_height &&
+ try2_dest.fmt.pix.height >= desired_height * 2 &&
try2_dest.fmt.pix.height <= desired_height * 5 / 2))) {
/* Success! */
try2_dest.fmt.pix.width = desired_width;
@@ -409,7 +444,15 @@ int v4lconvert_try_format(struct v4lconvert_data *data,
}
}
- /* Are we converting? */
+ /* Some applications / libs (*cough* gstreamer *cough*) will not work
+ correctly with planar YUV formats when the width is not a multiple of 8
+ or the height is not a multiple of 2. With RGB formats these apps require
+ the width to be a multiple of 4. We apply the same rounding to all
+ formats to not end up with 2 close but different resolutions. */
+ try_dest.fmt.pix.width &= ~7;
+ try_dest.fmt.pix.height &= ~1;
+
+ /* Are we converting / cropping ? */
if(try_src.fmt.pix.width != try_dest.fmt.pix.width ||
try_src.fmt.pix.height != try_dest.fmt.pix.height ||
try_src.fmt.pix.pixelformat != try_dest.fmt.pix.pixelformat)
@@ -427,19 +470,40 @@ int v4lconvert_needs_conversion(struct v4lconvert_data *data,
const struct v4l2_format *src_fmt, /* in */
const struct v4l2_format *dest_fmt) /* in */
{
- if(src_fmt->fmt.pix.width != dest_fmt->fmt.pix.width ||
- src_fmt->fmt.pix.height != dest_fmt->fmt.pix.height ||
- src_fmt->fmt.pix.pixelformat != dest_fmt->fmt.pix.pixelformat)
- return 1; /* Formats differ */
+ if (src_fmt->fmt.pix.width != dest_fmt->fmt.pix.width ||
+ src_fmt->fmt.pix.height != dest_fmt->fmt.pix.height ||
+ src_fmt->fmt.pix.pixelformat != dest_fmt->fmt.pix.pixelformat ||
+ (v4lcontrol_needs_conversion(data->control) &&
+ v4lconvert_supported_dst_format(dest_fmt->fmt.pix.pixelformat)))
+ return 1;
- if (!(data->flags & (V4LCONVERT_ROTATE_90|V4LCONVERT_ROTATE_180)))
- return 0; /* Formats identical and we don't need flip */
+ return 0;
+}
- /* Formats are identical, but we need flip, do we support the dest_fmt? */
- if (!v4lconvert_supported_dst_format(dest_fmt->fmt.pix.pixelformat))
- return 0; /* Needs flip but we cannot do it :( */
- else
- return 1; /* Needs flip and thus conversion */
+static int v4lconvert_processing_needs_double_conversion(
+ unsigned int src_pix_fmt, unsigned int dest_pix_fmt)
+{
+ switch (src_pix_fmt) {
+ case V4L2_PIX_FMT_RGB24:
+ case V4L2_PIX_FMT_BGR24:
+ case V4L2_PIX_FMT_SPCA561:
+ case V4L2_PIX_FMT_SN9C10X:
+ case V4L2_PIX_FMT_PAC207:
+ case V4L2_PIX_FMT_MR97310A:
+ case V4L2_PIX_FMT_SQ905C:
+ case V4L2_PIX_FMT_SBGGR8:
+ case V4L2_PIX_FMT_SGBRG8:
+ case V4L2_PIX_FMT_SGRBG8:
+ case V4L2_PIX_FMT_SRGGB8:
+ return 0;
+ }
+ switch (dest_pix_fmt) {
+ case V4L2_PIX_FMT_RGB24:
+ case V4L2_PIX_FMT_BGR24:
+ return 0;
+ }
+
+ return 1;
}
static unsigned char *v4lconvert_alloc_buffer(struct v4lconvert_data *data,
@@ -460,15 +524,15 @@ static unsigned char *v4lconvert_alloc_buffer(struct v4lconvert_data *data,
}
static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data,
- unsigned char *src, int src_size, unsigned char *dest,
- const struct v4l2_format *src_fmt, unsigned int dest_pix_fmt)
+ unsigned char *src, int src_size, unsigned char *dest, int dest_size,
+ struct v4l2_format *fmt, unsigned int dest_pix_fmt)
{
unsigned int header_width, header_height;
int result = 0, jpeg_flags = TINYJPEG_FLAGS_MJPEG_TABLE;
unsigned char *components[3];
- unsigned int src_pix_fmt = src_fmt->fmt.pix.pixelformat;
- unsigned int width = src_fmt->fmt.pix.width;
- unsigned int height = src_fmt->fmt.pix.height;
+ unsigned int src_pix_fmt = fmt->fmt.pix.pixelformat;
+ unsigned int width = fmt->fmt.pix.width;
+ unsigned int height = fmt->fmt.pix.height;
switch (src_pix_fmt) {
case V4L2_PIX_FMT_PJPG:
@@ -496,12 +560,14 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data,
if (header_width != width || header_height != height) {
/* Check for (pixart) rotated JPEG */
if (header_width == height && header_height == width) {
- if (!(data->flags & V4LCONVERT_ROTATE_90)) {
- V4LCONVERT_ERR("JPEG needs 90 degree rotation\n");
- data->flags |= V4LCONVERT_ROTATE_90;
- errno = EAGAIN;
+ if (!(data->control_flags & V4LCONTROL_ROTATED_90_JPEG)) {
+ V4LCONVERT_ERR("JPEG needs 90° rotation, please report "
+ "this to <hdegoede@redhat.com>\n");
+ errno = EIO;
return -1;
}
+ fmt->fmt.pix.width = header_width;
+ fmt->fmt.pix.height = header_height;
} else {
V4LCONVERT_ERR("unexpected width / height in JPEG header"
"expected: %ux%u, header: %ux%u\n", width, height,
@@ -509,6 +575,13 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data,
errno = EIO;
return -1;
}
+ } else if ((data->control_flags & V4LCONTROL_ROTATED_90_JPEG)) {
+ fprintf(stderr, "libv4lconvert: expected 90° rotated JPEG, but got "
+ "normal JPEG, please report this to <hdegoede@redhat.com>\n");
+ V4LCONVERT_ERR("expected 90° rotated JPEG, but got normal JPEG\n");
+ errno = EAGAIN;
+ data->control_flags &= ~V4LCONTROL_ROTATED_90_JPEG;
+ return -1;
}
components[0] = dest;
@@ -541,7 +614,8 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data,
are best thrown away to avoid flashes in the video stream. Tell
the upper layer this is an intermediate fault and it should try
again with a new buffer by setting errno to EAGAIN */
- if (src_pix_fmt == V4L2_PIX_FMT_PJPG) {
+ if (src_pix_fmt == V4L2_PIX_FMT_PJPG ||
+ data->flags & V4LCONVERT_IS_SN9C20X) {
V4LCONVERT_ERR("decompressing JPEG: %s",
tinyjpeg_get_errorstring(data->jdec));
errno = EAGAIN;
@@ -561,8 +635,11 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data,
case V4L2_PIX_FMT_SPCA505:
case V4L2_PIX_FMT_SPCA508:
case V4L2_PIX_FMT_SN9C20X_I420:
+ case V4L2_PIX_FMT_OV511:
+ case V4L2_PIX_FMT_OV518:
{
unsigned char *d;
+ int d_size;
int yvu = 0;
if (dest_pix_fmt != V4L2_PIX_FMT_YUV420 &&
@@ -571,8 +648,11 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data,
&data->convert_pixfmt_buf, &data->convert_pixfmt_buf_size);
if (!d)
return -1;
- } else
+ d_size = width * height * 3 / 2;
+ } else {
d = dest;
+ d_size = dest_size;
+ }
if (dest_pix_fmt == V4L2_PIX_FMT_YVU420)
yvu = 1;
@@ -590,6 +670,22 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data,
case V4L2_PIX_FMT_SN9C20X_I420:
v4lconvert_sn9c20x_to_yuv420(src, d, width, height, yvu);
break;
+ case V4L2_PIX_FMT_OV511:
+ if (v4lconvert_helper_decompress(data, LIBDIR "/libv4l/ov511-decomp",
+ src, src_size, d, d_size, width, height, yvu)) {
+ /* Corrupt frame, better get another one */
+ errno = EAGAIN;
+ return -1;
+ }
+ break;
+ case V4L2_PIX_FMT_OV518:
+ if (v4lconvert_helper_decompress(data, LIBDIR "/libv4l/ov518-decomp",
+ src, src_size, d, d_size, width, height, yvu)) {
+ /* Corrupt frame, better get another one */
+ errno = EAGAIN;
+ return -1;
+ }
+ break;
}
switch (dest_pix_fmt) {
@@ -631,6 +727,7 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data,
case V4L2_PIX_FMT_SQ905C:
{
unsigned char *tmpbuf;
+ struct v4l2_format tmpfmt = *fmt;
tmpbuf = v4lconvert_alloc_buffer(data, width * height,
&data->convert_pixfmt_buf, &data->convert_pixfmt_buf_size);
@@ -640,27 +737,33 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data,
switch (src_pix_fmt) {
case V4L2_PIX_FMT_SPCA561:
v4lconvert_decode_spca561(src, tmpbuf, width, height);
- src_pix_fmt = V4L2_PIX_FMT_SGBRG8;
+ tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SGBRG8;
break;
case V4L2_PIX_FMT_SN9C10X:
v4lconvert_decode_sn9c10x(src, tmpbuf, width, height);
- src_pix_fmt = V4L2_PIX_FMT_SBGGR8;
+ tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8;
break;
case V4L2_PIX_FMT_PAC207:
v4lconvert_decode_pac207(src, tmpbuf, width, height);
- src_pix_fmt = V4L2_PIX_FMT_SBGGR8;
+ tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8;
break;
case V4L2_PIX_FMT_MR97310A:
v4lconvert_decode_mr97310a(src, tmpbuf, width, height);
- src_pix_fmt = V4L2_PIX_FMT_SBGGR8;
+ tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8;
break;
case V4L2_PIX_FMT_SQ905C:
v4lconvert_decode_sq905c(src, tmpbuf, width, height);
- src_pix_fmt = V4L2_PIX_FMT_SRGGB8;
+ tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SRGGB8;
break;
}
- src = tmpbuf;
+ /* Do processing on the tmp buffer, because doing it on bayer data is
+ cheaper, and bayer == rgb and our dest_fmt may be yuv */
+ tmpfmt.fmt.pix.bytesperline = width;
+ tmpfmt.fmt.pix.sizeimage = width * height;
+ v4lprocessing_processing(data->processing, tmpbuf, &tmpfmt);
/* Deliberate fall through to raw bayer fmt code! */
+ src_pix_fmt = tmpfmt.fmt.pix.pixelformat;
+ src = tmpbuf;
}
/* Raw bayer formats */
@@ -690,10 +793,10 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data,
v4lconvert_swap_rgb(src, dest, width, height);
break;
case V4L2_PIX_FMT_YUV420:
- v4lconvert_rgb24_to_yuv420(src, dest, src_fmt, 0, 0);
+ v4lconvert_rgb24_to_yuv420(src, dest, fmt, 0, 0);
break;
case V4L2_PIX_FMT_YVU420:
- v4lconvert_rgb24_to_yuv420(src, dest, src_fmt, 0, 1);
+ v4lconvert_rgb24_to_yuv420(src, dest, fmt, 0, 1);
break;
}
break;
@@ -704,10 +807,10 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data,
v4lconvert_swap_rgb(src, dest, width, height);
break;
case V4L2_PIX_FMT_YUV420:
- v4lconvert_rgb24_to_yuv420(src, dest, src_fmt, 1, 0);
+ v4lconvert_rgb24_to_yuv420(src, dest, fmt, 1, 0);
break;
case V4L2_PIX_FMT_YVU420:
- v4lconvert_rgb24_to_yuv420(src, dest, src_fmt, 1, 1);
+ v4lconvert_rgb24_to_yuv420(src, dest, fmt, 1, 1);
break;
}
break;
@@ -723,7 +826,7 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data,
height, 0);
break;
case V4L2_PIX_FMT_YVU420:
- v4lconvert_swap_uv(src, dest, src_fmt);
+ v4lconvert_swap_uv(src, dest, fmt);
break;
}
break;
@@ -739,7 +842,7 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data,
height, 1);
break;
case V4L2_PIX_FMT_YUV420:
- v4lconvert_swap_uv(src, dest, src_fmt);
+ v4lconvert_swap_uv(src, dest, fmt);
break;
}
break;
@@ -802,6 +905,10 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data,
errno = EINVAL;
return -1;
}
+
+ fmt->fmt.pix.pixelformat = dest_pix_fmt;
+ v4lconvert_fixup_fmt(fmt);
+
return 0;
}
@@ -810,14 +917,31 @@ int v4lconvert_convert(struct v4lconvert_data *data,
const struct v4l2_format *dest_fmt, /* in */
unsigned char *src, int src_size, unsigned char *dest, int dest_size)
{
- int res, dest_needed, temp_needed, convert = 0, rotate = 0, crop = 0;
- unsigned char *convert_dest = dest, *rotate_src = src, *rotate_dest = dest;
+ int res, dest_needed, temp_needed, processing, convert = 0;
+ int rotate90, vflip, hflip, crop;
+ unsigned char *convert1_dest = dest;
+ int convert1_dest_size = dest_size;
+ unsigned char *convert2_src = src, *convert2_dest = dest;
+ int convert2_dest_size = dest_size;
+ unsigned char *rotate90_src = src, *rotate90_dest = dest;
+ unsigned char *flip_src = src, *flip_dest = dest;
unsigned char *crop_src = src;
struct v4l2_format my_src_fmt = *src_fmt;
struct v4l2_format my_dest_fmt = *dest_fmt;
- /* Special case when no conversion is needed */
- if (!v4lconvert_needs_conversion(data, src_fmt, dest_fmt)) {
+ processing = v4lprocessing_pre_processing(data->processing);
+ rotate90 = data->control_flags & V4LCONTROL_ROTATED_90_JPEG;
+ hflip = v4lcontrol_get_ctrl(data->control, V4LCONTROL_HFLIP);
+ vflip = v4lcontrol_get_ctrl(data->control, V4LCONTROL_VFLIP);
+ crop = my_dest_fmt.fmt.pix.width != my_src_fmt.fmt.pix.width ||
+ my_dest_fmt.fmt.pix.height != my_src_fmt.fmt.pix.height;
+
+ if (/* If no conversion/processing is needed */
+ (src_fmt->fmt.pix.pixelformat == dest_fmt->fmt.pix.pixelformat &&
+ !processing && !rotate90 && !hflip && !vflip && !crop) ||
+ /* or if we should do processing/rotating/flipping but the app tries to
+ use the native cam format, we just return an unprocessed frame copy */
+ !v4lconvert_supported_dst_format(dest_fmt->fmt.pix.pixelformat)) {
int to_copy = MIN(dest_size, src_size);
memcpy(dest, src, to_copy);
return to_copy;
@@ -856,52 +980,96 @@ int v4lconvert_convert(struct v4lconvert_data *data,
return -1;
}
- if (my_dest_fmt.fmt.pix.pixelformat != my_src_fmt.fmt.pix.pixelformat)
+
+ /* Sometimes we need foo -> rgb -> bar as video processing (whitebalance,
+ etc.) can only be done on rgb data */
+ if (processing && v4lconvert_processing_needs_double_conversion(
+ my_src_fmt.fmt.pix.pixelformat,
+ my_dest_fmt.fmt.pix.pixelformat))
+ convert = 2;
+ else if (my_dest_fmt.fmt.pix.pixelformat != my_src_fmt.fmt.pix.pixelformat)
convert = 1;
- if (data->flags & V4LCONVERT_ROTATE_90)
- rotate += 90;
- if (data->flags & V4LCONVERT_ROTATE_180)
- rotate += 180;
+ /* convert_pixfmt (only if convert == 2) -> processing -> convert_pixfmt ->
+ rotate -> flip -> crop, all steps are optional */
+ if (convert == 2) {
+ convert1_dest = v4lconvert_alloc_buffer(data,
+ my_src_fmt.fmt.pix.width * my_src_fmt.fmt.pix.height * 3,
+ &data->convert1_buf, &data->convert1_buf_size);
+ if (!convert1_dest)
+ return -1;
+
+ convert1_dest_size =
+ my_src_fmt.fmt.pix.width * my_src_fmt.fmt.pix.height * 3;
+ convert2_src = convert1_dest;
+ }
+
+ if (convert && (rotate90 || hflip || vflip || crop)) {
+ convert2_dest = v4lconvert_alloc_buffer(data, temp_needed,
+ &data->convert2_buf, &data->convert2_buf_size);
+ if (!convert2_dest)
+ return -1;
- if (my_dest_fmt.fmt.pix.width != my_src_fmt.fmt.pix.width ||
- my_dest_fmt.fmt.pix.height != my_src_fmt.fmt.pix.height)
- crop = 1;
+ convert2_dest_size = temp_needed;
+ rotate90_src = flip_src = crop_src = convert2_dest;
+ }
- /* convert_pixfmt -> rotate -> crop, all steps are optional */
- if (convert && (rotate || crop)) {
- convert_dest = v4lconvert_alloc_buffer(data, temp_needed,
- &data->convert_buf, &data->convert_buf_size);
- if (!convert_dest)
+ if (rotate90 && (hflip || vflip || crop)) {
+ rotate90_dest = v4lconvert_alloc_buffer(data, temp_needed,
+ &data->rotate90_buf, &data->rotate90_buf_size);
+ if (!rotate90_dest)
return -1;
- rotate_src = crop_src = convert_dest;
+ flip_src = crop_src = rotate90_dest;
}
- if (rotate && crop) {
- rotate_dest = v4lconvert_alloc_buffer(data, temp_needed,
- &data->rotate_buf, &data->rotate_buf_size);
- if (!rotate_dest)
+ if ((vflip || hflip) && crop) {
+ flip_dest = v4lconvert_alloc_buffer(data, temp_needed, &data->flip_buf,
+ &data->flip_buf_size);
+ if (!flip_dest)
return -1;
- crop_src = rotate_dest;
+ crop_src = flip_dest;
+ }
+
+ /* Done setting sources / dest and allocating intermediate buffers,
+ real conversion / processing / ... starts here. */
+ if (convert == 2) {
+ res = v4lconvert_convert_pixfmt(data, src, src_size,
+ convert1_dest, convert1_dest_size,
+ &my_src_fmt,
+ V4L2_PIX_FMT_RGB24);
+ if (res)
+ return res;
+
+ src_size = my_src_fmt.fmt.pix.sizeimage;
}
+ if (processing)
+ v4lprocessing_processing(data->processing, convert2_src, &my_src_fmt);
+
if (convert) {
- res = v4lconvert_convert_pixfmt(data, src, src_size, convert_dest,
+ res = v4lconvert_convert_pixfmt(data, convert2_src, src_size,
+ convert2_dest, convert2_dest_size,
&my_src_fmt,
my_dest_fmt.fmt.pix.pixelformat);
if (res)
return res;
- my_src_fmt.fmt.pix.pixelformat = my_dest_fmt.fmt.pix.pixelformat;
- v4lconvert_fixup_fmt(&my_src_fmt);
+ src_size = my_src_fmt.fmt.pix.sizeimage;
+
+ /* We call processing here again in case the source format was not
+ rgb, but the dest is. v4lprocessing checks it self it only actually
+ does the processing once per frame. */
+ if (processing)
+ v4lprocessing_processing(data->processing, convert2_dest, &my_src_fmt);
}
- if (rotate)
- v4lconvert_rotate(rotate_src, rotate_dest,
- my_src_fmt.fmt.pix.width, my_src_fmt.fmt.pix.height,
- my_src_fmt.fmt.pix.pixelformat, rotate);
+ if (rotate90)
+ v4lconvert_rotate90(rotate90_src, rotate90_dest, &my_src_fmt);
+
+ if (hflip || vflip)
+ v4lconvert_flip(flip_src, flip_dest, &my_src_fmt, hflip, vflip);
if (crop)
v4lconvert_crop(crop_src, dest, &my_src_fmt, &my_dest_fmt);
@@ -922,7 +1090,7 @@ static void v4lconvert_get_framesizes(struct v4lconvert_data *data,
for (i = 0; ; i++) {
frmsize.index = i;
- if (syscall(SYS_ioctl, data->fd, VIDIOC_ENUM_FRAMESIZES, &frmsize))
+ if (SYS_IOCTL(data->fd, VIDIOC_ENUM_FRAMESIZES, &frmsize))
break;
/* We got a framesize, check we don't have the same one already */
@@ -977,8 +1145,13 @@ static void v4lconvert_get_framesizes(struct v4lconvert_data *data,
int v4lconvert_enum_framesizes(struct v4lconvert_data *data,
struct v4l2_frmsizeenum *frmsize)
{
- if (!v4lconvert_supported_dst_format(frmsize->pixel_format))
- return syscall(SYS_ioctl, data->fd, VIDIOC_ENUM_FRAMESIZES, frmsize);
+ if (!v4lconvert_supported_dst_format(frmsize->pixel_format)) {
+ if (v4lconvert_supported_dst_fmt_only(data)) {
+ errno = EINVAL;
+ return -1;
+ }
+ return SYS_IOCTL(data->fd, VIDIOC_ENUM_FRAMESIZES, frmsize);
+ }
if (frmsize->index >= data->no_framesizes) {
errno = EINVAL;
@@ -989,6 +1162,9 @@ int v4lconvert_enum_framesizes(struct v4lconvert_data *data,
switch(frmsize->type) {
case V4L2_FRMSIZE_TYPE_DISCRETE:
frmsize->discrete = data->framesizes[frmsize->index].discrete;
+ /* Apply the same rounding algorithm as v4lconvert_try_format */
+ frmsize->discrete.width &= ~7;
+ frmsize->discrete.height &= ~1;
break;
case V4L2_FRMSIZE_TYPE_CONTINUOUS:
case V4L2_FRMSIZE_TYPE_STEPWISE:
@@ -1006,7 +1182,11 @@ int v4lconvert_enum_frameintervals(struct v4lconvert_data *data,
struct v4l2_format src_fmt, dest_fmt;
if (!v4lconvert_supported_dst_format(frmival->pixel_format)) {
- res = syscall(SYS_ioctl, data->fd, VIDIOC_ENUM_FRAMEINTERVALS, frmival);
+ if (v4lconvert_supported_dst_fmt_only(data)) {
+ errno = EINVAL;
+ return -1;
+ }
+ res = SYS_IOCTL(data->fd, VIDIOC_ENUM_FRAMEINTERVALS, frmival);
if (res)
V4LCONVERT_ERR("%s\n", strerror(errno));
return res;
@@ -1050,7 +1230,7 @@ int v4lconvert_enum_frameintervals(struct v4lconvert_data *data,
frmival->pixel_format = src_fmt.fmt.pix.pixelformat;
frmival->width = src_fmt.fmt.pix.width;
frmival->height = src_fmt.fmt.pix.height;
- res = syscall(SYS_ioctl, data->fd, VIDIOC_ENUM_FRAMEINTERVALS, frmival);
+ res = SYS_IOCTL(data->fd, VIDIOC_ENUM_FRAMEINTERVALS, frmival);
if (res) {
int dest_pixfmt = dest_fmt.fmt.pix.pixelformat;
int src_pixfmt = src_fmt.fmt.pix.pixelformat;
@@ -1076,3 +1256,15 @@ int v4lconvert_enum_frameintervals(struct v4lconvert_data *data,
return res;
}
+
+int v4lconvert_vidioc_queryctrl(struct v4lconvert_data *data, void *arg) {
+ return v4lcontrol_vidioc_queryctrl(data->control, arg);
+}
+
+int v4lconvert_vidioc_g_ctrl(struct v4lconvert_data *data, void *arg) {
+ return v4lcontrol_vidioc_g_ctrl(data->control, arg);
+}
+
+int v4lconvert_vidioc_s_ctrl(struct v4lconvert_data *data, void *arg){
+ return v4lcontrol_vidioc_s_ctrl(data->control, arg);
+}
diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lsyscall-priv.h b/v4l2-apps/libv4l/libv4lconvert/libv4lsyscall-priv.h
new file mode 100644
index 000000000..a456ceea3
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4lconvert/libv4lsyscall-priv.h
@@ -0,0 +1,112 @@
+/*-
+ * Copyright (c) 2009 Hans Petter Selasky. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * The following file allows for having the complete V4L stack and
+ * hardware drivers in userland.
+ */
+
+#ifndef _LIBV4LSYSCALL_PRIV_H_
+#define _LIBV4LSYSCALL_PRIV_H_
+
+/* Some of these headers are not needed by us, but by linux/videodev2.h,
+ which is broken on some systems and doesn't include them itself :( */
+
+#ifdef linux
+#include <sys/time.h>
+#include <syscall.h>
+#include <linux/types.h>
+#include <linux/ioctl.h>
+/* On 32 bits archs we always use mmap2, on 64 bits archs there is no mmap2 */
+#ifdef __NR_mmap2
+#define SYS_mmap2 __NR_mmap2
+#define MMAP2_PAGE_SHIFT 12
+#else
+#define SYS_mmap2 SYS_mmap
+#define MMAP2_PAGE_SHIFT 0
+#endif
+#endif
+
+#ifdef __FreeBSD__
+#include <sys/time.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#define _IOC_NR(cmd) ((cmd) & 0xFF)
+#define _IOC_TYPE(cmd) IOCGROUP(cmd)
+#define _IOC_SIZE(cmd) IOCPARM_LEN(cmd)
+#define MAP_ANONYMOUS MAP_ANON
+#define SYS_mmap2 SYS_mmap
+#define MMAP2_PAGE_SHIFT 0
+typedef off_t __off_t;
+#endif
+
+#undef SYS_OPEN
+#undef SYS_CLOSE
+#undef SYS_IOCTL
+#undef SYS_READ
+#undef SYS_WRITE
+#undef SYS_MMAP
+#undef SYS_MUNMAP
+
+#ifndef CONFIG_SYS_WRAPPER
+
+#define SYS_OPEN(file, oflag, mode) \
+ syscall(SYS_open, (const char *)(file), (int)(oflag), (mode_t)(mode))
+#define SYS_CLOSE(fd) \
+ syscall(SYS_close, (int)(fd))
+#define SYS_IOCTL(fd, cmd, arg) \
+ syscall(SYS_ioctl, (int)(fd), (unsigned long)(cmd), (void *)(arg))
+#define SYS_READ(fd, buf, len) \
+ syscall(SYS_read, (int)(fd), (void *)(buf), (size_t)(len));
+#define SYS_WRITE(fd, buf, len) \
+ syscall(SYS_write, (int)(fd), (void *)(buf), (size_t)(len));
+#define SYS_MMAP(addr, len, prot, flags, fd, off) \
+ syscall(SYS_mmap2, (void *)(addr), (size_t)(len), \
+ (int)(prot), (int)(flags), (int)(fd), (__off_t)((off) >> MMAP2_PAGE_SHIFT))
+#define SYS_MUNMAP(addr, len) \
+ syscall(SYS_munmap, (void *)(addr), (size_t)(len))
+
+#else
+
+int v4lx_open_wrapper(const char *, int, int);
+int v4lx_close_wrapper(int);
+int v4lx_ioctl_wrapper(int, unsigned long, void *);
+int v4lx_read_wrapper(int, void *, size_t);
+int v4lx_write_wrapper(int, void *, size_t);
+void *v4lx_mmap_wrapper(void *, size_t, int, int, int, off_t);
+int v4lx_munmap_wrapper(void *, size_t);
+
+#define SYS_OPEN(...) v4lx_open_wrapper(__VA_ARGS__)
+#define SYS_CLOSE(...) v4lx_close_wrapper(__VA_ARGS__)
+#define SYS_IOCTL(...) v4lx_ioctl_wrapper(__VA_ARGS__)
+#define SYS_READ(...) v4lx_read_wrapper(__VA_ARGS__)
+#define SYS_WRITE(...) v4lx_write_wrapper(__VA_ARGS__)
+#define SYS_MMAP(...) v4lx_mmap_wrapper(__VA_ARGS__)
+#define SYS_MUNMAP(...) v4lx_munmap_wrapper(__VA_ARGS__)
+
+#endif
+
+#endif /* _LIBV4LSYSCALL_PRIV_H_ */
diff --git a/v4l2-apps/libv4l/libv4lconvert/ov511-decomp.c b/v4l2-apps/libv4l/libv4lconvert/ov511-decomp.c
new file mode 100644
index 000000000..11ed2a601
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4lconvert/ov511-decomp.c
@@ -0,0 +1,666 @@
+/* We would like to embed this inside libv4l, but we cannot as I've failed
+ to contact Mark W. McClelland to get permission to relicense this,
+ so this lives in an external (GPL licensed) helper */
+
+/* OV511 Decompression Support Module
+ *
+ * Copyright (c) 1999-2003 Mark W. McClelland. All rights reserved.
+ * http://alpha.dyndns.org/ov511/
+ *
+ * Original decompression code Copyright 1998-2000 OmniVision Technologies
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ */
+
+#include <string.h>
+#include <unistd.h>
+#include "helper-funcs.h"
+
+/******************************************************************************
+ * Decompression Functions
+ ******************************************************************************/
+
+static void
+DecompressYHI(unsigned char *pIn,
+ unsigned char *pOut,
+ int *iIn, /* in/out */
+ int *iOut, /* in/out */
+ const int w,
+ const int YUVFlag)
+{
+ short ZigZag[64];
+ int temp[64];
+ int Zcnt_Flag = 0;
+ int Num8_Flag = 0;
+ int in_pos = *iIn;
+ int out_pos = *iOut;
+ int tmp, tmp1, tmp2, tmp3;
+ unsigned char header, ZTable[64];
+ short tmpl, tmph, half_byte, idx, count;
+ unsigned long ZigZag_length = 0, ZT_length, i, j;
+ short DeZigZag[64];
+
+ const short a = 11584;
+ const short b = 16068;
+ const short c = 15136;
+ const short d = 13624;
+ const short e = 9104;
+ const short f = 6270;
+ const short g = 3196;
+
+ int out_idx;
+
+ /* Take off every 'Zig' */
+ for (i = 0; i < 64; i++) {
+ ZigZag[i] = 0;
+ }
+
+ /*****************************
+ * Read in the Y header byte *
+ *****************************/
+
+ header = pIn[in_pos];
+ in_pos++;
+
+ ZigZag_length = header & 0x3f;
+ ZigZag_length = ZigZag_length + 1;
+
+ Num8_Flag = header & 0x40;
+ Zcnt_Flag = header & 0x80;
+
+ /*************************
+ * Read in the Y content *
+ *************************/
+
+ if (Zcnt_Flag == 0) { /* Without Zero Table read contents directly */
+ /* Read in ZigZag[0] */
+ ZigZag[0] = pIn[in_pos++];
+ tmpl = pIn[in_pos++];
+ tmph = tmpl<<8;
+ ZigZag[0] = ZigZag[0] | tmph;
+ ZigZag[0] = ZigZag[0]<<4;
+ ZigZag[0] = ZigZag[0]>>4;
+
+ if (Num8_Flag) { /* 8 Bits */
+ for (i = 1; i < ZigZag_length; i++) {
+ ZigZag[i] = pIn[in_pos++];
+ ZigZag[i] = ZigZag[i]<<8;
+ ZigZag[i] = ZigZag[i]>>8;
+ }
+ } else { /* 12 bits and has no Zero Table */
+ idx = 1;
+ half_byte = 0;
+ for (i = 1; i < ZigZag_length; i++) {
+ if (half_byte == 0) {
+ ZigZag[i] = pIn[in_pos++];
+ tmpl = pIn[in_pos++];
+ tmph = tmpl<<8;
+ tmph = tmph&0x0f00;
+ ZigZag[i] = ZigZag[i] | tmph;
+ ZigZag[i] = ZigZag[i]<<4;
+ ZigZag[i] = ZigZag[i]>>4;
+ half_byte = 1;
+ } else {
+ ZigZag[i] = pIn[in_pos++];
+ ZigZag[i] = ZigZag[i]<<8;
+ tmpl = tmpl & 0x00f0;
+ ZigZag[i] = ZigZag[i] | tmpl;
+ ZigZag[i] = ZigZag[i]>>4;
+ half_byte = 0;
+ }
+ }
+ }
+ } else { /* Has Zero Table */
+ /* Calculate Z-Table length */
+ ZT_length = ZigZag_length/8;
+ tmp = ZigZag_length%8;
+
+ if (tmp > 0) {
+ ZT_length = ZT_length + 1;
+ }
+
+ /* Read in Zero Table */
+ for (j = 0; j < ZT_length; j++) {
+ ZTable[j] = pIn[in_pos++];
+ }
+
+ /* Read in ZigZag[0] */
+ ZigZag[0] = pIn[in_pos++];
+ tmpl = pIn[in_pos++];
+ tmph = tmpl<<8;
+ ZigZag[0] = ZigZag[0] | tmph;
+ ZigZag[0] = ZigZag[0]<<4;
+ ZigZag[0] = ZigZag[0]>>4;
+
+ /* Decode ZigZag */
+ idx = 0;
+ ZTable[idx] = ZTable[idx]<<1;
+ count = 7;
+
+ if (Num8_Flag) { /* 8 Bits and has zero table */
+ for (i = 1; i < ZigZag_length; i++) {
+ if ((ZTable[idx]&0x80)) {
+ ZigZag[i] = pIn[in_pos++];
+ ZigZag[i] = ZigZag[i]<<8;
+ ZigZag[i] = ZigZag[i]>>8;
+ }
+
+ ZTable[idx]=ZTable[idx]<<1;
+ count--;
+ if (count == 0) {
+ count = 8;
+ idx++;
+ }
+ }
+ } else { /* 12 bits and has Zero Table */
+ half_byte = 0;
+ for (i = 1; i < ZigZag_length; i++) {
+ if (ZTable[idx]&0x80) {
+ if (half_byte == 0) {
+ ZigZag[i] = pIn[in_pos++];
+ tmpl = pIn[in_pos++];
+ tmph = tmpl <<8;
+ tmph = tmph & 0x0f00;
+ ZigZag[i] = ZigZag[i] | tmph;
+ ZigZag[i] = ZigZag[i]<<4;
+ ZigZag[i] = ZigZag[i]>>4;
+ half_byte = 1;
+ } else {
+ ZigZag[i] = pIn[in_pos++];
+ ZigZag[i] = ZigZag[i]<<8;
+ tmpl = tmpl & 0x00f0;
+ ZigZag[i] = ZigZag[i] | tmpl;
+ ZigZag[i] = ZigZag[i]>>4;
+ half_byte = 0;
+ }
+ }
+
+ ZTable[idx] = ZTable[idx]<<1;
+ count--;
+ if (count == 0) {
+ count = 8;
+ idx++;
+ }
+ }
+ }
+ }
+
+ /*************
+ * De-ZigZag *
+ *************/
+
+ for (j = 0; j < 64; j++) {
+ DeZigZag[j] = 0;
+ }
+
+ if (YUVFlag == 1) {
+ DeZigZag[0] = ZigZag[0];
+ DeZigZag[1] = ZigZag[1]<<1;
+ DeZigZag[2] = ZigZag[5]<<1;
+ DeZigZag[3] = ZigZag[6]<<2;
+
+ DeZigZag[8] = ZigZag[2]<<1;
+ DeZigZag[9] = ZigZag[4]<<1;
+ DeZigZag[10] = ZigZag[7]<<1;
+ DeZigZag[11] = ZigZag[13]<<2;
+
+ DeZigZag[16] = ZigZag[3]<<1;
+ DeZigZag[17] = ZigZag[8]<<1;
+ DeZigZag[18] = ZigZag[12]<<2;
+ DeZigZag[19] = ZigZag[17]<<2;
+
+ DeZigZag[24] = ZigZag[9]<<2;
+ DeZigZag[25] = ZigZag[11]<<2;
+ DeZigZag[26] = ZigZag[18]<<2;
+ DeZigZag[27] = ZigZag[24]<<3;
+ } else {
+ DeZigZag[0] = ZigZag[0];
+ DeZigZag[1] = ZigZag[1]<<2;
+ DeZigZag[2] = ZigZag[5]<<2;
+ DeZigZag[3] = ZigZag[6]<<3;
+
+ DeZigZag[8] = ZigZag[2]<<2;
+ DeZigZag[9] = ZigZag[4]<<2;
+ DeZigZag[10] = ZigZag[7]<<2;
+ DeZigZag[11] = ZigZag[13]<<4;
+
+ DeZigZag[16] = ZigZag[3]<<2;
+ DeZigZag[17] = ZigZag[8]<<2;
+ DeZigZag[18] = ZigZag[12]<<3;
+ DeZigZag[19] = ZigZag[17]<<4;
+
+ DeZigZag[24] = ZigZag[9]<<3;
+ DeZigZag[25] = ZigZag[11]<<4;
+ DeZigZag[26] = ZigZag[18]<<4;
+ DeZigZag[27] = ZigZag[24]<<4;
+ }
+
+ /*****************
+ **** IDCT 1D ****
+ *****************/
+
+#define IDCT_1D(c0, c1, c2, c3, in) \
+ do { \
+ tmp1=((c0)*DeZigZag[in])+((c2)*DeZigZag[(in)+2]); \
+ tmp2=(c1)*DeZigZag[(in)+1]; \
+ tmp3=(c3)*DeZigZag[(in)+3]; \
+ } while (0)
+
+#define COMPOSE_1(out1, out2) \
+ do { \
+ tmp=tmp1+tmp2+tmp3; \
+ temp[out1] = tmp>>15; \
+ tmp=tmp1-tmp2-tmp3; \
+ temp[out2] = tmp>>15; \
+ } while (0)
+
+#define COMPOSE_2(out1, out2) \
+ do { \
+ tmp=tmp1+tmp2-tmp3; \
+ temp[out1] = tmp>>15; \
+ tmp=tmp1-tmp2+tmp3; \
+ temp[out2] = tmp>>15; \
+ } while (0)
+
+ /* j = 0 */
+ IDCT_1D(a, b, c, d, 0); COMPOSE_1( 0, 56);
+ IDCT_1D(a, b, c, d, 8); COMPOSE_1( 1, 57);
+ IDCT_1D(a, b, c, d, 16); COMPOSE_1( 2, 58);
+ IDCT_1D(a, b, c, d, 24); COMPOSE_1( 3, 59);
+
+ /* j = 1 */
+ IDCT_1D(a, d, f, g, 0); COMPOSE_2( 8, 48);
+ IDCT_1D(a, d, f, g, 8); COMPOSE_2( 9, 49);
+ IDCT_1D(a, d, f, g, 16); COMPOSE_2(10, 50);
+ IDCT_1D(a, d, f, g, 24); COMPOSE_2(11, 51);
+
+ /* j = 2 */
+ IDCT_1D(a, e, -f, b, 0); COMPOSE_2(16, 40);
+ IDCT_1D(a, e, -f, b, 8); COMPOSE_2(17, 41);
+ IDCT_1D(a, e, -f, b, 16); COMPOSE_2(18, 42);
+ IDCT_1D(a, e, -f, b, 24); COMPOSE_2(19, 43);
+
+ /* j = 3 */
+ IDCT_1D(a, g, -c, e, 0); COMPOSE_2(24, 32);
+ IDCT_1D(a, g, -c, e, 8); COMPOSE_2(25, 33);
+ IDCT_1D(a, g, -c, e, 16); COMPOSE_2(26, 34);
+ IDCT_1D(a, g, -c, e, 24); COMPOSE_2(27, 35);
+
+#undef IDCT_1D
+#undef COMPOSE_1
+#undef COMPOSE_2
+
+ /*****************
+ **** IDCT 2D ****
+ *****************/
+
+#define IDCT_2D(c0, c1, c2, c3, in) \
+ do { \
+ tmp = temp[in]*(c0) + temp[(in)+1]*(c1) \
+ + temp[(in)+2]*(c2) + temp[(in)+3]*(c3); \
+ } while (0)
+
+#define STORE(i) \
+ do { \
+ tmp = tmp >> 15; \
+ tmp = tmp + 128; \
+ if (tmp > 255) tmp = 255; \
+ if (tmp < 0) tmp = 0; \
+ pOut[i] = (unsigned char) tmp; \
+ } while (0)
+
+#define IDCT_2D_ROW(in) \
+ do { \
+ IDCT_2D(a, b, c, d, in); STORE(0+out_idx); \
+ IDCT_2D(a, d, f, -g, in); STORE(1+out_idx); \
+ IDCT_2D(a, e, -f, -b, in); STORE(2+out_idx); \
+ IDCT_2D(a, g, -c, -e, in); STORE(3+out_idx); \
+ IDCT_2D(a, -g, -c, e, in); STORE(4+out_idx); \
+ IDCT_2D(a, -e, -f, b, in); STORE(5+out_idx); \
+ IDCT_2D(a, -d, f, g, in); STORE(6+out_idx); \
+ IDCT_2D(a, -b, c, -d, in); STORE(7+out_idx); \
+ } while (0)
+
+
+#define IDCT_2D_FAST(c0, c1, c2, c3, in) \
+ do { \
+ tmp1=((c0)*temp[in])+((c2)*temp[(in)+2]); \
+ tmp2=(c1)*temp[(in)+1]; \
+ tmp3=(c3)*temp[(in)+3]; \
+ } while (0)
+
+#define STORE_FAST_1(out1, out2) \
+ do { \
+ tmp=tmp1+tmp2+tmp3; \
+ STORE((out1)+out_idx); \
+ tmp=tmp1-tmp2-tmp3; \
+ STORE((out2)+out_idx); \
+ } while (0)
+
+#define STORE_FAST_2(out1, out2) \
+ do { \
+ tmp=tmp1+tmp2-tmp3; \
+ STORE((out1)+out_idx); \
+ tmp=tmp1-tmp2+tmp3; \
+ STORE((out2)+out_idx); \
+ } while (0)
+
+#define IDCT_2D_FAST_ROW(in) \
+ do { \
+ IDCT_2D_FAST(a, b, c, d, in); STORE_FAST_1(0, 7); \
+ IDCT_2D_FAST(a, d, f, g, in); STORE_FAST_2(1, 6); \
+ IDCT_2D_FAST(a, e, -f, b, in); STORE_FAST_2(2, 5); \
+ IDCT_2D_FAST(a, g, -c, e, in); STORE_FAST_2(3, 4); \
+ } while (0)
+
+ out_idx = out_pos;
+
+ IDCT_2D_ROW(0); out_idx += w;
+ IDCT_2D_ROW(8); out_idx += w;
+ IDCT_2D_ROW(16); out_idx += w;
+ IDCT_2D_ROW(24); out_idx += w;
+ IDCT_2D_ROW(32); out_idx += w;
+ IDCT_2D_ROW(40); out_idx += w;
+ IDCT_2D_FAST_ROW(48); out_idx += w;
+ IDCT_2D_FAST_ROW(56);
+
+ *iIn = in_pos;
+ *iOut = out_pos + 8;
+}
+
+#define DECOMP_Y() DecompressYHI(pIn, pY, &iIn, &iY, w, 1)
+#define DECOMP_U() DecompressYHI(pIn, pU, &iIn, &iU, w/2, 2)
+#define DECOMP_V() DecompressYHI(pIn, pV, &iIn, &iV, w/2, 2)
+
+#if 0
+inline static int
+Decompress400HiNoMMX(unsigned char *pIn,
+ unsigned char *pOut,
+ const int w,
+ const int h,
+ const int inSize)
+{
+ unsigned char *pY = pOut;
+ int x, y, iIn, iY;
+
+ iIn = 0;
+ for (y = 0; y < h; y += 8) {
+ iY = w*y;
+
+ for (x = 0; x < w; x += 8)
+ DECOMP_Y();
+ }
+
+ return 0;
+}
+#endif
+
+inline static int
+Decompress420HiNoMMX(unsigned char *pIn,
+ unsigned char *pOut,
+ const int w,
+ const int h,
+ const int inSize)
+{
+ unsigned char *pY = pOut;
+ unsigned char *pU = pY + w*h;
+ unsigned char *pV = pU + w*h/4;
+ int xY, xUV, iY, iU, iV, iIn, count;
+ const int nBlocks = (w*h) / (32*8);
+
+ iIn = 0;
+ iY = iU = iV = 0;
+ xY = xUV = 0;
+
+ for (count = 0; count < nBlocks; count++) {
+ DECOMP_U();
+ DECOMP_V(); xUV += 16;
+ if (xUV >= w) {
+ iU += (w*7)/2;
+ iV += (w*7)/2;
+ xUV = 0;
+ }
+
+ DECOMP_Y(); xY += 8;
+ DECOMP_Y(); xY += 8;
+ if (xY >= w) {
+ iY += w*7;
+ xY = 0;
+ }
+ DECOMP_Y(); xY += 8;
+ DECOMP_Y(); xY += 8;
+ if (xY >= w) {
+ iY += w*7;
+ xY = 0;
+ }
+ }
+
+ return 0;
+}
+
+/* Copies a 64-byte segment at pIn to an 8x8 block at pOut. The width of the
+ * image at pOut is specified by w.
+ */
+static inline void
+make_8x8(unsigned char *pIn, unsigned char *pOut, int w)
+{
+ unsigned char *pOut1 = pOut;
+ int x, y;
+
+ for (y = 0; y < 8; y++) {
+ pOut1 = pOut;
+ for (x = 0; x < 8; x++) {
+ *pOut1++ = *pIn++;
+ }
+ pOut += w;
+ }
+}
+
+#if 0
+/*
+ * For RAW BW (YUV 4:0:0) images, data show up in 256 byte segments.
+ * The segments represent 4 squares of 8x8 pixels as follows:
+ *
+ * 0 1 ... 7 64 65 ... 71 ... 192 193 ... 199
+ * 8 9 ... 15 72 73 ... 79 200 201 ... 207
+ * ... ... ...
+ * 56 57 ... 63 120 121 ... 127 248 249 ... 255
+ *
+ */
+static void
+yuv400raw_to_yuv400p(struct ov511_frame *frame,
+ unsigned char *pIn0, unsigned char *pOut0)
+{
+ int x, y;
+ unsigned char *pIn, *pOut, *pOutLine;
+
+ /* Copy Y */
+ pIn = pIn0;
+ pOutLine = pOut0;
+ for (y = 0; y < frame->rawheight - 1; y += 8) {
+ pOut = pOutLine;
+ for (x = 0; x < frame->rawwidth - 1; x += 8) {
+ make_8x8(pIn, pOut, frame->rawwidth);
+ pIn += 64;
+ pOut += 8;
+ }
+ pOutLine += 8 * frame->rawwidth;
+ }
+}
+#endif
+
+/*
+ * For YUV 4:2:0 images, the data show up in 384 byte segments.
+ * The first 64 bytes of each segment are U, the next 64 are V. The U and
+ * V are arranged as follows:
+ *
+ * 0 1 ... 7
+ * 8 9 ... 15
+ * ...
+ * 56 57 ... 63
+ *
+ * U and V are shipped at half resolution (1 U,V sample -> one 2x2 block).
+ *
+ * The next 256 bytes are full resolution Y data and represent 4 squares
+ * of 8x8 pixels as follows:
+ *
+ * 0 1 ... 7 64 65 ... 71 ... 192 193 ... 199
+ * 8 9 ... 15 72 73 ... 79 200 201 ... 207
+ * ... ... ...
+ * 56 57 ... 63 120 121 ... 127 ... 248 249 ... 255
+ *
+ * Note that the U and V data in one segment represent a 16 x 16 pixel
+ * area, but the Y data represent a 32 x 8 pixel area. If the width is not an
+ * even multiple of 32, the extra 8x8 blocks within a 32x8 block belong to the
+ * next horizontal stripe.
+ *
+ * If dumppix module param is set, _parse_data just dumps the incoming segments,
+ * verbatim, in order, into the frame. When used with vidcat -f ppm -s 640x480
+ * this puts the data on the standard output and can be analyzed with the
+ * parseppm.c utility I wrote. That's a much faster way for figuring out how
+ * these data are scrambled.
+ */
+
+/* Converts from raw, uncompressed segments at pIn0 to a YUV420P frame at pOut0.
+ *
+ * FIXME: Currently only handles width and height that are multiples of 16
+ */
+static void
+yuv420raw_to_yuv420p(unsigned char *pIn0, unsigned char *pOut0,
+ int width, int height)
+{
+ int k, x, y;
+ unsigned char *pIn, *pOut, *pOutLine;
+ const unsigned int a = width * height;
+ const unsigned int w = width / 2;
+
+ /* Copy U and V */
+ pIn = pIn0;
+ pOutLine = pOut0 + a;
+ for (y = 0; y < height - 1; y += 16) {
+ pOut = pOutLine;
+ for (x = 0; x < width - 1; x += 16) {
+ make_8x8(pIn, pOut, w);
+ make_8x8(pIn + 64, pOut + a/4, w);
+ pIn += 384;
+ pOut += 8;
+ }
+ pOutLine += 8 * w;
+ }
+
+ /* Copy Y */
+ pIn = pIn0 + 128;
+ pOutLine = pOut0;
+ k = 0;
+ for (y = 0; y < height - 1; y += 8) {
+ pOut = pOutLine;
+ for (x = 0; x < width - 1; x += 8) {
+ make_8x8(pIn, pOut, width);
+ pIn += 64;
+ pOut += 8;
+ if ((++k) > 3) {
+ k = 0;
+ pIn += 128;
+ }
+ }
+ pOutLine += 8 * width;
+ }
+}
+
+
+/* Remove all 0 blocks from input */
+static void remove0blocks(unsigned char *pIn, int *inSize)
+{
+ long long *in = (long long *)pIn;
+ long long *out = (long long *)pIn;
+ int i, j;
+
+ for (i = 0; i < *inSize; i += 32, in += 4) {
+ int all_zero = 1;
+ for (j = 0; j < 4; j++)
+ if (in[j]) {
+ all_zero = 0;
+ break;
+ }
+
+ /* Skip 32 byte blocks of all 0 */
+ if (all_zero)
+ continue;
+
+ for (j = 0; j < 4; j++)
+ *out++ = in[j];
+ }
+
+ *inSize -= (in - out) * 8;
+}
+
+static int v4lconvert_ov511_to_yuv420(unsigned char *src, unsigned char *dest,
+ int w, int h, int yvu, int src_size)
+{
+ int rc = 0;
+
+ src_size -= 11; /* Remove footer */
+
+ remove0blocks(src, &src_size);
+
+ /* Compressed ? */
+ if (src[8] & 0x40) {
+ rc = Decompress420HiNoMMX(src + 9, dest, w, h, src_size);
+ } else {
+ yuv420raw_to_yuv420p(src + 9, dest, w, h);
+ }
+
+ return rc;
+}
+
+int main(int argc, char *argv[])
+{
+ int width, height, yvu, src_size, dest_size;
+ unsigned char src_buf[500000];
+ unsigned char dest_buf[500000];
+
+ while (1) {
+ if (v4lconvert_helper_read(STDIN_FILENO, &width, sizeof(int), argv[0]))
+ return 1; /* Erm, no way to recover without loosing sync with libv4l */
+
+ if (v4lconvert_helper_read(STDIN_FILENO, &height, sizeof(int), argv[0]))
+ return 1; /* Erm, no way to recover without loosing sync with libv4l */
+
+ if (v4lconvert_helper_read(STDIN_FILENO, &yvu, sizeof(int), argv[0]))
+ return 1; /* Erm, no way to recover without loosing sync with libv4l */
+
+ if (v4lconvert_helper_read(STDIN_FILENO, &src_size, sizeof(int), argv[0]))
+ return 1; /* Erm, no way to recover without loosing sync with libv4l */
+
+ if (src_size > sizeof(src_buf)) {
+ fprintf(stderr, "%s: error: src_buf too small, need: %d\n",
+ argv[0], src_size);
+ return 2;
+ }
+
+ if (v4lconvert_helper_read(STDIN_FILENO, src_buf, src_size, argv[0]))
+ return 1; /* Erm, no way to recover without loosing sync with libv4l */
+
+
+ dest_size = width * height * 3 / 2;
+ if (dest_size > sizeof(dest_buf)) {
+ fprintf(stderr, "%s: error: dest_buf too small, need: %d\n",
+ argv[0], dest_size);
+ dest_size = -1;
+ } else if (v4lconvert_ov511_to_yuv420(src_buf, dest_buf, width, height,
+ yvu, src_size))
+ dest_size = -1;
+
+ if (v4lconvert_helper_write(STDOUT_FILENO, &dest_size, sizeof(int),
+ argv[0]))
+ return 1; /* Erm, no way to recover without loosing sync with libv4l */
+
+ if (dest_size == -1)
+ continue;
+
+ if (v4lconvert_helper_write(STDOUT_FILENO, dest_buf, dest_size, argv[0]))
+ return 1; /* Erm, no way to recover without loosing sync with libv4l */
+ }
+}
diff --git a/v4l2-apps/libv4l/libv4lconvert/ov518-decomp.c b/v4l2-apps/libv4l/libv4lconvert/ov518-decomp.c
new file mode 100644
index 000000000..51b8d8c60
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4lconvert/ov518-decomp.c
@@ -0,0 +1,1477 @@
+/* We would like to embed this inside libv4l, but we cannot as I've failed
+ to contact Mark W. McClelland to get permission to relicense this,
+ so this lives in an external (GPL licensed) helper */
+
+/* OV518 Decompression Support Module (No-MMX version)
+ *
+ * Copyright (c) 2002-2003 Mark W. McClelland. All rights reserved.
+ * http://alpha.dyndns.org/ov511/
+ *
+ * Fast integer iDCT by Yuri van Oers <yvanoers AT xs4all.nl>
+ * Original OV511 decompression code Copyright 1998-2000 OmniVision Technologies
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ */
+
+#include <string.h>
+#include <unistd.h>
+#include "helper-funcs.h"
+
+/******************************************************************************
+ * Compile-time Options
+ ******************************************************************************/
+
+/* Defining APPROXIMATE_MUL_BY_SHIFT increases performance by approximation
+ * the multiplications by shifts. I think there's no change in the
+ * calculated picture, but I'm not sure, so the choice is still in here. */
+#undef APPROXIMATE_MUL_BY_SHIFT
+
+/******************************************************************************
+ * Local Data Types
+ ******************************************************************************/
+
+/* Make sure this remains naturally aligned and 2^n bytes in size */
+struct tree_node {
+ short left; /* Pointer to left child node */
+ short right; /* Pointer to right child node */
+ signed char depth; /* Depth (starting at 1) if leaf, else -1 */
+ signed char coeffbits; /* Size of coefficient data, or zero if none */
+ signed char skip; /* Number of zero coefficients. Unused w/ DC */
+ char padding; /* Pad out to 8 bytes */
+};
+
+struct comp_info {
+ int bytes; /* Number of processed input bytes */
+ int bits; /* Number of unprocessed input bits */
+ int rawLen; /* Total number of bytes in input buffer */
+ unsigned char *qt; /* Current quantization table */
+};
+
+/******************************************************************************
+ * Constant Data Definitions
+ ******************************************************************************/
+
+/* Zig-Zag Table */
+static const unsigned char ZigZag518[] = {
+ 0x00, 0x02, 0x03, 0x09,
+ 0x01, 0x04, 0x08, 0x0a,
+ 0x05, 0x07, 0x0b, 0x11,
+ 0x06, 0x0c, 0x10, 0x12,
+ 0x0d, 0x0f, 0x13, 0x19,
+ 0x0e, 0x14, 0x18, 0x1a,
+ 0x15, 0x17, 0x1b, 0x1e,
+ 0x16, 0x1c, 0x1d, 0x1f
+};
+
+/* Huffman trees */
+
+static const struct tree_node treeYAC[] = {
+ { 1, 4, -1, 0, -1}, { 2, 3, -1, 0, -1},
+ { -1, -1, 2, 1, 0}, { -1, -1, 2, 2, 0},
+ { 5, 9, -1, 0, -1}, { 6, 7, -1, 0, -1},
+ { -1, -1, 3, 3, 0}, {323, 8, -1, 0, -1},
+ { -1, -1, 4, 4, 0}, { 10, 13, -1, 0, -1},
+ { 38, 11, -1, 0, -1}, { 12, 39, -1, 0, -1},
+ { -1, -1, 5, 5, 0}, { 59, 14, -1, 0, -1},
+ { 15, 18, -1, 0, -1}, { 16, 113, -1, 0, -1},
+ { 17, 40, -1, 0, -1}, { -1, -1, 7, 6, 0},
+ { 19, 22, -1, 0, -1}, { 20, 41, -1, 0, -1},
+ { 21, 61, -1, 0, -1}, { -1, -1, 8, 7, 0},
+ { 23, 27, -1, 0, -1}, {169, 24, -1, 0, -1},
+ {208, 25, -1, 0, -1}, { 26, 62, -1, 0, -1},
+ { -1, -1, 10, 8, 0}, { 44, 28, -1, 0, -1},
+ { 63, 29, -1, 0, -1}, { 30, 191, -1, 0, -1},
+ { 31, 119, -1, 0, -1}, { 32, 82, -1, 0, -1},
+ { 33, 55, -1, 0, -1}, { 34, 48, -1, 0, -1},
+ {171, 35, -1, 0, -1}, { 36, 37, -1, 0, -1},
+ { -1, -1, 16, 9, 0}, { -1, -1, 16, 10, 0},
+ { -1, -1, 4, 1, 1}, { -1, -1, 5, 2, 1},
+ { -1, -1, 7, 3, 1}, {151, 42, -1, 0, -1},
+ { 43, 79, -1, 0, -1}, { -1, -1, 9, 4, 1},
+ { 96, 45, -1, 0, -1}, {246, 46, -1, 0, -1},
+ { 47, 115, -1, 0, -1}, { -1, -1, 11, 5, 1},
+ { 49, 52, -1, 0, -1}, { 50, 51, -1, 0, -1},
+ { -1, -1, 16, 6, 1}, { -1, -1, 16, 7, 1},
+ { 53, 54, -1, 0, -1}, { -1, -1, 16, 8, 1},
+ { -1, -1, 16, 9, 1}, { 56, 71, -1, 0, -1},
+ { 57, 68, -1, 0, -1}, { 58, 67, -1, 0, -1},
+ { -1, -1, 16, 10, 1}, { 60, 77, -1, 0, -1},
+ { -1, -1, 5, 1, 2}, { -1, -1, 8, 2, 2},
+ { -1, -1, 10, 3, 2}, {265, 64, -1, 0, -1},
+ { 65, 134, -1, 0, -1}, { 66, 80, -1, 0, -1},
+ { -1, -1, 12, 4, 2}, { -1, -1, 16, 5, 2},
+ { 69, 70, -1, 0, -1}, { -1, -1, 16, 6, 2},
+ { -1, -1, 16, 7, 2}, { 72, 75, -1, 0, -1},
+ { 73, 74, -1, 0, -1}, { -1, -1, 16, 8, 2},
+ { -1, -1, 16, 9, 2}, { 76, 81, -1, 0, -1},
+ { -1, -1, 16, 10, 2}, { 78, 95, -1, 0, -1},
+ { -1, -1, 6, 1, 3}, { -1, -1, 9, 2, 3},
+ { -1, -1, 12, 3, 3}, { -1, -1, 16, 4, 3},
+ { 83, 101, -1, 0, -1}, { 84, 91, -1, 0, -1},
+ { 85, 88, -1, 0, -1}, { 86, 87, -1, 0, -1},
+ { -1, -1, 16, 5, 3}, { -1, -1, 16, 6, 3},
+ { 89, 90, -1, 0, -1}, { -1, -1, 16, 7, 3},
+ { -1, -1, 16, 8, 3}, { 92, 98, -1, 0, -1},
+ { 93, 94, -1, 0, -1}, { -1, -1, 16, 9, 3},
+ { -1, -1, 16, 10, 3}, { -1, -1, 6, 1, 4},
+ { 97, 225, -1, 0, -1}, { -1, -1, 10, 2, 4},
+ { 99, 100, -1, 0, -1}, { -1, -1, 16, 3, 4},
+ { -1, -1, 16, 4, 4}, {102, 109, -1, 0, -1},
+ {103, 106, -1, 0, -1}, {104, 105, -1, 0, -1},
+ { -1, -1, 16, 5, 4}, { -1, -1, 16, 6, 4},
+ {107, 108, -1, 0, -1}, { -1, -1, 16, 7, 4},
+ { -1, -1, 16, 8, 4}, {110, 116, -1, 0, -1},
+ {111, 112, -1, 0, -1}, { -1, -1, 16, 9, 4},
+ { -1, -1, 16, 10, 4}, {114, 133, -1, 0, -1},
+ { -1, -1, 7, 1, 5}, { -1, -1, 11, 2, 5},
+ {117, 118, -1, 0, -1}, { -1, -1, 16, 3, 5},
+ { -1, -1, 16, 4, 5}, {120, 156, -1, 0, -1},
+ {121, 139, -1, 0, -1}, {122, 129, -1, 0, -1},
+ {123, 126, -1, 0, -1}, {124, 125, -1, 0, -1},
+ { -1, -1, 16, 5, 5}, { -1, -1, 16, 6, 5},
+ {127, 128, -1, 0, -1}, { -1, -1, 16, 7, 5},
+ { -1, -1, 16, 8, 5}, {130, 136, -1, 0, -1},
+ {131, 132, -1, 0, -1}, { -1, -1, 16, 9, 5},
+ { -1, -1, 16, 10, 5}, { -1, -1, 7, 1, 6},
+ {135, 152, -1, 0, -1}, { -1, -1, 12, 2, 6},
+ {137, 138, -1, 0, -1}, { -1, -1, 16, 3, 6},
+ { -1, -1, 16, 4, 6}, {140, 147, -1, 0, -1},
+ {141, 144, -1, 0, -1}, {142, 143, -1, 0, -1},
+ { -1, -1, 16, 5, 6}, { -1, -1, 16, 6, 6},
+ {145, 146, -1, 0, -1}, { -1, -1, 16, 7, 6},
+ { -1, -1, 16, 8, 6}, {148, 153, -1, 0, -1},
+ {149, 150, -1, 0, -1}, { -1, -1, 16, 9, 6},
+ { -1, -1, 16, 10, 6}, { -1, -1, 8, 1, 7},
+ { -1, -1, 12, 2, 7}, {154, 155, -1, 0, -1},
+ { -1, -1, 16, 3, 7}, { -1, -1, 16, 4, 7},
+ {157, 175, -1, 0, -1}, {158, 165, -1, 0, -1},
+ {159, 162, -1, 0, -1}, {160, 161, -1, 0, -1},
+ { -1, -1, 16, 5, 7}, { -1, -1, 16, 6, 7},
+ {163, 164, -1, 0, -1}, { -1, -1, 16, 7, 7},
+ { -1, -1, 16, 8, 7}, {166, 172, -1, 0, -1},
+ {167, 168, -1, 0, -1}, { -1, -1, 16, 9, 7},
+ { -1, -1, 16, 10, 7}, {170, 187, -1, 0, -1},
+ { -1, -1, 9, 1, 8}, { -1, -1, 15, 2, 8},
+ {173, 174, -1, 0, -1}, { -1, -1, 16, 3, 8},
+ { -1, -1, 16, 4, 8}, {176, 183, -1, 0, -1},
+ {177, 180, -1, 0, -1}, {178, 179, -1, 0, -1},
+ { -1, -1, 16, 5, 8}, { -1, -1, 16, 6, 8},
+ {181, 182, -1, 0, -1}, { -1, -1, 16, 7, 8},
+ { -1, -1, 16, 8, 8}, {184, 188, -1, 0, -1},
+ {185, 186, -1, 0, -1}, { -1, -1, 16, 9, 8},
+ { -1, -1, 16, 10, 8}, { -1, -1, 9, 1, 9},
+ {189, 190, -1, 0, -1}, { -1, -1, 16, 2, 9},
+ { -1, -1, 16, 3, 9}, {192, 258, -1, 0, -1},
+ {193, 226, -1, 0, -1}, {194, 210, -1, 0, -1},
+ {195, 202, -1, 0, -1}, {196, 199, -1, 0, -1},
+ {197, 198, -1, 0, -1}, { -1, -1, 16, 4, 9},
+ { -1, -1, 16, 5, 9}, {200, 201, -1, 0, -1},
+ { -1, -1, 16, 6, 9}, { -1, -1, 16, 7, 9},
+ {203, 206, -1, 0, -1}, {204, 205, -1, 0, -1},
+ { -1, -1, 16, 8, 9}, { -1, -1, 16, 9, 9},
+ {207, 209, -1, 0, -1}, { -1, -1, 16, 10, 9},
+ { -1, -1, 9, 1, 10}, { -1, -1, 16, 2, 10},
+ {211, 218, -1, 0, -1}, {212, 215, -1, 0, -1},
+ {213, 214, -1, 0, -1}, { -1, -1, 16, 3, 10},
+ { -1, -1, 16, 4, 10}, {216, 217, -1, 0, -1},
+ { -1, -1, 16, 5, 10}, { -1, -1, 16, 6, 10},
+ {219, 222, -1, 0, -1}, {220, 221, -1, 0, -1},
+ { -1, -1, 16, 7, 10}, { -1, -1, 16, 8, 10},
+ {223, 224, -1, 0, -1}, { -1, -1, 16, 9, 10},
+ { -1, -1, 16, 10, 10}, { -1, -1, 10, 1, 11},
+ {227, 242, -1, 0, -1}, {228, 235, -1, 0, -1},
+ {229, 232, -1, 0, -1}, {230, 231, -1, 0, -1},
+ { -1, -1, 16, 2, 11}, { -1, -1, 16, 3, 11},
+ {233, 234, -1, 0, -1}, { -1, -1, 16, 4, 11},
+ { -1, -1, 16, 5, 11}, {236, 239, -1, 0, -1},
+ {237, 238, -1, 0, -1}, { -1, -1, 16, 6, 11},
+ { -1, -1, 16, 7, 11}, {240, 241, -1, 0, -1},
+ { -1, -1, 16, 8, 11}, { -1, -1, 16, 9, 11},
+ {243, 251, -1, 0, -1}, {244, 248, -1, 0, -1},
+ {245, 247, -1, 0, -1}, { -1, -1, 16, 10, 11},
+ { -1, -1, 10, 1, 12}, { -1, -1, 16, 2, 12},
+ {249, 250, -1, 0, -1}, { -1, -1, 16, 3, 12},
+ { -1, -1, 16, 4, 12}, {252, 255, -1, 0, -1},
+ {253, 254, -1, 0, -1}, { -1, -1, 16, 5, 12},
+ { -1, -1, 16, 6, 12}, {256, 257, -1, 0, -1},
+ { -1, -1, 16, 7, 12}, { -1, -1, 16, 8, 12},
+ {259, 292, -1, 0, -1}, {260, 277, -1, 0, -1},
+ {261, 270, -1, 0, -1}, {262, 267, -1, 0, -1},
+ {263, 264, -1, 0, -1}, { -1, -1, 16, 9, 12},
+ { -1, -1, 16, 10, 12}, {266, 322, -1, 0, -1},
+ { -1, -1, 11, 1, 13}, {268, 269, -1, 0, -1},
+ { -1, -1, 16, 2, 13}, { -1, -1, 16, 3, 13},
+ {271, 274, -1, 0, -1}, {272, 273, -1, 0, -1},
+ { -1, -1, 16, 4, 13}, { -1, -1, 16, 5, 13},
+ {275, 276, -1, 0, -1}, { -1, -1, 16, 6, 13},
+ { -1, -1, 16, 7, 13}, {278, 285, -1, 0, -1},
+ {279, 282, -1, 0, -1}, {280, 281, -1, 0, -1},
+ { -1, -1, 16, 8, 13}, { -1, -1, 16, 9, 13},
+ {283, 284, -1, 0, -1}, { -1, -1, 16, 10, 13},
+ { -1, -1, 16, 1, 14}, {286, 289, -1, 0, -1},
+ {287, 288, -1, 0, -1}, { -1, -1, 16, 2, 14},
+ { -1, -1, 16, 3, 14}, {290, 291, -1, 0, -1},
+ { -1, -1, 16, 4, 14}, { -1, -1, 16, 5, 14},
+ {293, 308, -1, 0, -1}, {294, 301, -1, 0, -1},
+ {295, 298, -1, 0, -1}, {296, 297, -1, 0, -1},
+ { -1, -1, 16, 6, 14}, { -1, -1, 16, 7, 14},
+ {299, 300, -1, 0, -1}, { -1, -1, 16, 8, 14},
+ { -1, -1, 16, 9, 14}, {302, 305, -1, 0, -1},
+ {303, 304, -1, 0, -1}, { -1, -1, 16, 10, 14},
+ { -1, -1, 16, 1, 15}, {306, 307, -1, 0, -1},
+ { -1, -1, 16, 2, 15}, { -1, -1, 16, 3, 15},
+ {309, 316, -1, 0, -1}, {310, 313, -1, 0, -1},
+ {311, 312, -1, 0, -1}, { -1, -1, 16, 4, 15},
+ { -1, -1, 16, 5, 15}, {314, 315, -1, 0, -1},
+ { -1, -1, 16, 6, 15}, { -1, -1, 16, 7, 15},
+ {317, 320, -1, 0, -1}, {318, 319, -1, 0, -1},
+ { -1, -1, 16, 8, 15}, { -1, -1, 16, 9, 15},
+ {321, -1, -1, 0, -1}, { -1, -1, 16, 10, 15},
+ { -1, -1, 11, 0, 16}, { -1, -1, 4, 0, -1},
+};
+
+static const struct tree_node treeUVAC[] = {
+ { 1, 3, -1, 0, -1}, {323, 2, -1, 0, -1},
+ { -1, -1, 2, 1, 0}, { 4, 8, -1, 0, -1},
+ { 5, 6, -1, 0, -1}, { -1, -1, 3, 2, 0},
+ { 7, 37, -1, 0, -1}, { -1, -1, 4, 3, 0},
+ { 9, 13, -1, 0, -1}, { 10, 60, -1, 0, -1},
+ { 11, 12, -1, 0, -1}, { -1, -1, 5, 4, 0},
+ { -1, -1, 5, 5, 0}, { 14, 17, -1, 0, -1},
+ { 15, 97, -1, 0, -1}, { 16, 38, -1, 0, -1},
+ { -1, -1, 6, 6, 0}, { 18, 21, -1, 0, -1},
+ { 19, 39, -1, 0, -1}, { 20, 135, -1, 0, -1},
+ { -1, -1, 7, 7, 0}, { 22, 26, -1, 0, -1},
+ { 82, 23, -1, 0, -1}, { 24, 99, -1, 0, -1},
+ { 25, 42, -1, 0, -1}, { -1, -1, 9, 8, 0},
+ { 27, 31, -1, 0, -1}, {211, 28, -1, 0, -1},
+ {248, 29, -1, 0, -1}, { 30, 63, -1, 0, -1},
+ { -1, -1, 10, 9, 0}, { 43, 32, -1, 0, -1},
+ { 33, 48, -1, 0, -1}, {153, 34, -1, 0, -1},
+ { 35, 64, -1, 0, -1}, { 36, 47, -1, 0, -1},
+ { -1, -1, 12, 10, 0}, { -1, -1, 4, 1, 1},
+ { -1, -1, 6, 2, 1}, {152, 40, -1, 0, -1},
+ { 41, 62, -1, 0, -1}, { -1, -1, 8, 3, 1},
+ { -1, -1, 9, 4, 1}, { 84, 44, -1, 0, -1},
+ {322, 45, -1, 0, -1}, { 46, 136, -1, 0, -1},
+ { -1, -1, 11, 5, 1}, { -1, -1, 12, 6, 1},
+ { 49, 189, -1, 0, -1}, { 50, 119, -1, 0, -1},
+ { 51, 76, -1, 0, -1}, { 66, 52, -1, 0, -1},
+ { 53, 69, -1, 0, -1}, { 54, 57, -1, 0, -1},
+ { 55, 56, -1, 0, -1}, { -1, -1, 16, 7, 1},
+ { -1, -1, 16, 8, 1}, { 58, 59, -1, 0, -1},
+ { -1, -1, 16, 9, 1}, { -1, -1, 16, 10, 1},
+ { 61, 81, -1, 0, -1}, { -1, -1, 5, 1, 2},
+ { -1, -1, 8, 2, 2}, { -1, -1, 10, 3, 2},
+ { 65, 86, -1, 0, -1}, { -1, -1, 12, 4, 2},
+ {286, 67, -1, 0, -1}, { 68, 304, -1, 0, -1},
+ { -1, -1, 15, 5, 2}, { 70, 73, -1, 0, -1},
+ { 71, 72, -1, 0, -1}, { -1, -1, 16, 6, 2},
+ { -1, -1, 16, 7, 2}, { 74, 75, -1, 0, -1},
+ { -1, -1, 16, 8, 2}, { -1, -1, 16, 9, 2},
+ { 77, 102, -1, 0, -1}, { 78, 91, -1, 0, -1},
+ { 79, 88, -1, 0, -1}, { 80, 87, -1, 0, -1},
+ { -1, -1, 16, 10, 2}, { -1, -1, 5, 1, 3},
+ { 83, 171, -1, 0, -1}, { -1, -1, 8, 2, 3},
+ { 85, 117, -1, 0, -1}, { -1, -1, 10, 3, 3},
+ { -1, -1, 12, 4, 3}, { -1, -1, 16, 5, 3},
+ { 89, 90, -1, 0, -1}, { -1, -1, 16, 6, 3},
+ { -1, -1, 16, 7, 3}, { 92, 95, -1, 0, -1},
+ { 93, 94, -1, 0, -1}, { -1, -1, 16, 8, 3},
+ { -1, -1, 16, 9, 3}, { 96, 101, -1, 0, -1},
+ { -1, -1, 16, 10, 3}, { 98, 116, -1, 0, -1},
+ { -1, -1, 6, 1, 4}, {100, 188, -1, 0, -1},
+ { -1, -1, 9, 2, 4}, { -1, -1, 16, 3, 4},
+ {103, 110, -1, 0, -1}, {104, 107, -1, 0, -1},
+ {105, 106, -1, 0, -1}, { -1, -1, 16, 4, 4},
+ { -1, -1, 16, 5, 4}, {108, 109, -1, 0, -1},
+ { -1, -1, 16, 6, 4}, { -1, -1, 16, 7, 4},
+ {111, 114, -1, 0, -1}, {112, 113, -1, 0, -1},
+ { -1, -1, 16, 8, 4}, { -1, -1, 16, 9, 4},
+ {115, 118, -1, 0, -1}, { -1, -1, 16, 10, 4},
+ { -1, -1, 6, 1, 5}, { -1, -1, 10, 2, 5},
+ { -1, -1, 16, 3, 5}, {120, 156, -1, 0, -1},
+ {121, 138, -1, 0, -1}, {122, 129, -1, 0, -1},
+ {123, 126, -1, 0, -1}, {124, 125, -1, 0, -1},
+ { -1, -1, 16, 4, 5}, { -1, -1, 16, 5, 5},
+ {127, 128, -1, 0, -1}, { -1, -1, 16, 6, 5},
+ { -1, -1, 16, 7, 5}, {130, 133, -1, 0, -1},
+ {131, 132, -1, 0, -1}, { -1, -1, 16, 8, 5},
+ { -1, -1, 16, 9, 5}, {134, 137, -1, 0, -1},
+ { -1, -1, 16, 10, 5}, { -1, -1, 7, 1, 6},
+ { -1, -1, 11, 2, 6}, { -1, -1, 16, 3, 6},
+ {139, 146, -1, 0, -1}, {140, 143, -1, 0, -1},
+ {141, 142, -1, 0, -1}, { -1, -1, 16, 4, 6},
+ { -1, -1, 16, 5, 6}, {144, 145, -1, 0, -1},
+ { -1, -1, 16, 6, 6}, { -1, -1, 16, 7, 6},
+ {147, 150, -1, 0, -1}, {148, 149, -1, 0, -1},
+ { -1, -1, 16, 8, 6}, { -1, -1, 16, 9, 6},
+ {151, 155, -1, 0, -1}, { -1, -1, 16, 10, 6},
+ { -1, -1, 7, 1, 7}, {154, 267, -1, 0, -1},
+ { -1, -1, 11, 2, 7}, { -1, -1, 16, 3, 7},
+ {157, 173, -1, 0, -1}, {158, 165, -1, 0, -1},
+ {159, 162, -1, 0, -1}, {160, 161, -1, 0, -1},
+ { -1, -1, 16, 4, 7}, { -1, -1, 16, 5, 7},
+ {163, 164, -1, 0, -1}, { -1, -1, 16, 6, 7},
+ { -1, -1, 16, 7, 7}, {166, 169, -1, 0, -1},
+ {167, 168, -1, 0, -1}, { -1, -1, 16, 8, 7},
+ { -1, -1, 16, 9, 7}, {170, 172, -1, 0, -1},
+ { -1, -1, 16, 10, 7}, { -1, -1, 8, 1, 8},
+ { -1, -1, 16, 2, 8}, {174, 181, -1, 0, -1},
+ {175, 178, -1, 0, -1}, {176, 177, -1, 0, -1},
+ { -1, -1, 16, 3, 8}, { -1, -1, 16, 4, 8},
+ {179, 180, -1, 0, -1}, { -1, -1, 16, 5, 8},
+ { -1, -1, 16, 6, 8}, {182, 185, -1, 0, -1},
+ {183, 184, -1, 0, -1}, { -1, -1, 16, 7, 8},
+ { -1, -1, 16, 8, 8}, {186, 187, -1, 0, -1},
+ { -1, -1, 16, 9, 8}, { -1, -1, 16, 10, 8},
+ { -1, -1, 9, 1, 9}, {190, 257, -1, 0, -1},
+ {191, 224, -1, 0, -1}, {192, 207, -1, 0, -1},
+ {193, 200, -1, 0, -1}, {194, 197, -1, 0, -1},
+ {195, 196, -1, 0, -1}, { -1, -1, 16, 2, 9},
+ { -1, -1, 16, 3, 9}, {198, 199, -1, 0, -1},
+ { -1, -1, 16, 4, 9}, { -1, -1, 16, 5, 9},
+ {201, 204, -1, 0, -1}, {202, 203, -1, 0, -1},
+ { -1, -1, 16, 6, 9}, { -1, -1, 16, 7, 9},
+ {205, 206, -1, 0, -1}, { -1, -1, 16, 8, 9},
+ { -1, -1, 16, 9, 9}, {208, 217, -1, 0, -1},
+ {209, 214, -1, 0, -1}, {210, 213, -1, 0, -1},
+ { -1, -1, 16, 10, 9}, {212, 230, -1, 0, -1},
+ { -1, -1, 9, 1, 10}, { -1, -1, 16, 2, 10},
+ {215, 216, -1, 0, -1}, { -1, -1, 16, 3, 10},
+ { -1, -1, 16, 4, 10}, {218, 221, -1, 0, -1},
+ {219, 220, -1, 0, -1}, { -1, -1, 16, 5, 10},
+ { -1, -1, 16, 6, 10}, {222, 223, -1, 0, -1},
+ { -1, -1, 16, 7, 10}, { -1, -1, 16, 8, 10},
+ {225, 241, -1, 0, -1}, {226, 234, -1, 0, -1},
+ {227, 231, -1, 0, -1}, {228, 229, -1, 0, -1},
+ { -1, -1, 16, 9, 10}, { -1, -1, 16, 10, 10},
+ { -1, -1, 9, 1, 11}, {232, 233, -1, 0, -1},
+ { -1, -1, 16, 2, 11}, { -1, -1, 16, 3, 11},
+ {235, 238, -1, 0, -1}, {236, 237, -1, 0, -1},
+ { -1, -1, 16, 4, 11}, { -1, -1, 16, 5, 11},
+ {239, 240, -1, 0, -1}, { -1, -1, 16, 6, 11},
+ { -1, -1, 16, 7, 11}, {242, 250, -1, 0, -1},
+ {243, 246, -1, 0, -1}, {244, 245, -1, 0, -1},
+ { -1, -1, 16, 8, 11}, { -1, -1, 16, 9, 11},
+ {247, 249, -1, 0, -1}, { -1, -1, 16, 10, 11},
+ { -1, -1, 9, 1, 12}, { -1, -1, 16, 2, 12},
+ {251, 254, -1, 0, -1}, {252, 253, -1, 0, -1},
+ { -1, -1, 16, 3, 12}, { -1, -1, 16, 4, 12},
+ {255, 256, -1, 0, -1}, { -1, -1, 16, 5, 12},
+ { -1, -1, 16, 6, 12}, {258, 291, -1, 0, -1},
+ {259, 275, -1, 0, -1}, {260, 268, -1, 0, -1},
+ {261, 264, -1, 0, -1}, {262, 263, -1, 0, -1},
+ { -1, -1, 16, 7, 12}, { -1, -1, 16, 8, 12},
+ {265, 266, -1, 0, -1}, { -1, -1, 16, 9, 12},
+ { -1, -1, 16, 10, 12}, { -1, -1, 11, 1, 13},
+ {269, 272, -1, 0, -1}, {270, 271, -1, 0, -1},
+ { -1, -1, 16, 2, 13}, { -1, -1, 16, 3, 13},
+ {273, 274, -1, 0, -1}, { -1, -1, 16, 4, 13},
+ { -1, -1, 16, 5, 13}, {276, 283, -1, 0, -1},
+ {277, 280, -1, 0, -1}, {278, 279, -1, 0, -1},
+ { -1, -1, 16, 6, 13}, { -1, -1, 16, 7, 13},
+ {281, 282, -1, 0, -1}, { -1, -1, 16, 8, 13},
+ { -1, -1, 16, 9, 13}, {284, 288, -1, 0, -1},
+ {285, 287, -1, 0, -1}, { -1, -1, 16, 10, 13},
+ { -1, -1, 14, 1, 14}, { -1, -1, 16, 2, 14},
+ {289, 290, -1, 0, -1}, { -1, -1, 16, 3, 14},
+ { -1, -1, 16, 4, 14}, {292, 308, -1, 0, -1},
+ {293, 300, -1, 0, -1}, {294, 297, -1, 0, -1},
+ {295, 296, -1, 0, -1}, { -1, -1, 16, 5, 14},
+ { -1, -1, 16, 6, 14}, {298, 299, -1, 0, -1},
+ { -1, -1, 16, 7, 14}, { -1, -1, 16, 8, 14},
+ {301, 305, -1, 0, -1}, {302, 303, -1, 0, -1},
+ { -1, -1, 16, 9, 14}, { -1, -1, 16, 10, 14},
+ { -1, -1, 15, 1, 15}, {306, 307, -1, 0, -1},
+ { -1, -1, 16, 2, 15}, { -1, -1, 16, 3, 15},
+ {309, 316, -1, 0, -1}, {310, 313, -1, 0, -1},
+ {311, 312, -1, 0, -1}, { -1, -1, 16, 4, 15},
+ { -1, -1, 16, 5, 15}, {314, 315, -1, 0, -1},
+ { -1, -1, 16, 6, 15}, { -1, -1, 16, 7, 15},
+ {317, 320, -1, 0, -1}, {318, 319, -1, 0, -1},
+ { -1, -1, 16, 8, 15}, { -1, -1, 16, 9, 15},
+ {321, -1, -1, 0, -1}, { -1, -1, 16, 10, 15},
+ { -1, -1, 10, 0, 16}, { -1, -1, 2, 0, -1},
+};
+
+static const struct tree_node treeYDC[] = {
+ { 1, 6, -1, 0}, { 2, 3, -1, 0},
+ { -1, -1, 2, 0}, { 4, 5, -1, 0},
+ { -1, -1, 3, 1}, { -1, -1, 3, 2},
+ { 7, 10, -1, 0}, { 8, 9, -1, 0},
+ { -1, -1, 3, 3}, { -1, -1, 3, 4},
+ { 11, 12, -1, 0}, { -1, -1, 3, 5},
+ { 13, 14, -1, 0}, { -1, -1, 4, 6},
+ { 15, 16, -1, 0}, { -1, -1, 5, 7},
+ { 17, 18, -1, 0}, { -1, -1, 6, 8},
+ { 19, 20, -1, 0}, { -1, -1, 7, 9},
+ { 21, 22, -1, 0}, { -1, -1, 8, 10},
+ { 23, -1, -1, 0}, { -1, -1, 9, 11},
+};
+
+static const struct tree_node treeUVDC[] = {
+ { 1, 4, -1, 0}, { 2, 3, -1, 0},
+ { -1, -1, 2, 0}, { -1, -1, 2, 1},
+ { 5, 6, -1, 0}, { -1, -1, 2, 2},
+ { 7, 8, -1, 0}, { -1, -1, 3, 3},
+ { 9, 10, -1, 0}, { -1, -1, 4, 4},
+ { 11, 12, -1, 0}, { -1, -1, 5, 5},
+ { 13, 14, -1, 0}, { -1, -1, 6, 6},
+ { 15, 16, -1, 0}, { -1, -1, 7, 7},
+ { 17, 18, -1, 0}, { -1, -1, 8, 8},
+ { 19, 20, -1, 0}, { -1, -1, 9, 9},
+ { 21, 22, -1, 0}, { -1, -1, 10, 10},
+ { 23, -1, -1, 0}, { -1, -1, 11, 11},
+};
+
+/******************************************************************************
+ * Huffman Decoder
+ ******************************************************************************/
+
+/* Note: There is no penalty for passing the tree as an argument, since dummy
+ * args are passed anyway (to maintain 16-byte stack alignment), and since the
+ * address is loaded into a register either way. */
+
+/* If no node is found, coeffbits and skip will not be modified */
+/* Return: Depth of node found, or -1 if invalid input code */
+static int
+getNodeAC(unsigned int in, signed char *coeffbits, signed char *skip,
+ const struct tree_node *tree)
+{
+ int node = 0;
+ int i = 0;
+ int depth;
+
+ do {
+ if ((in & 0x80000000) == 0)
+ node = tree[node].left;
+ else
+ node = tree[node].right;
+
+ if (node == -1)
+ break;
+
+ depth = tree[node].depth;
+
+ /* Is it a leaf? If not, branch downward */
+ if (depth != -1) {
+ *coeffbits = tree[node].coeffbits;
+ *skip = tree[node].skip;
+ return depth;
+ }
+
+ in <<= 1;
+ ++i;
+ } while (i <= 15);
+
+ return -1;
+}
+
+/* If no node is found, coeffbits will not be modified */
+/* Return: Depth of node found, or -1 if invalid input code */
+static int
+getNodeDC(unsigned int in, signed char *coeffbits, const struct tree_node *tree)
+{
+ int node = 0;
+ int i = 0;
+ int depth;
+
+ do {
+ if ((in & 0x80000000) == 0)
+ node = tree[node].left;
+ else
+ node = tree[node].right;
+
+ if (node == -1)
+ break;
+
+ depth = tree[node].depth;
+
+ /* Is it a leaf? If not, branch downward */
+ if (depth != -1) {
+ *coeffbits = tree[node].coeffbits;
+ return depth;
+ }
+
+ in <<= 1;
+ ++i;
+ } while (i <= 15);
+
+ return -1;
+}
+
+static inline unsigned int
+getBytes(int *rawData, struct comp_info *cinfo)
+{
+ int bufLen = cinfo->rawLen;
+ int bits = cinfo->bits;
+ int bytes = cinfo->bytes;
+ unsigned char *in = bytes + (unsigned char *) rawData;
+ unsigned char b1, b2, b3, b4, b5;
+ unsigned int packedIn;
+
+ /* Pull 5 bytes out of raw data */
+ if (bytes < bufLen - 4) {
+ b1 = in[0];
+ b2 = in[1];
+ b3 = in[2];
+ b4 = in[3];
+ b5 = in[4];
+ } else {
+ if (bytes < bufLen - 3) {
+ b1 = in[0];
+ b2 = in[1];
+ b3 = in[2];
+ b4 = in[3];
+ } else {
+ if (bytes < bufLen - 2) {
+ b1 = in[0];
+ b2 = in[1];
+ b3 = in[2];
+ } else {
+ if (bytes < bufLen - 1) {
+ b1 = in[0];
+ b2 = in[1];
+ } else {
+ if (bytes <= bufLen) {
+ b1 = in[0];
+ } else {
+ b1 = 0;
+ }
+ b2 = 0;
+ }
+ b3 = 0;
+ }
+ b4 = 0;
+ }
+ b5 = 0;
+ }
+
+ /* Pack the bytes */
+ packedIn = b1 << 24;
+ packedIn += b2 << 16;
+ packedIn += b3 << 8;
+ packedIn += b4;
+
+ if (bits != 0) {
+ packedIn = packedIn << bits;
+ packedIn += b5 >> (8 - bits);
+ }
+
+ return packedIn;
+}
+
+static int
+getACCoefficient(int *rawData, int *coeff, struct comp_info *cinfo,
+ const struct tree_node *tree)
+{
+ int input, bits, bytes, tmp_c;
+ signed char coeffbits = 0;
+ signed char skip = 0;
+
+ input = getBytes(rawData, cinfo);
+ bits = getNodeAC(input, &coeffbits, &skip, tree);
+
+ if (coeffbits) {
+ input = input << (bits - 1);
+ input &= 0x7fffffff;
+ if (! (input & 0x40000000))
+ input |= 0x80000000;
+
+ tmp_c = input >> (31 - coeffbits);
+ if (tmp_c < 0)
+ tmp_c++;
+ *coeff = tmp_c;
+
+ bits += coeffbits;
+ }
+
+ bytes = (bits + cinfo->bits) >> 3;
+ cinfo->bytes += bytes;
+ cinfo->bits += bits - (bytes << 3);
+
+ return skip;
+}
+
+static void
+getDCCoefficient(int *rawData, int *coeff, struct comp_info *cinfo,
+ const struct tree_node *tree)
+{
+ int input, bits, bytes, tmp_c;
+ signed char coeffbits = 0;
+
+ input = getBytes(rawData, cinfo);
+ bits = getNodeDC(input, &coeffbits, tree);
+
+ if (bits == -1) {
+ bits = 1; /* Try to re-sync at the next bit */
+ *coeff = 0; /* Indicates no change from last DC */
+ } else {
+
+ input = input << (bits - 1);
+ input &= 0x7fffffff;
+ if (! (input & 0x40000000))
+ input |= 0x80000000;
+
+ tmp_c = input >> (31 - coeffbits);
+ if (tmp_c < 0)
+ tmp_c++;
+ *coeff = tmp_c;
+
+ bits += coeffbits;
+ }
+
+ bytes = (bits + cinfo->bits) >> 3;
+ cinfo->bytes += bytes;
+ cinfo->bits += bits - (bytes << 3);
+}
+
+/* For AC coefficients, here is what the "skip" value means:
+ * -1: Either the 8x4 block has ended, or the decoding failed.
+ * 0: Use the returned coeff. Don't skip anything.
+ * 1-15: The next <skip> coeffs are zero. The returned coeff is used.
+ * 16: The next 16 coeffs are zero. The returned coeff is ignored.
+ *
+ * You must ensure that the C[] array not be overrun, or stack corruption will
+ * result.
+ */
+static void
+huffmanDecoderY(int *C, int *pIn, struct comp_info *cinfo)
+{
+ int coeff = 0;
+ int i = 1;
+ int k, skip;
+
+ getDCCoefficient(pIn, C, cinfo, treeYDC);
+
+ i = 1;
+ do {
+ skip = getACCoefficient(pIn, &coeff, cinfo, treeYAC);
+
+ if (skip == -1) {
+ break;
+ } else if (skip == 0) {
+ C[i++] = coeff;
+ } else if (skip == 16) {
+ k = 16;
+ if (i > 16)
+ k = 32 - i;
+
+ while (k--)
+ C[i++] = 0;
+ } else {
+ k = skip;
+ if (skip > 31 - i)
+ k = 31 - i;
+
+ while (k--)
+ C[i++] = 0;
+
+ C[i++] = coeff;
+ }
+ } while (i <= 31);
+
+ if (skip == -1)
+ while (i <= 31) C[i++] = 0;
+ else
+ getACCoefficient(pIn, &coeff, cinfo, treeYAC);
+}
+
+/* Same as huffmanDecoderY, except for the tables used */
+static void
+huffmanDecoderUV(int *C, int *pIn, struct comp_info *cinfo)
+{
+ int coeff = 0;
+ int i = 1;
+ int k, skip;
+
+ getDCCoefficient(pIn, C, cinfo, treeUVDC);
+
+ i = 1;
+ do {
+ skip = getACCoefficient(pIn, &coeff, cinfo, treeUVAC);
+
+ if (skip == -1) {
+ break;
+ } else if (skip == 0) {
+ C[i++] = coeff;
+ } else if (skip == 16) {
+ k = 16;
+ if (i > 16)
+ k = 32 - i;
+
+ while (k--)
+ C[i++] = 0;
+ } else {
+ k = skip;
+ if (skip > 31 - i)
+ k = 31 - i;
+
+ while (k--)
+ C[i++] = 0;
+
+ C[i++] = coeff;
+ }
+ } while (i <= 31);
+
+ if (skip == -1)
+ while (i <= 31) C[i++] = 0;
+ else
+ getACCoefficient(pIn, &coeff, cinfo, treeUVAC);
+}
+
+/******************************************************************************
+ * iDCT Functions
+ ******************************************************************************/
+
+#ifndef APPROXIMATE_MUL_BY_SHIFT
+
+#define IDCT_MESSAGE "iDCT with multiply"
+
+#define TIMES_16382(u) ((u)? 16382 * (u):0)
+#define TIMES_23168(u) ((u)? 23168 * (u):0)
+#define TIMES_30270(u) ((u)? 30270 * (u):0)
+#define TIMES_41986(u) ((u)? 41986 * (u):0)
+#define TIMES_35594(u) ((u)? 35594 * (u):0)
+#define TIMES_23783(u) ((u)? 23783 * (u):0)
+#define TIMES_8351(u) ((u)? 8351 * (u):0)
+#define TIMES_17391(u) ((u)? 17391 * (u):0)
+#define TIMES_14743(u) ((u)? 14743 * (u):0)
+#define TIMES_9851(u) ((u)? 9851 * (u):0)
+#define TIMES_3459(u) ((u)? 3459 * (u):0)
+#define TIMES_32134(u) ((u)? 32134 * (u):0)
+#define TIMES_27242(u) ((u)? 27242 * (u):0)
+#define TIMES_18202(u) ((u)? 18202 * (u):0)
+#define TIMES_6392(u) ((u)? 6392 * (u):0)
+#define TIMES_39550(u) ((u)? 39550 * (u):0)
+#define TIMES_6785(u) ((u)? 6785 * (u):0)
+#define TIMES_12538(u) ((u)? 12538 * (u):0)
+
+#else
+
+#define IDCT_MESSAGE "iDCT with shift"
+
+#define TIMES_16382(u) ( (u)? x=(u) , (x<<14) - (x<<1) :0 )
+#define TIMES_23168(u) ( (u)? x=(u) , (x<<14) + (x<<12) + (x<<11) + (x<<9) :0 )
+#define TIMES_30270(u) ( (u)? x=(u) , (x<<15) - (x<<11) :0 )
+#define TIMES_41986(u) ( (u)? x=(u) , (x<<15) + (x<<13) + (x<<10) :0 )
+#define TIMES_35594(u) ( (u)? x=(u) , (x<<15) + (x<<11) + (x<<9) + (x<<8) :0 )
+#define TIMES_23783(u) ( (u)? x=(u) , (x<<14) + (x<<13) - (x<<9) - (x<<8) :0 )
+#define TIMES_8351(u) ( (u)? x=(u) , (x<<13) :0 )
+#define TIMES_17391(u) ( (u)? x=(u) , (x<<14) + (x<<10) :0 )
+#define TIMES_14743(u) ( (u)? x=(u) , (x<<14) - (x<<10) - (x<<9) :0 )
+#define TIMES_9851(u) ( (u)? x=(u) , (x<<13) + (x<<10) + (x<<9) :0 )
+#define TIMES_3459(u) ( (u)? x=(u) , (x<<12) - (x<<9) :0 )
+#define TIMES_32134(u) ( (u)? x=(u) , (x<<15) - (x<<9) :0 )
+#define TIMES_27242(u) ( (u)? x=(u) , (x<<14) + (x<<13) + (x<<11) + (x<<9) :0 )
+#define TIMES_18202(u) ( (u)? x=(u) , (x<<14) + (x<<11) - (x<<8) :0 )
+#define TIMES_6392(u) ( (u)? x=(u) , (x<<13) - (x<<11) + (x<<8) :0 )
+#define TIMES_39550(u) ( (u)? x=(u) , (x<<15) + (x<<12) + (x<<11) + (x<<9) :0 )
+#define TIMES_6785(u) ( (u)? x=(u) , (x<<12) + (x<<11) + (x<<9) :0 )
+#define TIMES_12538(u) ( (u)? x=(u) , (x<<13) + (x<<12) + (x<<8) :0 )
+
+/*
+ * The variables C0, C4, C16 and C20 can also be removed from the algorithm
+ * if APPROXIMATE_MUL_BY_SHIFTS is defined. They store correction values
+ * and can be considered insignificant.
+ */
+
+#endif
+
+static void
+DCT_8x4(int *coeff, unsigned char *out)
+/* pre: coeff == coefficients
+ post: coeff != coefficients
+ ** DO NOT ASSUME coeff TO BE THE SAME BEFORE AND AFTER CALLING THIS FUNCTION!
+*/
+{
+ register int base,val1,val2,val3;
+ int tmp1,tmp2;
+ int C0,C4,C16,C20;
+ int C2_18,C6_22,C1_17,C3_19,C5_21,C7_23;
+ register int t;
+#ifdef APPROXIMATE_MUL_BY_SHIFT
+ register int x;
+#endif
+
+ C0=coeff[0];
+ C4=coeff[4];
+ C16=coeff[16];
+ C20=coeff[20];
+
+ coeff[0]=TIMES_23168(coeff[0]);
+ coeff[4]=TIMES_23168(coeff[4]);
+ coeff[16]=TIMES_23168(coeff[16]);
+ coeff[20]=TIMES_23168(coeff[20]);
+
+ C2_18 = coeff[2]+coeff[18];
+ C6_22 = coeff[6]+coeff[22];
+ C1_17 = coeff[1]+coeff[17];
+ C3_19 = coeff[3]+coeff[19];
+ C5_21 = coeff[5]+coeff[21];
+ C7_23 = coeff[7]+coeff[23];
+
+// 0,7,25,32
+
+ base = 0x1000000;
+ base += coeff[0]+coeff[4]+coeff[16]+coeff[20];
+ base += TIMES_30270(C2_18);
+ base += TIMES_12538(C6_22);
+
+ val1 = TIMES_41986(coeff[9]);
+ val1 += TIMES_35594(coeff[11]);
+ val1 += TIMES_23783(coeff[13]);
+ val1 += TIMES_8351(coeff[15]);
+ val1 += TIMES_17391(coeff[25]);
+ val1 += TIMES_14743(coeff[27]);
+ val1 += TIMES_9851(coeff[29]);
+ val1 += TIMES_3459(coeff[31]);
+
+ val2 = TIMES_32134(C1_17);
+ val2 += TIMES_27242(C3_19);
+ val2 += TIMES_18202(C5_21);
+ val2 += TIMES_6392(C7_23);
+
+ val3 = TIMES_39550(coeff[10]);
+ val3 += TIMES_16382(coeff[14]+coeff[26]);
+ val3 += TIMES_6785(coeff[30]);
+ val3 += TIMES_30270(coeff[8]+coeff[12]);
+ val3 += TIMES_12538(coeff[24]+coeff[28]);
+
+ t=(base + val1 + val2 + val3) >> 17;
+ out[0]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t;
+ t=(base - val1 - val2 + val3 - C4 - C20) >> 17;
+ out[7]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t;
+ t=(base - val1 + val2 - val3 - C16- C20) >> 17;
+ out[24]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t;
+ t=(base + val1 - val2 - val3 - C4 - C16 - C20) >> 17;
+ out[31]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t;
+
+//1,6,25,30
+
+ base = 0x1000000;
+ base += coeff[0]-coeff[4]+coeff[16]-coeff[20];
+ base += TIMES_12538(C2_18);
+ base -= TIMES_30270(C6_22);
+
+ val1 = TIMES_35594(coeff[9]);
+ val1 -= TIMES_8351(coeff[11]);
+ val1 -= TIMES_41986(coeff[13]);
+ val1 -= TIMES_23783(coeff[15]);
+ val1 -= TIMES_14743(coeff[25]);
+ val1 -= TIMES_3459(coeff[27]);
+ val1 -= TIMES_17391(coeff[29]);
+ val1 -= TIMES_9851(coeff[31]);
+
+ val2 = TIMES_27242(C1_17);
+ val2 -= TIMES_6392(C3_19);
+ val2 -= TIMES_32134(C5_21);
+ val2 -= TIMES_18202(C7_23);
+
+ val3 = TIMES_16382(coeff[10]-coeff[30]);
+ val3 -= TIMES_39550(coeff[14]);
+ val3 += TIMES_6785(coeff[26]);
+ val3 += TIMES_12538(coeff[24]-coeff[28]);
+ val3 += TIMES_30270(coeff[8]-coeff[12]);
+
+ t=(base + val1 + val2 + val3 + C4 + C20) >> 17;
+ out[1]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t;
+ t=(base - val1 - val2 + val3) >> 17;
+ out[6]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t;
+ t=(base - val1 + val2 - val3 + C4 - C16 + C20) >> 17;
+ out[25]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t;
+ t=(base + val1 - val2 - val3 + C20) >> 17;
+ out[30]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t;
+
+//2,5,26,29
+
+ base = 0x1000000;
+ base += coeff[0] - coeff[4] + coeff[16] - coeff[20];
+ base -= TIMES_12538(C2_18);
+ base += TIMES_30270(C6_22);
+
+ val1 = TIMES_23783(coeff[9]);
+ val1 -= TIMES_41986(coeff[11]);
+ val1 += TIMES_8351(coeff[13]);
+ val1 += TIMES_35594(coeff[15]);
+ val1 += TIMES_9851(coeff[25]);
+ val1 -= TIMES_17391(coeff[27]);
+ val1 += TIMES_3459(coeff[29]);
+ val1 += TIMES_14743(coeff[31]);
+
+ val2 = TIMES_18202(C1_17);
+ val2 -= TIMES_32134(C3_19);
+ val2 += TIMES_6392(C5_21);
+ val2 += TIMES_27242(C7_23);
+
+ val3 = -TIMES_16382(coeff[10] - coeff[30]);
+ val3 += TIMES_39550(coeff[14]);
+ val3 -= TIMES_6785(coeff[26]);
+ val3 += TIMES_12538(coeff[24] - coeff[28]);
+ val3 += TIMES_30270(coeff[8] - coeff[12]);
+
+ t=(base + val1 + val2 + val3) >> 17;
+ out[2]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t;
+ t=(base - val1 - val2 + val3) >> 17;
+ out[5]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t;
+ t=(base - val1 + val2 - val3 - C16) >> 17;
+ out[26]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t;
+ t=(base + val1 - val2 - val3 + C4 - C16 + C20) >> 17;
+ out[29]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t;
+
+//3,4,27,28
+
+ base = 0x1000000;
+ base += coeff[0] + coeff[4] + coeff[16] + coeff[20];
+ base -= TIMES_30270(C2_18);
+ base -= TIMES_12538(C6_22);
+
+ val1 = TIMES_8351(coeff[9]);
+ val1 -= TIMES_23783(coeff[11]);
+ val1 += TIMES_35594(coeff[13]);
+ val1 += TIMES_3459(coeff[25]);
+ val1 -= TIMES_9851(coeff[27]);
+ val1 += TIMES_14743(coeff[29]);
+
+ val2 = TIMES_6392(C1_17);
+ val2 -= TIMES_18202(C3_19);
+ val2 += TIMES_27242(C5_21);
+
+ val3 = -TIMES_39550(coeff[10]);
+ val3 += TIMES_16382(coeff[14] + coeff[26]);
+ val3 -= TIMES_6785(coeff[30]);
+ val3 += TIMES_30270(coeff[8] + coeff[12]);
+ val3 += TIMES_12538(coeff[24] + coeff[28]);
+
+ tmp1 = TIMES_32134(C7_23);
+ tmp2 = TIMES_41986(coeff[15]) + TIMES_17391(coeff[31]);
+
+ t=(base + val1 + val2 + val3 - tmp1 - tmp2 - C4 - C20) >> 17;
+ out[3]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t;
+ t=(base - val1 - val2 + val3) >> 17;
+ out[4]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t;
+ t=(base - val1 + val2 - val3 - tmp1 + tmp2) >> 17;
+ out[27]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t;
+ t=(base + val1 - val2 - val3 - C16 - C20) >> 17;
+ out[28]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t;
+
+// Second half
+ C2_18 = coeff[2] - coeff[18];
+ C6_22 = coeff[6] - coeff[22];
+ C1_17 = coeff[1] - coeff[17];
+ C3_19 = coeff[3] - coeff[19];
+ C5_21 = coeff[5] - coeff[21];
+ C7_23 = coeff[7] - coeff[23];
+
+// 8,15,16,23
+
+ base = 0x1000000;
+ base += coeff[0] + coeff[4] - coeff[16] - coeff[20];
+ base +=TIMES_30270(C2_18);
+ base +=TIMES_12538(C6_22);
+
+ val1 = TIMES_17391(coeff[9]);
+ val1 += TIMES_14743(coeff[11]);
+ val1 += TIMES_9851(coeff[13]);
+ val1 += TIMES_3459(coeff[15]);
+ val1 -= TIMES_41986(coeff[25]);
+ val1 -= TIMES_35594(coeff[27]);
+ val1 -= TIMES_23783(coeff[29]);
+ val1 -= TIMES_8351(coeff[31]);
+
+ val2 = TIMES_32134(C1_17);
+ val2 += TIMES_27242(C3_19);
+ val2 += TIMES_18202(C5_21);
+ val2 += TIMES_6392(C7_23);
+
+ val3 = TIMES_16382(coeff[10] - coeff[30]);
+ val3 += TIMES_6785(coeff[14]);
+ val3 -= TIMES_39550(coeff[26]);
+ val3 -=TIMES_30270(coeff[24] + coeff[28]);
+ val3 +=TIMES_12538(coeff[8] + coeff[12]);
+
+ t=(base + val1 + val2 + val3) >> 17;
+ out[8]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t;
+ t=(base - val1 - val2 + val3 - C4 + C16 + C20) >> 17;
+ out[15]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t;
+ t=(base - val1 + val2 - val3) >> 17;
+ out[16]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t;
+ t=(base + val1 - val2 - val3 - C4 + C20) >> 17;
+ out[23]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t;
+
+//9,14,17,22
+
+ base = 0x1000000;
+ base += coeff[0] - coeff[4] - coeff[16] + coeff[20];
+ base += TIMES_12538(C2_18);
+ base -= TIMES_30270(C6_22);
+
+ val1 = TIMES_14743(coeff[9]);
+ val1 -= TIMES_3459(coeff[11]);
+ val1 -= TIMES_17391(coeff[13]);
+ val1 -= TIMES_9851(coeff[15]);
+ val1 -= TIMES_35594(coeff[25]);
+ val1 += TIMES_8351(coeff[27]);
+ val1 += TIMES_41986(coeff[29]);
+ val1 += TIMES_23783(coeff[31]);
+
+ val2 = TIMES_27242(C1_17);
+ val2 -= TIMES_6392(C3_19);
+ val2 -= TIMES_32134(C5_21);
+ val2 -= TIMES_18202(C7_23);
+
+ val3 = TIMES_6785(coeff[10]);
+ val3 -= TIMES_16382(coeff[14] + coeff[26]);
+ val3 += TIMES_39550(coeff[30]);
+ val3 += TIMES_12538(coeff[8] - coeff[12]);
+ val3 -= TIMES_30270(coeff[24] - coeff[28]);
+
+ t=(base + val1 + val2 + val3 + C4 + C16 - C20) >> 17;
+ out[9]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t;
+ t=(base - val1 - val2 + val3 + C16) >> 17;
+ out[14]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t;
+ t=(base - val1 + val2 - val3 + C4) >> 17;
+ out[17]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t;
+ t=(base + val1 - val2 - val3) >> 17;
+ out[22]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t;
+
+//10,13,18,21
+
+ base = 0x1000000;
+ base += coeff[0] - coeff[4] - coeff[16] + coeff[20];
+ base -= TIMES_12538(C2_18);
+ base += TIMES_30270(C6_22);
+
+ val1 = TIMES_9851(coeff[9]);
+ val1 -= TIMES_17391(coeff[11]);
+ val1 += TIMES_3459(coeff[13]);
+ val1 += TIMES_14743(coeff[15]);
+ val1 -= TIMES_23783(coeff[25]);
+ val1 += TIMES_41986(coeff[27]);
+ val1 -= TIMES_8351(coeff[29]);
+ val1 -= TIMES_35594(coeff[31]);
+
+ val2 = TIMES_18202(C1_17);
+ val2 -= TIMES_32134(C3_19);
+ val2 += TIMES_6392(C5_21);
+ val2 += TIMES_27242(C7_23);
+
+ val3 = -TIMES_6785(coeff[10]);
+ val3 += TIMES_16382(coeff[14]+coeff[26]);
+ val3 -= TIMES_39550(coeff[30]);
+ val3 += TIMES_12538(coeff[8]-coeff[12]);
+ val3 -= TIMES_30270(coeff[24]-coeff[28]);
+
+ t=(base + val1 + val2 + val3) >> 17;
+ out[10]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t;
+ t=(base - val1 - val2 + val3 + C4 + C16 - C20) >> 17;
+ out[13]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t;
+ t=(base - val1 + val2 - val3) >> 17;
+ out[18]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t;
+ t=(base + val1 - val2 - val3 + C4) >> 17;
+ out[21]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t;
+
+// 11,12,19,20
+
+ base = 0x1000000;
+ base += coeff[0]+coeff[4]-coeff[16]-coeff[20];
+ base -= TIMES_30270(C2_18);
+ base -= TIMES_12538(C6_22);
+
+ val1 = TIMES_3459(coeff[9]);
+ val1 -= TIMES_9851(coeff[11]);
+ val1 += TIMES_14743(coeff[13]);
+ val1 -= TIMES_8351(coeff[25]);
+ val1 += TIMES_23783(coeff[27]);
+ val1 -= TIMES_35594(coeff[29]);
+
+ val2 = TIMES_6392(C1_17);
+ val2 -= TIMES_18202(C3_19);
+ val2 += TIMES_27242(C5_21);
+
+ val3 = -TIMES_16382(coeff[10] - coeff[30]);
+ val3 -= TIMES_6785(coeff[14]);
+ val3 += TIMES_39550(coeff[26]);
+ val3 -= TIMES_30270(coeff[24]+coeff[28]);
+ val3 += TIMES_12538(coeff[8]+coeff[12]);
+
+ tmp1 = TIMES_32134(C7_23);
+ tmp2 = -TIMES_17391(coeff[15]) + TIMES_41986(coeff[31]);
+
+ t=(base + val1 + val2 + val3 - tmp1 + tmp2 + C16 + C20) >> 17;
+ out[11]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t;
+ t=(base - val1 - val2 + val3 + C16 + C20) >> 17;
+ out[12]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t;
+ t=(base - val1 + val2 - val3 - tmp1 - tmp2 - C4 + C20) >> 17;
+ out[19]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t;
+ t=(base + val1 - val2 - val3) >> 17;
+ out[20]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t;
+}
+
+#undef TIMES_16382
+#undef TIMES_23168
+#undef TIMES_30270
+#undef TIMES_41986
+#undef TIMES_35594
+#undef TIMES_23783
+#undef TIMES_8351
+#undef TIMES_17391
+#undef TIMES_14743
+#undef TIMES_9851
+#undef TIMES_3459
+#undef TIMES_32134
+#undef TIMES_27242
+#undef TIMES_18202
+#undef TIMES_6392
+#undef TIMES_39550
+#undef TIMES_6785
+#undef TIMES_12538
+
+/******************************************************************************
+ * Main Decoder Functions
+ ******************************************************************************/
+
+/* This function handles the decompression of a single 8x4 block. It is
+ * independent of the palette (YUV422, YUV420, YUV400, GBR422...). cinfo->bytes
+ * determines the positin in the input buffer.
+ */
+static int
+decompress8x4(unsigned char *pOut,
+ unsigned char *pIn,
+ int *lastDC,
+ int uvFlag,
+ struct comp_info *cinfo)
+{
+ int i, x, y, dc;
+ int coeffs[32];
+ int deZigZag[32];
+ int *dest;
+ int *src;
+ unsigned char *qt = cinfo->qt;
+
+ if (! uvFlag) {
+ huffmanDecoderY(coeffs, (int*) pIn, cinfo);
+
+ /* iDPCM and dequantize first coefficient */
+ dc = (*lastDC) + coeffs[0];
+ coeffs[0] = dc * (qt[0] + 1);
+ *lastDC = dc;
+
+ /* ...and the second coefficient */
+ coeffs[1] = ((qt[1] + 1) * coeffs[1]) >> 1;
+
+ /* Dequantize, starting at 3rd element */
+ for (i = 2; i < 32; i++)
+ coeffs[i] = (qt[i] + 1) * coeffs[i];
+ } else {
+ huffmanDecoderUV(coeffs, (int*) pIn, cinfo);
+
+ /* iDPCM */
+ dc = (*lastDC) + coeffs[0];
+ coeffs[0] = dc;
+ *lastDC = dc;
+
+ /* Dequantize */
+ for (i = 0; i < 32; i++)
+ coeffs[i] = (qt[32 + i] + 1) * coeffs[i];
+ }
+
+ /* Dezigzag */
+ for (i = 0; i < 32; i++)
+ deZigZag[i] = coeffs[ZigZag518[i]];
+
+ /* Transpose the dezigzagged coefficient matrix */
+ src = deZigZag;
+ dest = coeffs;
+ for (y = 0; y <= 3; ++y) {
+ for (x = 0; x <= 7; ++x) {
+ dest[x] = src[x * 4];
+ }
+ src += 1;
+ dest += 8;
+ }
+
+ /* Do the inverse DCT transform */
+ DCT_8x4(coeffs, pOut);
+
+ return 0; /* Always returns 0 */
+}
+
+static inline void
+copyBlock(unsigned char *src, unsigned char *dest, int destInc)
+{
+ int i;
+ unsigned int *pSrc, *pDest;
+
+ for (i = 0; i <= 3; i++) {
+ pSrc = (unsigned int *) src;
+ pDest = (unsigned int *) dest;
+ pDest[0] = pSrc[0];
+ pDest[1] = pSrc[1];
+ src += 8;
+ dest += destInc;
+ }
+}
+
+#if 0
+static inline int
+decompress400NoMMXOV518(unsigned char *pIn,
+ unsigned char *pOut,
+ unsigned char *pTmp,
+ const int w,
+ const int h,
+ const int numpix,
+ struct comp_info *cinfo)
+{
+ int iOutY, x, y;
+ int lastYDC = 0;
+
+ /* Start Y loop */
+ y = 0;
+ do {
+ iOutY = w * y;
+ x = 0;
+ do {
+ decompress8x4(pTmp, pIn, &lastYDC, 0, cinfo);
+ copyBlock(pTmp, pOut + iOutY, w);
+ iOutY += 8;
+ x += 8;
+ } while (x < w);
+ y += 4;
+ } while (y < h);
+
+ /* Did we decode too much? */
+ if (cinfo->bytes > cinfo->rawLen + 897)
+ return 1;
+
+ /* Did we decode enough? */
+ if (cinfo->bytes >= cinfo->rawLen - 897)
+ return 0;
+ else
+ return 1;
+}
+#endif
+
+static inline int
+decompress420NoMMXOV518(unsigned char *pIn,
+ unsigned char *pOut,
+ unsigned char *pTmp,
+ const int w,
+ const int h,
+ const int numpix,
+ struct comp_info *cinfo,
+ int yvu)
+{
+ unsigned char *pOutU, *pOutV;
+ int iOutY, iOutU, iOutV, x, y;
+ int lastYDC = 0;
+ int lastUDC = 0;
+ int lastVDC = 0;
+
+ if (yvu) {
+ pOutV = pOut + numpix;
+ pOutU = pOutV + numpix / 4;
+ } else {
+ pOutU = pOut + numpix;
+ pOutV = pOutU + numpix / 4;
+ }
+
+ /* Start Y loop */
+ y = 0;
+ do {
+ iOutY = w * y;
+ iOutV = iOutU = iOutY / 4;
+
+ x = 0;
+ do {
+ decompress8x4(pTmp, pIn, &lastYDC, 0, cinfo);
+ copyBlock(pTmp, pOut + iOutY, w);
+ iOutY += 8;
+ x += 8;
+ } while (x < w);
+
+
+
+ iOutY = w * (y + 4);
+ x = 0;
+ do {
+ decompress8x4(pTmp, pIn, &lastUDC, 1, cinfo);
+ copyBlock(pTmp, pOutU + iOutU, w/2);
+ iOutU += 8;
+
+ decompress8x4(pTmp, pIn, &lastVDC, 1, cinfo);
+ copyBlock(pTmp, pOutV + iOutV, w/2);
+ iOutV += 8;
+
+ decompress8x4(pTmp, pIn, &lastYDC, 0, cinfo);
+ copyBlock(pTmp, pOut + iOutY, w);
+ iOutY += 8;
+
+ decompress8x4(pTmp, pIn, &lastYDC, 0, cinfo);
+ copyBlock(pTmp, pOut + iOutY, w);
+ iOutY += 8;
+
+ x += 16;
+ } while (x < w);
+
+ y += 8;
+ } while (y < h);
+
+ /* Did we decode too much? */
+ if (cinfo->bytes > cinfo->rawLen + 897)
+ return 1;
+
+ /* Did we decode enough? */
+ if (cinfo->bytes >= cinfo->rawLen - (897 + 64))
+ return 0;
+ else
+ return 1;
+}
+
+/* Get quantization tables from input
+ * Returns: <0 if error, or >=0 otherwise */
+static int
+get_qt_dynamic(unsigned char *pIn, struct comp_info *cinfo)
+{
+ int rawLen = cinfo->rawLen;
+
+ /* Make sure input is actually big enough to hold trailer */
+ if (rawLen < 72) {
+ return -1;
+ }
+
+ cinfo->qt = pIn + rawLen - 64;
+
+ return 0;
+}
+
+/* Remove all 0 blocks from input */
+static void remove0blocks(unsigned char *pIn, int *inSize)
+{
+ long long *in = (long long *)pIn;
+ long long *out = (long long *)pIn;
+ int i;
+
+ for (i = 0; i < *inSize; i += 8, in++)
+ /* Skip 8 byte blocks of all 0 */
+ if (*in)
+ *out++ = *in;
+
+ *inSize -= (in - out) * 8;
+}
+
+#if 0 /* not used */
+/* Input format is raw isoc. data (with intact SOF header, packet numbers
+ * stripped, and all-zero blocks removed).
+ * Output format is planar YUV400
+ * Returns uncompressed data length if success, or zero if error
+ */
+static int
+Decompress400(unsigned char *pIn,
+ unsigned char *pOut,
+ int w,
+ int h,
+ int inSize)
+{
+ struct comp_info cinfo;
+ int numpix = w * h;
+ unsigned char pTmp[32];
+
+ remove0blocks(pIn, &inSize);
+
+ cinfo.bytes = 0;
+ cinfo.bits = 0;
+ cinfo.rawLen = inSize;
+
+ if (get_qt_dynamic(pIn, &cinfo) < 0)
+ return 0;
+
+ /* Decompress, skipping the 8-byte SOF header */
+ if (decompress400NoMMXOV518(pIn + 8, pOut, pTmp, w, h, numpix, &cinfo))
+// return 0;
+ ; /* Don't return error yet */
+
+ return (numpix);
+}
+#endif
+
+/* Input format is raw isoc. data (with intact SOF header, packet numbers
+ * stripped, and all-zero blocks removed).
+ * Output format is planar YUV420
+ * Returns uncompressed data length if success, or zero if error
+ */
+static int v4lconvert_ov518_to_yuv420(unsigned char *src, unsigned char *dst,
+ int w, int h, int yvu, int inSize)
+{
+ struct comp_info cinfo;
+ int numpix = w * h;
+ unsigned char pTmp[32];
+
+ remove0blocks(src, &inSize);
+
+ cinfo.bytes = 0;
+ cinfo.bits = 0;
+ cinfo.rawLen = inSize;
+
+ if (get_qt_dynamic(src, &cinfo) < 0)
+ return -1;
+
+ /* Decompress, skipping the 8-byte SOF header */
+ if (decompress420NoMMXOV518(src + 8, dst, pTmp, w, h, numpix, &cinfo, yvu))
+ return -1;
+
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ int width, height, yvu, src_size, dest_size;
+ unsigned char src_buf[200000];
+ unsigned char dest_buf[500000];
+
+ while (1) {
+ if (v4lconvert_helper_read(STDIN_FILENO, &width, sizeof(int), argv[0]))
+ return 1; /* Erm, no way to recover without loosing sync with libv4l */
+
+ if (v4lconvert_helper_read(STDIN_FILENO, &height, sizeof(int), argv[0]))
+ return 1; /* Erm, no way to recover without loosing sync with libv4l */
+
+ if (v4lconvert_helper_read(STDIN_FILENO, &yvu, sizeof(int), argv[0]))
+ return 1; /* Erm, no way to recover without loosing sync with libv4l */
+
+ if (v4lconvert_helper_read(STDIN_FILENO, &src_size, sizeof(int), argv[0]))
+ return 1; /* Erm, no way to recover without loosing sync with libv4l */
+
+ if (src_size > sizeof(src_buf)) {
+ fprintf(stderr, "%s: error: src_buf too small, need: %d\n",
+ argv[0], src_size);
+ return 2;
+ }
+
+ if (v4lconvert_helper_read(STDIN_FILENO, src_buf, src_size, argv[0]))
+ return 1; /* Erm, no way to recover without loosing sync with libv4l */
+
+
+ dest_size = width * height * 3 / 2;
+ if (dest_size > sizeof(dest_buf)) {
+ fprintf(stderr, "%s: error: dest_buf too small, need: %d\n",
+ argv[0], dest_size);
+ dest_size = -1;
+ } else if (v4lconvert_ov518_to_yuv420(src_buf, dest_buf, width, height,
+ yvu, src_size))
+ dest_size = -1;
+
+ if (v4lconvert_helper_write(STDOUT_FILENO, &dest_size, sizeof(int),
+ argv[0]))
+ return 1; /* Erm, no way to recover without loosing sync with libv4l */
+
+ if (dest_size == -1)
+ continue;
+
+ if (v4lconvert_helper_write(STDOUT_FILENO, dest_buf, dest_size, argv[0]))
+ return 1; /* Erm, no way to recover without loosing sync with libv4l */
+ }
+}
diff --git a/v4l2-apps/libv4l/libv4lconvert/processing/autogain.c b/v4l2-apps/libv4l/libv4lconvert/processing/autogain.c
new file mode 100644
index 000000000..358264c68
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4lconvert/processing/autogain.c
@@ -0,0 +1,140 @@
+/*
+# (C) 2008-2009 Hans de Goede <hdegoede@redhat.com>
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser 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
+*/
+
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "libv4lprocessing.h"
+#include "libv4lprocessing-priv.h"
+#include "../libv4lconvert-priv.h" /* for PIX_FMT defines */
+#include "../libv4lsyscall-priv.h"
+
+static int autogain_active(struct v4lprocessing_data *data) {
+ return v4lcontrol_get_ctrl(data->control, V4LCONTROL_AUTOGAIN);
+}
+
+/* auto gain and exposure algorithm based on the knee algorithm described here:
+ http://ytse.tricolour.net/docs/LowLightOptimization.html */
+static int autogain_calculate_lookup_tables(
+ struct v4lprocessing_data *data,
+ unsigned char *buf, const struct v4l2_format *fmt)
+{
+ int x, y, target, steps, avg_lum = 0;
+ int gain, exposure, orig_gain, orig_exposure;
+ struct v4l2_control ctrl;
+ struct v4l2_queryctrl gainctrl, expoctrl;
+ const int deadzone = 8;
+
+ ctrl.id = V4L2_CID_EXPOSURE;
+ expoctrl.id = V4L2_CID_EXPOSURE;
+ if (SYS_IOCTL(data->fd, VIDIOC_QUERYCTRL, &expoctrl) ||
+ SYS_IOCTL(data->fd, VIDIOC_G_CTRL, &ctrl))
+ return 0;
+ exposure = orig_exposure = ctrl.value;
+
+ ctrl.id = V4L2_CID_GAIN;
+ gainctrl.id = V4L2_CID_GAIN;
+ if (SYS_IOCTL(data->fd, VIDIOC_QUERYCTRL, &gainctrl) ||
+ SYS_IOCTL(data->fd, VIDIOC_G_CTRL, &ctrl))
+ return 0;
+ gain = orig_gain = ctrl.value;
+
+ switch (fmt->fmt.pix.pixelformat) {
+ case V4L2_PIX_FMT_SGBRG8:
+ case V4L2_PIX_FMT_SGRBG8:
+ case V4L2_PIX_FMT_SBGGR8:
+ case V4L2_PIX_FMT_SRGGB8:
+ buf += fmt->fmt.pix.height * fmt->fmt.pix.bytesperline / 4 +
+ fmt->fmt.pix.width / 4;
+
+ for (y = 0; y < fmt->fmt.pix.height / 2; y++) {
+ for (x = 0; x < fmt->fmt.pix.width / 2; x++) {
+ avg_lum += *buf++;
+ }
+ buf += fmt->fmt.pix.bytesperline - fmt->fmt.pix.width / 2;
+ }
+ avg_lum /= fmt->fmt.pix.height * fmt->fmt.pix.width / 4;
+ break;
+
+ case V4L2_PIX_FMT_RGB24:
+ case V4L2_PIX_FMT_BGR24:
+ buf += fmt->fmt.pix.height * fmt->fmt.pix.bytesperline / 4 +
+ fmt->fmt.pix.width * 3 / 4;
+
+ for (y = 0; y < fmt->fmt.pix.height / 2; y++) {
+ for (x = 0; x < fmt->fmt.pix.width / 2; x++) {
+ avg_lum += *buf++;
+ avg_lum += *buf++;
+ avg_lum += *buf++;
+ }
+ buf += fmt->fmt.pix.bytesperline - fmt->fmt.pix.width * 3 / 2;
+ }
+ avg_lum /= fmt->fmt.pix.height * fmt->fmt.pix.width * 3 / 4;
+ break;
+ }
+
+ /* If we are off a multiple of deadzone, do multiple steps to reach the
+ desired lumination fast (with the risc of a slight overshoot) */
+ target = v4lcontrol_get_ctrl(data->control, V4LCONTROL_AUTOGAIN_TARGET);
+ steps = abs(target - avg_lum) / deadzone;
+
+ for (x = 0; x < steps; x++) {
+ if (avg_lum > target) {
+ if (exposure > expoctrl.default_value)
+ exposure--;
+ else if (gain > gainctrl.default_value)
+ gain--;
+ else if (exposure > expoctrl.minimum)
+ exposure--;
+ else if (gain > gainctrl.minimum)
+ gain--;
+ else
+ break;
+ } else {
+ if (gain < gainctrl.default_value)
+ gain++;
+ else if (exposure < expoctrl.default_value)
+ exposure++;
+ else if (gain < gainctrl.maximum)
+ gain++;
+ else if (exposure < expoctrl.maximum)
+ exposure++;
+ else
+ break;
+ }
+ }
+
+ if (gain != orig_gain) {
+ ctrl.id = V4L2_CID_GAIN;
+ ctrl.value = gain;
+ SYS_IOCTL(data->fd, VIDIOC_S_CTRL, &ctrl);
+ }
+ if (exposure != orig_exposure) {
+ ctrl.id = V4L2_CID_EXPOSURE;
+ ctrl.value = exposure;
+ SYS_IOCTL(data->fd, VIDIOC_S_CTRL, &ctrl);
+ }
+
+ return 0;
+}
+
+struct v4lprocessing_filter autogain_filter = {
+ autogain_active, autogain_calculate_lookup_tables };
diff --git a/v4l2-apps/libv4l/libv4lconvert/processing/gamma.c b/v4l2-apps/libv4l/libv4lconvert/processing/gamma.c
new file mode 100644
index 000000000..fcb5bb0cf
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4lconvert/processing/gamma.c
@@ -0,0 +1,57 @@
+/*
+# (C) 2008-2009 Hans de Goede <hdegoede@redhat.com>
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser 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
+*/
+
+#include <math.h>
+#include "libv4lprocessing.h"
+#include "libv4lprocessing-priv.h"
+
+#define CLIP(color) (unsigned char)(((color)>0xff)?0xff:(((color)<0)?0:(color)))
+
+static int gamma_active(struct v4lprocessing_data *data) {
+ int gamma = v4lcontrol_get_ctrl(data->control, V4LCONTROL_GAMMA);
+
+ return gamma && gamma != 1000;
+}
+
+static int gamma_calculate_lookup_tables(
+ struct v4lprocessing_data *data,
+ unsigned char *buf, const struct v4l2_format *fmt)
+{
+ int i, x, gamma;
+
+ gamma = v4lcontrol_get_ctrl(data->control, V4LCONTROL_GAMMA);
+
+ if (gamma != data->last_gamma) {
+ for (i = 0; i < 256; i++) {
+ x = powf(i / 255.0, 1000.0 / gamma) * 255;
+ data->gamma_table[i] = CLIP(x);
+ }
+ data->last_gamma = gamma;
+ }
+
+ for (i = 0; i < 256; i++) {
+ data->comp1[i] = data->gamma_table[data->comp1[i]];
+ data->green[i] = data->gamma_table[data->green[i]];
+ data->comp2[i] = data->gamma_table[data->comp2[i]];
+ }
+
+ return 1;
+}
+
+struct v4lprocessing_filter gamma_filter = {
+ gamma_active, gamma_calculate_lookup_tables };
diff --git a/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing-priv.h b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing-priv.h
new file mode 100644
index 000000000..b73c73b53
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing-priv.h
@@ -0,0 +1,60 @@
+/*
+# (C) 2008-2009 Elmar Kleijn <elmar_kleijn@hotmail.com>
+# (C) 2008-2009 Sjoerd Piepenbrink <need4weed@gmail.com>
+# (C) 2008-2009 Hans de Goede <hdegoede@redhat.com>
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser 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
+*/
+
+#ifndef __LIBV4LPROCESSING_PRIV_H
+#define __LIBV4LPROCESSING_PRIV_H
+
+#include "../control/libv4lcontrol.h"
+#include "../libv4lsyscall-priv.h"
+
+#define V4L2PROCESSING_UPDATE_RATE 10
+
+struct v4lprocessing_data {
+ struct v4lcontrol_data *control;
+ int fd;
+ int do_process;
+ /* True if any of the lookup tables does not contain
+ linear 0-255 */
+ int lookup_table_active;
+ /* Counts the number of processed frames until a
+ V4L2PROCESSING_UPDATE_RATE overflow happens */
+ int lookup_table_update_counter;
+ /* RGB/BGR lookup tables */
+ unsigned char comp1[256];
+ unsigned char green[256];
+ unsigned char comp2[256];
+ /* Filter private data for filters which need it */
+ int last_gamma;
+ unsigned char gamma_table[256];
+};
+
+struct v4lprocessing_filter {
+ /* Returns 1 if the filter is active */
+ int (*active)(struct v4lprocessing_data *data);
+ /* Returns 1 if any of the lookup tables was changed */
+ int (*calculate_lookup_tables)(struct v4lprocessing_data *data,
+ unsigned char *buf, const struct v4l2_format *fmt);
+};
+
+extern struct v4lprocessing_filter whitebalance_filter;
+extern struct v4lprocessing_filter autogain_filter;
+extern struct v4lprocessing_filter gamma_filter;
+
+#endif
diff --git a/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.c b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.c
new file mode 100644
index 000000000..cbbcca73c
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.c
@@ -0,0 +1,181 @@
+/*
+# (C) 2008-2009 Elmar Kleijn <elmar_kleijn@hotmail.com>
+# (C) 2008-2009 Sjoerd Piepenbrink <need4weed@gmail.com>
+# (C) 2008-2009 Hans de Goede <hdegoede@redhat.com>
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser 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
+*/
+
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "libv4lprocessing.h"
+#include "libv4lprocessing-priv.h"
+#include "../libv4lconvert-priv.h" /* for PIX_FMT defines */
+
+static struct v4lprocessing_filter *filters[] = {
+ &whitebalance_filter,
+ &autogain_filter,
+ &gamma_filter,
+};
+
+struct v4lprocessing_data *v4lprocessing_create(int fd, struct v4lcontrol_data* control)
+{
+ struct v4lprocessing_data *data =
+ calloc(1, sizeof(struct v4lprocessing_data));
+
+ if (!data)
+ return NULL;
+
+ data->fd = fd;
+ data->control = control;
+
+ return data;
+}
+
+void v4lprocessing_destroy(struct v4lprocessing_data *data)
+{
+ free(data);
+}
+
+int v4lprocessing_pre_processing(struct v4lprocessing_data *data)
+{
+ int i;
+
+ data->do_process = 0;
+ for (i = 0; i < ARRAY_SIZE(filters); i++) {
+ if (filters[i]->active(data))
+ data->do_process = 1;
+ }
+
+ return data->do_process;
+}
+
+static void v4lprocessing_update_lookup_tables(struct v4lprocessing_data *data,
+ unsigned char *buf, const struct v4l2_format *fmt)
+{
+ int i;
+
+ for (i = 0; i < 256; i++) {
+ data->comp1[i] = i;
+ data->green[i] = i;
+ data->comp2[i] = i;
+ }
+
+ data->lookup_table_active = 0;
+ for (i = 0; i < ARRAY_SIZE(filters); i++) {
+ if (filters[i]->active(data)) {
+ if (filters[i]->calculate_lookup_tables(data, buf, fmt))
+ data->lookup_table_active = 1;
+ }
+ }
+}
+
+static void v4lprocessing_do_processing(struct v4lprocessing_data *data,
+ unsigned char *buf, const struct v4l2_format *fmt)
+{
+ int x, y;
+
+ switch (fmt->fmt.pix.pixelformat) {
+ case V4L2_PIX_FMT_SGBRG8:
+ case V4L2_PIX_FMT_SGRBG8: /* Bayer patterns starting with green */
+ for (y = 0; y < fmt->fmt.pix.height / 2; y++) {
+ for (x = 0; x < fmt->fmt.pix.width / 2; x++) {
+ *buf = data->green[*buf];
+ buf++;
+ *buf = data->comp1[*buf];
+ buf++;
+ }
+ buf += fmt->fmt.pix.bytesperline - fmt->fmt.pix.width;
+ for (x = 0; x < fmt->fmt.pix.width / 2; x++) {
+ *buf = data->comp2[*buf];
+ buf++;
+ *buf = data->green[*buf];
+ buf++;
+ }
+ buf += fmt->fmt.pix.bytesperline - fmt->fmt.pix.width;
+ }
+ break;
+
+ case V4L2_PIX_FMT_SBGGR8:
+ case V4L2_PIX_FMT_SRGGB8: /* Bayer patterns *NOT* starting with green */
+ for (y = 0; y < fmt->fmt.pix.height / 2; y++) {
+ for (x = 0; x < fmt->fmt.pix.width / 2; x++) {
+ *buf = data->comp1[*buf];
+ buf++;
+ *buf = data->green[*buf];
+ buf++;
+ }
+ buf += fmt->fmt.pix.bytesperline - fmt->fmt.pix.width;
+ for (x = 0; x < fmt->fmt.pix.width / 2; x++) {
+ *buf = data->green[*buf];
+ buf++;
+ *buf = data->comp2[*buf];
+ buf++;
+ }
+ buf += fmt->fmt.pix.bytesperline - fmt->fmt.pix.width;
+ }
+ break;
+
+ case V4L2_PIX_FMT_RGB24:
+ case V4L2_PIX_FMT_BGR24:
+ for (y = 0; y < fmt->fmt.pix.height; y++) {
+ for (x = 0; x < fmt->fmt.pix.width; x++) {
+ *buf = data->comp1[*buf];
+ buf++;
+ *buf = data->green[*buf];
+ buf++;
+ *buf = data->comp2[*buf];
+ buf++;
+ }
+ buf += fmt->fmt.pix.bytesperline - 3 * fmt->fmt.pix.width;
+ }
+ break;
+ }
+}
+
+void v4lprocessing_processing(struct v4lprocessing_data *data,
+ unsigned char *buf, const struct v4l2_format *fmt)
+{
+ if (!data->do_process)
+ return;
+
+ /* Do we support the current pixformat? */
+ switch (fmt->fmt.pix.pixelformat) {
+ case V4L2_PIX_FMT_SGBRG8:
+ case V4L2_PIX_FMT_SGRBG8:
+ case V4L2_PIX_FMT_SBGGR8:
+ case V4L2_PIX_FMT_SRGGB8:
+ case V4L2_PIX_FMT_RGB24:
+ case V4L2_PIX_FMT_BGR24:
+ break;
+ default:
+ return; /* Non supported pix format */
+ }
+
+ if (v4lcontrol_controls_changed(data->control) ||
+ data->lookup_table_update_counter == V4L2PROCESSING_UPDATE_RATE) {
+ v4lprocessing_update_lookup_tables(data, buf, fmt);
+ data->lookup_table_update_counter = 0;
+ } else
+ data->lookup_table_update_counter++;
+
+ if (data->lookup_table_active)
+ v4lprocessing_do_processing(data, buf, fmt);
+
+ data->do_process = 0;
+}
diff --git a/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.h b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.h
new file mode 100644
index 000000000..69d8865b2
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4lconvert/processing/libv4lprocessing.h
@@ -0,0 +1,43 @@
+/*
+# (C) 2008-2009 Elmar Kleijn <elmar_kleijn@hotmail.com>
+# (C) 2008-2009 Sjoerd Piepenbrink <need4weed@gmail.com>
+# (C) 2008-2009 Hans de Goede <hdegoede@redhat.com>
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 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 Lesser 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
+*/
+
+#ifndef __LIBV4LPROCESSING_H
+#define __LIBV4LPROCESSING_H
+
+#include "../libv4lsyscall-priv.h"
+#include <linux/videodev2.h>
+
+struct v4lprocessing_data;
+struct v4lcontrol_data;
+
+struct v4lprocessing_data *v4lprocessing_create(int fd, struct v4lcontrol_data *data);
+void v4lprocessing_destroy(struct v4lprocessing_data *data);
+
+/* Prepare to process 1 frame, returns 1 if processing is necesary,
+ return 0 if no processing will be done */
+int v4lprocessing_pre_processing(struct v4lprocessing_data *data);
+
+/* Do the actual processing, this is a nop if v4lprocessing_pre_processing()
+ returned 0, or if called more then 1 time after a single
+ v4lprocessing_pre_processing() call. */
+void v4lprocessing_processing(struct v4lprocessing_data *data,
+ unsigned char *buf, const struct v4l2_format *fmt);
+
+#endif
diff --git a/v4l2-apps/libv4l/libv4lconvert/processing/whitebalance.c b/v4l2-apps/libv4l/libv4lconvert/processing/whitebalance.c
new file mode 100644
index 000000000..64d20b3ff
--- /dev/null
+++ b/v4l2-apps/libv4l/libv4lconvert/processing/whitebalance.c
@@ -0,0 +1,142 @@
+/*
+# (C) 2008-2009 Elmar Kleijn <elmar_kleijn@hotmail.com>
+# (C) 2008-2009 Sjoerd Piepenbrink <need4weed@gmail.com>
+# (C) 2008-2009 Hans de Goede <hdegoede@redhat.com>
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser 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
+*/
+
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "libv4lprocessing.h"
+#include "libv4lprocessing-priv.h"
+#include "../libv4lconvert-priv.h" /* for PIX_FMT defines */
+
+#define CLIP(color) (unsigned char)(((color)>0xff)?0xff:(((color)<0)?0:(color)))
+
+static int whitebalance_active(struct v4lprocessing_data *data) {
+ return v4lcontrol_get_ctrl(data->control, V4LCONTROL_WHITEBALANCE);
+}
+
+static int whitebalance_calculate_lookup_tables_bayer(
+ struct v4lprocessing_data *data, unsigned char *buf,
+ const struct v4l2_format *fmt, int starts_with_green)
+{
+ int x, y, a1 = 0, a2 = 0, b1 = 0, b2 = 0;
+ int green_avg, comp1_avg, comp2_avg, avg_avg;
+
+ for (y = 0; y < fmt->fmt.pix.height; y += 2) {
+ for (x = 0; x < fmt->fmt.pix.width; x += 2) {
+ a1 += *buf++;
+ a2 += *buf++;
+ }
+ buf += fmt->fmt.pix.bytesperline - fmt->fmt.pix.width;
+ for (x = 0; x < fmt->fmt.pix.width; x += 2) {
+ b1 += *buf++;
+ b2 += *buf++;
+ }
+ buf += fmt->fmt.pix.bytesperline - fmt->fmt.pix.width;
+ }
+
+ if (starts_with_green) {
+ green_avg = (a1 + b2) / 512;
+ comp1_avg = a2 / 256;
+ comp2_avg = b1 / 256;
+ } else {
+ green_avg = (a2 + b1) / 512;
+ comp1_avg = a1 / 256;
+ comp2_avg = b2 / 256;
+ }
+
+ x = fmt->fmt.pix.width * fmt->fmt.pix.height / 64;
+ if (abs(green_avg - comp1_avg) < x &&
+ abs(green_avg - comp2_avg) < x &&
+ abs(comp1_avg - comp2_avg) < x)
+ return 0;
+
+ avg_avg = (green_avg + comp1_avg + comp2_avg) / 3;
+
+ for (x = 0; x < 256; x++) {
+ data->comp1[x] = CLIP(data->comp1[x] * avg_avg / comp1_avg);
+ data->green[x] = CLIP(data->green[x] * avg_avg / green_avg);
+ data->comp2[x] = CLIP(data->comp2[x] * avg_avg / comp2_avg);
+ }
+
+ return 1;
+}
+
+static int whitebalance_calculate_lookup_tables_rgb(
+ struct v4lprocessing_data *data, unsigned char *buf,
+ const struct v4l2_format *fmt)
+{
+ int x, y, green_avg = 0, comp1_avg = 0, comp2_avg = 0, avg_avg;
+
+ for (y = 0; y < fmt->fmt.pix.height; y++) {
+ for (x = 0; x < fmt->fmt.pix.width; x++) {
+ comp1_avg += *buf++;
+ green_avg += *buf++;
+ comp2_avg += *buf++;
+ }
+ buf += fmt->fmt.pix.bytesperline - fmt->fmt.pix.width * 3;
+ }
+
+ x = fmt->fmt.pix.width * fmt->fmt.pix.height * 4;
+ if (abs(green_avg - comp1_avg) < x &&
+ abs(green_avg - comp2_avg) < x &&
+ abs(comp1_avg - comp2_avg) < x)
+ return 0;
+
+ /* scale to avoid integer overflows */
+ green_avg /= 256;
+ comp1_avg /= 256;
+ comp2_avg /= 256;
+ avg_avg = (green_avg + comp1_avg + comp2_avg) / 3;
+
+ for (x = 0; x < 256; x++) {
+ data->comp1[x] = CLIP(data->comp1[x] * avg_avg / comp1_avg);
+ data->green[x] = CLIP(data->green[x] * avg_avg / green_avg);
+ data->comp2[x] = CLIP(data->comp2[x] * avg_avg / comp2_avg);
+ }
+
+ return 1;
+}
+
+
+static int whitebalance_calculate_lookup_tables(
+ struct v4lprocessing_data *data,
+ unsigned char *buf, const struct v4l2_format *fmt)
+{
+ switch (fmt->fmt.pix.pixelformat) {
+ case V4L2_PIX_FMT_SGBRG8:
+ case V4L2_PIX_FMT_SGRBG8: /* Bayer patterns starting with green */
+ return whitebalance_calculate_lookup_tables_bayer(data, buf, fmt, 1);
+
+ case V4L2_PIX_FMT_SBGGR8:
+ case V4L2_PIX_FMT_SRGGB8: /* Bayer patterns *NOT* starting with green */
+ return whitebalance_calculate_lookup_tables_bayer(data, buf, fmt, 0);
+
+ case V4L2_PIX_FMT_RGB24:
+ case V4L2_PIX_FMT_BGR24:
+ return whitebalance_calculate_lookup_tables_rgb(data, buf, fmt);
+ }
+
+ return 0; /* Should never happen */
+}
+
+struct v4lprocessing_filter whitebalance_filter = {
+ whitebalance_active, whitebalance_calculate_lookup_tables };
diff --git a/v4l2-apps/libv4l/libv4lconvert/rgbyuv.c b/v4l2-apps/libv4l/libv4lconvert/rgbyuv.c
index 00706be9d..31cbc3c68 100644
--- a/v4l2-apps/libv4l/libv4lconvert/rgbyuv.c
+++ b/v4l2-apps/libv4l/libv4lconvert/rgbyuv.c
@@ -135,7 +135,7 @@ void v4lconvert_yuv420_to_bgr24(const unsigned char *src, unsigned char *dest,
vsrc++;
}
/* Rewind u and v for next line */
- if (i&1) {
+ if (!(i&1)) {
usrc -= width / 2;
vsrc -= width / 2;
}
@@ -189,7 +189,7 @@ void v4lconvert_yuv420_to_rgb24(const unsigned char *src, unsigned char *dest,
vsrc++;
}
/* Rewind u and v for next line */
- if (i&1) {
+ if (!(i&1)) {
usrc -= width / 2;
vsrc -= width / 2;
}
@@ -409,7 +409,6 @@ void v4lconvert_uyvy_to_yuv420(const unsigned char *src, unsigned char *dest,
}
/* copy the U and V values */
- src++; /* point to V */
src1 = src + width * 2; /* next line */
if (yvu) {
vdest = dest;
diff --git a/v4l2-apps/util/v4l2-ctl.cpp b/v4l2-apps/util/v4l2-ctl.cpp
index dec9edd61..309e14312 100644
--- a/v4l2-apps/util/v4l2-ctl.cpp
+++ b/v4l2-apps/util/v4l2-ctl.cpp
@@ -131,6 +131,8 @@ enum Option {
OptOverlay,
OptGetJpegComp,
OptSetJpegComp,
+ OptGetModulator,
+ OptSetModulator,
OptListDevices,
OptLast = 256
};
@@ -260,6 +262,8 @@ static struct option long_options[] = {
{"set-crop-output-overlay", required_argument, 0, OptSetOutputOverlayCrop},
{"get-jpeg-comp", no_argument, 0, OptGetJpegComp},
{"set-jpeg-comp", required_argument, 0, OptSetJpegComp},
+ {"get-modulator", no_argument, 0, OptGetModulator},
+ {"set-modulator", required_argument, 0, OptSetModulator},
{"overlay", required_argument, 0, OptOverlay},
{"list-devices", no_argument, 0, OptListDevices},
{0, 0, 0, 0}
@@ -404,6 +408,15 @@ static void usage(void)
" display audio outputs [VIDIOC_ENUMAUDOUT]\n"
" --list-audio-inputs\n"
" display audio inputs [VIDIOC_ENUMAUDIO]\n"
+ " --get-modulator query the modulator settings [VIDIOC_G_MODULATOR]\n"
+ " --set-modulator=<txsubchans>\n"
+ " set the sub-carrier modulation [VIDIOC_S_MODULATOR]\n"
+ " <txsubchans> is one of:\n"
+ " mono: Modulate as mono\n"
+ " stereo: Modulate as stereo\n"
+ " bilingual: Modulate as bilingual\n"
+ " mono-sap: Modulate as mono with Second Audio Program\n"
+ " stereo-sap: Modulate as stereo with Second Audio Program\n"
"\n");
printf("Expert options:\n"
" --streamoff turn the stream off [VIDIOC_STREAMOFF]\n"
@@ -946,6 +959,21 @@ static std::string rxsubchans2s(int rxsubchans)
return s;
}
+static std::string txsubchans2s(int txsubchans)
+{
+ std::string s;
+
+ if (txsubchans & V4L2_TUNER_SUB_MONO)
+ s += "mono";
+ if (txsubchans & V4L2_TUNER_SUB_STEREO)
+ s += "stereo";
+ if (txsubchans & V4L2_TUNER_SUB_LANG1)
+ s += "bilingual";
+ if (txsubchans & V4L2_TUNER_SUB_SAP)
+ s += "+sap";
+ return s;
+}
+
static std::string tcap2s(unsigned cap)
{
std::string s;
@@ -1384,6 +1412,7 @@ int main(int argc, char **argv)
struct v4l2_jpegcompression jpegcomp; /* jpeg compression */
int input; /* set_input/get_input */
int output; /* set_output/get_output */
+ int txsubchans; /* set_modulator */
v4l2_std_id std; /* get_std/set_std */
double freq = 0; /* get/set frequency */
struct v4l2_frequency vf; /* get_freq/set_freq */
@@ -1695,6 +1724,24 @@ int main(int argc, char **argv)
return 1;
}
break;
+ case OptSetModulator:
+ txsubchans = strtol(optarg, 0L, 0);
+ if (!strcmp(optarg, "stereo"))
+ txsubchans = V4L2_TUNER_SUB_STEREO;
+ else if (!strcmp(optarg, "stereo-sap"))
+ txsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_SAP;
+ else if (!strcmp(optarg, "bilingual"))
+ txsubchans = V4L2_TUNER_SUB_LANG1;
+ else if (!strcmp(optarg, "mono"))
+ txsubchans = V4L2_TUNER_SUB_MONO;
+ else if (!strcmp(optarg, "mono-sap"))
+ txsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_SAP;
+ else {
+ fprintf(stderr, "Unknown txsubchans value\n");
+ usage();
+ return 1;
+ }
+ break;
case OptSetSlicedVbiFormat:
case OptSetSlicedVbiOutFormat:
case OptTrySlicedVbiFormat:
@@ -1861,6 +1908,7 @@ int main(int argc, char **argv)
options[OptGetStandard] = 1;
options[OptGetFreq] = 1;
options[OptGetTuner] = 1;
+ options[OptGetModulator] = 1;
options[OptGetOverlayFormat] = 1;
options[OptGetOutputOverlayFormat] = 1;
options[OptGetVbiFormat] = 1;
@@ -1954,6 +2002,16 @@ int main(int argc, char **argv)
}
}
+ if (options[OptSetModulator]) {
+ struct v4l2_modulator mt;
+
+ memset(&mt, 0, sizeof(struct v4l2_modulator));
+ if (doioctl(fd, VIDIOC_G_MODULATOR, &mt, "VIDIOC_G_MODULATOR") == 0) {
+ mt.txsubchans = txsubchans;
+ doioctl(fd, VIDIOC_S_MODULATOR, &mt, "VIDIOC_S_MODULATOR");
+ }
+ }
+
if (options[OptSetVideoFormat] || options[OptTryVideoFormat]) {
struct v4l2_format in_vfmt;
@@ -2403,6 +2461,7 @@ set_vid_fmt_error:
if (options[OptGetTuner]) {
struct v4l2_tuner vt;
+
memset(&vt, 0, sizeof(struct v4l2_tuner));
if (doioctl(fd, VIDIOC_G_TUNER, &vt, "VIDIOC_G_TUNER") == 0) {
printf("Tuner:\n");
@@ -2421,6 +2480,25 @@ set_vid_fmt_error:
}
}
+ if (options[OptGetModulator]) {
+ struct v4l2_modulator mt;
+
+ memset(&mt, 0, sizeof(struct v4l2_modulator));
+ if (doioctl(fd, VIDIOC_G_MODULATOR, &mt, "VIDIOC_G_MODULATOR") == 0) {
+ printf("Modulator:\n");
+ printf("\tName : %s\n", mt.name);
+ printf("\tCapabilities : %s\n", tcap2s(mt.capability).c_str());
+ if (mt.capability & V4L2_TUNER_CAP_LOW)
+ printf("\tFrequency range : %.1f MHz - %.1f MHz\n",
+ mt.rangelow / 16000.0, mt.rangehigh / 16000.0);
+ else
+ printf("\tFrequency range : %.1f MHz - %.1f MHz\n",
+ mt.rangelow / 16.0, mt.rangehigh / 16.0);
+ printf("\tSubchannel modulation: %s\n",
+ txsubchans2s(mt.txsubchans).c_str());
+ }
+ }
+
if (options[OptLogStatus]) {
static char buf[40960];
int len;
diff --git a/v4l2-spec/pixfmt.sgml b/v4l2-spec/pixfmt.sgml
index 3f39b408e..36a6934c7 100644
--- a/v4l2-spec/pixfmt.sgml
+++ b/v4l2-spec/pixfmt.sgml
@@ -724,6 +724,11 @@ kernel sources in the file <filename>Documentation/video4linux/cx2341x/README.hm
<entry>'M310'</entry>
<entry>Compressed BGGR Bayer format used by the gspca driver.</entry>
</row>
+ <row id="V4L2-PIX-FMT-OV518">
+ <entry><constant>V4L2_PIX_FMT_OV518</constant></entry>
+ <entry>'0518'</entry>
+ <entry>OV518 JPEG format used by the gspca driver.</entry>
+ </row>
<row id="V4L2-PIX-FMT-PJPG">
<entry><constant>V4L2_PIX_FMT_PJPG</constant></entry>
<entry>'PJPG'</entry>
diff --git a/v4l2-spec/vidioc-g-modulator.sgml b/v4l2-spec/vidioc-g-modulator.sgml
index e5d4a3f24..a3ea5ef8a 100644
--- a/v4l2-spec/vidioc-g-modulator.sgml
+++ b/v4l2-spec/vidioc-g-modulator.sgml
@@ -166,7 +166,7 @@ combine with <constant>V4L2_TUNER_SUB_STEREO</constant> or
channel of a stereo audio signal. When the input has only one channel
or two channels and <constant>V4L2_TUNER_SUB_SAP</constant> is also
set, channel 1 is encoded as left and right channel. This flag does
-not combine with <constant>V4L2_TUNER_SUB_MONO </constant> or
+not combine with <constant>V4L2_TUNER_SUB_MONO</constant> or
<constant>V4L2_TUNER_SUB_LANG1</constant>. When the driver does not
support stereo audio it shall fall back to mono.</entry>
</row>
@@ -177,8 +177,9 @@ support stereo audio it shall fall back to mono.</entry>
language of a bilingual audio signal. When the input has only one
channel it is used for both languages. It is not possible to encode
the primary or secondary language only. This flag does not combine
-with <constant>V4L2_TUNER_SUB_MONO </constant> or
-<constant>V4L2_TUNER_SUB_STEREO</constant>. If the hardware does not
+with <constant>V4L2_TUNER_SUB_MONO</constant>,
+<constant>V4L2_TUNER_SUB_STEREO</constant> or
+<constant>V4L2_TUNER_SUB_SAP</constant>. If the hardware does not
support the respective audio matrix, or the current video standard
does not permit bilingual audio the
<constant>VIDIOC_S_MODULATOR</constant> ioctl shall return an &EINVAL;
@@ -188,7 +189,7 @@ and the driver shall fall back to mono or stereo mode.</entry>
<entry><constant>V4L2_TUNER_SUB_LANG2</constant></entry>
<entry>0x0004</entry>
<entry>Same effect as
-<constant>V4L2_TUNER_SUB_LANG1</constant>.</entry>
+<constant>V4L2_TUNER_SUB_SAP</constant>.</entry>
</row>
<row>
<entry><constant>V4L2_TUNER_SUB_SAP</constant></entry>
@@ -198,7 +199,7 @@ and the driver shall fall back to mono or stereo mode.</entry>
channel as Second Audio Program. When the input has only one channel
it is used for both audio tracks. When the input has three channels
the mono track is a down-mix of channel 1 and 2. When combined with
-<constant>V4L2_TUNER_SUB_STEREO </constant> channel 1 and 2 are
+<constant>V4L2_TUNER_SUB_STEREO</constant> channel 1 and 2 are
encoded as left and right stereo audio, channel 3 as Second Audio
Program. When the input has only two channels, the first is encoded as
left and right channel and the second as SAP. When the input has only
@@ -207,7 +208,7 @@ encode a Second Audio Program only. This flag must combine with
<constant>V4L2_TUNER_SUB_MONO</constant> or
<constant>V4L2_TUNER_SUB_STEREO</constant>. If the hardware does not
support the respective audio matrix, or the current video standard
-does not permit SAP the <constant> VIDIOC_S_MODULATOR</constant> ioctl
+does not permit SAP the <constant>VIDIOC_S_MODULATOR</constant> ioctl
shall return an &EINVAL; and driver shall fall back to mono or stereo
mode.</entry>
</row>