summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@redhat.com>2009-06-23 03:06:49 -0300
committerMauro Carvalho Chehab <mchehab@redhat.com>2009-06-23 03:06:49 -0300
commit8b3ed0d52132397a5de88531f5287b5e7864b76e (patch)
tree8a2ce91805633daa4063b1910f50c7bad1c327a5
parent9bd4b1d143281470bf7a00afda20a7368154e213 (diff)
parent3f5baede21113b8adf1b40d403e19a1ced1b07b8 (diff)
downloadmediapointer-dvb-s2-8b3ed0d52132397a5de88531f5287b5e7864b76e.tar.gz
mediapointer-dvb-s2-8b3ed0d52132397a5de88531f5287b5e7864b76e.tar.bz2
merge: http://www.linuxtv.org/hg/~hverkuil/v4l-dvb-subdev2
From: Mauro Carvalho Chehab <mchehab@redhat.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rwxr-xr-xlinux/Documentation/dvb/get_dvb_firmware2
-rw-r--r--linux/Documentation/video4linux/CARDLIST.cx886
-rw-r--r--linux/Documentation/video4linux/CARDLIST.em28xx2
-rw-r--r--linux/Documentation/video4linux/CARDLIST.saa71342
-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/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/dvb/b2c2/flexcop-fe-tuner.c196
-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/dvb_net.c65
-rw-r--r--linux/drivers/media/dvb/dvb-usb/Kconfig3
-rw-r--r--linux/drivers/media/dvb/dvb-usb/af9015.c2
-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/frontends/au8522_dig.c98
-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/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/frontends/tda10048.c1
-rw-r--r--linux/drivers/media/dvb/siano/smscoreapi.c4
-rw-r--r--linux/drivers/media/radio/dsbr100.c109
-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/bt8xx/bttv-driver.c11
-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/cx231xx/cx231xx-avcore.c2
-rw-r--r--linux/drivers/media/video/cx2341x.c2
-rw-r--r--linux/drivers/media/video/cx23885/cx23885-dvb.c33
-rw-r--r--linux/drivers/media/video/cx23885/cx23885-video.c14
-rw-r--r--linux/drivers/media/video/cx88/cx88-alsa.c7
-rw-r--r--linux/drivers/media/video/cx88/cx88-cards.c94
-rw-r--r--linux/drivers/media/video/cx88/cx88-video.c14
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-cards.c128
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-core.c21
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-dvb.c15
-rw-r--r--linux/drivers/media/video/em28xx/em28xx.h2
-rw-r--r--linux/drivers/media/video/gspca/gspca.c120
-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.c4
-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/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/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.c2
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-queue.c3
-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-audio.c14
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-cs53l32a.c24
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c37
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c60
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c35
-rw-r--r--linux/drivers/media/video/pwc/pwc-if.c6
-rw-r--r--linux/drivers/media/video/pxa_camera.c18
-rw-r--r--linux/drivers/media/video/saa7134/Makefile3
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-cards.c8
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-core.c17
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-empress.c11
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-ts.c120
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-video.c1
-rw-r--r--linux/drivers/media/video/saa7134/saa7134.h12
-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/soc_camera.c2
-rw-r--r--linux/drivers/media/video/tcm825x.c4
-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.c25
-rw-r--r--linux/drivers/media/video/uvc/uvc_queue.c14
-rw-r--r--linux/drivers/media/video/uvc/uvc_v4l2.c17
-rw-r--r--linux/drivers/media/video/uvc/uvcvideo.h2
-rw-r--r--linux/drivers/media/video/v4l2-common.c9
-rw-r--r--linux/drivers/media/video/v4l2-ioctl.c17
-rw-r--r--linux/drivers/media/video/videobuf-core.c1
-rw-r--r--linux/drivers/media/video/videobuf-dma-sg.c2
-rw-r--r--linux/drivers/media/video/vino.c6
-rw-r--r--linux/drivers/media/video/zoran/zoran_card.c2
-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/tuner.h1
-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.h7
-rwxr-xr-xv4l/scripts/make_config_compat.pl46
-rw-r--r--v4l/versions.txt8
-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
162 files changed, 9377 insertions, 1733 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.cx88 b/linux/Documentation/video4linux/CARDLIST.cx88
index 89093f531..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]
diff --git a/linux/Documentation/video4linux/CARDLIST.em28xx b/linux/Documentation/video4linux/CARDLIST.em28xx
index b03a68586..873630e7e 100644
--- a/linux/Documentation/video4linux/CARDLIST.em28xx
+++ b/linux/Documentation/video4linux/CARDLIST.em28xx
@@ -64,3 +64,5 @@
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 e56934e50..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]
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/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/dvb/b2c2/flexcop-fe-tuner.c b/linux/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
index 3f485bf13..efb4a6c2b 100644
--- a/linux/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
+++ b/linux/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
@@ -175,23 +175,23 @@ static int skystar23_samsung_tbdu18132_tuner_set_params(struct dvb_frontend *fe,
return 0;
}
-static void skystar2_rev23_attach(struct flexcop_device *fc,
+static int skystar2_rev23_attach(struct flexcop_device *fc,
struct i2c_adapter *i2c)
{
- fc->fe = dvb_attach(mt312_attach,
- &skystar23_samsung_tbdu18132_config, 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->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->dev_type = FC_SKY_REV23;
+ return 1;
}
+ return 0;
}
#endif
@@ -307,7 +307,7 @@ static struct stv0299_config samsung_tbmu24112_config = {
.set_symbol_rate = samsung_tbmu24112_set_symbol_rate,
};
-static void skystar2_rev26_attach(struct flexcop_device *fc,
+static int skystar2_rev26_attach(struct flexcop_device *fc,
struct i2c_adapter *i2c)
{
fc->fe = dvb_attach(stv0299_attach, &samsung_tbmu24112_config, i2c);
@@ -317,7 +317,9 @@ static void skystar2_rev26_attach(struct flexcop_device *fc,
ops->set_voltage = flexcop_set_voltage;
fc->fe_sleep = ops->sleep;
ops->sleep = flexcop_sleep;
+ return 1;
}
+ return 0;
}
#endif
@@ -334,43 +336,54 @@ static struct itd1000_config skystar2_rev2_7_itd1000_config = {
.i2c_address = 0x61,
};
-static void skystar2_rev27_attach(struct flexcop_device *fc,
+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 != NULL) {
- flexcop_ibi_value r108;
- struct i2c_adapter *i2c_tuner \
- = s5h1420_get_tuner_i2c_adapter(fc->fe);
- struct dvb_frontend_ops *ops = &fc->fe->ops;
+ fc->fe = dvb_attach(s5h1420_attach, &skystar2_rev2_7_s5h1420_config,
+ i2c);
+ if (!fc->fe)
+ goto fail;
- fc->fe_sleep = ops->sleep;
- 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) == NULL)
- err("ISL6421 could NOT be attached");
- else
- 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 (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");
- }
- } else
- fc->fc_i2c_adap[0].no_base_addr = 0;
- /* for the next devices we need it again */
+ 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
@@ -387,32 +400,38 @@ static const struct cx24113_config skystar2_rev2_8_cx24113_config = {
.xtal_khz = 10111,
};
-static void skystar2_rev28_attach(struct flexcop_device *fc,
+static int skystar2_rev28_attach(struct flexcop_device *fc,
struct i2c_adapter *i2c)
{
- fc->fe = dvb_attach(cx24123_attach,
- &skystar2_rev2_8_cx24123_config, i2c);
- if (fc->fe != NULL) {
- struct i2c_adapter *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");
- }
+ 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;
- 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");
+ 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
@@ -466,12 +485,15 @@ static struct mt352_config samsung_tdtc9251dh0_config = {
.demod_init = samsung_tdtc9251dh0_demod_init,
};
-static void airstar_dvbt_attach(struct flexcop_device *fc,
+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)
+ if (fc->fe != NULL) {
fc->fe->ops.tuner_ops.calc_regs = samsung_tdtc9251dh0_calc_regs;
+ return 1;
+ }
+ return 0;
}
#endif
@@ -489,10 +511,11 @@ static struct bcm3510_config air2pc_atsc_first_gen_config = {
.request_firmware = flexcop_fe_request_firmware,
};
-static void airstar_atsc1_attach(struct flexcop_device *fc,
+static int airstar_atsc1_attach(struct flexcop_device *fc,
struct i2c_adapter *i2c)
{
fc->fe = dvb_attach(bcm3510_attach, &air2pc_atsc_first_gen_config, i2c);
+ return fc->fe != NULL;
}
#endif
@@ -502,13 +525,15 @@ static struct nxt200x_config samsung_tbmv_config = {
.demod_address = 0x0a,
};
-static void airstar_atsc2_attach(struct flexcop_device *fc,
+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 != NULL)
- dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL,
- DVB_PLL_SAMSUNG_TBMV);
+ if (!fc->fe)
+ return 0;
+
+ return !!dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL,
+ DVB_PLL_SAMSUNG_TBMV);
}
#endif
@@ -521,14 +546,15 @@ static struct lgdt330x_config air2pc_atsc_hd5000_config = {
.clock_polarity_flip = 1,
};
-static void airstar_atsc3_attach(struct flexcop_device *fc,
+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 != NULL) {
- dvb_attach(simple_tuner_attach, fc->fe, i2c, 0x61,
- TUNER_LG_TDVS_H06XF);
- }
+ if (!fc->fe)
+ return 0;
+
+ return !!dvb_attach(simple_tuner_attach, fc->fe, i2c, 0x61,
+ TUNER_LG_TDVS_H06XF);
}
#endif
@@ -659,22 +685,24 @@ static struct stv0297_config alps_tdee4_stv0297_config = {
.inittab = alps_tdee4_stv0297_inittab,
};
-static void cablestar2_attach(struct flexcop_device *fc,
+static int cablestar2_attach(struct flexcop_device *fc,
struct i2c_adapter *i2c)
{
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->fe->ops.tuner_ops.set_params \
- = alps_tdee4_stv0297_tuner_set_params;
- else
+ if (!fc->fe) {
+ /* Reset for next frontend to try */
fc->fc_i2c_adap[0].no_base_addr = 0;
+ return 0;
+ }
+ fc->fe->ops.tuner_ops.set_params = alps_tdee4_stv0297_tuner_set_params;
+ return 1;
}
#endif
static struct {
flexcop_device_type_t type;
- void (*attach)(struct flexcop_device *, struct i2c_adapter *);
+ int (*attach)(struct flexcop_device *, struct i2c_adapter *);
} flexcop_frontends[] = {
#if defined(CONFIG_DVB_S5H1420_MODULE)
{ FC_SKY_REV27, skystar2_rev27_attach },
@@ -713,9 +741,13 @@ int flexcop_frontend_init(struct flexcop_device *fc)
/* type needs to be set before, because of some workarounds
* done based on the probed card type */
fc->dev_type = flexcop_frontends[i].type;
- flexcop_frontends[i].attach(fc, &fc->fc_i2c_adap[0].i2c_adap);
- if (fc->fe != NULL)
+ 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");
@@ -724,10 +756,8 @@ int flexcop_frontend_init(struct flexcop_device *fc)
fe_found:
info("found '%s' .", fc->fe->ops.info.name);
if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) {
- struct dvb_frontend_ops *ops = &fc->fe->ops;
err("frontend registration failed!");
- if (ops->release != NULL)
- ops->release(fc->fe);
+ dvb_frontend_detach(fc->fe);
fc->fe = NULL;
return -EINVAL;
}
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/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 a50bf34af..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++) {
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/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/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/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/frontends/tda10048.c b/linux/drivers/media/dvb/frontends/tda10048.c
index 04596baa9..edf5a19a3 100644
--- a/linux/drivers/media/dvb/frontends/tda10048.c
+++ b/linux/drivers/media/dvb/frontends/tda10048.c
@@ -210,6 +210,7 @@ static struct pll_tab {
{ TDA10048_CLK_4000, TDA10048_IF_36130, 10, 0, 0 },
{ TDA10048_CLK_16000, TDA10048_IF_3300, 10, 3, 0 },
{ TDA10048_CLK_16000, TDA10048_IF_3500, 10, 3, 0 },
+ { TDA10048_CLK_16000, TDA10048_IF_3800, 10, 3, 0 },
{ TDA10048_CLK_16000, TDA10048_IF_4000, 10, 3, 0 },
{ TDA10048_CLK_16000, TDA10048_IF_4300, 10, 3, 0 },
{ TDA10048_CLK_16000, TDA10048_IF_36130, 10, 3, 0 },
diff --git a/linux/drivers/media/dvb/siano/smscoreapi.c b/linux/drivers/media/dvb/siano/smscoreapi.c
index e513408fc..54f59f24e 100644
--- a/linux/drivers/media/dvb/siano/smscoreapi.c
+++ b/linux/drivers/media/dvb/siano/smscoreapi.c
@@ -1477,8 +1477,8 @@ int smscore_gpio_configure(struct smscore_device_t *coredev, u8 PinNum,
struct smscore_gpio_config *pGpioConfig) {
u32 totalLen;
- u32 TranslatedPinNum;
- u32 GroupNum;
+ u32 TranslatedPinNum = 0;
+ u32 GroupNum = 0;
u32 ElectricChar;
u32 groupCfg;
void *buffer;
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-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/bt8xx/bttv-driver.c b/linux/drivers/media/video/bt8xx/bttv-driver.c
index 67d06eb6c..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)
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/cx231xx/cx231xx-avcore.c b/linux/drivers/media/video/cx231xx/cx231xx-avcore.c
index bbbb3f50e..28f48f41f 100644
--- a/linux/drivers/media/video/cx231xx/cx231xx-avcore.c
+++ b/linux/drivers/media/video/cx231xx/cx231xx-avcore.c
@@ -2046,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/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-dvb.c b/linux/drivers/media/video/cx23885/cx23885-dvb.c
index 9c3259b22..71f196ec5 100644
--- a/linux/drivers/media/video/cx23885/cx23885-dvb.c
+++ b/linux/drivers/media/video/cx23885/cx23885-dvb.c
@@ -46,6 +46,7 @@
#include "dibx000_common.h"
#include "zl10353.h"
#include "stv0900.h"
+#include "stv0900_reg.h"
#include "stv6110.h"
#include "lnbh24.h"
#include "cx24116.h"
@@ -243,12 +244,22 @@ static struct tda18271_std_map hauppauge_tda18271_std_map = {
.if_lvl = 6, .rfagc_top = 0x37 },
};
+static struct tda18271_std_map hauppauge_hvr1200_tda18271_std_map = {
+ .dvbt_6 = { .if_freq = 3300, .agc_mode = 3, .std = 4,
+ .if_lvl = 1, .rfagc_top = 0x37, },
+ .dvbt_7 = { .if_freq = 3800, .agc_mode = 3, .std = 5,
+ .if_lvl = 1, .rfagc_top = 0x37, },
+ .dvbt_8 = { .if_freq = 4300, .agc_mode = 3, .std = 6,
+ .if_lvl = 1, .rfagc_top = 0x37, },
+};
+
static struct tda18271_config hauppauge_tda18271_config = {
.std_map = &hauppauge_tda18271_std_map,
.gate = TDA18271_GATE_ANALOG,
};
static struct tda18271_config hauppauge_hvr1200_tuner_config = {
+ .std_map = &hauppauge_hvr1200_tda18271_std_map,
.gate = TDA18271_GATE_ANALOG,
};
@@ -371,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 */
@@ -737,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");
@@ -757,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");
diff --git a/linux/drivers/media/video/cx23885/cx23885-video.c b/linux/drivers/media/video/cx23885/cx23885-video.c
index 378943605..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)
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 825b1f25d..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] = {
@@ -2471,6 +2483,41 @@ static const struct cx88_subid cx88_subids[] = {
.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,
},
};
@@ -2479,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) {
@@ -2492,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",
@@ -2746,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:
@@ -2758,6 +2809,7 @@ 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);
}
@@ -2947,6 +2999,7 @@ static void cx88_card_setup_pre_i2c(struct cx88_core *core)
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);
@@ -2983,6 +3036,7 @@ void cx88_setup_xc3028(struct cx88_core *core, struct xc2028_ctrl *ctl)
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:
/*
@@ -3026,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-video.c b/linux/drivers/media/video/cx88/cx88-video.c
index 70b086fb7..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)
diff --git a/linux/drivers/media/video/em28xx/em28xx-cards.c b/linux/drivers/media/video/em28xx/em28xx-cards.c
index 5b89c1821..b824eed46 100644
--- a/linux/drivers/media/video/em28xx/em28xx-cards.c
+++ b/linux/drivers/media/video/em28xx/em28xx-cards.c
@@ -122,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},
@@ -134,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},
@@ -1160,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,
@@ -1464,6 +1532,33 @@ struct em28xx_board em28xx_boards[] = {
.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);
@@ -1501,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),
@@ -1588,6 +1685,7 @@ 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 */
@@ -1770,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);
@@ -1840,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;
}
@@ -2081,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:
@@ -2110,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);
@@ -2132,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;
}
diff --git a/linux/drivers/media/video/em28xx/em28xx-core.c b/linux/drivers/media/video/em28xx/em28xx-core.c
index 02e51af9d..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;
}
diff --git a/linux/drivers/media/video/em28xx/em28xx-dvb.c b/linux/drivers/media/video/em28xx/em28xx-dvb.c
index de919504f..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"
@@ -444,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);
@@ -452,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.h b/linux/drivers/media/video/em28xx/em28xx.h
index db07d92f6..6fb890efa 100644
--- a/linux/drivers/media/video/em28xx/em28xx.h
+++ b/linux/drivers/media/video/em28xx/em28xx.h
@@ -106,6 +106,8 @@
#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
diff --git a/linux/drivers/media/video/gspca/gspca.c b/linux/drivers/media/video/gspca/gspca.c
index 3bf8b4866..f06aac676 100644
--- a/linux/drivers/media/video/gspca/gspca.c
+++ b/linux/drivers/media/video/gspca/gspca.c
@@ -1021,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;
}
@@ -1066,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?*/
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 14341b6be..21a9366c7 100644
--- a/linux/drivers/media/video/gspca/ov534.c
+++ b/linux/drivers/media/video/gspca/ov534.c
@@ -958,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
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/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/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 eed4d2364..484a323f1 100644
--- a/linux/drivers/media/video/ivtv/ivtv-i2c.c
+++ b/linux/drivers/media/video/ivtv/ivtv-i2c.c
@@ -639,6 +639,7 @@ int init_ivtv_i2c(struct ivtv *itv)
retval = i2c_add_adapter(&itv->i2c_adap);
else
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) {
@@ -666,6 +667,7 @@ int init_ivtv_i2c(struct ivtv *itv)
i2c_new_probed_device(&itv->i2c_adap, &info, addr_list);
}
#endif
+
return retval;
}
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/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-audio.c b/linux/drivers/media/video/pvrusb2/pvrusb2-audio.c
index 86049f412..42875ec21 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-audio.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-audio.c
@@ -49,11 +49,13 @@ static const int routing_scheme0[] = {
MSP_DSP_IN_SCART),
};
-static const struct routing_scheme routing_schemes[] = {
- [PVR2_ROUTING_SCHEME_HAUPPAUGE] = {
- .def = routing_scheme0,
- .cnt = ARRAY_SIZE(routing_scheme0),
- },
+static const struct routing_scheme routing_def0 = {
+ .def = routing_scheme0,
+ .cnt = ARRAY_SIZE(routing_scheme0),
+};
+
+static const struct routing_scheme *routing_schemes[] = {
+ [PVR2_ROUTING_SCHEME_HAUPPAUGE] = &routing_def0,
};
void pvr2_msp3400_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd)
@@ -66,7 +68,7 @@ void pvr2_msp3400_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd)
pvr2_trace(PVR2_TRACE_CHIPS, "subdev msp3400 v4l2 set_stereo");
if ((sid < ARRAY_SIZE(routing_schemes)) &&
- ((sp = routing_schemes + sid) != NULL) &&
+ ((sp = routing_schemes[sid]) != NULL) &&
(hdw->input_val >= 0) &&
(hdw->input_val < sp->cnt)) {
input = sp->def[hdw->input_val];
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-cs53l32a.c b/linux/drivers/media/video/pvrusb2/pvrusb2-cs53l32a.c
index f99b77c92..7bcaa0cd4 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-cs53l32a.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-cs53l32a.c
@@ -50,11 +50,13 @@ static const int routing_scheme1[] = {
[PVR2_CVAL_INPUT_SVIDEO] = 0,
};
-static const struct routing_scheme routing_schemes[] = {
- [PVR2_ROUTING_SCHEME_ONAIR] = {
- .def = routing_scheme1,
- .cnt = ARRAY_SIZE(routing_scheme1),
- },
+static const struct routing_scheme routing_def1 = {
+ .def = routing_scheme1,
+ .cnt = ARRAY_SIZE(routing_scheme1),
+};
+
+static const struct routing_scheme *routing_schemes[] = {
+ [PVR2_ROUTING_SCHEME_ONAIR] = &routing_def1,
};
@@ -66,12 +68,11 @@ void pvr2_cs53l32a_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd)
u32 input;
pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 set_input(%d)",
hdw->input_val);
- if ((sid < ARRAY_SIZE(routing_schemes)) &&
- ((sp = routing_schemes + sid) != NULL) &&
- (hdw->input_val >= 0) &&
- (hdw->input_val < sp->cnt)) {
- input = sp->def[hdw->input_val];
- } else {
+ sp = (sid < ARRAY_SIZE(routing_schemes)) ?
+ routing_schemes[sid] : NULL;
+ if ((sp == NULL) ||
+ (hdw->input_val < 0) ||
+ (hdw->input_val >= sp->cnt)) {
pvr2_trace(PVR2_TRACE_ERROR_LEGS,
"*** WARNING *** subdev v4l2 set_input:"
" Invalid routing scheme (%u)"
@@ -79,6 +80,7 @@ void pvr2_cs53l32a_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd)
sid, hdw->input_val);
return;
}
+ input = sp->def[hdw->input_val];
sd->ops->audio->s_routing(sd, input, 0, 0);
}
}
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c b/linux/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
index ef47c3874..e15d7fb6c 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
@@ -69,6 +69,11 @@ static const struct routing_scheme_item routing_scheme0[] = {
},
};
+static const struct routing_scheme routing_def0 = {
+ .def = routing_scheme0,
+ .cnt = ARRAY_SIZE(routing_scheme0),
+};
+
/* Specific to gotview device */
static const struct routing_scheme_item routing_schemegv[] = {
[PVR2_CVAL_INPUT_TV] = {
@@ -91,15 +96,14 @@ static const struct routing_scheme_item routing_schemegv[] = {
},
};
-static const struct routing_scheme routing_schemes[] = {
- [PVR2_ROUTING_SCHEME_HAUPPAUGE] = {
- .def = routing_scheme0,
- .cnt = ARRAY_SIZE(routing_scheme0),
- },
- [PVR2_ROUTING_SCHEME_GOTVIEW] = {
- .def = routing_schemegv,
- .cnt = ARRAY_SIZE(routing_schemegv),
- },
+static const struct routing_scheme routing_defgv = {
+ .def = routing_schemegv,
+ .cnt = ARRAY_SIZE(routing_schemegv),
+};
+
+static const struct routing_scheme *routing_schemes[] = {
+ [PVR2_ROUTING_SCHEME_HAUPPAUGE] = &routing_def0,
+ [PVR2_ROUTING_SCHEME_GOTVIEW] = &routing_defgv,
};
void pvr2_cx25840_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd)
@@ -111,13 +115,11 @@ void pvr2_cx25840_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd)
const struct routing_scheme *sp;
unsigned int sid = hdw->hdw_desc->signal_routing_scheme;
- if ((sid < ARRAY_SIZE(routing_schemes)) &&
- ((sp = routing_schemes + sid) != NULL) &&
- (hdw->input_val >= 0) &&
- (hdw->input_val < sp->cnt)) {
- vid_input = sp->def[hdw->input_val].vid;
- aud_input = sp->def[hdw->input_val].aud;
- } else {
+ sp = (sid < ARRAY_SIZE(routing_schemes)) ?
+ routing_schemes[sid] : NULL;
+ if ((sp == NULL) ||
+ (hdw->input_val < 0) ||
+ (hdw->input_val >= sp->cnt)) {
pvr2_trace(PVR2_TRACE_ERROR_LEGS,
"*** WARNING *** subdev cx2584x set_input:"
" Invalid routing scheme (%u)"
@@ -125,7 +127,8 @@ void pvr2_cx25840_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd)
sid, hdw->input_val);
return;
}
-
+ vid_input = sp->def[hdw->input_val].vid;
+ aud_input = sp->def[hdw->input_val].aud;
pvr2_trace(PVR2_TRACE_CHIPS,
"subdev cx2584x set_input vid=0x%x aud=0x%x",
vid_input, aud_input);
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c
index 3411cb36a..0bbd20f13 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c
@@ -86,8 +86,8 @@ MODULE_PARM_DESC(video_std,"specify initial video standard");
module_param_array(tolerance, int, NULL, 0444);
MODULE_PARM_DESC(tolerance,"specify stream error tolerance");
-/* US Broadcast channel 7 (175.25 MHz) */
-static int default_tv_freq = 175250000L;
+/* US Broadcast channel 3 (61.25 MHz), to help with testing */
+static int default_tv_freq = 61250000L;
/* 104.3 MHz, a usable FM station for my area */
static int default_radio_freq = 104300000L;
@@ -2004,6 +2004,34 @@ static unsigned int pvr2_copy_i2c_addr_list(
}
+static void pvr2_hdw_cx25840_vbi_hack(struct pvr2_hdw *hdw)
+{
+ /*
+ Mike Isely <isely@pobox.com> 19-Nov-2006 - This bit of nuttiness
+ for cx25840 causes that module to correctly set up its video
+ scaling. This is really a problem in the cx25840 module itself,
+ but we work around it here. The problem has not been seen in
+ ivtv because there VBI is supported and set up. We don't do VBI
+ here (at least not yet) and thus we never attempted to even set
+ it up.
+ */
+ struct v4l2_format fmt;
+ if (hdw->decoder_client_id != PVR2_CLIENT_ID_CX25840) {
+ /* We're not using a cx25840 so don't enable the hack */
+ return;
+ }
+
+ pvr2_trace(PVR2_TRACE_INIT,
+ "Module ID %u:"
+ " Executing cx25840 VBI hack",
+ hdw->decoder_client_id);
+ memset(&fmt, 0, sizeof(fmt));
+ fmt.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
+ v4l2_device_call_all(&hdw->v4l2_dev, hdw->decoder_client_id,
+ video, s_fmt, &fmt);
+}
+
+
static int pvr2_hdw_load_subdev(struct pvr2_hdw *hdw,
const struct pvr2_device_client_desc *cd)
{
@@ -2095,30 +2123,6 @@ static int pvr2_hdw_load_subdev(struct pvr2_hdw *hdw,
/* client-specific setup... */
switch (mid) {
case PVR2_CLIENT_ID_CX25840:
- hdw->decoder_client_id = mid;
- {
- /*
- Mike Isely <isely@pobox.com> 19-Nov-2006 - This
- bit of nuttiness for cx25840 causes that module
- to correctly set up its video scaling. This is
- really a problem in the cx25840 module itself,
- but we work around it here. The problem has not
- been seen in ivtv because there VBI is supported
- and set up. We don't do VBI here (at least not
- yet) and thus we never attempted to even set it
- up.
- */
- struct v4l2_format fmt;
- pvr2_trace(PVR2_TRACE_INIT,
- "Module ID %u:"
- " Executing cx25840 VBI hack",
- mid);
- memset(&fmt, 0, sizeof(fmt));
- fmt.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
- v4l2_device_call_all(&hdw->v4l2_dev, mid,
- video, s_fmt, &fmt);
- }
- break;
case PVR2_CLIENT_ID_SAA7115:
hdw->decoder_client_id = mid;
break;
@@ -2219,6 +2223,8 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
cptr->info->set_value(cptr,~0,cptr->info->default_value);
}
+ pvr2_hdw_cx25840_vbi_hack(hdw);
+
/* Set up special default values for the television and radio
frequencies here. It's not really important what these defaults
are, but I set them to something usable in the Chicago area just
@@ -2976,6 +2982,7 @@ static void pvr2_subdev_update(struct pvr2_hdw *hdw)
vs = hdw->std_mask_cur;
v4l2_device_call_all(&hdw->v4l2_dev, 0,
core, s_std, vs);
+ pvr2_hdw_cx25840_vbi_hack(hdw);
}
hdw->tuner_signal_stale = !0;
hdw->cropcap_stale = !0;
@@ -4170,6 +4177,7 @@ int pvr2_hdw_cmd_decoder_reset(struct pvr2_hdw *hdw)
if (hdw->decoder_client_id) {
v4l2_device_call_all(&hdw->v4l2_dev, hdw->decoder_client_id,
core, reset, 0);
+ pvr2_hdw_cx25840_vbi_hack(hdw);
return 0;
}
pvr2_trace(PVR2_TRACE_INIT,
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c b/linux/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c
index d240331a6..4be489c45 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c
@@ -55,6 +55,11 @@ static const int routing_scheme0[] = {
[PVR2_CVAL_INPUT_SVIDEO] = SAA7115_SVIDEO2,
};
+static const struct routing_scheme routing_def0 = {
+ .def = routing_scheme0,
+ .cnt = ARRAY_SIZE(routing_scheme0),
+};
+
static const int routing_scheme1[] = {
[PVR2_CVAL_INPUT_TV] = SAA7115_COMPOSITE4,
[PVR2_CVAL_INPUT_RADIO] = SAA7115_COMPOSITE5,
@@ -62,15 +67,14 @@ static const int routing_scheme1[] = {
[PVR2_CVAL_INPUT_SVIDEO] = SAA7115_SVIDEO2, /* or SVIDEO0, it seems */
};
-static const struct routing_scheme routing_schemes[] = {
- [PVR2_ROUTING_SCHEME_HAUPPAUGE] = {
- .def = routing_scheme0,
- .cnt = ARRAY_SIZE(routing_scheme0),
- },
- [PVR2_ROUTING_SCHEME_ONAIR] = {
- .def = routing_scheme1,
- .cnt = ARRAY_SIZE(routing_scheme1),
- },
+static const struct routing_scheme routing_def1 = {
+ .def = routing_scheme1,
+ .cnt = ARRAY_SIZE(routing_scheme1),
+};
+
+static const struct routing_scheme *routing_schemes[] = {
+ [PVR2_ROUTING_SCHEME_HAUPPAUGE] = &routing_def0,
+ [PVR2_ROUTING_SCHEME_ONAIR] = &routing_def1,
};
void pvr2_saa7115_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd)
@@ -82,12 +86,12 @@ void pvr2_saa7115_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd)
pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 set_input(%d)",
hdw->input_val);
- if ((sid < ARRAY_SIZE(routing_schemes)) &&
- ((sp = routing_schemes + sid) != NULL) &&
- (hdw->input_val >= 0) &&
- (hdw->input_val < sp->cnt)) {
- input = sp->def[hdw->input_val];
- } else {
+
+ sp = (sid < ARRAY_SIZE(routing_schemes)) ?
+ routing_schemes[sid] : NULL;
+ if ((sp == NULL) ||
+ (hdw->input_val < 0) ||
+ (hdw->input_val >= sp->cnt)) {
pvr2_trace(PVR2_TRACE_ERROR_LEGS,
"*** WARNING *** subdev v4l2 set_input:"
" Invalid routing scheme (%u)"
@@ -95,6 +99,7 @@ void pvr2_saa7115_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd)
sid, hdw->input_val);
return;
}
+ input = sp->def[hdw->input_val];
sd->ops->video->s_routing(sd, input, 0, 0);
}
}
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 2c122ec90..8964d60cd 100644
--- a/linux/drivers/media/video/pxa_camera.c
+++ b/linux/drivers/media/video/pxa_camera.c
@@ -1403,13 +1403,15 @@ static int pxa_camera_try_fmt(struct soc_camera_device *icd,
return -EINVAL;
}
- /* Limit to pxa hardware capabilities. YUV422P planar format requires
+ /*
+ * 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. */
- v4l2_bound_align_image(&pix->width, 48, 2048, 1,
- &pix->height, 32, 2048, 0,
- xlate->host_fmt->fourcc == V4L2_PIX_FMT_YUV422P ? 4 : 0);
+ * the YUV422P standard.
+ */
+ 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);
@@ -1541,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;
@@ -1716,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/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 587209fdd..e2d98ff5c 100644
--- a/linux/drivers/media/video/saa7134/saa7134-cards.c
+++ b/linux/drivers/media/video/saa7134/saa7134-cards.c
@@ -4497,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,
@@ -4571,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 */
@@ -6239,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 dc692d7a7..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 */
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-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 518de9b2c..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)
diff --git a/linux/drivers/media/video/saa7134/saa7134.h b/linux/drivers/media/video/saa7134/saa7134.h
index 385bc26bd..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 */
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/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/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 8d193376c..40df6828f 100644
--- a/linux/drivers/media/video/uvc/uvc_driver.c
+++ b/linux/drivers/media/video/uvc/uvc_driver.c
@@ -644,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:
@@ -709,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:
@@ -1919,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,
@@ -1928,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
@@ -1948,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_v4l2.c b/linux/drivers/media/video/uvc/uvc_v4l2.c
index 160c01314..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);
@@ -538,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)
@@ -555,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);
@@ -574,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/uvcvideo.h b/linux/drivers/media/video/uvc/uvcvideo.h
index 6b254fd39..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 */
@@ -749,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;
diff --git a/linux/drivers/media/video/v4l2-common.c b/linux/drivers/media/video/v4l2-common.c
index af1a64969..ab91734b1 100644
--- a/linux/drivers/media/video/v4l2-common.c
+++ b/linux/drivers/media/video/v4l2-common.c
@@ -1163,6 +1163,8 @@ const unsigned short *v4l2_i2c_tuner_addrs(enum v4l2_i2c_tuner_type type)
}
EXPORT_SYMBOL_GPL(v4l2_i2c_tuner_addrs);
+#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
@@ -1219,10 +1221,13 @@ void v4l_bound_align_image(u32 *w, unsigned int wmin, unsigned int wmax,
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 (walign <= halign && walign < wmaxa) {
+ if (halign >= hmaxa ||
+ (walign <= halign && walign < wmaxa)) {
*w = clamp_align(*w, wmin, wmax, walign + 1);
walign = __ffs(*w);
} else {
@@ -1233,5 +1238,3 @@ void v4l_bound_align_image(u32 *w, unsigned int wmin, unsigned int wmax,
}
}
EXPORT_SYMBOL_GPL(v4l_bound_align_image);
-
-#endif
diff --git a/linux/drivers/media/video/v4l2-ioctl.c b/linux/drivers/media/video/v4l2-ioctl.c
index 22b380dfd..625fe7698 100644
--- a/linux/drivers/media/video/v4l2-ioctl.c
+++ b/linux/drivers/media/video/v4l2-ioctl.c
@@ -1718,24 +1718,29 @@ static long __video_do_ioctl(struct file *file,
ret = ops->vidioc_enum_framesizes(file, fh, p);
dbgarg(cmd,
- "index=%d, pixelformat=%d, type=%d ",
- p->index, p->pixel_format, p->type);
+ "index=%d, pixelformat=%c%c%c%c, type=%d ",
+ p->index,
+ (p->pixel_format & 0xff),
+ (p->pixel_format >> 8) & 0xff,
+ (p->pixel_format >> 16) & 0xff,
+ (p->pixel_format >> 24) & 0xff,
+ p->type);
switch (p->type) {
case V4L2_FRMSIZE_TYPE_DISCRETE:
- dbgarg2("width = %d, height=%d\n",
+ printk("width = %d, height=%d\n",
p->discrete.width, p->discrete.height);
break;
case V4L2_FRMSIZE_TYPE_STEPWISE:
- dbgarg2("min %dx%d, max %dx%d, step %dx%d\n",
+ printk("min %dx%d, max %dx%d, step %dx%d\n",
p->stepwise.min_width, p->stepwise.min_height,
p->stepwise.step_width, p->stepwise.step_height,
p->stepwise.max_width, p->stepwise.max_height);
break;
case V4L2_FRMSIZE_TYPE_CONTINUOUS:
- dbgarg2("continuous\n");
+ printk("continuous\n");
break;
default:
- dbgarg2("- Unknown type!\n");
+ printk("- Unknown type!\n");
}
break;
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 623e2fc12..da83ac706 100644
--- a/linux/drivers/media/video/videobuf-dma-sg.c
+++ b/linux/drivers/media/video/videobuf-dma-sg.c
@@ -253,7 +253,7 @@ int videobuf_dma_map(struct videobuf_queue* q, struct videobuf_dmabuf *dma)
vfree(dma->sglist);
dma->sglist = NULL;
dma->sglen = 0;
- return -EIO;
+ return -ENOMEM;
}
}
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/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/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/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-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 b861c518a..56eb30853 100644
--- a/v4l/compat.h
+++ b/v4l/compat.h
@@ -289,10 +289,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
@@ -468,6 +472,7 @@ static inline int snd_card_create(int idx, const char *id,
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)
{
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 1e3527dc0..7e8e2fa6e 100644
--- a/v4l/versions.txt
+++ b/v4l/versions.txt
@@ -4,18 +4,14 @@
[2.6.29]
# Needs defines that are only available from 2.6.29
VIDEO_PXA27x
-# Needs the newer I2C binding model
-VIDEO_ADV7343
-VIDEO_THS7303
-
-[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>