]> err.no Git - linux-2.6/commitdiff
V4L/DVB (8157): gspca: all subdrivers
authorJean-Francois Moine <moinejf@free.fr>
Mon, 30 Jun 2008 18:50:11 +0000 (15:50 -0300)
committerMauro Carvalho Chehab <mchehab@infradead.org>
Sun, 20 Jul 2008 10:14:49 +0000 (07:14 -0300)
- remaning subdrivers added
- remove the decoding helper and some specific frame decodings

Signed-off-by: Jean-Francois Moine <moinejf@free.fr>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
27 files changed:
Documentation/video4linux/gspca.txt
drivers/media/video/Makefile
drivers/media/video/gspca/Kconfig
drivers/media/video/gspca/Makefile
drivers/media/video/gspca/conex.c [new file with mode: 0644]
drivers/media/video/gspca/etoms.c [new file with mode: 0644]
drivers/media/video/gspca/gspca.c
drivers/media/video/gspca/gspca.h
drivers/media/video/gspca/mars.c [new file with mode: 0644]
drivers/media/video/gspca/ov519.c [new file with mode: 0644]
drivers/media/video/gspca/pac207.c
drivers/media/video/gspca/pac7311.c [new file with mode: 0644]
drivers/media/video/gspca/sonixb.c [new file with mode: 0644]
drivers/media/video/gspca/sonixj.c [new file with mode: 0644]
drivers/media/video/gspca/spca500.c [new file with mode: 0644]
drivers/media/video/gspca/spca501.c [new file with mode: 0644]
drivers/media/video/gspca/spca505.c [new file with mode: 0644]
drivers/media/video/gspca/spca506.c [new file with mode: 0644]
drivers/media/video/gspca/spca508.c [new file with mode: 0644]
drivers/media/video/gspca/spca561.c [new file with mode: 0644]
drivers/media/video/gspca/stk014.c
drivers/media/video/gspca/sunplus.c [new file with mode: 0644]
drivers/media/video/gspca/t613.c [new file with mode: 0644]
drivers/media/video/gspca/tv8532.c [new file with mode: 0644]
drivers/media/video/gspca/vc032x.c [new file with mode: 0644]
drivers/media/video/gspca/zc3xx.c
include/linux/videodev2.h

index 9c404b56dbb30a50f1810a14bfd2b4273c2b4152..37996e59d516d92ae8f0d4b7451c564f1c2da330 100644 (file)
@@ -1,4 +1,4 @@
-Here the list of the known working cameras with gspca.
+List of the webcams know by gspca.
 
 The modules are:
        gspca_main      main driver
@@ -6,106 +6,73 @@ The modules are:
 
 xxxx           vend:prod
 ----
-conex          0572:0041       Creative Notebook cx11646
-etoms          102c:6151       Qcam Sangha CIF
-etoms          102c:6251       Qcam xxxxxx VGA
-mars           093a:050f       Mars-Semi Pc-Camera
+spca501                0000:0000       MystFromOri Unknow Camera
+spca501                040a:0002       Kodak DVC-325
+spca500                040a:0300       Kodak EZ200
+zc3xx          041e:041e       Creative WebCam Live!
+spca500                041e:400a       Creative PC-CAM 300
+sunplus                041e:400b       Creative PC-CAM 600
+sunplus                041e:4012       PC-Cam350
+sunplus                041e:4013       Creative Pccam750
+zc3xx          041e:4017       Creative Webcam Mobile PD1090
+spca508                041e:4018       Creative Webcam Vista (PD1100)
+spca561                041e:401a       Creative Webcam Vista (PD1100)
+zc3xx          041e:401c       Creative NX
+spca505                041e:401d       Creative Webcam NX ULTRA
+zc3xx          041e:401e       Creative Nx Pro
+zc3xx          041e:401f       Creative Webcam Notebook PD1171
+pac207         041e:4028       Creative Webcam Vista Plus
+zc3xx          041e:4029       Creative WebCam Vista Pro
+zc3xx          041e:4034       Creative Instant P0620
+zc3xx          041e:4035       Creative Instant P0620D
+zc3xx          041e:4036       Creative Live !
+zc3xx          041e:403a       Creative Nx Pro 2
+spca561                041e:403b       Creative Webcam Vista (VF0010)
+zc3xx          041e:4051       Creative Live!Cam Notebook Pro (VF0250)
 ov519          041e:4052       Creative Live! VISTA IM
+zc3xx          041e:4053       Creative Live!Cam Video IM
 ov519          041e:405f       Creative Live! VISTA VF0330
 ov519          041e:4060       Creative Live! VISTA VF0350
 ov519          041e:4061       Creative Live! VISTA VF0400
 ov519          041e:4064       Creative Live! VISTA VF0420
 ov519          041e:4068       Creative Live! VISTA VF0470
-ov519          045e:028c       Micro$oft xbox cam
-ov519          054c:0154       Sonny toy4
-ov519          054c:0155       Sonny toy5
-ov519          05a9:0519       OmniVision
-ov519          05a9:4519       OmniVision
-ov519          05a9:8519       OmniVision
-ov519          05a9:0530       OmniVision
-pac207         041e:4028       Creative Webcam Vista Plus
-pac207         093a:2460       PAC207 Qtec Webcam 100
-pac207         093a:2463       Philips spc200nc pac207
-pac207         093a:2464       Labtec Webcam 1200
-pac207         093a:2468       PAC207
-pac207         093a:2470       Genius GF112
-pac207         093a:2471       PAC207 Genius VideoCam ge111
-pac207         093a:2472       PAC207 Genius VideoCam ge110
-pac7311                093a:2600       PAC7311 Typhoon
-pac7311                093a:2601       PAC7311 Phillips SPC610NC
-pac7311                093a:2603       PAC7312
-pac7311                093a:2608       PAC7311 Trust WB-3300p
-pac7311                093a:260e       PAC7311 Gigaware VGA PC Camera, Trust WB-3350p, SIGMA cam 2350
-pac7311                093a:260f       PAC7311 SnakeCam
-sonixb         0c45:6001       Genius VideoCAM NB
-sonixb         0c45:6005       Sweex Tas5110
-sonixb         0c45:6007       Sonix sn9c101 + Tas5110D
-sonixb         0c45:6009       spcaCam@120
-sonixb         0c45:600d       spcaCam@120
-sonixb         0c45:6011       MAX Webcam (Microdia - OV6650 - SN9C101G)
-sonixb         0c45:6019       Generic Sonix OV7630
-sonixb         0c45:6024       Generic Sonix Tas5130c
-sonixb         0c45:6025       Xcam Shanga
-sonixb         0c45:6028       Sonix Btc Pc380
-sonixb         0c45:6029       spcaCam@150
-sonixb         0c45:602c       Generic Sonix OV7630
-sonixb         0c45:602d       LIC-200 LG
-sonixb         0c45:602e       Genius VideoCam Messenger
+spca561                0458:7004       Genius VideoCAM Express V2
+sunplus                0458:7006       Genius Dsc 1.3 Smart
+zc3xx          0458:7007       Genius VideoCam V2
+zc3xx          0458:700c       Genius VideoCam V3
+zc3xx          0458:700f       Genius VideoCam Web V2
 sonixj         0458:7025       Genius Eye 311Q
 sonixj         045e:00f5       MicroSoft VX3000
 sonixj         045e:00f7       MicroSoft VX1000
-sonixj         0471:0327       Philips SPC 600 NC
-sonixj         0471:0328       Philips SPC 700 NC
-sonixj         0471:0330       Philips SPC 710NC
-sonixj         0c45:6040       Speed NVC 350K
-sonixj         0c45:607c       Sonix sn9c102p Hv7131R
-sonixj         0c45:60c0       Sangha Sn535
-sonixj         0c45:60ec       SN9C105+MO4000
-sonixj         0c45:60fb       Surfer NoName
-sonixj         0c45:60fc       LG-LIC300
-sonixj         0c45:612a       Avant Camera
-sonixj         0c45:612c       Typhoon Rasy Cam 1.3MPix
-sonixj         0c45:6130       Sonix Pccam
-sonixj         0c45:6138       Sn9c120 Mo4000
-sonixj         0c45:613b       Surfer SN-206
-sonixj         0c45:613c       Sonix Pccam168
-spca500                040a:0300       Kodak EZ200
-spca500                041e:400a       Creative PC-CAM 300
+ov519          045e:028c       Micro$oft xbox cam
+spca508                0461:0815       Micro Innovation IC200
+zc3xx          0461:0a00       MicroInnovation WebCam320
 spca500                046d:0890       Logitech QuickCam traveler
+vc032x         046d:0892       Logitech Orbicam
+vc032x         046d:0896       Logitech Orbicam
+zc3xx          046d:08a0       Logitech QC IM
+zc3xx          046d:08a1       Logitech QC IM 0x08A1 +sound
+zc3xx          046d:08a2       Labtec Webcam Pro
+zc3xx          046d:08a3       Logitech QC Chat
+zc3xx          046d:08a6       Logitech QCim
+zc3xx          046d:08a7       Logitech QuickCam Image
+zc3xx          046d:08a9       Logitech Notebook Deluxe
+zc3xx          046d:08aa       Labtec Webcam  Notebook
+zc3xx          046d:08ac       Logitech QuickCam Cool
+zc3xx          046d:08ad       Logitech QCCommunicate STX
+zc3xx          046d:08ae       Logitech QuickCam for Notebooks
+zc3xx          046d:08af       Logitech QuickCam Cool
+zc3xx          046d:08b9       Logitech QC IM ???
+zc3xx          046d:08d7       Logitech QCam STX
+zc3xx          046d:08d9       Logitech QuickCam IM/Connect
+zc3xx          046d:08d8       Logitech Notebook Deluxe
+zc3xx          046d:08da       Logitech QuickCam Messenger
+zc3xx          046d:08dd       Logitech QuickCam for Notebooks
 spca500                046d:0900       Logitech Inc. ClickSmart 310
 spca500                046d:0901       Logitech Inc. ClickSmart 510
-spca500                04a5:300c       Benq DC1016
-spca500                04fc:7333       PalmPixDC85
-spca500                055f:c200       Mustek Gsmart 300
-spca500                055f:c220       Gsmart Mini
-spca500                06bd:0404       Agfa CL20
-spca500                06be:0800       Optimedia
-spca500                084d:0003       D-Link DSC-350
-spca500                08ca:0103       Aiptek PocketDV
-spca500                2899:012c       Toptro Industrial
-spca500                8086:0630       Intel Pocket PC Camera
-spca501                040a:0002       Kodak DVC-325
-spca501                0497:c001       Smile International
-spca501                0506:00df       3Com HomeConnect Lite
-spca501                0733:0401       Intel Create and Share
-spca501                0733:0402       ViewQuest M318B
-spca501                1776:501c       Arowana 300K CMOS Camera
-spca501                0000:0000       MystFromOri Unknow Camera
-spca505                041e:401d       Creative Webcam NX ULTRA
-spca505                0733:0430       Intel PC Camera Pro
-spca506                06e1:a190       ADS Instant VCD
-spca506                0734:043b       3DeMon USB Capture aka
-spca506                99fa:8988       Grandtec V.cap
-spca506                99fa:8988       Grandtec V.cap
-spca508                041e:4018       Creative Webcam Vista (PD1100)
-spca508                0461:0815       Micro Innovation IC200
-spca508                0733:0110       ViewQuest VQ110
-spca508                0af9:0010       Hama USB Sightcam 100
-spca508                0af9:0011       Hama USB Sightcam 100
-spca508                8086:0110       Intel Easy PC Camera
-spca561                041e:401a       Creative Webcam Vista (PD1100)
-spca561                041e:403b       Creative Webcam Vista (VF0010)
-spca561                0458:7004       Genius VideoCAM Express V2
+sunplus                046d:0905       Logitech ClickSmart 820
+tv8532         046d:0920       QC Express
+tv8532         046d:0921       Labtec Webcam
 spca561                046d:0928       Logitech QC Express Etch2
 spca561                046d:0929       Labtec Webcam Elch2
 spca561                046d:092a       Logitech QC for Notebook
@@ -114,33 +81,42 @@ spca561            046d:092c       Logitech QC chat Elch2
 spca561                046d:092d       Logitech QC Elch2
 spca561                046d:092e       Logitech QC Elch2
 spca561                046d:092f       Logitech QC Elch2
-spca561                04fc:0561       Flexcam 100
-spca561                060b:a001       Maxell Compact Pc PM3
-spca561                10fd:7e50       FlyCam Usb 100
-spca561                abcd:cdee       Petcam
-stk014         05e1:0893       Syntek DV4000
-sunplus                041e:400b       Creative PC-CAM 600
-sunplus                041e:4012       PC-Cam350
-sunplus                041e:4013       Creative Pccam750
-sunplus                0458:7006       Genius Dsc 1.3 Smart
-sunplus                046d:0905       Logitech ClickSmart 820
 sunplus                046d:0960       Logitech ClickSmart 420
 sunplus                0471:0322       Philips DMVC1300K
+zc3xx          0471:0325       Philips SPC 200 NC
+zc3xx          0471:0326       Philips SPC 300 NC
+sonixj         0471:0327       Philips SPC 600 NC
+sonixj         0471:0328       Philips SPC 700 NC
+zc3xx          0471:032d       Philips spc210nc
+zc3xx          0471:032e       Philips spc315nc
+sonixj         0471:0330       Philips SPC 710NC
+spca501                0497:c001       Smile International
 sunplus                04a5:3003       Benq DC 1300
 sunplus                04a5:3008       Benq DC 1500
 sunplus                04a5:300a       Benq DC3410
+spca500                04a5:300c       Benq DC1016
 sunplus                04f1:1001       JVC GC A50
+spca561                04fc:0561       Flexcam 100
 sunplus                04fc:500c       Sunplus CA500C
 sunplus                04fc:504a       Aiptek Mini PenCam 1.3
 sunplus                04fc:504b       Maxell MaxPocket LE 1.3
 sunplus                04fc:5330       Digitrex 2110
 sunplus                04fc:5360       Sunplus Generic
+spca500                04fc:7333       PalmPixDC85
 sunplus                04fc:ffff       Pure DigitalDakota
+spca501                0506:00df       3Com HomeConnect Lite
 sunplus                052b:1513       Megapix V4
+tv8532         0545:808b       Veo Stingray
+tv8532         0545:8333       Veo Stingray
 sunplus                0546:3155       Polaroid PDC3070
 sunplus                0546:3191       Polaroid Ion 80
 sunplus                0546:3273       Polaroid PDC2030
+ov519          054c:0154       Sonny toy4
+ov519          054c:0155       Sonny toy5
+zc3xx          055f:c005       Mustek Wcam300A
+spca500                055f:c200       Mustek Gsmart 300
 sunplus                055f:c211       Kowa Bs888e Microcamera
+spca500                055f:c220       Gsmart Mini
 sunplus                055f:c230       Mustek Digicam 330K
 sunplus                055f:c232       Mustek MDC3500
 sunplus                055f:c360       Mustek DV4000 Mpeg4
@@ -152,14 +128,34 @@ sunplus           055f:c530       Mustek Gsmart LCD 3
 sunplus                055f:c540       Gsmart D30
 sunplus                055f:c630       Mustek MDC4000
 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:0530       OmniVision
+ov519          05a9:4519       OmniVision
+ov519          05a9:8519       OmniVision
 sunplus                05da:1018       Digital Dream Enigma 1.3
+stk014         05e1:0893       Syntek DV4000
+spca561                060b:a001       Maxell Compact Pc PM3
+zc3xx          0698:2003       CTX M730V built in
+spca500                06bd:0404       Agfa CL20
+spca500                06be:0800       Optimedia
 sunplus                06d6:0031       Trust 610 LCD PowerC@m Zoom
+spca506                06e1:a190       ADS Instant VCD
+spca508                0733:0110       ViewQuest VQ110
+spca501                0733:0401       Intel Create and Share
+spca501                0733:0402       ViewQuest M318B
+spca505                0733:0430       Intel PC Camera Pro
 sunplus                0733:1311       Digital Dream Epsilon 1.3
 sunplus                0733:1314       Mercury 2.1MEG Deluxe Classic Cam
 sunplus                0733:2211       Jenoptik jdc 21 LCD
 sunplus                0733:2221       Mercury Digital Pro 3.1p
 sunplus                0733:3261       Concord 3045 spca536a
 sunplus                0733:3281       Cyberpix S550V
+spca506                0734:043b       3DeMon USB Capture aka
+spca500                084d:0003       D-Link DSC-350
+spca500                08ca:0103       Aiptek PocketDV
 sunplus                08ca:0104       Aiptek PocketDVII 1.3
 sunplus                08ca:0106       Aiptek Pocket DV3100+
 sunplus                08ca:2008       Aiptek Mini PenCam 2 M
@@ -173,66 +169,72 @@ sunplus           08ca:2028       Aiptek PocketCam4M
 sunplus                08ca:2040       Aiptek PocketDV4100M
 sunplus                08ca:2042       Aiptek PocketDV5100
 sunplus                08ca:2060       Aiptek PocketDV5300
-sunplus                0d64:0303       Sunplus FashionCam DXG
-tv8532         046d:0920       QC Express
-tv8532         046d:0921       Labtec Webcam
-tv8532         0545:808b       Veo Stingray
-tv8532         0545:8333       Veo Stingray
 tv8532         0923:010f       ICM532 cams
-vc032x         046d:0892       Logitech Orbicam
-vc032x         046d:0896       Logitech Orbicam
+mars           093a:050f       Mars-Semi Pc-Camera
+pac207         093a:2460       PAC207 Qtec Webcam 100
+pac207         093a:2463       Philips spc200nc pac207
+pac207         093a:2464       Labtec Webcam 1200
+pac207         093a:2468       PAC207
+pac207         093a:2470       Genius GF112
+pac207         093a:2471       PAC207 Genius VideoCam ge111
+pac207         093a:2472       PAC207 Genius VideoCam ge110
+pac7311                093a:2600       PAC7311 Typhoon
+pac7311                093a:2601       PAC7311 Phillips SPC610NC
+pac7311                093a:2603       PAC7312
+pac7311                093a:2608       PAC7311 Trust WB-3300p
+pac7311                093a:260e       PAC7311 Gigaware VGA PC Camera, Trust WB-3350p, SIGMA cam 2350
+pac7311                093a:260f       PAC7311 SnakeCam
+pac7311                093a:2621       PAC731x
+zc3xx          0ac8:0302       Z-star Vimicro zc0302
 vc032x         0ac8:0321       Vimicro generic vc0321
 vc032x         0ac8:0323       Vimicro Vc0323
 vc032x         0ac8:0328       A4Tech PK-130MG
-vc032x         0ac8:c001       Sony embedded vimicro
-vc032x         0ac8:c002       Sony embedded vimicro
-vc032x         17ef:4802       Lenovo Vc0323+MI1310_SOC
-zc3xx          041e:041e       Creative WebCam Live!
-zc3xx          041e:4017       Creative Webcam Mobile PD1090
-zc3xx          041e:401c       Creative NX
-zc3xx          041e:401e       Creative Nx Pro
-zc3xx          041e:401f       Creative Webcam Notebook PD1171
-zc3xx          041e:4029       Creative WebCam Vista Pro
-zc3xx          041e:4034       Creative Instant P0620
-zc3xx          041e:4035       Creative Instant P0620D
-zc3xx          041e:4036       Creative Live !
-zc3xx          041e:403a       Creative Nx Pro 2
-zc3xx          041e:4051       Creative Live!Cam Notebook Pro (VF0250)
-zc3xx          041e:4053       Creative Live!Cam Video IM
-zc3xx          0458:7007       Genius VideoCam V2
-zc3xx          0458:700c       Genius VideoCam V3
-zc3xx          0458:700f       Genius VideoCam Web V2
-zc3xx          0461:0a00       MicroInnovation WebCam320
-zc3xx          046d:08a0       Logitech QC IM
-zc3xx          046d:08a1       Logitech QC IM 0x08A1 +sound
-zc3xx          046d:08a2       Labtec Webcam Pro
-zc3xx          046d:08a3       Logitech QC Chat
-zc3xx          046d:08a6       Logitech QCim
-zc3xx          046d:08a7       Logitech QuickCam Image
-zc3xx          046d:08a9       Logitech Notebook Deluxe
-zc3xx          046d:08aa       Labtec Webcam  Notebook
-zc3xx          046d:08ac       Logitech QuickCam Cool
-zc3xx          046d:08ad       Logitech QCCommunicate STX
-zc3xx          046d:08ae       Logitech QuickCam for Notebooks
-zc3xx          046d:08af       Logitech QuickCam Cool
-zc3xx          046d:08b9       Logitech QC IM ???
-zc3xx          046d:08d7       Logitech QCam STX
-zc3xx          046d:08d9       Logitech QuickCam IM/Connect
-zc3xx          046d:08d8       Logitech Notebook Deluxe
-zc3xx          046d:08da       Logitech QuickCam Messenger
-zc3xx          046d:08dd       Logitech QuickCam for Notebooks
-zc3xx          0471:0325       Philips SPC 200 NC
-zc3xx          0471:0326       Philips SPC 300 NC
-zc3xx          0471:032d       Philips spc210nc
-zc3xx          0471:032e       Philips spc315nc
-zc3xx          055f:c005       Mustek Wcam300A
-zc3xx          055f:d003       Mustek WCam300A
-zc3xx          055f:d004       Mustek WCam300 AN
-zc3xx          0698:2003       CTX M730V built in
-zc3xx          0ac8:0302       Z-star Vimicro zc0302
 zc3xx          0ac8:301b       Z-Star zc301b
 zc3xx          0ac8:303b       Vimicro 0x303b
 zc3xx          0ac8:305b       Z-star Vimicro zc0305b
 zc3xx          0ac8:307b       Ldlc VC302+Ov7620
+vc032x         0ac8:c001       Sony embedded vimicro
+vc032x         0ac8:c002       Sony embedded vimicro
+spca508                0af9:0010       Hama USB Sightcam 100
+spca508                0af9:0011       Hama USB Sightcam 100
+sonixb         0c45:6001       Genius VideoCAM NB
+sonixb         0c45:6005       Sweex Tas5110
+sonixb         0c45:6007       Sonix sn9c101 + Tas5110D
+sonixb         0c45:6009       spcaCam@120
+sonixb         0c45:600d       spcaCam@120
+sonixb         0c45:6011       MAX Webcam (Microdia - OV6650 - SN9C101G)
+sonixb         0c45:6019       Generic Sonix OV7630
+sonixb         0c45:6024       Generic Sonix Tas5130c
+sonixb         0c45:6025       Xcam Shanga
+sonixb         0c45:6028       Sonix Btc Pc380
+sonixb         0c45:6029       spcaCam@150
+sonixb         0c45:602c       Generic Sonix OV7630
+sonixb         0c45:602d       LIC-200 LG
+sonixb         0c45:602e       Genius VideoCam Messenger
+sonixj         0c45:6040       Speed NVC 350K
+sonixj         0c45:607c       Sonix sn9c102p Hv7131R
+sonixj         0c45:60c0       Sangha Sn535
+sonixj         0c45:60ec       SN9C105+MO4000
+sonixj         0c45:60fb       Surfer NoName
+sonixj         0c45:60fc       LG-LIC300
+sonixj         0c45:612a       Avant Camera
+sonixj         0c45:612c       Typhoon Rasy Cam 1.3MPix
+sonixj         0c45:6130       Sonix Pccam
+sonixj         0c45:6138       Sn9c120 Mo4000
+sonixj         0c45:613b       Surfer SN-206
+sonixj         0c45:613c       Sonix Pccam168
+sunplus                0d64:0303       Sunplus FashionCam DXG
+etoms          102c:6151       Qcam Sangha CIF
+etoms          102c:6251       Qcam xxxxxx VGA
 zc3xx          10fd:0128       Typhoon Webshot II USB 300k 0x0128
+spca561                10fd:7e50       FlyCam Usb 100
 zc3xx          10fd:8050       Typhoon Webshot II USB 300k
+spca501                1776:501c       Arowana 300K CMOS Camera
+t613           17a1:0128       T613/TAS5130A
+vc032x         17ef:4802       Lenovo Vc0323+MI1310_SOC
+pac207         2001:f115       D-Link DSB-C120
+spca500                2899:012c       Toptro Industrial
+spca508                8086:0110       Intel Easy PC Camera
+spca500                8086:0630       Intel Pocket PC Camera
+spca506                99fa:8988       Grandtec V.cap
+spca561                abcd:cdee       Petcam
index 2ec920dc32e01d76d409dc4ac7953a019e8e3cd1..d5f6eea7d2fde3350e32fb06121d7d4c01680b1b 100644 (file)
@@ -117,6 +117,7 @@ obj-$(CONFIG_USB_SN9C102)       += sn9c102/
 obj-$(CONFIG_USB_ET61X251)      += et61x251/
 obj-$(CONFIG_USB_PWC)           += pwc/
 obj-$(CONFIG_USB_ZC0301)        += zc0301/
+obj-$(CONFIG_USB_GSPCA)         += gspca/
 
 obj-$(CONFIG_USB_IBMCAM)        += usbvideo/
 obj-$(CONFIG_USB_KONICAWC)      += usbvideo/
index a04e413e1258a7af9f43abaf722619d4653c34fa..42b90742b40be6b4abc42d0f89d1928d5c4625c0 100644 (file)
@@ -2,7 +2,7 @@ config USB_GSPCA
        tristate "USB GSPCA driver"
        depends on VIDEO_V4L2
        ---help---
-         Say Y here if you want support for various USB cameras.
+         Say Y here if you want support for various USB webcams.
 
          See <file:Documentation/video4linux/gspca.txt> for more info.
 
index d959f7771526851be914569b7054a48fbd9c21cc..e68a8965297a70d7cff5ba6fb33ea83a32d4ee96 100644 (file)
@@ -1,7 +1,29 @@
-obj-$(CONFIG_GSPCA)    += gspca_main.o \
-       gspca_pac207.o gspca_stk014.o gspca_zc3xx.o
+obj-$(CONFIG_USB_GSPCA)        += gspca_main.o \
+       gspca_conex.o gspca_etoms.o gspca_mars.o \
+       gspca_ov519.o gspca_pac207.o gspca_pac7311.o \
+       gspca_sonixb.o gspca_sonixj.o gspca_spca500.o gspca_spca501.o \
+       gspca_spca505.o gspca_spca506.o gspca_spca508.o gspca_spca561.o \
+       gspca_sunplus.o gspca_stk014.o gspca_t613.o gspca_tv8532.o \
+       gspca_vc032x.o gspca_zc3xx.o
 
 gspca_main-objs := gspca.o
+gspca_conex-objs := conex.o
+gspca_etoms-objs := etoms.o
+gspca_mars-objs := mars.o
+gspca_ov519-objs := ov519.o
 gspca_pac207-objs := pac207.o
+gspca_pac7311-objs := pac7311.o
+gspca_sonixb-objs := sonixb.o
+gspca_sonixj-objs := sonixj.o
+gspca_spca500-objs := spca500.o
+gspca_spca501-objs := spca501.o
+gspca_spca505-objs := spca505.o
+gspca_spca506-objs := spca506.o
+gspca_spca508-objs := spca508.o
+gspca_spca561-objs := spca561.o
 gspca_stk014-objs := stk014.o
+gspca_sunplus-objs := sunplus.o
+gspca_t613-objs := t613.o
+gspca_tv8532-objs := tv8532.o
+gspca_vc032x-objs := vc032x.o
 gspca_zc3xx-objs := zc3xx.o
diff --git a/drivers/media/video/gspca/conex.c b/drivers/media/video/gspca/conex.c
new file mode 100644 (file)
index 0000000..b0294c9
--- /dev/null
@@ -0,0 +1,1059 @@
+/*
+ *             Connexant Cx11646 library
+ *             Copyright (C) 2004 Michel Xhaard mxhaard@magic.fr
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define MODULE_NAME "conex"
+
+#include "gspca.h"
+#define CONEX_CAM 1            /* special JPEG header */
+#include "jpeg.h"
+
+#define DRIVER_VERSION_NUMBER  KERNEL_VERSION(2, 1, 0)
+static const char version[] = "2.1.0";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("GSPCA USB Conexant Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+       struct gspca_dev gspca_dev;     /* !! must be the first item */
+
+       unsigned char brightness;
+       unsigned char contrast;
+       unsigned char colors;
+
+       unsigned char qindex;
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+#define SD_BRIGHTNESS 0
+       {
+           {
+               .id      = V4L2_CID_BRIGHTNESS,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Brightness",
+               .minimum = 0,
+               .maximum = 255,
+               .step    = 1,
+               .default_value = 0xd4,
+           },
+           .set = sd_setbrightness,
+           .get = sd_getbrightness,
+       },
+#define SD_CONTRAST 1
+       {
+           {
+               .id      = V4L2_CID_CONTRAST,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Contrast",
+               .minimum = 0x0a,
+               .maximum = 0x1f,
+               .step    = 1,
+               .default_value = 0x0c,
+           },
+           .set = sd_setcontrast,
+           .get = sd_getcontrast,
+       },
+#define SD_COLOR 2
+       {
+           {
+               .id      = V4L2_CID_SATURATION,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Color",
+               .minimum = 0,
+               .maximum = 7,
+               .step    = 1,
+               .default_value = 3,
+           },
+           .set = sd_setcolors,
+           .get = sd_getcolors,
+       },
+};
+
+static struct cam_mode vga_mode[] = {
+       {V4L2_PIX_FMT_JPEG, 176, 144, 3},
+       {V4L2_PIX_FMT_JPEG, 320, 240, 2},
+       {V4L2_PIX_FMT_JPEG, 352, 288, 1},
+       {V4L2_PIX_FMT_JPEG, 640, 480, 0},
+};
+
+static void reg_r(struct usb_device *dev,
+                          __u16 index,
+                          __u8 *buffer, __u16 length)
+{
+       usb_control_msg(dev,
+                       usb_rcvctrlpipe(dev, 0),
+                       0,
+                       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       0,
+                       index, buffer, length,
+                       500);
+       PDEBUG(D_USBI, "reg read i:%02x -> %02x", index, *buffer);
+}
+
+static void reg_w(struct usb_device *dev,
+                 __u16 index,
+                 const __u8 *buffer, __u16 length)
+{
+       PDEBUG(D_USBO, "reg write i:%02x = %02x", index, *buffer);
+       usb_control_msg(dev,
+                       usb_sndctrlpipe(dev, 0),
+                       0,
+                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       0,
+                       index, (__u8 *) buffer, length,
+                       500);
+}
+
+static const __u8 cx_sensor_init[][4] = {
+       {0x88, 0x11, 0x01, 0x01},
+       {0x88, 0x12, 0x70, 0x01},
+       {0x88, 0x0f, 0x00, 0x01},
+       {0x88, 0x05, 0x01, 0x01},
+       {}
+};
+
+static const __u8 cx11646_fw1[][3] = {
+       {0x00, 0x02, 0x00},
+       {0x01, 0x43, 0x00},
+       {0x02, 0xA7, 0x00},
+       {0x03, 0x8B, 0x01},
+       {0x04, 0xE9, 0x02},
+       {0x05, 0x08, 0x04},
+       {0x06, 0x08, 0x05},
+       {0x07, 0x07, 0x06},
+       {0x08, 0xE7, 0x06},
+       {0x09, 0xC6, 0x07},
+       {0x0A, 0x86, 0x08},
+       {0x0B, 0x46, 0x09},
+       {0x0C, 0x05, 0x0A},
+       {0x0D, 0xA5, 0x0A},
+       {0x0E, 0x45, 0x0B},
+       {0x0F, 0xE5, 0x0B},
+       {0x10, 0x85, 0x0C},
+       {0x11, 0x25, 0x0D},
+       {0x12, 0xC4, 0x0D},
+       {0x13, 0x45, 0x0E},
+       {0x14, 0xE4, 0x0E},
+       {0x15, 0x64, 0x0F},
+       {0x16, 0xE4, 0x0F},
+       {0x17, 0x64, 0x10},
+       {0x18, 0xE4, 0x10},
+       {0x19, 0x64, 0x11},
+       {0x1A, 0xE4, 0x11},
+       {0x1B, 0x64, 0x12},
+       {0x1C, 0xE3, 0x12},
+       {0x1D, 0x44, 0x13},
+       {0x1E, 0xC3, 0x13},
+       {0x1F, 0x24, 0x14},
+       {0x20, 0xA3, 0x14},
+       {0x21, 0x04, 0x15},
+       {0x22, 0x83, 0x15},
+       {0x23, 0xE3, 0x15},
+       {0x24, 0x43, 0x16},
+       {0x25, 0xA4, 0x16},
+       {0x26, 0x23, 0x17},
+       {0x27, 0x83, 0x17},
+       {0x28, 0xE3, 0x17},
+       {0x29, 0x43, 0x18},
+       {0x2A, 0xA3, 0x18},
+       {0x2B, 0x03, 0x19},
+       {0x2C, 0x63, 0x19},
+       {0x2D, 0xC3, 0x19},
+       {0x2E, 0x22, 0x1A},
+       {0x2F, 0x63, 0x1A},
+       {0x30, 0xC3, 0x1A},
+       {0x31, 0x23, 0x1B},
+       {0x32, 0x83, 0x1B},
+       {0x33, 0xE2, 0x1B},
+       {0x34, 0x23, 0x1C},
+       {0x35, 0x83, 0x1C},
+       {0x36, 0xE2, 0x1C},
+       {0x37, 0x23, 0x1D},
+       {0x38, 0x83, 0x1D},
+       {0x39, 0xE2, 0x1D},
+       {0x3A, 0x23, 0x1E},
+       {0x3B, 0x82, 0x1E},
+       {0x3C, 0xC3, 0x1E},
+       {0x3D, 0x22, 0x1F},
+       {0x3E, 0x63, 0x1F},
+       {0x3F, 0xC1, 0x1F},
+       {}
+};
+static void cx11646_fw(struct gspca_dev*gspca_dev)
+{
+       __u8 val;
+       int i = 0;
+
+       val = 0x02;
+       reg_w(gspca_dev->dev, 0x006a, &val, 1);
+       while (cx11646_fw1[i][1]) {
+               reg_w(gspca_dev->dev, 0x006b, cx11646_fw1[i], 3);
+               i++;
+       }
+       val = 0x00;
+       reg_w(gspca_dev->dev, 0x006a, &val, 1);
+}
+
+static __u8 cxsensor[] = {
+       0x88, 0x12, 0x70, 0x01,
+       0x88, 0x0d, 0x02, 0x01,
+       0x88, 0x0f, 0x00, 0x01,
+       0x88, 0x03, 0x71, 0x01, 0x88, 0x04, 0x00, 0x01, /* 3 */
+       0x88, 0x02, 0x10, 0x01,
+       0x88, 0x00, 0xD4, 0x01, 0x88, 0x01, 0x01, 0x01, /* 5 */
+       0x88, 0x0B, 0x00, 0x01,
+       0x88, 0x0A, 0x0A, 0x01,
+       0x88, 0x00, 0x08, 0x01, 0x88, 0x01, 0x00, 0x01, /* 8 */
+       0x88, 0x05, 0x01, 0x01,
+       0xA1, 0x18, 0x00, 0x01,
+       0x00
+};
+
+static __u8 reg20[] = { 0x10, 0x42, 0x81, 0x19, 0xd3, 0xff, 0xa7, 0xff };
+static __u8 reg28[] = { 0x87, 0x00, 0x87, 0x00, 0x8f, 0xff, 0xea, 0xff };
+static __u8 reg10[] = { 0xb1, 0xb1 };
+static __u8 reg71a[] = { 0x08, 0x18, 0x0a, 0x1e };     /* 640 */
+static __u8 reg71b[] = { 0x04, 0x0c, 0x05, 0x0f };
+       /* 352{0x04,0x0a,0x06,0x12}; //352{0x05,0x0e,0x06,0x11}; //352 */
+static __u8 reg71c[] = { 0x02, 0x07, 0x03, 0x09 };
+                                       /* 320{0x04,0x0c,0x05,0x0f}; //320 */
+static __u8 reg71d[] = { 0x02, 0x07, 0x03, 0x09 };     /* 176 */
+static __u8 reg7b[] = { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff };
+
+static void cx_sensor(struct gspca_dev*gspca_dev)
+{
+       __u8 val = 0;
+       int i = 0;
+       __u8 bufread[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+       int length = 0;
+       __u8 *ptsensor = cxsensor;
+
+       reg_w(gspca_dev->dev, 0x0020, reg20, 8);
+       reg_w(gspca_dev->dev, 0x0028, reg28, 8);
+       reg_w(gspca_dev->dev, 0x0010, reg10, 8);
+       val = 0x03;
+       reg_w(gspca_dev->dev, 0x0092, &val, 1);
+
+       switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].mode) {
+       case 0:
+               reg_w(gspca_dev->dev, 0x0071, reg71a, 4);
+               break;
+       case 1:
+               reg_w(gspca_dev->dev, 0x0071, reg71b, 4);
+               break;
+       default:
+/* case 2: */
+               reg_w(gspca_dev->dev, 0x0071, reg71c, 4);
+               break;
+       case 3:
+               reg_w(gspca_dev->dev, 0x0071, reg71d, 4);
+               break;
+       }
+       reg_w(gspca_dev->dev, 0x007b, reg7b, 6);
+       val = 0x00;
+       reg_w(gspca_dev->dev, 0x00f8, &val, 1);
+       reg_w(gspca_dev->dev, 0x0010, reg10, 8);
+       val = 0x41;
+       reg_w(gspca_dev->dev, 0x0098, &val, 1);
+       for (i = 0; i < 11; i++) {
+               if (i == 3 || i == 5 || i == 8)
+                       length = 8;
+               else
+                       length = 4;
+               reg_w(gspca_dev->dev, 0x00e5, ptsensor, length);
+               if (length == 4)
+                       reg_r(gspca_dev->dev, 0x00e8, &val, 1);
+               else
+                       reg_r(gspca_dev->dev, 0x00e8, bufread, length);
+               ptsensor += length;
+       }
+       reg_r(gspca_dev->dev, 0x00e7, bufread, 8);
+}
+
+static __u8 cx_inits_176[] = {
+       0x33, 0x81, 0xB0, 0x00, 0x90, 0x00, 0x0A, 0x03, /* 176x144 */
+       0x00, 0x03, 0x03, 0x03, 0x1B, 0x05, 0x30, 0x03,
+       0x65, 0x15, 0x18, 0x25, 0x03, 0x25, 0x08, 0x30,
+       0x3B, 0x25, 0x10, 0x00, 0x04, 0x00, 0x00, 0x00,
+       0xDC, 0xFF, 0xEE, 0xFF, 0xC5, 0xFF, 0xBF, 0xFF,
+       0xF7, 0xFF, 0x88, 0xFF, 0x66, 0x02, 0x28, 0x02,
+       0x1E, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+static __u8 cx_inits_320[] = {
+       0x7f, 0x7f, 0x40, 0x01, 0xf0, 0x00, 0x02, 0x01,
+       0x00, 0x01, 0x01, 0x01, 0x10, 0x00, 0x02, 0x01,
+       0x65, 0x45, 0xfa, 0x4c, 0x2c, 0xdf, 0xb9, 0x81,
+       0x30, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+       0xe2, 0xff, 0xf1, 0xff, 0xc2, 0xff, 0xbc, 0xff,
+       0xf5, 0xff, 0x6d, 0xff, 0xf6, 0x01, 0x43, 0x02,
+       0xd3, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+static __u8 cx_inits_352[] = {
+       0x2e, 0x7c, 0x60, 0x01, 0x20, 0x01, 0x05, 0x03,
+       0x00, 0x06, 0x03, 0x06, 0x1b, 0x10, 0x05, 0x3b,
+       0x30, 0x25, 0x18, 0x25, 0x08, 0x30, 0x03, 0x25,
+       0x3b, 0x30, 0x25, 0x1b, 0x10, 0x05, 0x00, 0x00,
+       0xe3, 0xff, 0xf1, 0xff, 0xc2, 0xff, 0xbc, 0xff,
+       0xf5, 0xff, 0x6b, 0xff, 0xee, 0x01, 0x43, 0x02,
+       0xe4, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+static __u8 cx_inits_640[] = {
+       0x7e, 0x7e, 0x80, 0x02, 0xe0, 0x01, 0x01, 0x01,
+       0x00, 0x02, 0x01, 0x02, 0x10, 0x30, 0x01, 0x01,
+       0x65, 0x45, 0xf7, 0x52, 0x2c, 0xdf, 0xb9, 0x81,
+       0x30, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+       0xe2, 0xff, 0xf1, 0xff, 0xc2, 0xff, 0xbc, 0xff,
+       0xf6, 0xff, 0x7b, 0xff, 0x01, 0x02, 0x43, 0x02,
+       0x77, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static int cx11646_initsize(struct gspca_dev *gspca_dev)
+{
+       __u8 *cxinit;
+       __u8 val;
+       static const __u8 reg12[] = { 0x08, 0x05, 0x07, 0x04, 0x24 };
+       static const __u8 reg17[] =
+                       { 0x0a, 0x00, 0xf2, 0x01, 0x0f, 0x00, 0x97, 0x02 };
+
+       switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].mode) {
+       case 0:
+               cxinit = cx_inits_640;
+               break;
+       case 1:
+               cxinit = cx_inits_352;
+               break;
+       default:
+/*     case 2: */
+               cxinit = cx_inits_320;
+               break;
+       case 3:
+               cxinit = cx_inits_176;
+               break;
+       }
+       val = 0x01;
+       reg_w(gspca_dev->dev, 0x009a, &val, 1);
+       val = 0x10;
+       reg_w(gspca_dev->dev, 0x0010, &val, 1);
+       reg_w(gspca_dev->dev, 0x0012, reg12, 5);
+       reg_w(gspca_dev->dev, 0x0017, reg17, 8);
+       val = 0x00;
+       reg_w(gspca_dev->dev, 0x00c0, &val, 1);
+       val = 0x04;
+       reg_w(gspca_dev->dev, 0x00c1, &val, 1);
+       val = 0x04;
+       reg_w(gspca_dev->dev, 0x00c2, &val, 1);
+
+       reg_w(gspca_dev->dev, 0x0061, cxinit, 8);
+       cxinit += 8;
+       reg_w(gspca_dev->dev, 0x00ca, cxinit, 8);
+       cxinit += 8;
+       reg_w(gspca_dev->dev, 0x00d2, cxinit, 8);
+       cxinit += 8;
+       reg_w(gspca_dev->dev, 0x00da, cxinit, 6);
+       cxinit += 8;
+       reg_w(gspca_dev->dev, 0x0041, cxinit, 8);
+       cxinit += 8;
+       reg_w(gspca_dev->dev, 0x0049, cxinit, 8);
+       cxinit += 8;
+       reg_w(gspca_dev->dev, 0x0051, cxinit, 2);
+
+       reg_r(gspca_dev->dev, 0x0010, &val, 1);
+       return val;
+}
+
+static __u8 cx_jpeg_init[][8] = {
+       {0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x15},       /* 1 */
+       {0x0f, 0x10, 0x12, 0x10, 0x0d, 0x15, 0x12, 0x11},
+       {0x12, 0x18, 0x16, 0x15, 0x19, 0x20, 0x35, 0x22},
+       {0x20, 0x1d, 0x1d, 0x20, 0x41, 0x2e, 0x31, 0x26},
+       {0x35, 0x4d, 0x43, 0x51, 0x4f, 0x4b, 0x43, 0x4a},
+       {0x49, 0x55, 0x5F, 0x79, 0x67, 0x55, 0x5A, 0x73},
+       {0x5B, 0x49, 0x4A, 0x6A, 0x90, 0x6B, 0x73, 0x7D},
+       {0x81, 0x88, 0x89, 0x88, 0x52, 0x66, 0x95, 0xA0},
+       {0x94, 0x84, 0x9E, 0x79, 0x85, 0x88, 0x83, 0x01},
+       {0x15, 0x0F, 0x10, 0x12, 0x10, 0x0D, 0x15, 0x12},
+       {0x11, 0x12, 0x18, 0x16, 0x15, 0x19, 0x20, 0x35},
+       {0x22, 0x20, 0x1D, 0x1D, 0x20, 0x41, 0x2E, 0x31},
+       {0x26, 0x35, 0x4D, 0x43, 0x51, 0x4F, 0x4B, 0x43},
+       {0x4A, 0x49, 0x55, 0x5F, 0x79, 0x67, 0x55, 0x5A},
+       {0x73, 0x5B, 0x49, 0x4A, 0x6A, 0x90, 0x6B, 0x73},
+       {0x7D, 0x81, 0x88, 0x89, 0x88, 0x52, 0x66, 0x95},
+       {0xA0, 0x94, 0x84, 0x9E, 0x79, 0x85, 0x88, 0x83},
+       {0xFF, 0xC4, 0x01, 0xA2, 0x00, 0x00, 0x01, 0x05},
+       {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00},
+       {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02},
+       {0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A},
+       {0x0B, 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01},
+       {0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00},
+       {0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05},
+       {0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x10, 0x00},
+       {0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05},
+       {0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7D, 0x01},
+       {0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21},
+       {0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22},
+       {0x71, 0x14, 0x32, 0x81, 0x91, 0xA1, 0x08, 0x23},
+       {0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1, 0xF0, 0x24},
+       {0x33, 0x62, 0x72, 0x82, 0x09, 0x0A, 0x16, 0x17},
+       {0x18, 0x19, 0x1A, 0x25, 0x26, 0x27, 0x28, 0x29},
+       {0x2A, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A},
+       {0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A},
+       {0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A},
+       {0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A},
+       {0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A},
+       {0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A},
+       {0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99},
+       {0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8},
+       {0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7},
+       {0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6},
+       {0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5},
+       {0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE1, 0xE2, 0xE3},
+       {0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF1},
+       {0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9},
+       {0xFA, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04},
+       {0x03, 0x04, 0x07, 0x05, 0x04, 0x04, 0x00, 0x01},
+       {0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, 0x04},
+       {0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07},
+       {0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14},
+       {0x42, 0x91, 0xA1, 0xB1, 0xC1, 0x09, 0x23, 0x33},
+       {0x52, 0xF0, 0x15, 0x62, 0x72, 0xD1, 0x0A, 0x16},
+       {0x24, 0x34, 0xE1, 0x25, 0xF1, 0x17, 0x18, 0x19},
+       {0x1A, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x35, 0x36},
+       {0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46},
+       {0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56},
+       {0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66},
+       {0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76},
+       {0x77, 0x78, 0x79, 0x7A, 0x82, 0x83, 0x84, 0x85},
+       {0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94},
+       {0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3},
+       {0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2},
+       {0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA},
+       {0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9},
+       {0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8},
+       {0xD9, 0xDA, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7},
+       {0xE8, 0xE9, 0xEA, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6},
+       {0xF7, 0xF8, 0xF9, 0xFA, 0xFF, 0x20, 0x00, 0x1F},
+       {0x02, 0x0C, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00},
+       {0x00, 0x00, 0x11, 0x00, 0x11, 0x22, 0x00, 0x22},
+       {0x22, 0x11, 0x22, 0x22, 0x11, 0x33, 0x33, 0x11},
+       {0x44, 0x66, 0x22, 0x55, 0x66, 0xFF, 0xDD, 0x00},
+       {0x04, 0x00, 0x14, 0xFF, 0xC0, 0x00, 0x11, 0x08},
+       {0x00, 0xF0, 0x01, 0x40, 0x03, 0x00, 0x21, 0x00},
+       {0x01, 0x11, 0x01, 0x02, 0x11, 0x01, 0xFF, 0xDA},
+       {0x00, 0x0C, 0x03, 0x00, 0x00, 0x01, 0x11, 0x02},
+       {0x11, 0x00, 0x3F, 0x00, 0xFF, 0xD9, 0x00, 0x00}        /* 79 */
+};
+
+
+static __u8 cxjpeg_640[][8] = {
+       {0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x10},       /* 1 */
+       {0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e, 0x0d},
+       {0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28, 0x1a},
+       {0x18, 0x16, 0x16, 0x18, 0x31, 0x23, 0x25, 0x1d},
+       {0x28, 0x3a, 0x33, 0x3D, 0x3C, 0x39, 0x33, 0x38},
+       {0x37, 0x40, 0x48, 0x5C, 0x4E, 0x40, 0x44, 0x57},
+       {0x45, 0x37, 0x38, 0x50, 0x6D, 0x51, 0x57, 0x5F},
+       {0x62, 0x67, 0x68, 0x67, 0x3E, 0x4D, 0x71, 0x79},
+       {0x70, 0x64, 0x78, 0x5C, 0x65, 0x67, 0x63, 0x01},
+       {0x10, 0x0B, 0x0C, 0x0E, 0x0C, 0x0A, 0x10, 0x0E},
+       {0x0D, 0x0E, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28},
+       {0x1A, 0x18, 0x16, 0x16, 0x18, 0x31, 0x23, 0x25},
+       {0x1D, 0x28, 0x3A, 0x33, 0x3D, 0x3C, 0x39, 0x33},
+       {0x38, 0x37, 0x40, 0x48, 0x5C, 0x4E, 0x40, 0x44},
+       {0x57, 0x45, 0x37, 0x38, 0x50, 0x6D, 0x51, 0x57},
+       {0x5F, 0x62, 0x67, 0x68, 0x67, 0x3E, 0x4D, 0x71},
+       {0x79, 0x70, 0x64, 0x78, 0x5C, 0x65, 0x67, 0x63},
+       {0xFF, 0x20, 0x00, 0x1F, 0x00, 0x83, 0x00, 0x00},
+       {0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00},
+       {0x11, 0x22, 0x00, 0x22, 0x22, 0x11, 0x22, 0x22},
+       {0x11, 0x33, 0x33, 0x11, 0x44, 0x66, 0x22, 0x55},
+       {0x66, 0xFF, 0xDD, 0x00, 0x04, 0x00, 0x28, 0xFF},
+       {0xC0, 0x00, 0x11, 0x08, 0x01, 0xE0, 0x02, 0x80},
+       {0x03, 0x00, 0x21, 0x00, 0x01, 0x11, 0x01, 0x02},
+       {0x11, 0x01, 0xFF, 0xDA, 0x00, 0x0C, 0x03, 0x00},
+       {0x00, 0x01, 0x11, 0x02, 0x11, 0x00, 0x3F, 0x00},
+       {0xFF, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}        /* 27 */
+};
+static __u8 cxjpeg_352[][8] = {
+       {0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x0d},
+       {0x09, 0x09, 0x0b, 0x09, 0x08, 0x0D, 0x0b, 0x0a},
+       {0x0b, 0x0e, 0x0d, 0x0d, 0x0f, 0x13, 0x1f, 0x14},
+       {0x13, 0x11, 0x11, 0x13, 0x26, 0x1b, 0x1d, 0x17},
+       {0x1F, 0x2D, 0x28, 0x30, 0x2F, 0x2D, 0x28, 0x2C},
+       {0x2B, 0x32, 0x38, 0x48, 0x3D, 0x32, 0x35, 0x44},
+       {0x36, 0x2B, 0x2C, 0x3F, 0x55, 0x3F, 0x44, 0x4A},
+       {0x4D, 0x50, 0x51, 0x50, 0x30, 0x3C, 0x58, 0x5F},
+       {0x58, 0x4E, 0x5E, 0x48, 0x4F, 0x50, 0x4D, 0x01},
+       {0x0D, 0x09, 0x09, 0x0B, 0x09, 0x08, 0x0D, 0x0B},
+       {0x0A, 0x0B, 0x0E, 0x0D, 0x0D, 0x0F, 0x13, 0x1F},
+       {0x14, 0x13, 0x11, 0x11, 0x13, 0x26, 0x1B, 0x1D},
+       {0x17, 0x1F, 0x2D, 0x28, 0x30, 0x2F, 0x2D, 0x28},
+       {0x2C, 0x2B, 0x32, 0x38, 0x48, 0x3D, 0x32, 0x35},
+       {0x44, 0x36, 0x2B, 0x2C, 0x3F, 0x55, 0x3F, 0x44},
+       {0x4A, 0x4D, 0x50, 0x51, 0x50, 0x30, 0x3C, 0x58},
+       {0x5F, 0x58, 0x4E, 0x5E, 0x48, 0x4F, 0x50, 0x4D},
+       {0xFF, 0x20, 0x00, 0x1F, 0x01, 0x83, 0x00, 0x00},
+       {0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00},
+       {0x11, 0x22, 0x00, 0x22, 0x22, 0x11, 0x22, 0x22},
+       {0x11, 0x33, 0x33, 0x11, 0x44, 0x66, 0x22, 0x55},
+       {0x66, 0xFF, 0xDD, 0x00, 0x04, 0x00, 0x16, 0xFF},
+       {0xC0, 0x00, 0x11, 0x08, 0x01, 0x20, 0x01, 0x60},
+       {0x03, 0x00, 0x21, 0x00, 0x01, 0x11, 0x01, 0x02},
+       {0x11, 0x01, 0xFF, 0xDA, 0x00, 0x0C, 0x03, 0x00},
+       {0x00, 0x01, 0x11, 0x02, 0x11, 0x00, 0x3F, 0x00},
+       {0xFF, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+};
+static __u8 cxjpeg_320[][8] = {
+       {0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x05},
+       {0x03, 0x04, 0x04, 0x04, 0x03, 0x05, 0x04, 0x04},
+       {0x04, 0x05, 0x05, 0x05, 0x06, 0x07, 0x0c, 0x08},
+       {0x07, 0x07, 0x07, 0x07, 0x0f, 0x0b, 0x0b, 0x09},
+       {0x0C, 0x11, 0x0F, 0x12, 0x12, 0x11, 0x0f, 0x11},
+       {0x11, 0x13, 0x16, 0x1C, 0x17, 0x13, 0x14, 0x1A},
+       {0x15, 0x11, 0x11, 0x18, 0x21, 0x18, 0x1A, 0x1D},
+       {0x1D, 0x1F, 0x1F, 0x1F, 0x13, 0x17, 0x22, 0x24},
+       {0x22, 0x1E, 0x24, 0x1C, 0x1E, 0x1F, 0x1E, 0x01},
+       {0x05, 0x03, 0x04, 0x04, 0x04, 0x03, 0x05, 0x04},
+       {0x04, 0x04, 0x05, 0x05, 0x05, 0x06, 0x07, 0x0C},
+       {0x08, 0x07, 0x07, 0x07, 0x07, 0x0F, 0x0B, 0x0B},
+       {0x09, 0x0C, 0x11, 0x0F, 0x12, 0x12, 0x11, 0x0F},
+       {0x11, 0x11, 0x13, 0x16, 0x1C, 0x17, 0x13, 0x14},
+       {0x1A, 0x15, 0x11, 0x11, 0x18, 0x21, 0x18, 0x1A},
+       {0x1D, 0x1D, 0x1F, 0x1F, 0x1F, 0x13, 0x17, 0x22},
+       {0x24, 0x22, 0x1E, 0x24, 0x1C, 0x1E, 0x1F, 0x1E},
+       {0xFF, 0x20, 0x00, 0x1F, 0x02, 0x0C, 0x00, 0x00},
+       {0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00},
+       {0x11, 0x22, 0x00, 0x22, 0x22, 0x11, 0x22, 0x22},
+       {0x11, 0x33, 0x33, 0x11, 0x44, 0x66, 0x22, 0x55},
+       {0x66, 0xFF, 0xDD, 0x00, 0x04, 0x00, 0x14, 0xFF},
+       {0xC0, 0x00, 0x11, 0x08, 0x00, 0xF0, 0x01, 0x40},
+       {0x03, 0x00, 0x21, 0x00, 0x01, 0x11, 0x01, 0x02},
+       {0x11, 0x01, 0xFF, 0xDA, 0x00, 0x0C, 0x03, 0x00},
+       {0x00, 0x01, 0x11, 0x02, 0x11, 0x00, 0x3F, 0x00},
+       {0xFF, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}        /* 27 */
+};
+static __u8 cxjpeg_176[][8] = {
+       {0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x0d},
+       {0x09, 0x09, 0x0B, 0x09, 0x08, 0x0D, 0x0B, 0x0A},
+       {0x0B, 0x0E, 0x0D, 0x0D, 0x0F, 0x13, 0x1F, 0x14},
+       {0x13, 0x11, 0x11, 0x13, 0x26, 0x1B, 0x1D, 0x17},
+       {0x1F, 0x2D, 0x28, 0x30, 0x2F, 0x2D, 0x28, 0x2C},
+       {0x2B, 0x32, 0x38, 0x48, 0x3D, 0x32, 0x35, 0x44},
+       {0x36, 0x2B, 0x2C, 0x3F, 0x55, 0x3F, 0x44, 0x4A},
+       {0x4D, 0x50, 0x51, 0x50, 0x30, 0x3C, 0x58, 0x5F},
+       {0x58, 0x4E, 0x5E, 0x48, 0x4F, 0x50, 0x4D, 0x01},
+       {0x0D, 0x09, 0x09, 0x0B, 0x09, 0x08, 0x0D, 0x0B},
+       {0x0A, 0x0B, 0x0E, 0x0D, 0x0D, 0x0F, 0x13, 0x1F},
+       {0x14, 0x13, 0x11, 0x11, 0x13, 0x26, 0x1B, 0x1D},
+       {0x17, 0x1F, 0x2D, 0x28, 0x30, 0x2F, 0x2D, 0x28},
+       {0x2C, 0x2B, 0x32, 0x38, 0x48, 0x3D, 0x32, 0x35},
+       {0x44, 0x36, 0x2B, 0x2C, 0x3F, 0x55, 0x3F, 0x44},
+       {0x4A, 0x4D, 0x50, 0x51, 0x50, 0x30, 0x3C, 0x58},
+       {0x5F, 0x58, 0x4E, 0x5E, 0x48, 0x4F, 0x50, 0x4D},
+       {0xFF, 0x20, 0x00, 0x1F, 0x03, 0xA1, 0x00, 0x00},
+       {0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00},
+       {0x11, 0x22, 0x00, 0x22, 0x22, 0x11, 0x22, 0x22},
+       {0x11, 0x33, 0x33, 0x11, 0x44, 0x66, 0x22, 0x55},
+       {0x66, 0xFF, 0xDD, 0x00, 0x04, 0x00, 0x0B, 0xFF},
+       {0xC0, 0x00, 0x11, 0x08, 0x00, 0x90, 0x00, 0xB0},
+       {0x03, 0x00, 0x21, 0x00, 0x01, 0x11, 0x01, 0x02},
+       {0x11, 0x01, 0xFF, 0xDA, 0x00, 0x0C, 0x03, 0x00},
+       {0x00, 0x01, 0x11, 0x02, 0x11, 0x00, 0x3F, 0x00},
+       {0xFF, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+};
+static __u8 cxjpeg_qtable[][8] = {     /* 640 take with the zcx30x part */
+       {0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x08},
+       {0x06, 0x06, 0x07, 0x06, 0x05, 0x08, 0x07, 0x07},
+       {0x07, 0x09, 0x09, 0x08, 0x0a, 0x0c, 0x14, 0x0a},
+       {0x0c, 0x0b, 0x0b, 0x0c, 0x19, 0x12, 0x13, 0x0f},
+       {0x14, 0x1d, 0x1a, 0x1f, 0x1e, 0x1d, 0x1a, 0x1c},
+       {0x1c, 0x20, 0x24, 0x2e, 0x27, 0x20, 0x22, 0x2c},
+       {0x23, 0x1c, 0x1c, 0x28, 0x37, 0x29, 0x2c, 0x30},
+       {0x31, 0x34, 0x34, 0x34, 0x1f, 0x27, 0x39, 0x3d},
+       {0x38, 0x32, 0x3c, 0x2e, 0x33, 0x34, 0x32, 0x01},
+       {0x09, 0x09, 0x09, 0x0c, 0x0b, 0x0c, 0x18, 0x0a},
+       {0x0a, 0x18, 0x32, 0x21, 0x1c, 0x21, 0x32, 0x32},
+       {0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32},
+       {0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32},
+       {0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32},
+       {0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32},
+       {0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32},
+       {0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32},
+       {0xFF, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}        /* 18 */
+};
+
+
+static void cx11646_jpegInit(struct gspca_dev*gspca_dev)
+{
+       __u8 val;
+       int i;
+       int length;
+
+       val = 0x01;
+       reg_w(gspca_dev->dev, 0x00c0, &val, 1);
+       val = 0x00;
+       reg_w(gspca_dev->dev, 0x00c3, &val, 1);
+       val = 0x00;
+       reg_w(gspca_dev->dev, 0x00c0, &val, 1);
+       reg_r(gspca_dev->dev, 0x0001, &val, 1);
+       length = 8;
+       for (i = 0; i < 79; i++) {
+               if (i == 78)
+                       length = 6;
+               reg_w(gspca_dev->dev, 0x0008, cx_jpeg_init[i], length);
+       }
+       reg_r(gspca_dev->dev, 0x0002, &val, 1);
+       val = 0x14;
+       reg_w(gspca_dev->dev, 0x0055, &val, 1);
+}
+
+static __u8 reg12[] = { 0x0a, 0x05, 0x07, 0x04, 0x19 };
+static __u8 regE5_8[] = { 0x88, 0x00, 0xd4, 0x01, 0x88, 0x01, 0x01, 0x01 };
+static __u8 regE5a[] = { 0x88, 0x0a, 0x0c, 0x01 };
+static __u8 regE5b[] = { 0x88, 0x0b, 0x12, 0x01 };
+static __u8 regE5c[] = { 0x88, 0x05, 0x01, 0x01 };
+static __u8 reg51[] = { 0x77, 0x03 };
+static __u8 reg70 = 0x03;
+
+static void cx11646_jpeg(struct gspca_dev*gspca_dev)
+{
+       __u8 val;
+       int i;
+       int length = 8;
+       __u8 Reg55 = 0x14;
+       __u8 bufread[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+       int retry = 50;
+
+       val = 0x01;
+       reg_w(gspca_dev->dev, 0x00c0, &val, 1);
+       val = 0x00;
+       reg_w(gspca_dev->dev, 0x00c3, &val, 1);
+       val = 0x00;
+       reg_w(gspca_dev->dev, 0x00c0, &val, 1);
+       reg_r(gspca_dev->dev, 0x0001, &val, 1);
+       switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].mode) {
+       case 0:
+               for (i = 0; i < 27; i++) {
+                       if (i == 26)
+                               length = 2;
+                       reg_w(gspca_dev->dev, 0x0008,
+                                       cxjpeg_640[i], length);
+               }
+               Reg55 = 0x28;
+               break;
+       case 1:
+               for (i = 0; i < 27; i++) {
+                       if (i == 26)
+                               length = 2;
+                       reg_w(gspca_dev->dev, 0x0008,
+                                       cxjpeg_352[i], length);
+               }
+               Reg55 = 0x16;
+               break;
+       default:
+/*     case 2: */
+               for (i = 0; i < 27; i++) {
+                       if (i == 26)
+                               length = 2;
+                       reg_w(gspca_dev->dev, 0x0008,
+                                       cxjpeg_320[i], length);
+               }
+               Reg55 = 0x14;
+               break;
+       case 3:
+               for (i = 0; i < 27; i++) {
+                       if (i == 26)
+                               length = 2;
+                       reg_w(gspca_dev->dev, 0x0008,
+                                       cxjpeg_176[i], length);
+               }
+               Reg55 = 0x0B;
+               break;
+       }
+
+       reg_r(gspca_dev->dev, 0x0002, &val, 1);
+       val = Reg55;
+       reg_w(gspca_dev->dev, 0x0055, &val, 1);
+       reg_r(gspca_dev->dev, 0x0002, &val, 1);
+       reg_w(gspca_dev->dev, 0x0010, reg10, 2);
+       val = 0x02;
+       reg_w(gspca_dev->dev, 0x0054, &val, 1);
+       val = 0x01;
+       reg_w(gspca_dev->dev, 0x0054, &val, 1);
+       val = 0x94;
+       reg_w(gspca_dev->dev, 0x0000, &val, 1);
+       val = 0xc0;
+       reg_w(gspca_dev->dev, 0x0053, &val, 1);
+       val = 0xe1;
+       reg_w(gspca_dev->dev, 0x00fc, &val, 1);
+       val = 0x00;
+       reg_w(gspca_dev->dev, 0x0000, &val, 1);
+       /* wait for completion */
+       while (retry--) {
+               reg_r(gspca_dev->dev, 0x0002, &val, 1);
+                                                       /* 0x07 until 0x00 */
+               if (val == 0x00)
+                       break;
+               val = 0x00;
+               reg_w(gspca_dev->dev, 0x0053, &val, 1);
+       }
+       if (retry == 0)
+               PDEBUG(D_ERR, "Damned Errors sending jpeg Table");
+       /* send the qtable now */
+       reg_r(gspca_dev->dev, 0x0001, &val, 1);         /* -> 0x18 */
+       length = 8;
+       for (i = 0; i < 18; i++) {
+               if (i == 17)
+                       length = 2;
+               reg_w(gspca_dev->dev, 0x0008,
+                               cxjpeg_qtable[i], length);
+
+       }
+       reg_r(gspca_dev->dev, 0x0002, &val, 1); /* 0x00 */
+       reg_r(gspca_dev->dev, 0x0053, &val, 1); /* 0x00 */
+       val = 0x02;
+       reg_w(gspca_dev->dev, 0x0054, &val, 1);
+       val = 0x01;
+       reg_w(gspca_dev->dev, 0x0054, &val, 1);
+       val = 0x94;
+       reg_w(gspca_dev->dev, 0x0000, &val, 1);
+       val = 0xc0;
+       reg_w(gspca_dev->dev, 0x0053, &val, 1);
+
+       reg_r(gspca_dev->dev, 0x0038, &val, 1); /* 0x40 */
+       reg_r(gspca_dev->dev, 0x0038, &val, 1); /* 0x40 */
+       reg_r(gspca_dev->dev, 0x001f, &val, 1); /* 0x38 */
+       reg_w(gspca_dev->dev, 0x0012, reg12, 5);
+       reg_w(gspca_dev->dev, 0x00e5, regE5_8, 8);
+       reg_r(gspca_dev->dev, 0x00e8, bufread, 8);
+       reg_w(gspca_dev->dev, 0x00e5, regE5a, 4);
+       reg_r(gspca_dev->dev, 0x00e8, &val, 1); /* 0x00 */
+       val = 0x01;
+       reg_w(gspca_dev->dev, 0x009a, &val, 1);
+       reg_w(gspca_dev->dev, 0x00e5, regE5b, 4);
+       reg_r(gspca_dev->dev, 0x00e8, &val, 1); /* 0x00 */
+       reg_w(gspca_dev->dev, 0x00e5, regE5c, 4);
+       reg_r(gspca_dev->dev, 0x00e8, &val, 1); /* 0x00 */
+
+       reg_w(gspca_dev->dev, 0x0051, reg51, 2);
+       reg_w(gspca_dev->dev, 0x0010, reg10, 2);
+       reg_w(gspca_dev->dev, 0x0070, &reg70, 1);
+}
+
+static void cx11646_init1(struct gspca_dev *gspca_dev)
+{
+       __u8 val;
+       int i = 0;
+
+       val = 0;
+       reg_w(gspca_dev->dev, 0x0010, &val, 1);
+       reg_w(gspca_dev->dev, 0x0053, &val, 1);
+       reg_w(gspca_dev->dev, 0x0052, &val, 1);
+       val = 0x2f;
+       reg_w(gspca_dev->dev, 0x009b, &val, 1);
+       val = 0x10;
+       reg_w(gspca_dev->dev, 0x009c, &val, 1);
+       reg_r(gspca_dev->dev, 0x0098, &val, 1);
+       val = 0x40;
+       reg_w(gspca_dev->dev, 0x0098, &val, 1);
+       reg_r(gspca_dev->dev, 0x0099, &val, 1);
+       val = 0x07;
+       reg_w(gspca_dev->dev, 0x0099, &val, 1);
+       val = 0x40;
+       reg_w(gspca_dev->dev, 0x0039, &val, 1);
+       val = 0xff;
+       reg_w(gspca_dev->dev, 0x003c, &val, 1);
+       val = 0x1f;
+       reg_w(gspca_dev->dev, 0x003f, &val, 1);
+       val = 0x40;
+       reg_w(gspca_dev->dev, 0x003d, &val, 1);
+/* val= 0x60; */
+/* reg_w(gspca_dev->dev,0x00,0x00,0x003d,&val,1); */
+       reg_r(gspca_dev->dev, 0x0099, &val, 1);                 /* ->0x07 */
+
+       while (cx_sensor_init[i][0]) {
+               reg_w(gspca_dev->dev, 0x00e5, cx_sensor_init[i], 1);
+               reg_r(gspca_dev->dev, 0x00e8, &val, 1);         /* -> 0x00 */
+               if (i == 1) {
+                       val = 1;
+                       reg_w(gspca_dev->dev, 0x00ed, &val, 1);
+                       reg_r(gspca_dev->dev, 0x00ed, &val, 1); /* -> 0x01 */
+               }
+               i++;
+       }
+       val = 0x00;
+       reg_w(gspca_dev->dev, 0x00c3, &val, 1);
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+                       const struct usb_device_id *id)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct cam *cam;
+
+       cam = &gspca_dev->cam;
+       cam->dev_name = (char *) id->driver_info;
+       cam->epaddr = 0x01;
+       cam->cam_mode = vga_mode;
+       cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+
+       sd->qindex = 0;                 /* set the quantization table */
+       sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
+       sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
+       sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value;
+       return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+       cx11646_init1(gspca_dev);
+       cx11646_initsize(gspca_dev);
+       cx11646_fw(gspca_dev);
+       cx_sensor(gspca_dev);
+       cx11646_jpegInit(gspca_dev);
+       return 0;
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+       cx11646_initsize(gspca_dev);
+       cx11646_fw(gspca_dev);
+       cx_sensor(gspca_dev);
+       cx11646_jpeg(gspca_dev);
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+       int retry = 50;
+       __u8 val;
+
+       val = 0;
+       reg_w(gspca_dev->dev, 0x0000, &val, 1);
+       reg_r(gspca_dev->dev, 0x0002, &val, 1);
+       val = 0;
+       reg_w(gspca_dev->dev, 0x0053, &val, 1);
+
+       while (retry--) {
+/*             reg_r (gspca_dev->dev,0x00,0x00,0x0002,&val,1);*/
+               reg_r(gspca_dev->dev, 0x0053, &val, 1);
+               if (val == 0)
+                       break;
+       }
+       val = 0;
+       reg_w(gspca_dev->dev, 0x0000, &val, 1);
+       reg_r(gspca_dev->dev, 0x0002, &val, 1);
+
+       val = 0;
+       reg_w(gspca_dev->dev, 0x0010, &val, 1);
+       reg_r(gspca_dev->dev, 0x0033, &val, 1);
+       val = 0xe0;
+       reg_w(gspca_dev->dev, 0x00fc, &val, 1);
+}
+
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+                       struct gspca_frame *frame,      /* target */
+                       unsigned char *data,            /* isoc packet */
+                       int len)                        /* iso packet length */
+{
+       if (data[0] == 0xff && data[1] == 0xd8) {
+
+               /* start of frame */
+               frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+                                       data, 0);
+
+               /* put the JPEG header in the new frame */
+               jpeg_put_header(gspca_dev, frame,
+                               ((struct sd *) gspca_dev)->qindex,
+                               0x22);
+               data += 2;
+               len -= 2;
+       }
+       gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+}
+
+static void setbrightness(struct gspca_dev*gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       __u8 regE5cbx[] = { 0x88, 0x00, 0xd4, 0x01, 0x88, 0x01, 0x01, 0x01 };
+       __u8 reg51c[] = { 0x77, 0x03 };
+       __u8 bright;
+       __u8 colors;
+       __u8 val;
+       __u8 bufread[8];
+
+       bright = sd->brightness;
+       colors = sd->colors;
+       regE5cbx[2] = bright;
+       reg51c[1] = colors;
+       reg_w(gspca_dev->dev, 0x00e5, regE5cbx, 8);
+       reg_r(gspca_dev->dev, 0x00e8, bufread, 8);
+       reg_w(gspca_dev->dev, 0x00e5, regE5c, 4);
+       reg_r(gspca_dev->dev, 0x00e8, &val, 1); /* 0x00 */
+
+       reg_w(gspca_dev->dev, 0x0051, reg51c, 2);
+       reg_w(gspca_dev->dev, 0x0010, reg10, 2);
+       reg_w(gspca_dev->dev, 0x0070, &reg70, 1);
+}
+
+static void setcontrast(struct gspca_dev*gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       __u8 regE5acx[] = { 0x88, 0x0a, 0x0c, 0x01 };   /* seem MSB */
+       /* __u8 regE5bcx[]={0x88,0x0b,0x12,0x01}; // LSB */
+       __u8 reg51c[] = { 0x77, 0x03 };
+       __u8 val;
+
+       reg51c[1] = sd->colors;
+       regE5acx[2] = sd->contrast;
+       reg_w(gspca_dev->dev, 0x00e5, regE5acx, 4);
+       reg_r(gspca_dev->dev, 0x00e8, &val, 1); /* 0x00 */
+       reg_w(gspca_dev->dev, 0x0051, reg51c, 2);
+       reg_w(gspca_dev->dev, 0x0010, reg10, 2);
+       reg_w(gspca_dev->dev, 0x0070, &reg70, 1);
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->brightness = val;
+       if (gspca_dev->streaming)
+               setbrightness(gspca_dev);
+       return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->brightness;
+       return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->contrast = val;
+       if (gspca_dev->streaming)
+               setcontrast(gspca_dev);
+       return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->contrast;
+       return 0;
+}
+
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->colors = val;
+       if (gspca_dev->streaming) {
+               setbrightness(gspca_dev);
+               setcontrast(gspca_dev);
+       }
+       return 0;
+}
+
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->colors;
+       return 0;
+}
+
+/* sub-driver description */
+static struct sd_desc sd_desc = {
+       .name = MODULE_NAME,
+       .ctrls = sd_ctrls,
+       .nctrls = ARRAY_SIZE(sd_ctrls),
+       .config = sd_config,
+       .open = sd_open,
+       .start = sd_start,
+       .stopN = sd_stopN,
+       .stop0 = sd_stop0,
+       .close = sd_close,
+       .pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static __devinitdata struct usb_device_id device_table[] = {
+       {USB_DEVICE(0x0572, 0x0041), DVNM("Creative Notebook cx11646")},
+       {}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+                       const struct usb_device_id *id)
+{
+       return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+                               THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+       .name = MODULE_NAME,
+       .id_table = device_table,
+       .probe = sd_probe,
+       .disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+       if (usb_register(&sd_driver) < 0)
+               return -1;
+       PDEBUG(D_PROBE, "v%s registered", version);
+       return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+       usb_deregister(&sd_driver);
+       PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/etoms.c b/drivers/media/video/gspca/etoms.c
new file mode 100644 (file)
index 0000000..c479f63
--- /dev/null
@@ -0,0 +1,1062 @@
+/*
+ * Etoms Et61x151 GPL Linux driver by Michel Xhaard (09/09/2004)
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define MODULE_NAME "etoms"
+
+#include "gspca.h"
+
+#define DRIVER_VERSION_NUMBER  KERNEL_VERSION(2, 1, 0)
+static const char version[] = "2.1.0";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("Etoms USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+       struct gspca_dev gspca_dev;     /* !! must be the first item */
+
+       unsigned char brightness;
+       unsigned char contrast;
+       unsigned char colors;
+       unsigned char autogain;
+
+       char sensor;
+#define SENSOR_PAS106 0
+#define SENSOR_TAS5130CXX 1
+       signed char ag_cnt;
+#define AG_CNT_START 13
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+#define SD_BRIGHTNESS 0
+       {
+        {
+         .id = V4L2_CID_BRIGHTNESS,
+         .type = V4L2_CTRL_TYPE_INTEGER,
+         .name = "Brightness",
+         .minimum = 1,
+         .maximum = 127,
+         .step = 1,
+         .default_value = 63,
+         },
+        .set = sd_setbrightness,
+        .get = sd_getbrightness,
+        },
+#define SD_CONTRAST 1
+       {
+        {
+         .id = V4L2_CID_CONTRAST,
+         .type = V4L2_CTRL_TYPE_INTEGER,
+         .name = "Contrast",
+         .minimum = 0,
+         .maximum = 255,
+         .step = 1,
+         .default_value = 127,
+         },
+        .set = sd_setcontrast,
+        .get = sd_getcontrast,
+        },
+#define SD_COLOR 2
+       {
+        {
+         .id = V4L2_CID_SATURATION,
+         .type = V4L2_CTRL_TYPE_INTEGER,
+         .name = "Color",
+         .minimum = 0,
+         .maximum = 15,
+         .step = 1,
+         .default_value = 7,
+         },
+        .set = sd_setcolors,
+        .get = sd_getcolors,
+        },
+#define SD_AUTOGAIN 3
+       {
+        {
+         .id = V4L2_CID_AUTOGAIN,
+         .type = V4L2_CTRL_TYPE_BOOLEAN,
+         .name = "Auto Gain",
+         .minimum = 0,
+         .maximum = 1,
+         .step = 1,
+         .default_value = 1,
+         },
+        .set = sd_setautogain,
+        .get = sd_getautogain,
+        },
+};
+
+static struct cam_mode vga_mode[] = {
+       {V4L2_PIX_FMT_SBGGR8, 320, 240, 1},
+/*     {V4L2_PIX_FMT_SBGGR8, 640, 480, 0}, */
+};
+
+static struct cam_mode sif_mode[] = {
+       {V4L2_PIX_FMT_SBGGR8, 176, 144, 1},
+       {V4L2_PIX_FMT_SBGGR8, 352, 288, 0},
+};
+
+#define ETOMS_ALT_SIZE_1000   12
+
+#define ET_GPIO_DIR_CTRL 0x04  /* Control IO bit[0..5] (0 in  1 out) */
+#define ET_GPIO_OUT 0x05       /* Only IO data */
+#define ET_GPIO_IN 0x06                /* Read Only IO data */
+#define ET_RESET_ALL 0x03
+#define ET_ClCK 0x01
+#define ET_CTRL 0x02           /* enable i2c OutClck Powerdown mode */
+
+#define ET_COMP 0x12           /* Compression register */
+#define ET_MAXQt 0x13
+#define ET_MINQt 0x14
+#define ET_COMP_VAL0 0x02
+#define ET_COMP_VAL1 0x03
+
+#define ET_REG1d 0x1d
+#define ET_REG1e 0x1e
+#define ET_REG1f 0x1f
+#define ET_REG20 0x20
+#define ET_REG21 0x21
+#define ET_REG22 0x22
+#define ET_REG23 0x23
+#define ET_REG24 0x24
+#define ET_REG25 0x25
+/* base registers for luma calculation */
+#define ET_LUMA_CENTER 0x39
+
+#define ET_G_RED 0x4d
+#define ET_G_GREEN1 0x4e
+#define ET_G_BLUE 0x4f
+#define ET_G_GREEN2 0x50
+#define ET_G_GR_H 0x51
+#define ET_G_GB_H 0x52
+
+#define ET_O_RED 0x34
+#define ET_O_GREEN1 0x35
+#define ET_O_BLUE 0x36
+#define ET_O_GREEN2 0x37
+
+#define ET_SYNCHRO 0x68
+#define ET_STARTX 0x69
+#define ET_STARTY 0x6a
+#define ET_WIDTH_LOW 0x6b
+#define ET_HEIGTH_LOW 0x6c
+#define ET_W_H_HEIGTH 0x6d
+
+#define ET_REG6e 0x6e          /* OBW */
+#define ET_REG6f 0x6f          /* OBW */
+#define ET_REG70 0x70          /* OBW_AWB */
+#define ET_REG71 0x71          /* OBW_AWB */
+#define ET_REG72 0x72          /* OBW_AWB */
+#define ET_REG73 0x73          /* Clkdelay ns */
+#define ET_REG74 0x74          /* test pattern */
+#define ET_REG75 0x75          /* test pattern */
+
+#define ET_I2C_CLK 0x8c
+#define ET_PXL_CLK 0x60
+
+#define ET_I2C_BASE 0x89
+#define ET_I2C_COUNT 0x8a
+#define ET_I2C_PREFETCH 0x8b
+#define ET_I2C_REG 0x88
+#define ET_I2C_DATA7 0x87
+#define ET_I2C_DATA6 0x86
+#define ET_I2C_DATA5 0x85
+#define ET_I2C_DATA4 0x84
+#define ET_I2C_DATA3 0x83
+#define ET_I2C_DATA2 0x82
+#define ET_I2C_DATA1 0x81
+#define ET_I2C_DATA0 0x80
+
+#define PAS106_REG2 0x02       /* pxlClk = systemClk/(reg2) */
+#define PAS106_REG3 0x03       /* line/frame H [11..4] */
+#define PAS106_REG4 0x04       /* line/frame L [3..0] */
+#define PAS106_REG5 0x05       /* exposure time line offset(default 5) */
+#define PAS106_REG6 0x06       /* exposure time pixel offset(default 6) */
+#define PAS106_REG7 0x07       /* signbit Dac (default 0) */
+#define PAS106_REG9 0x09
+#define PAS106_REG0e 0x0e      /* global gain [4..0](default 0x0e) */
+#define PAS106_REG13 0x13      /* end i2c write */
+
+static __u8 GainRGBG[] = { 0x80, 0x80, 0x80, 0x80, 0x00, 0x00 };
+
+static __u8 I2c2[] = { 0x08, 0x08, 0x08, 0x08, 0x0d };
+
+static __u8 I2c3[] = { 0x12, 0x05 };
+
+static __u8 I2c4[] = { 0x41, 0x08 };
+
+static void Et_RegRead(struct usb_device *dev,
+                      __u16 index, __u8 *buffer, int len)
+{
+       usb_control_msg(dev,
+                       usb_rcvctrlpipe(dev, 0),
+                       0,
+                       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+                       0, index, buffer, len, 500);
+}
+
+static void Et_RegWrite(struct usb_device *dev,
+                       __u16 index, __u8 *buffer, __u16 len)
+{
+       usb_control_msg(dev,
+                       usb_sndctrlpipe(dev, 0),
+                       0,
+                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+                       0, index, buffer, len, 500);
+}
+
+static int Et_i2cwrite(struct usb_device *dev, __u8 reg, __u8 * buffer,
+                      __u16 length, __u8 mode)
+{
+/* buffer should be [D0..D7] */
+       int i, j;
+       __u8 base = 0x40;       /* sensor base for the pas106 */
+       __u8 ptchcount = 0;
+
+       ptchcount = (((length & 0x07) << 4) | (mode & 0x03));
+/* set the base address */
+       Et_RegWrite(dev, ET_I2C_BASE, &base, 1);
+/* set count and prefetch */
+       Et_RegWrite(dev, ET_I2C_COUNT, &ptchcount, 1);
+/* set the register base */
+       Et_RegWrite(dev, ET_I2C_REG, &reg, 1);
+       j = length - 1;
+       for (i = 0; i < length; i++) {
+               Et_RegWrite(dev, (ET_I2C_DATA0 + j), &buffer[j], 1);
+               j--;
+       }
+       return 0;
+}
+
+static int Et_i2cread(struct usb_device *dev, __u8 reg, __u8 * buffer,
+                     __u16 length, __u8 mode)
+{
+/* buffer should be [D0..D7] */
+       int i, j;
+       __u8 base = 0x40;       /* sensor base for the pas106 */
+       __u8 ptchcount;
+       __u8 prefetch = 0x02;
+
+       ptchcount = (((length & 0x07) << 4) | (mode & 0x03));
+/* set the base address */
+       Et_RegWrite(dev, ET_I2C_BASE, &base, 1);
+/* set count and prefetch */
+       Et_RegWrite(dev, ET_I2C_COUNT, &ptchcount, 1);
+/* set the register base */
+       Et_RegWrite(dev, ET_I2C_REG, &reg, 1);
+       Et_RegWrite(dev, ET_I2C_PREFETCH, &prefetch, 1);
+       prefetch = 0x00;
+       Et_RegWrite(dev, ET_I2C_PREFETCH, &prefetch, 1);
+       j = length - 1;
+       for (i = 0; i < length; i++) {
+               Et_RegRead(dev, (ET_I2C_DATA0 + j), &buffer[j], 1);
+               j--;
+       }
+       return 0;
+}
+
+static int Et_WaitStatus(struct usb_device *dev)
+{
+       __u8 bytereceived;
+       int retry = 10;
+
+       while (retry--) {
+               Et_RegRead(dev, ET_ClCK, &bytereceived, 1);
+               if (bytereceived != 0)
+                       return 1;
+       }
+       return 0;
+}
+
+static int Et_videoOff(struct usb_device *dev)
+{
+       int err;
+       __u8 stopvideo = 0;
+
+       Et_RegWrite(dev, ET_GPIO_OUT, &stopvideo, 1);
+       err = Et_WaitStatus(dev);
+       if (!err)
+               PDEBUG(D_ERR, "timeout Et_waitStatus VideoON");
+       return err;
+}
+
+static int Et_videoOn(struct usb_device *dev)
+{
+       int err;
+       __u8 startvideo = 0x10; /* set Bit5 */
+
+       Et_RegWrite(dev, ET_GPIO_OUT, &startvideo, 1);
+       err = Et_WaitStatus(dev);
+       if (!err)
+               PDEBUG(D_ERR, "timeout Et_waitStatus VideoOFF");
+       return err;
+}
+
+static void Et_init2(struct gspca_dev *gspca_dev)
+{
+       struct usb_device *dev = gspca_dev->dev;
+       __u8 value = 0x00;
+       __u8 received = 0x00;
+       __u8 FormLine[] = { 0x84, 0x03, 0x14, 0xf4, 0x01, 0x05 };
+
+       PDEBUG(D_STREAM, "Open Init2 ET");
+       value = 0x2f;
+       Et_RegWrite(dev, ET_GPIO_DIR_CTRL, &value, 1);
+       value = 0x10;
+       Et_RegWrite(dev, ET_GPIO_OUT, &value, 1);
+       Et_RegRead(dev, ET_GPIO_IN, &received, 1);
+       value = 0x14;           /* 0x14 // 0x16 enabled pattern */
+       Et_RegWrite(dev, ET_ClCK, &value, 1);
+       value = 0x1b;
+       Et_RegWrite(dev, ET_CTRL, &value, 1);
+
+       /*  compression et subsampling */
+       if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].mode)
+               value = ET_COMP_VAL1;   /* 320 */
+       else
+               value = ET_COMP_VAL0;   /* 640 */
+       Et_RegWrite(dev, ET_COMP, &value, 1);
+       value = 0x1f;
+       Et_RegWrite(dev, ET_MAXQt, &value, 1);
+       value = 0x04;
+       Et_RegWrite(dev, ET_MINQt, &value, 1);
+       /* undocumented registers */
+       value = 0xff;
+       Et_RegWrite(dev, ET_REG1d, &value, 1);
+       value = 0xff;
+       Et_RegWrite(dev, ET_REG1e, &value, 1);
+       value = 0xff;
+       Et_RegWrite(dev, ET_REG1f, &value, 1);
+       value = 0x35;
+       Et_RegWrite(dev, ET_REG20, &value, 1);
+       value = 0x01;
+       Et_RegWrite(dev, ET_REG21, &value, 1);
+       value = 0x00;
+       Et_RegWrite(dev, ET_REG22, &value, 1);
+       value = 0xff;
+       Et_RegWrite(dev, ET_REG23, &value, 1);
+       value = 0xff;
+       Et_RegWrite(dev, ET_REG24, &value, 1);
+       value = 0x0f;
+       Et_RegWrite(dev, ET_REG25, &value, 1);
+       /* colors setting */
+       value = 0x11;
+       Et_RegWrite(dev, 0x30, &value, 1);      /* 0x30 */
+       value = 0x40;
+       Et_RegWrite(dev, 0x31, &value, 1);
+       value = 0x00;
+       Et_RegWrite(dev, 0x32, &value, 1);
+       value = 0x00;
+       Et_RegWrite(dev, ET_O_RED, &value, 1);  /* 0x34 */
+       value = 0x00;
+       Et_RegWrite(dev, ET_O_GREEN1, &value, 1);
+       value = 0x00;
+       Et_RegWrite(dev, ET_O_BLUE, &value, 1);
+       value = 0x00;
+       Et_RegWrite(dev, ET_O_GREEN2, &value, 1);
+       /*************/
+       value = 0x80;
+       Et_RegWrite(dev, ET_G_RED, &value, 1);  /* 0x4d */
+       value = 0x80;
+       Et_RegWrite(dev, ET_G_GREEN1, &value, 1);
+       value = 0x80;
+       Et_RegWrite(dev, ET_G_BLUE, &value, 1);
+       value = 0x80;
+       Et_RegWrite(dev, ET_G_GREEN2, &value, 1);
+       value = 0x00;
+       Et_RegWrite(dev, ET_G_GR_H, &value, 1);
+       value = 0x00;
+       Et_RegWrite(dev, ET_G_GB_H, &value, 1); /* 0x52 */
+       /* Window control registers */
+
+       value = 0x80;           /* use cmc_out */
+       Et_RegWrite(dev, 0x61, &value, 1);
+
+       value = 0x02;
+       Et_RegWrite(dev, 0x62, &value, 1);
+       value = 0x03;
+       Et_RegWrite(dev, 0x63, &value, 1);
+       value = 0x14;
+       Et_RegWrite(dev, 0x64, &value, 1);
+       value = 0x0e;
+       Et_RegWrite(dev, 0x65, &value, 1);
+       value = 0x02;
+       Et_RegWrite(dev, 0x66, &value, 1);
+       value = 0x02;
+       Et_RegWrite(dev, 0x67, &value, 1);
+
+       /**************************************/
+       value = 0x8f;
+       Et_RegWrite(dev, ET_SYNCHRO, &value, 1);        /* 0x68 */
+       value = 0x69;           /* 0x6a //0x69 */
+       Et_RegWrite(dev, ET_STARTX, &value, 1);
+       value = 0x0d;           /* 0x0d //0x0c */
+       Et_RegWrite(dev, ET_STARTY, &value, 1);
+       value = 0x80;
+       Et_RegWrite(dev, ET_WIDTH_LOW, &value, 1);
+       value = 0xe0;
+       Et_RegWrite(dev, ET_HEIGTH_LOW, &value, 1);
+       value = 0x60;
+       Et_RegWrite(dev, ET_W_H_HEIGTH, &value, 1);     /* 6d */
+       value = 0x86;
+       Et_RegWrite(dev, ET_REG6e, &value, 1);
+       value = 0x01;
+       Et_RegWrite(dev, ET_REG6f, &value, 1);
+       value = 0x26;
+       Et_RegWrite(dev, ET_REG70, &value, 1);
+       value = 0x7a;
+       Et_RegWrite(dev, ET_REG71, &value, 1);
+       value = 0x01;
+       Et_RegWrite(dev, ET_REG72, &value, 1);
+       /* Clock Pattern registers ***************** */
+       value = 0x00;
+       Et_RegWrite(dev, ET_REG73, &value, 1);
+       value = 0x18;           /* 0x28 */
+       Et_RegWrite(dev, ET_REG74, &value, 1);
+       value = 0x0f;           /* 0x01 */
+       Et_RegWrite(dev, ET_REG75, &value, 1);
+       /**********************************************/
+       value = 0x20;
+       Et_RegWrite(dev, 0x8a, &value, 1);
+       value = 0x0f;
+       Et_RegWrite(dev, 0x8d, &value, 1);
+       value = 0x08;
+       Et_RegWrite(dev, 0x8e, &value, 1);
+       /**************************************/
+       value = 0x08;
+       Et_RegWrite(dev, 0x03, &value, 1);
+       value = 0x03;
+       Et_RegWrite(dev, ET_PXL_CLK, &value, 1);
+       value = 0xff;
+       Et_RegWrite(dev, 0x81, &value, 1);
+       value = 0x00;
+       Et_RegWrite(dev, 0x80, &value, 1);
+       value = 0xff;
+       Et_RegWrite(dev, 0x81, &value, 1);
+       value = 0x20;
+       Et_RegWrite(dev, 0x80, &value, 1);
+       value = 0x01;
+       Et_RegWrite(dev, 0x03, &value, 1);
+       value = 0x00;
+       Et_RegWrite(dev, 0x03, &value, 1);
+       value = 0x08;
+       Et_RegWrite(dev, 0x03, &value, 1);
+       /********************************************/
+
+       /* Et_RegRead(dev,0x0,ET_I2C_BASE,&received,1);
+                                        always 0x40 as the pas106 ??? */
+       /* set the sensor */
+       if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].mode) {
+               value = 0x04;   /* 320 */
+               Et_RegWrite(dev, ET_PXL_CLK, &value, 1);
+               /* now set by fifo the FormatLine setting */
+               Et_RegWrite(dev, 0x62, FormLine, 6);
+       } else {                /* 640 */
+               /* setting PixelClock
+                  0x03 mean 24/(3+1) = 6 Mhz
+                  0x05 -> 24/(5+1) = 4 Mhz
+                  0x0b -> 24/(11+1) = 2 Mhz
+                  0x17 -> 24/(23+1) = 1 Mhz
+                */
+               value = 0x1e;   /* 0x17 */
+               Et_RegWrite(dev, ET_PXL_CLK, &value, 1);
+               /* now set by fifo the FormatLine setting */
+               Et_RegWrite(dev, 0x62, FormLine, 6);
+       }
+
+       /* set exposure times [ 0..0x78] 0->longvalue 0x78->shortvalue */
+       value = 0x47;           /* 0x47; */
+       Et_RegWrite(dev, 0x81, &value, 1);
+       value = 0x40;           /* 0x40; */
+       Et_RegWrite(dev, 0x80, &value, 1);
+       /* Pedro change */
+       /* Brightness change Brith+ decrease value */
+       /* Brigth- increase value */
+       /* original value = 0x70; */
+       value = 0x30;           /* 0x20; */
+       Et_RegWrite(dev, 0x81, &value, 1);      /* set brightness */
+       value = 0x20;           /* 0x20; */
+       Et_RegWrite(dev, 0x80, &value, 1);
+}
+
+static void setcolors(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct usb_device *dev = gspca_dev->dev;
+       static __u8 I2cc[] = { 0x05, 0x02, 0x02, 0x05, 0x0d };
+       __u8 i2cflags = 0x01;
+       /* __u8 green = 0; */
+       __u8 colors = sd->colors;
+
+       I2cc[3] = colors;       /* red */
+       I2cc[0] = 15 - colors;  /* blue */
+       /* green = 15 - ((((7*I2cc[0]) >> 2 ) + I2cc[3]) >> 1); */
+       /* I2cc[1] = I2cc[2] = green; */
+       if (sd->sensor == SENSOR_PAS106) {
+               Et_i2cwrite(dev, PAS106_REG13, &i2cflags, 1, 3);
+               Et_i2cwrite(dev, PAS106_REG9, I2cc, sizeof(I2cc), 1);
+       }
+/*     PDEBUG(D_CONF , "Etoms red %d blue %d green %d",
+               I2cc[3], I2cc[0], green); */
+}
+
+static void getcolors(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       /* __u8 valblue = 0; */
+       __u8 valred;
+
+       if (sd->sensor == SENSOR_PAS106) {
+               /* Et_i2cread(gspca_dev->dev,PAS106_REG9,&valblue,1,1); */
+               Et_i2cread(gspca_dev->dev, PAS106_REG9 + 3, &valred, 1, 1);
+               sd->colors = valred & 0x0f;
+       }
+}
+
+static void Et_init1(struct gspca_dev *gspca_dev)
+{
+       struct usb_device *dev = gspca_dev->dev;
+       __u8 value = 0x00;
+       __u8 received = 0x00;
+/*     __u8 I2c0 [] ={0x0a,0x12,0x05,0x22,0xac,0x00,0x01,0x00}; */
+       __u8 I2c0[] = { 0x0a, 0x12, 0x05, 0x6d, 0xcd, 0x00, 0x01, 0x00 };
+                                               /* try 1/120 0x6d 0xcd 0x40 */
+/*     __u8 I2c0 [] ={0x0a,0x12,0x05,0xfe,0xfe,0xc0,0x01,0x00};
+                                                * 1/60000 hmm ?? */
+
+       PDEBUG(D_STREAM, "Open Init1 ET");
+       value = 7;
+       Et_RegWrite(dev, ET_GPIO_DIR_CTRL, &value, 1);
+       Et_RegRead(dev, ET_GPIO_IN, &received, 1);
+       value = 1;
+       Et_RegWrite(dev, ET_RESET_ALL, &value, 1);
+       value = 0;
+       Et_RegWrite(dev, ET_RESET_ALL, &value, 1);
+       value = 0x10;
+       Et_RegWrite(dev, ET_ClCK, &value, 1);
+       value = 0x19;
+       Et_RegWrite(dev, ET_CTRL, &value, 1);
+       /*   compression et subsampling */
+       if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].mode)
+               value = ET_COMP_VAL1;
+       else
+               value = ET_COMP_VAL0;
+
+       PDEBUG(D_STREAM, "Open mode %d Compression %d",
+              gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].mode,
+              value);
+       Et_RegWrite(dev, ET_COMP, &value, 1);
+       value = 0x1d;
+       Et_RegWrite(dev, ET_MAXQt, &value, 1);
+       value = 0x02;
+       Et_RegWrite(dev, ET_MINQt, &value, 1);
+       /* undocumented registers */
+       value = 0xff;
+       Et_RegWrite(dev, ET_REG1d, &value, 1);
+       value = 0xff;
+       Et_RegWrite(dev, ET_REG1e, &value, 1);
+       value = 0xff;
+       Et_RegWrite(dev, ET_REG1f, &value, 1);
+       value = 0x35;
+       Et_RegWrite(dev, ET_REG20, &value, 1);
+       value = 0x01;
+       Et_RegWrite(dev, ET_REG21, &value, 1);
+       value = 0x00;
+       Et_RegWrite(dev, ET_REG22, &value, 1);
+       value = 0xf7;
+       Et_RegWrite(dev, ET_REG23, &value, 1);
+       value = 0xff;
+       Et_RegWrite(dev, ET_REG24, &value, 1);
+       value = 0x07;
+       Et_RegWrite(dev, ET_REG25, &value, 1);
+       /* colors setting */
+       value = 0x80;
+       Et_RegWrite(dev, ET_G_RED, &value, 1);
+       value = 0x80;
+       Et_RegWrite(dev, ET_G_GREEN1, &value, 1);
+       value = 0x80;
+       Et_RegWrite(dev, ET_G_BLUE, &value, 1);
+       value = 0x80;
+       Et_RegWrite(dev, ET_G_GREEN2, &value, 1);
+       value = 0x00;
+       Et_RegWrite(dev, ET_G_GR_H, &value, 1);
+       value = 0x00;
+       Et_RegWrite(dev, ET_G_GB_H, &value, 1);
+       /* Window control registers */
+       value = 0xf0;
+       Et_RegWrite(dev, ET_SYNCHRO, &value, 1);
+       value = 0x56;           /* 0x56 */
+       Et_RegWrite(dev, ET_STARTX, &value, 1);
+       value = 0x05;           /* 0x04 */
+       Et_RegWrite(dev, ET_STARTY, &value, 1);
+       value = 0x60;
+       Et_RegWrite(dev, ET_WIDTH_LOW, &value, 1);
+       value = 0x20;
+       Et_RegWrite(dev, ET_HEIGTH_LOW, &value, 1);
+       value = 0x50;
+       Et_RegWrite(dev, ET_W_H_HEIGTH, &value, 1);
+       value = 0x86;
+       Et_RegWrite(dev, ET_REG6e, &value, 1);
+       value = 0x01;
+       Et_RegWrite(dev, ET_REG6f, &value, 1);
+       value = 0x86;
+       Et_RegWrite(dev, ET_REG70, &value, 1);
+       value = 0x14;
+       Et_RegWrite(dev, ET_REG71, &value, 1);
+       value = 0x00;
+       Et_RegWrite(dev, ET_REG72, &value, 1);
+       /* Clock Pattern registers */
+       value = 0x00;
+       Et_RegWrite(dev, ET_REG73, &value, 1);
+       value = 0x00;
+       Et_RegWrite(dev, ET_REG74, &value, 1);
+       value = 0x0a;
+       Et_RegWrite(dev, ET_REG75, &value, 1);
+       value = 0x04;
+       Et_RegWrite(dev, ET_I2C_CLK, &value, 1);
+       value = 0x01;
+       Et_RegWrite(dev, ET_PXL_CLK, &value, 1);
+       /* set the sensor */
+       if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].mode) {
+               I2c0[0] = 0x06;
+               Et_i2cwrite(dev, PAS106_REG2, I2c0, sizeof(I2c0), 1);
+               Et_i2cwrite(dev, PAS106_REG9, I2c2, sizeof(I2c2), 1);
+               value = 0x06;
+               Et_i2cwrite(dev, PAS106_REG2, &value, 1, 1);
+               Et_i2cwrite(dev, PAS106_REG3, I2c3, sizeof(I2c3), 1);
+               /* value = 0x1f; */
+               value = 0x04;
+               Et_i2cwrite(dev, PAS106_REG0e, &value, 1, 1);
+       } else {
+               I2c0[0] = 0x0a;
+
+               Et_i2cwrite(dev, PAS106_REG2, I2c0, sizeof(I2c0), 1);
+               Et_i2cwrite(dev, PAS106_REG9, I2c2, sizeof(I2c2), 1);
+               value = 0x0a;
+
+               Et_i2cwrite(dev, PAS106_REG2, &value, 1, 1);
+               Et_i2cwrite(dev, PAS106_REG3, I2c3, sizeof(I2c3), 1);
+               value = 0x04;
+               /* value = 0x10; */
+               Et_i2cwrite(dev, PAS106_REG0e, &value, 1, 1);
+               /* bit 2 enable bit 1:2 select 0 1 2 3
+                  value = 0x07;                                * curve 0 *
+                  Et_i2cwrite(dev,PAS106_REG0f,&value,1,1);
+                */
+       }
+
+/*     value = 0x01; */
+/*     value = 0x22; */
+/*     Et_i2cwrite(dev, PAS106_REG5, &value, 1, 1); */
+       /* magnetude and sign bit for DAC */
+       Et_i2cwrite(dev, PAS106_REG7, I2c4, sizeof I2c4, 1);
+       /* now set by fifo the whole colors setting */
+       Et_RegWrite(dev, ET_G_RED, GainRGBG, 6);
+       getcolors(gspca_dev);
+       setcolors(gspca_dev);
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+                    const struct usb_device_id *id)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct cam *cam;
+       __u16 vendor;
+       __u16 product;
+
+       vendor = id->idVendor;
+       product = id->idProduct;
+/*     switch (vendor) { */
+/*     case 0x102c:            * Etoms */
+               switch (product) {
+               case 0x6151:
+                       sd->sensor = SENSOR_PAS106;     /* Etoms61x151 */
+                       break;
+               case 0x6251:
+                       sd->sensor = SENSOR_TAS5130CXX; /* Etoms61x251 */
+                       break;
+/*             } */
+/*             break; */
+       }
+       cam = &gspca_dev->cam;
+       cam->dev_name = (char *) id->driver_info;
+       cam->epaddr = 1;
+       if (sd->sensor == SENSOR_PAS106) {
+               cam->cam_mode = sif_mode;
+               cam->nmodes = sizeof sif_mode / sizeof sif_mode[0];
+       } else {
+               cam->cam_mode = vga_mode;
+               cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+       }
+       sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
+       sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
+       sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value;
+       sd->autogain = sd_ctrls[SD_AUTOGAIN].qctrl.default_value;
+       return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct usb_device *dev = gspca_dev->dev;
+       int err;
+       __u8 value;
+
+       PDEBUG(D_STREAM, "Initialize ET1");
+       if (sd->sensor == SENSOR_PAS106)
+               Et_init1(gspca_dev);
+       else
+               Et_init2(gspca_dev);
+       value = 0x08;
+       Et_RegWrite(dev, ET_RESET_ALL, &value, 1);
+       err = Et_videoOff(dev);
+       PDEBUG(D_STREAM, "Et_Init_VideoOff %d", err);
+       return 0;
+}
+
+/* -- start the camera -- */
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct usb_device *dev = gspca_dev->dev;
+       int err;
+       __u8 value;
+
+       if (sd->sensor == SENSOR_PAS106)
+               Et_init1(gspca_dev);
+       else
+               Et_init2(gspca_dev);
+
+       value = 0x08;
+       Et_RegWrite(dev, ET_RESET_ALL, &value, 1);
+       err = Et_videoOn(dev);
+       PDEBUG(D_STREAM, "Et_VideoOn %d", err);
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+       int err;
+
+       err = Et_videoOff(gspca_dev->dev);
+       PDEBUG(D_STREAM, "Et_VideoOff %d", err);
+
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int i;
+       __u8 brightness = sd->brightness;
+
+       for (i = 0; i < 4; i++)
+               Et_RegWrite(gspca_dev->dev, (ET_O_RED + i), &brightness, 1);
+}
+
+static void getbrightness(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int i;
+       int brightness = 0;
+       __u8 value = 0;
+
+       for (i = 0; i < 4; i++) {
+               Et_RegRead(gspca_dev->dev, (ET_O_RED + i), &value, 1);
+               brightness += value;
+       }
+       sd->brightness = brightness >> 3;
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       __u8 RGBG[] = { 0x80, 0x80, 0x80, 0x80, 0x00, 0x00 };
+       __u8 contrast = sd->contrast;
+
+       memset(RGBG, contrast, sizeof RGBG - 2);
+       Et_RegWrite(gspca_dev->dev, ET_G_RED, RGBG, 6);
+}
+
+static void getcontrast(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int i;
+       int contrast = 0;
+       __u8 value = 0;
+
+       for (i = 0; i < 4; i++) {
+               Et_RegRead(gspca_dev->dev, (ET_G_RED + i), &value, 1);
+               contrast += value;
+       }
+       sd->contrast = contrast >> 2;
+}
+
+static __u8 Et_getgainG(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       __u8 value = 0;
+
+       if (sd->sensor == SENSOR_PAS106) {
+               Et_i2cread(gspca_dev->dev, PAS106_REG0e, &value, 1, 1);
+               PDEBUG(D_CONF, "Etoms gain G %d", value);
+               return value;
+       }
+       return 0x1f;
+}
+
+static void Et_setgainG(struct gspca_dev *gspca_dev, __u8 gain)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct usb_device *dev = gspca_dev->dev;
+       __u8 i2cflags = 0x01;
+
+       if (sd->sensor == SENSOR_PAS106) {
+               Et_i2cwrite(dev, PAS106_REG13, &i2cflags, 1, 3);
+               Et_i2cwrite(dev, PAS106_REG0e, &gain, 1, 1);
+       }
+}
+
+#define BLIMIT(bright) \
+       (__u8)((bright > 0x1f)?0x1f:((bright < 4)?3:bright))
+#define LIMIT(color) \
+       (unsigned char)((color > 0xff)?0xff:((color < 0)?0:color))
+
+static void setautogain(struct gspca_dev *gspca_dev)
+{
+       struct usb_device *dev = gspca_dev->dev;
+       __u8 GRBG[] = { 0, 0, 0, 0 };
+       __u8 luma = 0;
+       __u8 luma_mean = 128;
+       __u8 luma_delta = 20;
+       __u8 spring = 4;
+       int Gbright = 0;
+       __u8 r, g, b;
+
+       Gbright = Et_getgainG(gspca_dev);
+       Et_RegRead(dev, ET_LUMA_CENTER, GRBG, 4);
+       g = (GRBG[0] + GRBG[3]) >> 1;
+       r = GRBG[1];
+       b = GRBG[2];
+       r = ((r << 8) - (r << 4) - (r << 3)) >> 10;
+       b = ((b << 7) >> 10);
+       g = ((g << 9) + (g << 7) + (g << 5)) >> 10;
+       luma = LIMIT(r + g + b);
+       PDEBUG(D_FRAM, "Etoms luma G %d", luma);
+       if (luma < luma_mean - luma_delta || luma > luma_mean + luma_delta) {
+               Gbright += (luma_mean - luma) >> spring;
+               Gbright = BLIMIT(Gbright);
+               PDEBUG(D_FRAM, "Etoms Gbright %d", Gbright);
+               Et_setgainG(gspca_dev, (__u8) Gbright);
+       }
+}
+
+#undef BLIMIT
+#undef LIMIT
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+                       struct gspca_frame *frame,      /* target */
+                       unsigned char *data,            /* isoc packet */
+                       int len)                        /* iso packet length */
+{
+       struct sd *sd;
+       int seqframe;
+
+       seqframe = data[0] & 0x3f;
+       len = (int) (((data[0] & 0xc0) << 2) | data[1]);
+       if (seqframe == 0x3f) {
+               PDEBUG(D_FRAM,
+                      "header packet found datalength %d !!", len);
+               PDEBUG(D_FRAM, "G %d R %d G %d B %d",
+                      data[2], data[3], data[4], data[5]);
+               data += 30;
+               /* don't change datalength as the chips provided it */
+               frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+                                       data, 0);
+               gspca_frame_add(gspca_dev, FIRST_PACKET, frame, data, len);
+               sd = (struct sd *) gspca_dev;
+               if (sd->ag_cnt >= 0) {
+                       if (--sd->ag_cnt < 0) {
+                               sd->ag_cnt = AG_CNT_START;
+                               setautogain(gspca_dev);
+                       }
+               }
+               return;
+       }
+       if (len) {
+               data += 8;
+               gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+       } else {                        /* Drop Packet */
+               gspca_dev->last_packet_type = DISCARD_PACKET;
+       }
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->brightness = val;
+       if (gspca_dev->streaming)
+               setbrightness(gspca_dev);
+       return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       getbrightness(gspca_dev);
+       *val = sd->brightness;
+       return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->contrast = val;
+       if (gspca_dev->streaming)
+               setcontrast(gspca_dev);
+       return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       getcontrast(gspca_dev);
+       *val = sd->contrast;
+       return 0;
+}
+
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->colors = val;
+       if (gspca_dev->streaming)
+               setcolors(gspca_dev);
+       return 0;
+}
+
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       getcolors(gspca_dev);
+       *val = sd->colors;
+       return 0;
+}
+
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->autogain = val;
+       if (val)
+               sd->ag_cnt = AG_CNT_START;
+       else
+               sd->ag_cnt = -1;
+       return 0;
+}
+
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->autogain;
+       return 0;
+}
+
+/* sub-driver description */
+static struct sd_desc sd_desc = {
+       .name = MODULE_NAME,
+       .ctrls = sd_ctrls,
+       .nctrls = ARRAY_SIZE(sd_ctrls),
+       .config = sd_config,
+       .open = sd_open,
+       .start = sd_start,
+       .stopN = sd_stopN,
+       .stop0 = sd_stop0,
+       .close = sd_close,
+       .pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static __devinitdata struct usb_device_id device_table[] = {
+       {USB_DEVICE(0x102c, 0x6151), DVNM("Qcam Sangha CIF")},
+       {USB_DEVICE(0x102c, 0x6251), DVNM("Qcam xxxxxx VGA")},
+       {}
+};
+
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+                   const struct usb_device_id *id)
+{
+       return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+                              THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+       .name = MODULE_NAME,
+       .id_table = device_table,
+       .probe = sd_probe,
+       .disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+       if (usb_register(&sd_driver) < 0)
+               return -1;
+       PDEBUG(D_PROBE, "v%s registered", version);
+       return 0;
+}
+
+static void __exit sd_mod_exit(void)
+{
+       usb_deregister(&sd_driver);
+       PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
index 423ebbdc4b4f2995b334595acfa0b959986162e6..5583c53e48631e9fbdbf3c87b9023f753ec0c35c 100644 (file)
 
 #include "gspca.h"
 
-/* option */
-#define GSPCA_HLP 0
+#undef CONFIG_VIDEO_V4L1_COMPAT
 
 /* global values */
 #define DEF_NURBS 2            /* default number of URBs (mmap) */
+#define USR_NURBS 5            /* default number of URBs (userptr) */
 
 MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>");
 MODULE_DESCRIPTION("GSPCA USB Camera Driver");
 MODULE_LICENSE("GPL");
 
-#define DRIVER_VERSION_NUMBER  KERNEL_VERSION(0, 2, 15)
-static const char version[] = "0.2.15";
+#define DRIVER_VERSION_NUMBER  KERNEL_VERSION(2, 1, 0)
+static const char version[] = "2.1.0";
 
 static int video_nr = -1;
 
 static int comp_fac = 30;      /* Buffer size ratio when compressed in % */
 
-#ifdef GSPCA_DEBUG
+#ifdef VIDEO_ADV_DEBUG
 int gspca_debug = D_ERR | D_PROBE;
 EXPORT_SYMBOL(gspca_debug);
 
@@ -81,224 +81,7 @@ static void PDEBUG_MODE(char *txt, __u32 pixfmt, int w, int h)
 #define GSPCA_MEMORY_NO 0      /* V4L2_MEMORY_xxx starts from 1 */
 #define GSPCA_MEMORY_READ 7
 
-#ifndef GSPCA_HLP
 #define BUF_ALL_FLAGS (V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE)
-#else
-#define GSPCA_BUF_FLAG_DECODE  0x1000  /* internal buffer flag */
-#define BUF_ALL_FLAGS (V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE \
-                       | GSPCA_BUF_FLAG_DECODE)
-
-static int autostart = 4;
-module_param(autostart, int, 0644);
-MODULE_PARM_DESC(autostart,
-               "Automatically start the helper process");
-
-/* try to start the helper process */
-static void start_hlp(void)
-{
-       int ret;
-       static char *argv[] = {"gspca_hlp", NULL};
-       static char *env[] = {NULL};
-
-       if (autostart <= 0) {
-               if (autostart < 0)
-                       PDEBUG(D_ERR|D_PROBE, "Too many helper restart");
-               return;
-       }
-       autostart--;
-       if (autostart == 0)
-               autostart = -1;
-       ret = call_usermodehelper("/sbin/gspca_hlp", argv, env,
-                               UMH_WAIT_EXEC);
-       if (ret != 0)
-               PDEBUG(D_ERR|D_PROBE,
-                       "/sbin/gspca_hlp start failed %d", ret);
-}
-
-/* /dev/gspca_hlp stuff */
-#include <linux/miscdevice.h>
-#include "gspca_hlp.h"
-
-/* !! possible decodings defined in decoder.c */
-static __u32 bayer_to_tb[] = {
-       V4L2_PIX_FMT_SBGGR8,
-       V4L2_PIX_FMT_YUYV,
-       V4L2_PIX_FMT_YUV420,
-       V4L2_PIX_FMT_RGB24,
-       V4L2_PIX_FMT_BGR24,
-       V4L2_PIX_FMT_RGB565,
-};
-static __u32 jpeg_to_tb[] = {
-       V4L2_PIX_FMT_JPEG,
-       V4L2_PIX_FMT_YUYV,
-       V4L2_PIX_FMT_YUV420,
-       V4L2_PIX_FMT_RGB24,
-       V4L2_PIX_FMT_BGR24,
-       V4L2_PIX_FMT_RGB565,
-};
-
-/* /dev/gspca_hlp device */
-struct hlp_dev {
-       struct gspca_dev *gspca_dev;    /* associated device */
-       struct gspca_frame *frame;      /* frame being decoded */
-       __u32 pixfmt;                   /* webcam pixel format */
-       atomic_t nevent;                /* nb of frames ready to decode */
-       wait_queue_head_t wq;           /* wait queue */
-       char fr_d;                      /* next frame to decode */
-} *hlp;
-
-static int hlp_open(struct inode *inode, struct file *file)
-{
-       struct hlp_dev *hlp_dev;
-
-       PDEBUG(D_CONF, "hlp open");
-       if (hlp != 0)
-               return -EBUSY;
-       hlp_dev = kzalloc(sizeof *hlp_dev, GFP_KERNEL);
-       if (hlp_dev == NULL) {
-               err("couldn't kzalloc hlp struct");
-               return -EIO;
-       }
-       init_waitqueue_head(&hlp_dev->wq);
-       file->private_data = hlp_dev;
-       hlp = hlp_dev;
-       return 0;
-}
-
-static int hlp_close(struct inode *inode, struct file *file)
-{
-       struct gspca_dev *gspca_dev;
-       int mode;
-
-       PDEBUG(D_CONF, "hlp close");
-       file->private_data = NULL;
-
-       /* stop decoding */
-       gspca_dev = hlp->gspca_dev;
-       if (gspca_dev != 0) {
-               mode = gspca_dev->curr_mode;
-               gspca_dev->pixfmt = gspca_dev->cam.cam_mode[mode].pixfmt;
-       }
-
-       /* destroy the helper structure */
-       kfree(hlp);
-       hlp = 0;
-
-       /* try to restart the helper process */
-       start_hlp();
-       return 0;
-}
-
-static ssize_t hlp_read(struct file *file, char __user *buf,
-                   size_t cnt, loff_t *ppos)
-{
-       struct hlp_dev *hlp_dev = file->private_data;
-       struct gspca_dev *gspca_dev;
-       struct gspca_frame *frame;
-       struct gspca_hlp_read_hd head;
-       int i, j, len, ret;
-
-       PDEBUG(D_FRAM, "hlp read (%d)", cnt);
-
-       /* check / wait till a frame is ready */
-       for (;;) {
-               gspca_dev = hlp_dev->gspca_dev;
-               if (gspca_dev != 0 && gspca_dev->streaming) {
-                       i = hlp_dev->fr_d;      /* frame to decode */
-                       j = gspca_dev->fr_queue[i];
-                       frame = &gspca_dev->frame[j];
-                       if (frame->v4l2_buf.flags & GSPCA_BUF_FLAG_DECODE)
-                               break;
-               }
-               ret = wait_event_interruptible(hlp_dev->wq,
-                                       atomic_read(&hlp_dev->nevent) > 0);
-               if (ret < 0) {                  /* helper process is killed */
-                       autostart = 0;          /* don't restart it */
-                       return ret;
-               }
-       }
-       atomic_dec(&hlp_dev->nevent);
-       hlp_dev->fr_d = (i + 1) % gspca_dev->nframes;
-       PDEBUG(D_FRAM, "hlp read q:%d i:%d d:%d o:%d",
-               gspca_dev->fr_q,
-               gspca_dev->fr_i,
-               hlp_dev->fr_d,
-               gspca_dev->fr_o);
-
-       hlp_dev->frame = frame;         /* memorize the current frame */
-       len = frame->v4l2_buf.bytesused;
-       if (cnt < sizeof head - sizeof head.data + len)
-/*fixme: special errno?*/
-               return -EINVAL;
-       head.pixfmt_out = gspca_dev->pixfmt;
-       head.pixfmt_in = hlp_dev->pixfmt;
-       head.width = gspca_dev->width;
-       head.height = gspca_dev->height;
-       copy_to_user(buf, &head, sizeof head);
-       copy_to_user(buf + sizeof head - sizeof head.data,
-                       frame->data, len);
-       return sizeof head - sizeof head.data + len;
-}
-
-static ssize_t hlp_write(struct file *file,
-                       const char __user *buf,
-                       size_t cnt, loff_t *ppos)
-{
-       struct hlp_dev *hlp_dev = file->private_data;
-       struct gspca_dev *gspca_dev;
-       struct gspca_frame *frame;
-
-       PDEBUG(D_FRAM, "hlp write (%d)", cnt);
-       gspca_dev = hlp_dev->gspca_dev;
-       if (gspca_dev == 0)
-               return cnt;
-       if (mutex_lock_interruptible(&gspca_dev->queue_lock))
-               return -ERESTARTSYS;
-       if (!gspca_dev->streaming)
-               goto out;
-       frame = hlp_dev->frame;
-       hlp_dev->frame = 0;
-       if (frame == 0)
-               goto out;
-       if (cnt > frame->v4l2_buf.length) {
-               PDEBUG(D_ERR|D_FRAM, "bad frame size %d - %d",
-                       cnt, frame->v4l2_buf.length);
-               cnt = -EINVAL;
-               goto out;
-       }
-       copy_from_user(frame->data, buf, cnt);
-       frame->v4l2_buf.bytesused = cnt;
-       frame->v4l2_buf.flags &= ~(V4L2_BUF_FLAG_QUEUED
-                                 | GSPCA_BUF_FLAG_DECODE);
-       frame->v4l2_buf.flags |= V4L2_BUF_FLAG_DONE;
-       mutex_unlock(&gspca_dev->queue_lock);
-       atomic_inc(&gspca_dev->nevent);
-       wake_up_interruptible(&gspca_dev->wq);  /* event = new frame */
-       PDEBUG(D_FRAM, "hlp write q:%d i:%d d:%d o:%d",
-               gspca_dev->fr_q,
-               gspca_dev->fr_i,
-               hlp_dev->fr_d,
-               gspca_dev->fr_o);
-       return cnt;
-out:
-       mutex_unlock(&gspca_dev->queue_lock);
-       return cnt;
-}
-
-static struct file_operations hlp_fops = {
-       .owner = THIS_MODULE,
-       .open = hlp_open,
-       .release = hlp_close,
-       .read = hlp_read,
-       .write = hlp_write,
-       .llseek = no_llseek
-};
-static struct miscdevice hlp_device = {
-       .minor = MISC_DYNAMIC_MINOR,
-       .name = "gspca_hlp",
-       .fops = &hlp_fops,
-};
-#endif
 
 /*
  * VMA operations.
@@ -331,10 +114,14 @@ static void fill_frame(struct gspca_dev *gspca_dev,
                        struct urb *urb)
 {
        struct gspca_frame *frame;
-       unsigned char *data;    /* address of data in the iso message */
+       __u8 *data;             /* address of data in the iso message */
        int i, j, len, st;
        cam_pkt_op pkt_scan;
 
+       if (urb->status != 0) {
+               PDEBUG(D_ERR|D_PACK, "urb status: %d", urb->status);
+               return;         /* disconnection ? */
+       }
        pkt_scan = gspca_dev->sd_desc->pkt_scan;
        for (i = 0; i < urb->number_of_packets; i++) {
 
@@ -350,20 +137,21 @@ static void fill_frame(struct gspca_dev *gspca_dev,
 
                /* check the packet status and length */
                len = urb->iso_frame_desc[i].actual_length;
+               if (len == 0)
+                       continue;
                st = urb->iso_frame_desc[i].status;
                if (st) {
-                       PDEBUG(D_ERR, "ISOC data error: [%d] len=%d, status=%d",
+                       PDEBUG(D_ERR,
+                               "ISOC data error: [%d] len=%d, status=%d",
                                i, len, st);
                        gspca_dev->last_packet_type = DISCARD_PACKET;
                        continue;
                }
-               if (len == 0)
-                       continue;
 
                /* let the packet be analyzed by the subdriver */
                PDEBUG(D_PACK, "packet [%d] o:%d l:%d",
                        i, urb->iso_frame_desc[i].offset, len);
-               data = (unsigned char *) urb->transfer_buffer
+               data = (__u8 *) urb->transfer_buffer
                                        + urb->iso_frame_desc[i].offset;
                pkt_scan(gspca_dev, frame, data, len);
        }
@@ -390,7 +178,8 @@ static void fill_frame(struct gspca_dev *gspca_dev,
  *       buffers are in user space (userptr). The frame detection
  *       and copy is done by the application.
  */
-static void isoc_irq_mmap(struct urb *urb)
+static void isoc_irq_mmap(struct urb *urb
+)
 {
        struct gspca_dev *gspca_dev = (struct gspca_dev *) urb->context;
 
@@ -400,7 +189,8 @@ static void isoc_irq_mmap(struct urb *urb)
        fill_frame(gspca_dev, urb);
 }
 
-static void isoc_irq_user(struct urb *urb)
+static void isoc_irq_user(struct urb *urb
+)
 {
        struct gspca_dev *gspca_dev = (struct gspca_dev *) urb->context;
        int i;
@@ -459,7 +249,7 @@ static void isoc_transfer(struct gspca_dev *gspca_dev)
 struct gspca_frame *gspca_frame_add(struct gspca_dev *gspca_dev,
                                    int packet_type,
                                    struct gspca_frame *frame,
-                                   unsigned char *data,
+                                   __u8 *data,
                                    int len)
 {
        int i, j;
@@ -503,23 +293,10 @@ struct gspca_frame *gspca_frame_add(struct gspca_dev *gspca_dev,
        /* if last packet, wake the application and advance in the queue */
        if (packet_type == LAST_PACKET) {
                frame->v4l2_buf.bytesused = frame->data_end - frame->data;
-#ifndef GSPCA_HLP
                frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_QUEUED;
                frame->v4l2_buf.flags |= V4L2_BUF_FLAG_DONE;
                atomic_inc(&gspca_dev->nevent);
                wake_up_interruptible(&gspca_dev->wq);  /* event = new frame */
-#else /*GSPCA_HLP*/
-               if (hlp != 0 && hlp->gspca_dev == gspca_dev) {
-                       frame->v4l2_buf.flags |= GSPCA_BUF_FLAG_DECODE;
-                       atomic_inc(&hlp->nevent);
-                       wake_up_interruptible(&hlp->wq);
-               } else {
-                       frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_QUEUED;
-                       frame->v4l2_buf.flags |= V4L2_BUF_FLAG_DONE;
-                       atomic_inc(&gspca_dev->nevent);
-                       wake_up_interruptible(&gspca_dev->wq);  /* new frame */
-               }
-#endif /*GSPCA_HLP*/
                i = (gspca_dev->fr_i + 1) % gspca_dev->nframes;
                gspca_dev->fr_i = i;
                PDEBUG(D_FRAM, "frame complete len:%d q:%d i:%d o:%d",
@@ -581,13 +358,13 @@ static void rvfree(void *mem, unsigned long size)
 static __u32 get_v4l2_depth(__u32 pixfmt)
 {
        switch (pixfmt) {
-       case V4L2_PIX_FMT_BGR32:
+/*     case V4L2_PIX_FMT_BGR32:
        case V4L2_PIX_FMT_RGB32:
-               return 32;
+               return 32; */
        case V4L2_PIX_FMT_RGB24:        /* 'RGB3' */
        case V4L2_PIX_FMT_BGR24:
                return 24;
-       case V4L2_PIX_FMT_RGB565:       /* 'RGBP' */
+/*     case V4L2_PIX_FMT_RGB565:        * 'RGBP' */
        case V4L2_PIX_FMT_YUYV:         /* 'YUYV' packed 4.2.2 */
        case V4L2_PIX_FMT_YYUV:         /* 'YYUV' */
                return 16;
@@ -596,6 +373,9 @@ static __u32 get_v4l2_depth(__u32 pixfmt)
        case V4L2_PIX_FMT_MJPEG:
        case V4L2_PIX_FMT_JPEG:
        case V4L2_PIX_FMT_SBGGR8:       /* 'BA81' Bayer */
+       case V4L2_PIX_FMT_SN9C10X:      /* 'S910' SN9C10x compression */
+       case V4L2_PIX_FMT_SPCA501:      /* 'S501' YUYV per line */
+       case V4L2_PIX_FMT_SPCA561:      /* 'S561' compressed BGGR bayer */
                return 8;
        }
        PDEBUG(D_ERR|D_CONF, "Unknown pixel format %c%c%c%c",
@@ -603,7 +383,7 @@ static __u32 get_v4l2_depth(__u32 pixfmt)
                (pixfmt >> 8) & 0xff,
                (pixfmt >> 16) & 0xff,
                pixfmt >> 24);
-       return -EINVAL;
+       return 24;
 }
 
 static int gspca_get_buff_size(struct gspca_dev *gspca_dev)
@@ -632,7 +412,7 @@ static int frame_alloc(struct gspca_dev *gspca_dev,
                count = GSPCA_MAX_FRAMES;
        /* if compressed (JPEG), reduce the buffer size */
        if (gspca_is_compressed(gspca_dev->pixfmt))
-               frsz = (frsz * comp_fac) / 100 + 600;   /* plus JPEG header */
+               frsz = (frsz * comp_fac) / 100 + 600; /* (+ JPEG header sz) */
        frsz = PAGE_ALIGN(frsz);
        PDEBUG(D_STREAM, "new fr_sz: %d", frsz);
        gspca_dev->frsz = frsz;
@@ -660,17 +440,6 @@ static int frame_alloc(struct gspca_dev *gspca_dev,
                }
        }
        gspca_dev->fr_i = gspca_dev->fr_o = gspca_dev->fr_q = 0;
-#ifdef GSPCA_HLP
-       {
-               struct hlp_dev *hlp_dev;
-
-               hlp_dev = hlp;
-               if (hlp != 0 && hlp_dev->gspca_dev == gspca_dev) {
-                       hlp_dev->fr_d = 0;
-                       atomic_set(&hlp_dev->nevent, 0);
-               }
-       }
-#endif /*GSPCA_HLP*/
        gspca_dev->last_packet_type = DISCARD_PACKET;
        gspca_dev->sequence = 0;
        atomic_set(&gspca_dev->nevent, 0);
@@ -752,13 +521,14 @@ struct usb_host_endpoint *get_isoc_ep(struct gspca_dev *gspca_dev)
        int i, ret;
 
        intf = usb_ifnum_to_if(gspca_dev->dev, gspca_dev->iface);
+       ep = NULL;
        i = gspca_dev->alt;                     /* previous alt setting */
        while (--i > 0) {                       /* alt 0 is unusable */
                ep = alt_isoc(&intf->altsetting[i], gspca_dev->cam.epaddr);
                if (ep)
                        break;
        }
-       if (i <= 0) {
+       if (ep == NULL) {
                err("no ISOC endpoint found");
                return NULL;
        }
@@ -796,11 +566,14 @@ static int create_urbs(struct gspca_dev *gspca_dev,
                "isoc %d pkts size %d (bsize:%d)", npkt, psize, bsize);
 /*fixme:change for userptr*/
 /*fixme:don't submit all URBs when userptr*/
-       gspca_dev->nurbs = nurbs = DEF_NURBS;
-       if (gspca_dev->memory == V4L2_MEMORY_MMAP)
+       if (gspca_dev->memory == V4L2_MEMORY_MMAP) {
                usb_complete = isoc_irq_mmap;
-       else
+               nurbs = DEF_NURBS;
+       } else {
                usb_complete = isoc_irq_user;
+               nurbs = USR_NURBS;
+       }
+       gspca_dev->nurbs = nurbs;
        for (n = 0; n < nurbs; n++) {
                urb = usb_alloc_urb(npkt, GFP_KERNEL);
                if (!urb) {
@@ -904,16 +677,6 @@ static void gspca_stream_off(struct gspca_dev *gspca_dev)
 {
        gspca_dev->streaming = 0;
        atomic_set(&gspca_dev->nevent, 0);
-#ifdef GSPCA_HLP
-       {
-               struct hlp_dev *hlp_dev;
-
-               hlp_dev = hlp;
-               if (hlp_dev != 0
-                   && hlp_dev->gspca_dev == gspca_dev)
-                       atomic_set(&hlp_dev->nevent, 0);
-       }
-#endif
        if (gspca_dev->present) {
                gspca_dev->sd_desc->stopN(gspca_dev);
                destroy_urbs(gspca_dev);
@@ -979,15 +742,11 @@ static int vidioc_enum_fmt_cap(struct file *file, void  *priv,
                                struct v4l2_fmtdesc *fmtdesc)
 {
        struct gspca_dev *gspca_dev = priv;
-       int i;
-#ifndef GSPCA_HLP
-       int j, index;
+       int i, j, index;
        __u32 fmt_tb[8];
-#endif
 
        PDEBUG(D_CONF, "enum fmt cap");
 
-#ifndef GSPCA_HLP
        /* give an index to each format */
        index = 0;
        j = 0;
@@ -1013,36 +772,6 @@ static int vidioc_enum_fmt_cap(struct file *file, void  *priv,
        fmtdesc->pixelformat = fmt_tb[index];
        if (gspca_is_compressed(fmt_tb[index]))
                fmtdesc->flags = V4L2_FMT_FLAG_COMPRESSED;
-#else /*GSPCA_HLP*/
-       /* !! code tied to the decoding functions in decoder.c */
-       i = gspca_dev->cam.nmodes - 1;
-       if (fmtdesc->index == 0) {      /* (assume one format per subdriver) */
-               fmtdesc->pixelformat = gspca_dev->cam.cam_mode[i].pixfmt;
-               if (gspca_is_compressed(fmtdesc->pixelformat))
-                       fmtdesc->flags = V4L2_FMT_FLAG_COMPRESSED;
-       } else {
-               if (hlp == 0
-                   || (hlp->gspca_dev != 0
-                       && hlp->gspca_dev != gspca_dev))
-                       return -EINVAL;
-               switch (gspca_dev->cam.cam_mode[i].pixfmt) {
-               case V4L2_PIX_FMT_JPEG:
-                       if (fmtdesc->index >= sizeof jpeg_to_tb
-                                                / sizeof jpeg_to_tb[0])
-                               return -EINVAL;
-                       fmtdesc->pixelformat = jpeg_to_tb[fmtdesc->index];
-                       break;
-               case V4L2_PIX_FMT_SBGGR8:
-                       if (fmtdesc->index >= sizeof bayer_to_tb
-                                                / sizeof bayer_to_tb[0])
-                               return -EINVAL;
-                       fmtdesc->pixelformat = bayer_to_tb[fmtdesc->index];
-                       break;
-               default:
-                       return -EINVAL;
-               }
-       }
-#endif /*GSPCA_HLP*/
        fmtdesc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        fmtdesc->description[0] = fmtdesc->pixelformat & 0xff;
        fmtdesc->description[1] = (fmtdesc->pixelformat >> 8) & 0xff;
@@ -1057,25 +786,12 @@ static int vidioc_g_fmt_cap(struct file *file, void *priv,
 {
        struct gspca_dev *gspca_dev = priv;
 
-#ifdef GSPCA_HLP
-       int i;
-
-       /* if the pixel format is not the one of the device and
-        * if the helper is inactive or busy, restore */
-       i = gspca_dev->curr_mode;
-       if (gspca_dev->pixfmt != gspca_dev->cam.cam_mode[i].pixfmt) {
-               struct hlp_dev *hlp_dev;
-
-               hlp_dev = hlp;
-               if (hlp_dev == 0 || hlp_dev->gspca_dev != gspca_dev)
-                       gspca_dev->pixfmt = gspca_dev->cam.cam_mode[i].pixfmt;
-       }
-#endif /*GSPCA_HLP*/
-
+       if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
        fmt->fmt.pix.width = gspca_dev->width;
        fmt->fmt.pix.height = gspca_dev->height;
        fmt->fmt.pix.pixelformat = gspca_dev->pixfmt;
-#ifdef GSPCA_DEBUG
+#ifdef VIDEO_ADV_DEBUG
        if (gspca_debug & D_CONF) {
                PDEBUG_MODE("get fmt cap",
                        fmt->fmt.pix.pixelformat,
@@ -1099,13 +815,15 @@ static int try_fmt_cap(struct gspca_dev *gspca_dev,
 {
        int w, h, mode, mode2, frsz;
 
+       if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
        w = fmt->fmt.pix.width;
        h = fmt->fmt.pix.height;
 
        /* (luvcview problem) */
        if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG)
                fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_JPEG;
-#ifdef GSPCA_DEBUG
+#ifdef VIDEO_ADV_DEBUG
        if (gspca_debug & D_CONF)
                PDEBUG_MODE("try fmt cap", fmt->fmt.pix.pixelformat, w, h);
 #endif
@@ -1121,44 +839,11 @@ static int try_fmt_cap(struct gspca_dev *gspca_dev,
                if (mode2 >= 0) {
                        mode = mode2;
                } else {
-                       __u32 pixfmt;
-
-                       pixfmt = gspca_dev->cam.cam_mode[mode].pixfmt;
-#ifndef GSPCA_HLP
 
                        /* no chance, return this mode */
-                       fmt->fmt.pix.pixelformat = pixfmt;
-#else /*GSPCA_HLP*/
-                       if (hlp != 0
-                           && (hlp->gspca_dev == 0
-                               || hlp->gspca_dev == gspca_dev)
-/* decoding works for JPEG and Bayer only */
-                           && (pixfmt == V4L2_PIX_FMT_JPEG
-                               || pixfmt == V4L2_PIX_FMT_SBGGR8)) {
-                               switch (fmt->fmt.pix.pixelformat) {
-                               case V4L2_PIX_FMT_YUYV:         /* 'YUYV' */
-                               case V4L2_PIX_FMT_BGR24:        /* 'BGR3' */
-                               case V4L2_PIX_FMT_RGB24:        /* 'RGB3' */
-                               case V4L2_PIX_FMT_YUV420:       /* 'YU12' */
-                               case V4L2_PIX_FMT_RGB565:       /* 'RGBP' */
-                                       break;
-                               default: {
-                                       /* return any of the supported fmt's */
-                                       __u8 u;
-
-                                       u = get_jiffies_64();
-                                       u %= sizeof bayer_to_tb
-                                               / sizeof bayer_to_tb[0] - 1;
-                                       fmt->fmt.pix.pixelformat =
-                                                       bayer_to_tb[u + 1];
-                                       break;
-                                   }
-                               }
-                       } else {
-                               fmt->fmt.pix.pixelformat = pixfmt;
-                       }
-#endif /*GSPCA_HLP*/
-#ifdef GSPCA_DEBUG
+                       fmt->fmt.pix.pixelformat =
+                                       gspca_dev->cam.cam_mode[mode].pixfmt;
+#ifdef VIDEO_ADV_DEBUG
                        if (gspca_debug & D_CONF) {
                                PDEBUG_MODE("new format",
                                        fmt->fmt.pix.pixelformat,
@@ -1198,7 +883,17 @@ static int vidioc_s_fmt_cap(struct file *file, void *priv,
        struct gspca_dev *gspca_dev = priv;
        int ret;
 
-#ifdef GSPCA_DEBUG
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+       /* if v4l1 got JPEG */
+       if (fmt->fmt.pix.pixelformat == 0
+           && gspca_dev->streaming) {
+               fmt->fmt.pix.width = gspca_dev->width;
+               fmt->fmt.pix.height = gspca_dev->height;
+               fmt->fmt.pix.pixelformat = gspca_dev->pixfmt;
+               return 0;
+       }
+#endif
+#ifdef VIDEO_ADV_DEBUG
        if (gspca_debug & D_CONF) {
                PDEBUG_MODE("set fmt cap",
                        fmt->fmt.pix.pixelformat,
@@ -1218,14 +913,8 @@ static int vidioc_s_fmt_cap(struct file *file, void *priv,
                goto out;
        }
 
-#ifndef GSPCA_HLP
        if (ret == gspca_dev->curr_mode)
                goto out;                       /* same mode */
-#else /*GSPCA_HLP*/
-       if (ret == gspca_dev->curr_mode
-           && gspca_dev->pixfmt == fmt->fmt.pix.pixelformat)
-               goto out;                       /* same mode */
-#endif /*GSPCA_HLP*/
 
        if (gspca_dev->streaming) {
                ret = -EBUSY;
@@ -1236,26 +925,6 @@ static int vidioc_s_fmt_cap(struct file *file, void *priv,
        gspca_dev->pixfmt = fmt->fmt.pix.pixelformat;
        gspca_dev->curr_mode = ret;
 
-#ifdef GSPCA_HLP
-       /* if frame decoding is required */
-       if (gspca_dev->pixfmt != gspca_dev->cam.cam_mode[ret].pixfmt) {
-               struct hlp_dev *hlp_dev;
-
-               hlp_dev = hlp;
-               if (hlp_dev == 0
-                   || (hlp_dev->gspca_dev != 0
-                       && hlp_dev->gspca_dev != gspca_dev)) { /* helper busy */
-                       fmt->fmt.pix.pixelformat =
-                               gspca_dev->pixfmt =
-                                       gspca_dev->cam.cam_mode[ret].pixfmt;
-               } else {                                /* helper active */
-                       hlp_dev->gspca_dev = gspca_dev;
-                       hlp_dev->pixfmt = gspca_dev->cam.cam_mode[ret].pixfmt;
-                       hlp_dev->fr_d = gspca_dev->fr_i;
-               }
-       } else if (hlp != 0 && hlp->gspca_dev == gspca_dev)
-               hlp->gspca_dev = 0;
-#endif /*GSPCA_HLP*/
        ret = 0;
 out:
        mutex_unlock(&gspca_dev->queue_lock);
@@ -1294,7 +963,7 @@ static int dev_open(struct inode *inode, struct file *file)
        }
        gspca_dev->users++;
        file->private_data = gspca_dev;
-#ifdef GSPCA_DEBUG
+#ifdef VIDEO_ADV_DEBUG
        /* activate the v4l2 debug */
        if (gspca_debug & D_V4L2)
                gspca_dev->vdev.debug |= 3;
@@ -1329,22 +998,6 @@ static int dev_close(struct inode *inode, struct file *file)
                frame_free(gspca_dev);
                gspca_dev->capt_file = 0;
                gspca_dev->memory = GSPCA_MEMORY_NO;
-#ifdef GSPCA_HLP
-               {
-                       struct hlp_dev *hlp_dev;
-                       int mode;
-
-                       hlp_dev = hlp;
-                       if (hlp_dev != 0
-                           && hlp_dev->gspca_dev == gspca_dev) {
-                               hlp_dev->gspca_dev = 0;
-                               hlp_dev->frame = 0;
-                               mode = gspca_dev->curr_mode;
-                               gspca_dev->pixfmt =
-                                       gspca_dev->cam.cam_mode[mode].pixfmt;
-                       }
-               }
-#endif /*GSPCA_HLP*/
        }
        file->private_data = NULL;
        mutex_unlock(&gspca_dev->queue_lock);
@@ -1370,23 +1023,38 @@ static int vidioc_querycap(struct file *file, void  *priv,
        return 0;
 }
 
+/* the use of V4L2_CTRL_FLAG_NEXT_CTRL asks for the controls to be sorted */
 static int vidioc_queryctrl(struct file *file, void *priv,
                           struct v4l2_queryctrl *q_ctrl)
 {
        struct gspca_dev *gspca_dev = priv;
        int i;
-
-       PDEBUG(D_CONF, "queryctrl");
+       u32 id;
+
+       id = q_ctrl->id;
+       if (id & V4L2_CTRL_FLAG_NEXT_CTRL) {
+               id &= V4L2_CTRL_ID_MASK;
+               id++;
+               for (i = 0; i < gspca_dev->sd_desc->nctrls; i++) {
+                       if (id >= gspca_dev->sd_desc->ctrls[i].qctrl.id) {
+                               memcpy(q_ctrl,
+                                       &gspca_dev->sd_desc->ctrls[i].qctrl,
+                                       sizeof *q_ctrl);
+                               return 0;
+                       }
+               }
+               return -EINVAL;
+       }
        for (i = 0; i < gspca_dev->sd_desc->nctrls; i++) {
-               if (q_ctrl->id == gspca_dev->sd_desc->ctrls[i].qctrl.id) {
+               if (id == gspca_dev->sd_desc->ctrls[i].qctrl.id) {
                        memcpy(q_ctrl,
                                &gspca_dev->sd_desc->ctrls[i].qctrl,
                                sizeof *q_ctrl);
                        return 0;
                }
        }
-       if (q_ctrl->id >= V4L2_CID_BASE
-           && q_ctrl->id <= V4L2_CID_LASTP1) {
+       if (id >= V4L2_CID_BASE
+           && id <= V4L2_CID_LASTP1) {
                q_ctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
                return 0;
        }
@@ -1489,13 +1157,8 @@ static int vidioc_reqbufs(struct file *file, void *priv,
                return -EINVAL;
        switch (rb->memory) {
        case V4L2_MEMORY_MMAP:
-               break;
        case V4L2_MEMORY_USERPTR:
-#ifdef GSPCA_HLP
-               if (hlp == 0 || hlp->gspca_dev != gspca_dev)
-                       break;
-#endif
-               return -EINVAL;
+               break;
        default:
                return -EINVAL;
        }
@@ -1578,7 +1241,7 @@ static int vidioc_streamon(struct file *file, void *priv,
                if (ret < 0)
                        goto out;
        }
-#ifdef GSPCA_DEBUG
+#ifdef VIDEO_ADV_DEBUG
        if (gspca_debug & D_STREAM) {
                PDEBUG_MODE("stream on OK",
                        gspca_dev->pixfmt,
@@ -1657,7 +1320,7 @@ static int vidioc_g_parm(struct file *filp, void *priv,
 {
        struct gspca_dev *gspca_dev = priv;
 
-       memset(parm, 0, sizeof parm);
+       memset(parm, 0, sizeof *parm);
        parm->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        parm->parm.capture.readbuffers = gspca_dev->nbufread;
        return 0;
@@ -1677,6 +1340,12 @@ static int vidioc_s_parm(struct file *filp, void *priv,
        return 0;
 }
 
+static int vidioc_s_std(struct file *filp, void *priv,
+                       v4l2_std_id *parm)
+{
+       return 0;
+}
+
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
 static int vidiocgmbuf(struct file *file, void *priv,
                        struct video_mbuf *mbuf)
@@ -1686,29 +1355,32 @@ static int vidiocgmbuf(struct file *file, void *priv,
 
        PDEBUG(D_STREAM, "cgmbuf");
        if (gspca_dev->nframes == 0) {
-               struct v4l2_requestbuffers rb;
                int ret;
-               __u32 pixfmt;
-               short width, height;
-
-               /* as the final format is not yet defined, allocate
-                  buffers with the max size */
-               pixfmt = gspca_dev->pixfmt;
-               width = gspca_dev->width;
-               height = gspca_dev->height;
-               gspca_dev->pixfmt = V4L2_PIX_FMT_BGR32;
-               gspca_dev->width = 640;
-               gspca_dev->height = 480;
-               memset(&rb, 0, sizeof rb);
-               rb.count = 4;
-               rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-               rb.memory = V4L2_MEMORY_MMAP;
-               ret = vidioc_reqbufs(file, priv, &rb);
-               gspca_dev->pixfmt = pixfmt;
-               gspca_dev->width = width;
-               gspca_dev->height = height;
-               if (ret != 0)
-                       return ret;
+
+               {
+                       struct v4l2_format fmt;
+
+                       memset(&fmt, 0, sizeof fmt);
+                       fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+                       i = gspca_dev->cam.nmodes - 1;  /* highest mode */
+                       fmt.fmt.pix.width = gspca_dev->cam.cam_mode[i].width;
+                       fmt.fmt.pix.height = gspca_dev->cam.cam_mode[i].height;
+                       fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_BGR24;
+                       ret = vidioc_s_fmt_cap(file, priv, &fmt);
+                       if (ret != 0)
+                               return ret;
+               }
+               {
+                       struct v4l2_requestbuffers rb;
+
+                       memset(&rb, 0, sizeof rb);
+                       rb.count = 4;
+                       rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+                       rb.memory = V4L2_MEMORY_MMAP;
+                       ret = vidioc_reqbufs(file, priv, &rb);
+                       if (ret != 0)
+                               return ret;
+               }
        }
        mbuf->frames = gspca_dev->nframes;
        mbuf->size = gspca_dev->frsz * gspca_dev->nframes;
@@ -1951,7 +1623,7 @@ static int vidioc_qbuf(struct file *file, void *priv,
 
        if (frame->v4l2_buf.memory == V4L2_MEMORY_USERPTR) {
                frame->data = frame->data_end =
-                               (unsigned char *) v4l2_buf->m.userptr;
+                               (__u8 *) v4l2_buf->m.userptr;
                frame->v4l2_buf.m.userptr = v4l2_buf->m.userptr;
                frame->v4l2_buf.length = v4l2_buf->length;
        }
@@ -2154,6 +1826,9 @@ static struct file_operations dev_fops = {
        .read = dev_read,
        .mmap = dev_mmap,
        .ioctl = video_ioctl2,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl = v4l_compat_ioctl32,
+#endif
        .llseek = no_llseek,
        .poll   = dev_poll,
 };
@@ -2186,6 +1861,7 @@ static struct video_device gspca_template = {
        .vidioc_s_jpegcomp      = vidioc_s_jpegcomp,
        .vidioc_g_parm          = vidioc_g_parm,
        .vidioc_s_parm          = vidioc_s_parm,
+       .vidioc_s_std           = vidioc_s_std,
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
        .vidiocgmbuf          = vidiocgmbuf,
 #endif
@@ -2207,12 +1883,8 @@ int gspca_dev_probe(struct usb_interface *intf,
        struct gspca_dev *gspca_dev;
        struct usb_device *dev = interface_to_usbdev(intf);
        int ret;
-       __u16 vendor;
-       __u16 product;
 
-       vendor = id->idVendor;
-       product = id->idProduct;
-       PDEBUG(D_PROBE, "probing %04x:%04x", vendor, product);
+       PDEBUG(D_PROBE, "probing %04x:%04x", id->idVendor, id->idProduct);
 
        /* we don't handle multi-config cameras */
        if (dev->descriptor.bNumConfigurations != 1)
@@ -2309,35 +1981,24 @@ EXPORT_SYMBOL(gspca_disconnect);
 /* -- module insert / remove -- */
 static int __init gspca_init(void)
 {
-#ifdef GSPCA_HLP
-       int ret;
-
-       /* create /dev/gspca_hlp */
-       ret = misc_register(&hlp_device);
-       if (ret < 0)
-               err("misc_register err %d", ret);
-       start_hlp();            /* try to start the helper process */
-#endif
        info("main v%s registered", version);
        return 0;
 }
 static void __exit gspca_exit(void)
 {
-#ifdef GSPCA_HLP
-       misc_deregister(&hlp_device);
-#endif
        info("main deregistered");
 }
 
 module_init(gspca_init);
 module_exit(gspca_exit);
 
+#ifdef VIDEO_ADV_DEBUG
 module_param_named(debug, gspca_debug, int, 0644);
 MODULE_PARM_DESC(debug,
                "Debug (bit) 0x01:error 0x02:probe 0x04:config"
                " 0x08:stream 0x10:frame 0x20:packet 0x40:USBin 0x80:USBout"
                " 0x0100: v4l2");
-
+#endif
 module_param(comp_fac, int, 0644);
 MODULE_PARM_DESC(comp_fac,
                "Buffer size ratio when compressed in percent");
index e69d8472a284c41ce6ca78519fd18c8be61058a1..1581fa808b6f7858cc6908f0ace6c2c040705c8b 100644 (file)
@@ -9,7 +9,26 @@
 #include <media/v4l2-common.h>
 #include <linux/mutex.h>
 
-#ifdef GSPCA_DEBUG
+/* values in 2.6.27 */
+#ifndef V4L2_PIX_FMT_SPCA501
+#define V4L2_PIX_FMT_SPCA501 v4l2_fourcc('S', '5', '0', '1')
+#endif
+#ifndef V4L2_PIX_FMT_SPCA561
+#define V4L2_PIX_FMT_SPCA561 v4l2_fourcc('S', '5', '6', '1')
+#endif
+
+/* values in 2.6.26 */
+#ifndef V4L2_CID_POWER_LINE_FREQUENCY
+#define V4L2_CID_POWER_LINE_FREQUENCY  (V4L2_CID_BASE+24)
+#endif
+#ifndef V4L2_CID_WHITE_BALANCE_TEMPERATURE
+#define V4L2_CID_WHITE_BALANCE_TEMPERATURE (V4L2_CID_BASE + 26)
+#endif
+#ifndef V4L2_CID_SHARPNESS
+#define V4L2_CID_SHARPNESS  (V4L2_CID_BASE+27)
+#endif
+
+#ifdef VIDEO_ADV_DEBUG
 /* GSPCA our debug messages */
 extern int gspca_debug;
 #define PDEBUG(level, fmt, args...) \
@@ -47,7 +66,7 @@ extern int gspca_debug;
 
 #define GSPCA_MAX_FRAMES 16    /* maximum number of video frame buffers */
 /* ISOC transfers */
-#define MAX_NURBS 32           /* max number of URBs (read & userptr) */
+#define MAX_NURBS 16           /* max number of URBs */
 #define ISO_MAX_PKT 32         /* max number of packets in an ISOC transfer */
 #define ISO_MAX_SIZE 0x8000    /* max size of one URB buffer (32 Kb) */
 
@@ -79,7 +98,7 @@ typedef int (*cam_qmnu_op) (struct gspca_dev *,
                        struct v4l2_querymenu *);
 typedef void (*cam_pkt_op) (struct gspca_dev *gspca_dev,
                                struct gspca_frame *frame,
-                               unsigned char *data,
+                               __u8 *data,
                                int len);
 
 struct ctrl {
@@ -116,8 +135,8 @@ struct sd_desc {
 #define LAST_PACKET    3
 
 struct gspca_frame {
-       unsigned char *data;            /* frame buffer */
-       unsigned char *data_end;        /* end of frame while filling */
+       __u8 *data;                     /* frame buffer */
+       __u8 *data_end;                 /* end of frame while filling */
        int vma_use_count;
        struct v4l2_buffer v4l2_buf;
 };
@@ -135,7 +154,7 @@ struct gspca_dev {
 
        __u8 *frbuf;                            /* buffer for nframes */
        struct gspca_frame frame[GSPCA_MAX_FRAMES];
-       unsigned int frsz;                      /* frame size */
+       __u32 frsz;                             /* frame size */
        char nframes;                           /* number of frames */
        char fr_i;                              /* frame being filled */
        char fr_q;                              /* next frame to queue */
@@ -145,10 +164,10 @@ struct gspca_dev {
 
        __u8 iface;                     /* USB interface number */
        __u8 alt;                       /* USB alternate setting */
-       unsigned char curr_mode;        /* current camera mode */
+       __u8 curr_mode;                 /* current camera mode */
        __u32 pixfmt;                   /* current mode parameters */
-       short width;
-       short height;
+       __u16 width;
+       __u16 height;
 
        atomic_t nevent;                /* number of frames done */
        wait_queue_head_t wq;           /* wait queue */
@@ -176,6 +195,6 @@ void gspca_disconnect(struct usb_interface *intf);
 struct gspca_frame *gspca_frame_add(struct gspca_dev *gspca_dev,
                                    int packet_type,
                                    struct gspca_frame *frame,
-                                   unsigned char *data,
+                                   __u8 *data,
                                    int len);
 #endif /* GSPCAV2_H */
diff --git a/drivers/media/video/gspca/mars.c b/drivers/media/video/gspca/mars.c
new file mode 100644 (file)
index 0000000..48b861d
--- /dev/null
@@ -0,0 +1,455 @@
+/*
+ *             Mars-Semi MR97311A library
+ *             Copyright (C) 2005 <bradlch@hotmail.com>
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define MODULE_NAME "mars"
+
+#include "gspca.h"
+#include "jpeg.h"
+
+#define DRIVER_VERSION_NUMBER  KERNEL_VERSION(2, 1, 0)
+static const char version[] = "2.1.0";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("GSPCA/Mars USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+       struct gspca_dev gspca_dev;     /* !! must be the first item */
+
+       char qindex;
+};
+
+/* V4L2 controls supported by the driver */
+static struct ctrl sd_ctrls[] = {
+};
+
+static struct cam_mode vga_mode[] = {
+       {V4L2_PIX_FMT_JPEG, 320, 240, 2},
+       {V4L2_PIX_FMT_JPEG, 640, 480, 1},
+};
+
+/* MI Register table //elvis */
+enum {
+       REG_HW_MI_0,
+       REG_HW_MI_1,
+       REG_HW_MI_2,
+       REG_HW_MI_3,
+       REG_HW_MI_4,
+       REG_HW_MI_5,
+       REG_HW_MI_6,
+       REG_HW_MI_7,
+       REG_HW_MI_9 = 0x09,
+       REG_HW_MI_B = 0x0B,
+       REG_HW_MI_C,
+       REG_HW_MI_D,
+       REG_HW_MI_1E = 0x1E,
+       REG_HW_MI_20 = 0x20,
+       REG_HW_MI_2B = 0x2B,
+       REG_HW_MI_2C,
+       REG_HW_MI_2D,
+       REG_HW_MI_2E,
+       REG_HW_MI_35 = 0x35,
+       REG_HW_MI_5F = 0x5f,
+       REG_HW_MI_60,
+       REG_HW_MI_61,
+       REG_HW_MI_62,
+       REG_HW_MI_63,
+       REG_HW_MI_64,
+       REG_HW_MI_F1 = 0xf1,
+       ATTR_TOTAL_MI_REG = 242
+};
+
+static int pcam_reg_write(struct usb_device *dev,
+                         __u16 index, unsigned char *value, int length)
+{
+       int rc;
+
+       rc = usb_control_msg(dev,
+                        usb_sndbulkpipe(dev, 4),
+                        0x12,
+/* ?? 0xc8 = USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_??? !? */
+                        0xc8,
+                        0,             /* value */
+                        index, value, length, 500);
+       PDEBUG(D_USBO, "reg write: 0x%02X , result = 0x%x", index, rc);
+
+       if (rc < 0)
+               PDEBUG(D_ERR, "reg write: error %d", rc);
+       return rc;
+}
+
+static void MISensor_BulkWrite(struct usb_device *dev, unsigned short *pch,
+                                  char Address)
+{
+       int result;
+       unsigned char data[6];
+
+       data[0] = 0x1f;
+       data[1] = 0;
+       data[2] = Address;
+       data[3] = *pch >> 8;            /* high byte */
+       data[4] = *pch;                 /* low byte */
+       data[5] = 0;
+
+       result = usb_control_msg(dev,
+                                usb_sndbulkpipe(dev, 4),
+                                0x12,
+/* ?? 0xc8 = USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_??? !? */
+                                0xc8,
+                                0,             /* value */
+                                Address,       /* index */
+                                data, 5, 500);
+       PDEBUG(D_USBO, "bulk write 0x%02x = 0x%04x", Address, *pch);
+
+       if (result < 0)
+               PDEBUG(D_ERR, "reg write: error %d", result);
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+                       const struct usb_device_id *id)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct cam *cam;
+
+       cam = &gspca_dev->cam;
+       cam->dev_name = (char *) id->driver_info;
+       cam->epaddr = 0x01;
+       cam->cam_mode = vga_mode;
+       cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+       sd->qindex = 1;                 /* set the quantization table */
+       return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+       return 0;
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+       struct usb_device *dev = gspca_dev->dev;
+       int err_code;
+       __u8 data[12];
+       __u16 MI_buf[242];
+       int h_size, v_size;
+       int intpipe;
+       /* struct usb_device *dev = pcam->dev; */
+       memset(data, 0, sizeof data);
+       memset(MI_buf, 0, sizeof MI_buf);
+
+       PDEBUG(D_STREAM, "camera start, iface %d, alt 8", gspca_dev->iface);
+       if (usb_set_interface(dev, gspca_dev->iface, 8) < 0) {
+               PDEBUG(D_ERR|D_STREAM, "Set packet size: set interface error");
+               return;
+       }
+
+       data[0] = 0x01;         /* address */
+       data[1] = 0x01;
+
+       err_code = pcam_reg_write(dev, data[0], data, 0x02);
+       if (err_code < 0)
+               return;
+
+       /*
+          Initialize the MR97113 chip register
+        */
+       data[0] = 0x00;         /* address */
+       data[1] = 0x0c | 0x01;  /* reg 0 */
+       data[2] = 0x01;         /* reg 1 */
+       h_size = gspca_dev->width;
+       v_size = gspca_dev->height;
+       data[3] = h_size / 8;   /* h_size , reg 2 */
+       data[4] = v_size / 8;   /* v_size , reg 3 */
+       data[5] = 0x30;         /* reg 4, MI, PAS5101 :
+                                *      0x30 for 24mhz , 0x28 for 12mhz */
+       data[6] = 4;            /* reg 5, H start */
+       data[7] = 0xc0;         /* reg 6, gamma 1.5 */
+       data[8] = 3;            /* reg 7, V start */
+/*     if(h_size == 320 ) */
+/*             data[9]= 0x56;   * reg 8, 24MHz, 2:1 scale down */
+/*     else */
+       data[9] = 0x52;         /* reg 8, 24MHz, no scale down */
+       data[10] = 0x5d;        /* reg 9, I2C device address
+                                *      [for PAS5101 (0x40)] [for MI (0x5d)] */
+
+       err_code = pcam_reg_write(dev, data[0], data, 0x0b);
+       if (err_code < 0)
+               return;
+
+       data[0] = 0x23;         /* address */
+       data[1] = 0x09;         /* reg 35, append frame header */
+
+       err_code = pcam_reg_write(dev, data[0], data, 0x02);
+       if (err_code < 0) {
+               PDEBUG(D_ERR, "Register write failed");
+               return;
+       }
+
+       data[0] = 0x3C;         /* address */
+/*     if (pcam->width == 1280) */
+/*             data[1] = 200;   * reg 60, pc-cam frame size
+                                *      (unit: 4KB) 800KB */
+/*     else */
+       data[1] = 50;           /* 50 reg 60, pc-cam frame size
+                                *      (unit: 4KB) 200KB */
+       err_code = pcam_reg_write(dev, data[0], data, 0x02);
+       if (err_code < 0)
+               return;
+
+       if (0) {                        /* fixed dark-gain */
+               data[1] = 0;            /* reg 94, Y Gain (1.75) */
+               data[2] = 0;            /* reg 95, UV Gain (1.75) */
+               data[3] = 0x3f;         /* reg 96, Y Gain/UV Gain/disable auto dark-gain */
+               data[4] = 0;            /* reg 97, set fixed dark level */
+               data[5] = 0;            /* reg 98, don't care */
+       } else {                        /* auto dark-gain */
+               data[1] = 0;            /* reg 94, Y Gain (auto) */
+               data[2] = 0;            /* reg 95, UV Gain (1.75) */
+               data[3] = 0x78;         /* reg 96, Y Gain/UV Gain/disable auto dark-gain */
+               switch (gspca_dev->width) {
+/*             case 1280: */
+/*                     data[4] = 154;
+                                * reg 97, %3 shadow point (unit: 256 pixel) */
+/*                     data[5] = 51;
+                                * reg 98, %1 highlight point
+                                *      (uint: 256 pixel) */
+/*                     break; */
+               default:
+/*             case 640: */
+                       data[4] = 36;   /* reg 97, %3 shadow point
+                                        *      (unit: 256 pixel) */
+                       data[5] = 12;   /* reg 98, %1 highlight point
+                                        *      (uint: 256 pixel) */
+                       break;
+               case 320:
+                       data[4] = 9;    /* reg 97, %3 shadow point
+                                        *      (unit: 256 pixel) */
+                       data[5] = 3;    /* reg 98, %1 highlight point
+                                        *      (uint: 256 pixel) */
+                       break;
+               }
+       }
+       /* auto dark-gain */
+       data[0] = 0x5e;         /* address */
+
+       err_code = pcam_reg_write(dev, data[0], data, 0x06);
+       if (err_code < 0)
+               return;
+
+       data[0] = 0x67;
+       data[1] = 0x13;         /* reg 103, first pixel B, disable sharpness */
+       err_code = pcam_reg_write(dev, data[0], data, 0x02);
+       if (err_code < 0)
+               return;
+
+       /*
+        * initialize the value of MI sensor...
+        */
+       MI_buf[REG_HW_MI_1] = 0x000a;
+       MI_buf[REG_HW_MI_2] = 0x000c;
+       MI_buf[REG_HW_MI_3] = 0x0405;
+       MI_buf[REG_HW_MI_4] = 0x0507;
+       /* mi_Attr_Reg_[REG_HW_MI_5]     = 0x01ff;//13 */
+       MI_buf[REG_HW_MI_5] = 0x0013;   /* 13 */
+       MI_buf[REG_HW_MI_6] = 0x001f;   /* vertical blanking */
+       /* mi_Attr_Reg_[REG_HW_MI_6]     = 0x0400;  // vertical blanking */
+       MI_buf[REG_HW_MI_7] = 0x0002;
+       /* mi_Attr_Reg_[REG_HW_MI_9]     = 0x015f; */
+       /* mi_Attr_Reg_[REG_HW_MI_9]     = 0x030f; */
+       MI_buf[REG_HW_MI_9] = 0x0374;
+       MI_buf[REG_HW_MI_B] = 0x0000;
+       MI_buf[REG_HW_MI_C] = 0x0000;
+       MI_buf[REG_HW_MI_D] = 0x0000;
+       MI_buf[REG_HW_MI_1E] = 0x8000;
+/* mi_Attr_Reg_[REG_HW_MI_20]    = 0x1104; */
+       MI_buf[REG_HW_MI_20] = 0x1104;  /* 0x111c; */
+       MI_buf[REG_HW_MI_2B] = 0x0008;
+/* mi_Attr_Reg_[REG_HW_MI_2C]    = 0x000f; */
+       MI_buf[REG_HW_MI_2C] = 0x001f;  /* lita suggest */
+       MI_buf[REG_HW_MI_2D] = 0x0008;
+       MI_buf[REG_HW_MI_2E] = 0x0008;
+       MI_buf[REG_HW_MI_35] = 0x0051;
+       MI_buf[REG_HW_MI_5F] = 0x0904;  /* fail to write */
+       MI_buf[REG_HW_MI_60] = 0x0000;
+       MI_buf[REG_HW_MI_61] = 0x0000;
+       MI_buf[REG_HW_MI_62] = 0x0498;
+       MI_buf[REG_HW_MI_63] = 0x0000;
+       MI_buf[REG_HW_MI_64] = 0x0000;
+       MI_buf[REG_HW_MI_F1] = 0x0001;
+       /* changing while setting up the different value of dx/dy */
+
+       if (gspca_dev->width != 1280) {
+               MI_buf[0x01] = 0x010a;
+               MI_buf[0x02] = 0x014c;
+               MI_buf[0x03] = 0x01e5;
+               MI_buf[0x04] = 0x0287;
+       }
+       MI_buf[0x20] = 0x1104;
+
+       MISensor_BulkWrite(dev, MI_buf + 1, 1);
+       MISensor_BulkWrite(dev, MI_buf + 2, 2);
+       MISensor_BulkWrite(dev, MI_buf + 3, 3);
+       MISensor_BulkWrite(dev, MI_buf + 4, 4);
+       MISensor_BulkWrite(dev, MI_buf + 5, 5);
+       MISensor_BulkWrite(dev, MI_buf + 6, 6);
+       MISensor_BulkWrite(dev, MI_buf + 7, 7);
+       MISensor_BulkWrite(dev, MI_buf + 9, 9);
+       MISensor_BulkWrite(dev, MI_buf + 0x0b, 0x0b);
+       MISensor_BulkWrite(dev, MI_buf + 0x0c, 0x0c);
+       MISensor_BulkWrite(dev, MI_buf + 0x0d, 0x0d);
+       MISensor_BulkWrite(dev, MI_buf + 0x1e, 0x1e);
+       MISensor_BulkWrite(dev, MI_buf + 0x20, 0x20);
+       MISensor_BulkWrite(dev, MI_buf + 0x2b, 0x2b);
+       MISensor_BulkWrite(dev, MI_buf + 0x2c, 0x2c);
+       MISensor_BulkWrite(dev, MI_buf + 0x2d, 0x2d);
+       MISensor_BulkWrite(dev, MI_buf + 0x2e, 0x2e);
+       MISensor_BulkWrite(dev, MI_buf + 0x35, 0x35);
+       MISensor_BulkWrite(dev, MI_buf + 0x5f, 0x5f);
+       MISensor_BulkWrite(dev, MI_buf + 0x60, 0x60);
+       MISensor_BulkWrite(dev, MI_buf + 0x61, 0x61);
+       MISensor_BulkWrite(dev, MI_buf + 0x62, 0x62);
+       MISensor_BulkWrite(dev, MI_buf + 0x63, 0x63);
+       MISensor_BulkWrite(dev, MI_buf + 0x64, 0x64);
+       MISensor_BulkWrite(dev, MI_buf + 0xf1, 0xf1);
+
+       intpipe = usb_sndintpipe(dev, 0);
+       err_code = usb_clear_halt(dev, intpipe);
+
+       data[0] = 0x00;
+       data[1] = 0x4d;         /* ISOC transfering enable... */
+       pcam_reg_write(dev, data[0], data, 0x02);
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+       int result;
+       __u8 data[2];
+
+       data[0] = 1;
+       data[1] = 0;
+       result = pcam_reg_write(gspca_dev->dev, data[0], data, 2);
+       if (result < 0)
+               PDEBUG(D_ERR, "Camera Stop failed");
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+                       struct gspca_frame *frame,      /* target */
+                       unsigned char *data,            /* isoc packet */
+                       int len)                        /* iso packet length */
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int p;
+
+       if (len < 6) {
+/*             gspca_dev->last_packet_type = DISCARD_PACKET; */
+               return;
+       }
+       for (p = 0; p < len - 6; p++) {
+               if (data[0 + p] == 0xff
+                   && data[1 + p] == 0xff
+                   && data[2 + p] == 0x00
+                   && data[3 + p] == 0xff
+                   && data[4 + p] == 0x96) {
+                       if (data[5 + p] == 0x64
+                           || data[5 + p] == 0x65
+                           || data[5 + p] == 0x66
+                           || data[5 + p] == 0x67) {
+                               PDEBUG(D_PACK, "sof offset: %d leng: %d",
+                                       p, len);
+                               frame = gspca_frame_add(gspca_dev, LAST_PACKET,
+                                                       frame, data, 0);
+
+                               /* put the JPEG header */
+                               jpeg_put_header(gspca_dev, frame,
+                                               sd->qindex, 0x21);
+                               data += 16;
+                               len -= 16;
+                               break;
+                       }
+               }
+       }
+       gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+}
+
+/* sub-driver description */
+static struct sd_desc sd_desc = {
+       .name = MODULE_NAME,
+       .ctrls = sd_ctrls,
+       .nctrls = ARRAY_SIZE(sd_ctrls),
+       .config = sd_config,
+       .open = sd_open,
+       .start = sd_start,
+       .stopN = sd_stopN,
+       .stop0 = sd_stop0,
+       .close = sd_close,
+       .pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static __devinitdata struct usb_device_id device_table[] = {
+       {USB_DEVICE(0x093a, 0x050f), DVNM("Mars-Semi Pc-Camera")},
+       {}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+                       const struct usb_device_id *id)
+{
+       return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+                               THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+       .name = MODULE_NAME,
+       .id_table = device_table,
+       .probe = sd_probe,
+       .disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+       if (usb_register(&sd_driver) < 0)
+               return -1;
+       PDEBUG(D_PROBE, "v%s registered", version);
+       return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+       usb_deregister(&sd_driver);
+       PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/ov519.c b/drivers/media/video/gspca/ov519.c
new file mode 100644 (file)
index 0000000..7d6237f
--- /dev/null
@@ -0,0 +1,2174 @@
+/**
+ * OV519 driver
+ *
+ * Copyright (C) 2008 Jean-Francois Moine (http://moinejf.free.fr)
+ *
+ * (This module is adapted from the ov51x-jpeg package)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#define MODULE_NAME "ov519"
+
+#include "gspca.h"
+
+#define DRIVER_VERSION_NUMBER  KERNEL_VERSION(2, 1, 0)
+static const char version[] = "2.1.0";
+
+MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>");
+MODULE_DESCRIPTION("OV519 USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* global parameters */
+static int frame_rate;
+
+/* Number of times to retry a failed I2C transaction. Increase this if you
+ * are getting "Failed to read sensor ID..." */
+static int i2c_detect_tries = 10;
+
+/* ov519 device descriptor */
+struct sd {
+       struct gspca_dev gspca_dev;             /* !! must be the first item */
+
+       /* Determined by sensor type */
+       short maxwidth;
+       short maxheight;
+
+       unsigned char primary_i2c_slave;        /* I2C write id of sensor */
+
+       unsigned char brightness;
+       unsigned char contrast;
+       unsigned char colors;
+
+       char compress;          /* Should the next frame be compressed? */
+       char compress_inited;   /* Are compression params uploaded? */
+       char stopped;           /* Streaming is temporarily paused */
+
+       char frame_rate;        /* current Framerate (OV519 only) */
+       char clockdiv;          /* clockdiv override for OV519 only */
+
+       char sensor;            /* Type of image sensor chip (SEN_*) */
+#define SEN_UNKNOWN 0
+#define SEN_OV6620 1
+#define SEN_OV6630 2
+#define SEN_OV7610 3
+#define SEN_OV7620 4
+#define SEN_OV7630 5
+#define SEN_OV7640 6
+#define SEN_OV7670 7
+#define SEN_OV76BE 8
+#define SEN_OV8610 9
+
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+#define SD_BRIGHTNESS 0
+       {
+           {
+               .id      = V4L2_CID_BRIGHTNESS,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Brightness",
+               .minimum = 0,
+               .maximum = 255,
+               .step    = 1,
+               .default_value = 127,
+           },
+           .set = sd_setbrightness,
+           .get = sd_getbrightness,
+       },
+#define SD_CONTRAST 1
+       {
+           {
+               .id      = V4L2_CID_CONTRAST,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Contrast",
+               .minimum = 0,
+               .maximum = 255,
+               .step    = 1,
+               .default_value = 127,
+           },
+           .set = sd_setcontrast,
+           .get = sd_getcontrast,
+       },
+#define SD_COLOR 2
+       {
+           {
+               .id      = V4L2_CID_SATURATION,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Saturation",
+               .minimum = 0,
+               .maximum = 255,
+               .step    = 1,
+               .default_value = 127,
+           },
+           .set = sd_setcolors,
+           .get = sd_getcolors,
+       },
+};
+
+static struct cam_mode vga_mode[] = {
+       {V4L2_PIX_FMT_JPEG, 320, 240},
+       {V4L2_PIX_FMT_JPEG, 640, 480},
+};
+static struct cam_mode sif_mode[] = {
+       {V4L2_PIX_FMT_JPEG, 176, 144},
+       {V4L2_PIX_FMT_JPEG, 352, 288},
+};
+
+/* OV519 Camera interface register numbers */
+#define OV519_CAM_H_SIZE               0x10
+#define OV519_CAM_V_SIZE               0x11
+#define OV519_CAM_X_OFFSETL            0x12
+#define OV519_CAM_X_OFFSETH            0x13
+#define OV519_CAM_Y_OFFSETL            0x14
+#define OV519_CAM_Y_OFFSETH            0x15
+#define OV519_CAM_DIVIDER              0x16
+#define OV519_CAM_DFR                  0x20
+#define OV519_CAM_FORMAT               0x25
+
+/* OV519 System Controller register numbers */
+#define OV519_SYS_RESET1 0x51
+#define OV519_SYS_EN_CLK1 0x54
+
+#define OV519_GPIO_DATA_OUT0           0x71
+#define OV519_GPIO_IO_CTRL0            0x72
+
+#define OV511_ENDPOINT_ADDRESS  1      /* Isoc endpoint number */
+
+/* I2C registers */
+#define R51x_I2C_W_SID         0x41
+#define R51x_I2C_SADDR_3       0x42
+#define R51x_I2C_SADDR_2       0x43
+#define R51x_I2C_R_SID         0x44
+#define R51x_I2C_DATA          0x45
+#define R518_I2C_CTL           0x47    /* OV518(+) only */
+
+/* I2C ADDRESSES */
+#define OV7xx0_SID   0x42
+#define OV8xx0_SID   0xa0
+#define OV6xx0_SID   0xc0
+
+/* OV7610 registers */
+#define OV7610_REG_GAIN                0x00    /* gain setting (5:0) */
+#define OV7610_REG_SAT         0x03    /* saturation */
+#define OV8610_REG_HUE         0x04    /* 04 reserved */
+#define OV7610_REG_CNT         0x05    /* Y contrast */
+#define OV7610_REG_BRT         0x06    /* Y brightness */
+#define OV7610_REG_COM_C       0x14    /* misc common regs */
+#define OV7610_REG_ID_HIGH     0x1c    /* manufacturer ID MSB */
+#define OV7610_REG_ID_LOW      0x1d    /* manufacturer ID LSB */
+#define OV7610_REG_COM_I       0x29    /* misc settings */
+
+/* OV7670 registers */
+#define OV7670_REG_GAIN        0x00    /* Gain lower 8 bits (rest in vref) */
+#define OV7670_REG_BLUE        0x01    /* blue gain */
+#define OV7670_REG_RED         0x02    /* red gain */
+#define OV7670_REG_VREF        0x03    /* Pieces of GAIN, VSTART, VSTOP */
+#define OV7670_REG_COM1        0x04    /* Control 1 */
+#define OV7670_REG_AECHH       0x07    /* AEC MS 5 bits */
+#define OV7670_REG_COM3        0x0c    /* Control 3 */
+#define OV7670_REG_COM4        0x0d    /* Control 4 */
+#define OV7670_REG_COM5        0x0e    /* All "reserved" */
+#define OV7670_REG_COM6        0x0f    /* Control 6 */
+#define OV7670_REG_AECH        0x10    /* More bits of AEC value */
+#define OV7670_REG_CLKRC       0x11    /* Clock control */
+#define OV7670_REG_COM7        0x12    /* Control 7 */
+#define   OV7670_COM7_FMT_VGA    0x00
+#define   OV7670_COM7_YUV        0x00    /* YUV */
+#define   OV7670_COM7_FMT_QVGA   0x10    /* QVGA format */
+#define   OV7670_COM7_FMT_MASK   0x38
+#define   OV7670_COM7_RESET      0x80    /* Register reset */
+#define OV7670_REG_COM8        0x13    /* Control 8 */
+#define   OV7670_COM8_AEC        0x01    /* Auto exposure enable */
+#define   OV7670_COM8_AWB        0x02    /* White balance enable */
+#define   OV7670_COM8_AGC        0x04    /* Auto gain enable */
+#define   OV7670_COM8_BFILT      0x20    /* Band filter enable */
+#define   OV7670_COM8_AECSTEP    0x40    /* Unlimited AEC step size */
+#define   OV7670_COM8_FASTAEC    0x80    /* Enable fast AGC/AEC */
+#define OV7670_REG_COM9        0x14    /* Control 9  - gain ceiling */
+#define OV7670_REG_COM10       0x15    /* Control 10 */
+#define OV7670_REG_HSTART      0x17    /* Horiz start high bits */
+#define OV7670_REG_HSTOP       0x18    /* Horiz stop high bits */
+#define OV7670_REG_VSTART      0x19    /* Vert start high bits */
+#define OV7670_REG_VSTOP       0x1a    /* Vert stop high bits */
+#define OV7670_REG_MVFP        0x1e    /* Mirror / vflip */
+#define   OV7670_MVFP_MIRROR     0x20    /* Mirror image */
+#define OV7670_REG_AEW         0x24    /* AGC upper limit */
+#define OV7670_REG_AEB         0x25    /* AGC lower limit */
+#define OV7670_REG_VPT         0x26    /* AGC/AEC fast mode op region */
+#define OV7670_REG_HREF        0x32    /* HREF pieces */
+#define OV7670_REG_TSLB        0x3a    /* lots of stuff */
+#define OV7670_REG_COM11       0x3b    /* Control 11 */
+#define   OV7670_COM11_EXP       0x02
+#define   OV7670_COM11_HZAUTO    0x10    /* Auto detect 50/60 Hz */
+#define OV7670_REG_COM12       0x3c    /* Control 12 */
+#define OV7670_REG_COM13       0x3d    /* Control 13 */
+#define   OV7670_COM13_GAMMA     0x80    /* Gamma enable */
+#define   OV7670_COM13_UVSAT     0x40    /* UV saturation auto adjustment */
+#define OV7670_REG_COM14       0x3e    /* Control 14 */
+#define OV7670_REG_EDGE        0x3f    /* Edge enhancement factor */
+#define OV7670_REG_COM15       0x40    /* Control 15 */
+#define   OV7670_COM15_R00FF     0xc0    /*            00 to FF */
+#define OV7670_REG_COM16       0x41    /* Control 16 */
+#define   OV7670_COM16_AWBGAIN   0x08    /* AWB gain enable */
+#define OV7670_REG_BRIGHT      0x55    /* Brightness */
+#define OV7670_REG_CONTRAS     0x56    /* Contrast control */
+#define OV7670_REG_GFIX        0x69    /* Fix gain control */
+#define OV7670_REG_RGB444      0x8c    /* RGB 444 control */
+#define OV7670_REG_HAECC1      0x9f    /* Hist AEC/AGC control 1 */
+#define OV7670_REG_HAECC2      0xa0    /* Hist AEC/AGC control 2 */
+#define OV7670_REG_BD50MAX     0xa5    /* 50hz banding step limit */
+#define OV7670_REG_HAECC3      0xa6    /* Hist AEC/AGC control 3 */
+#define OV7670_REG_HAECC4      0xa7    /* Hist AEC/AGC control 4 */
+#define OV7670_REG_HAECC5      0xa8    /* Hist AEC/AGC control 5 */
+#define OV7670_REG_HAECC6      0xa9    /* Hist AEC/AGC control 6 */
+#define OV7670_REG_HAECC7      0xaa    /* Hist AEC/AGC control 7 */
+#define OV7670_REG_BD60MAX     0xab    /* 60hz banding step limit */
+
+struct ovsensor_window {
+       short x;
+       short y;
+       short width;
+       short height;
+/*     int format; */
+       short quarter;          /* Scale width and height down 2x */
+       short clockdiv;         /* Clock divisor setting */
+};
+
+static unsigned char ov7670_abs_to_sm(unsigned char v)
+{
+       if (v > 127)
+               return v & 0x7f;
+       return (128 - v) | 0x80;
+}
+
+/* Write a OV519 register */
+static int reg_w(struct sd *sd, __u16 index, __u8 value)
+{
+       int ret;
+       __u8 buf[4];
+
+       buf[0] = value;
+       ret = usb_control_msg(sd->gspca_dev.dev,
+                       usb_sndctrlpipe(sd->gspca_dev.dev, 0),
+                       1,                      /* REQ_IO (ov518/519) */
+                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       0, index,
+                       &buf[0], 1, 500);
+       if (ret < 0)
+               PDEBUG(D_ERR, "Write reg [%02x] %02x failed", index, value);
+       return ret;
+}
+
+/* Read from a OV519 register */
+/* returns: negative is error, pos or zero is data */
+static int reg_r(struct sd *sd, __u16 index)
+{
+       int ret;
+       __u8 buf[4];
+
+       ret = usb_control_msg(sd->gspca_dev.dev,
+                       usb_rcvctrlpipe(sd->gspca_dev.dev, 0),
+                       1,                      /* REQ_IO */
+                       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       0, index, &buf[0], 1, 500);
+
+       if (ret >= 0)
+               ret = buf[0];
+       else
+               PDEBUG(D_ERR, "Read reg [0x%02x] failed", index);
+       return ret;
+}
+
+/* Read 8 values from a OV519 register */
+static int reg_r8(struct sd *sd,
+               __u16 index)
+{
+       int ret;
+       __u8 buf[8];
+
+       ret = usb_control_msg(sd->gspca_dev.dev,
+                       usb_rcvctrlpipe(sd->gspca_dev.dev, 0),
+                       1,                      /* REQ_IO */
+                       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       0, index, &buf[0], 8, 500);
+
+       if (ret >= 0)
+               ret = buf[0];
+       else
+               PDEBUG(D_ERR, "Read reg 8 [0x%02x] failed", index);
+       return ret;
+}
+
+/*
+ * Writes bits at positions specified by mask to an OV51x reg. Bits that are in
+ * the same position as 1's in "mask" are cleared and set to "value". Bits
+ * that are in the same position as 0's in "mask" are preserved, regardless
+ * of their respective state in "value".
+ */
+static int reg_w_mask(struct sd *sd,
+                       __u16 index,
+                       __u8 value,
+                       __u8 mask)
+{
+       int ret;
+       __u8 oldval;
+
+       if (mask != 0xff) {
+               value &= mask;                  /* Enforce mask on value */
+               ret = reg_r(sd, index);
+               if (ret < 0)
+                       return ret;
+
+               oldval = ret & ~mask;           /* Clear the masked bits */
+               value |= oldval;                /* Set the desired bits */
+       }
+       return reg_w(sd, index, value);
+}
+
+/*
+ * The OV518 I2C I/O procedure is different, hence, this function.
+ * This is normally only called from i2c_w(). Note that this function
+ * always succeeds regardless of whether the sensor is present and working.
+ */
+static int i2c_w(struct sd *sd,
+               __u8 reg,
+               __u8 value)
+{
+       int rc;
+
+       PDEBUG(D_USBO, "i2c 0x%02x -> [0x%02x]", value, reg);
+
+       /* Select camera register */
+       rc = reg_w(sd, R51x_I2C_SADDR_3, reg);
+       if (rc < 0)
+               return rc;
+
+       /* Write "value" to I2C data port of OV511 */
+       rc = reg_w(sd, R51x_I2C_DATA, value);
+       if (rc < 0)
+               return rc;
+
+       /* Initiate 3-byte write cycle */
+       rc = reg_w(sd, R518_I2C_CTL, 0x01);
+
+       /* wait for write complete */
+       msleep(4);
+       if (rc < 0)
+               return rc;
+       return reg_r8(sd, R518_I2C_CTL);
+}
+
+/*
+ * returns: negative is error, pos or zero is data
+ *
+ * The OV518 I2C I/O procedure is different, hence, this function.
+ * This is normally only called from i2c_r(). Note that this function
+ * always succeeds regardless of whether the sensor is present and working.
+ */
+static int i2c_r(struct sd *sd, __u8 reg)
+{
+       int rc, value;
+
+       /* Select camera register */
+       rc = reg_w(sd, R51x_I2C_SADDR_2, reg);
+       if (rc < 0)
+               return rc;
+
+       /* Initiate 2-byte write cycle */
+       rc = reg_w(sd, R518_I2C_CTL, 0x03);
+       if (rc < 0)
+               return rc;
+
+       /* Initiate 2-byte read cycle */
+       rc = reg_w(sd, R518_I2C_CTL, 0x05);
+       if (rc < 0)
+               return rc;
+       value = reg_r(sd, R51x_I2C_DATA);
+       PDEBUG(D_USBI, "i2c [0x%02X] -> 0x%02X", reg, value);
+       return value;
+}
+
+/* Writes bits at positions specified by mask to an I2C reg. Bits that are in
+ * the same position as 1's in "mask" are cleared and set to "value". Bits
+ * that are in the same position as 0's in "mask" are preserved, regardless
+ * of their respective state in "value".
+ */
+static int i2c_w_mask(struct sd *sd,
+                  __u8 reg,
+                  __u8 value,
+                  __u8 mask)
+{
+       int rc;
+       __u8 oldval;
+
+       value &= mask;                  /* Enforce mask on value */
+       rc = i2c_r(sd, reg);
+       if (rc < 0)
+               return rc;
+       oldval = rc & ~mask;            /* Clear the masked bits */
+       value |= oldval;                /* Set the desired bits */
+       return i2c_w(sd, reg, value);
+}
+
+/* Temporarily stops OV511 from functioning. Must do this before changing
+ * registers while the camera is streaming */
+static inline int ov51x_stop(struct sd *sd)
+{
+       PDEBUG(D_STREAM, "stopping");
+       sd->stopped = 1;
+       return reg_w(sd, OV519_SYS_RESET1, 0x0f);
+}
+
+/* Restarts OV511 after ov511_stop() is called. Has no effect if it is not
+ * actually stopped (for performance). */
+static inline int ov51x_restart(struct sd *sd)
+{
+       PDEBUG(D_STREAM, "restarting");
+       if (!sd->stopped)
+               return 0;
+       sd->stopped = 0;
+
+       /* Reinitialize the stream */
+       return reg_w(sd, OV519_SYS_RESET1, 0x00);
+}
+
+/* This does an initial reset of an OmniVision sensor and ensures that I2C
+ * is synchronized. Returns <0 on failure.
+ */
+static int init_ov_sensor(struct sd *sd)
+{
+       int i, success;
+
+       /* Reset the sensor */
+       if (i2c_w(sd, 0x12, 0x80) < 0)
+               return -EIO;
+
+       /* Wait for it to initialize */
+       msleep(150);
+
+       for (i = 0, success = 0; i < i2c_detect_tries && !success; i++) {
+               if (i2c_r(sd, OV7610_REG_ID_HIGH) == 0x7f &&
+                   i2c_r(sd, OV7610_REG_ID_LOW) == 0xa2) {
+                       success = 1;
+                       continue;
+               }
+
+               /* Reset the sensor */
+               if (i2c_w(sd, 0x12, 0x80) < 0)
+                       return -EIO;
+               /* Wait for it to initialize */
+               msleep(150);
+               /* Dummy read to sync I2C */
+               if (i2c_r(sd, 0x00) < 0)
+                       return -EIO;
+       }
+       if (!success)
+               return -EIO;
+       PDEBUG(D_PROBE, "I2C synced in %d attempt(s)", i);
+       return 0;
+}
+
+/* Switch on standard JPEG compression. Returns 0 for success. */
+static int ov519_init_compression(struct sd *sd)
+{
+       if (!sd->compress_inited) {
+               if (reg_w_mask(sd, OV519_SYS_EN_CLK1, 1 << 2, 1 << 2) < 0) {
+                       PDEBUG(D_ERR, "Error switching to compressed mode");
+                       return -EIO;
+               }
+               sd->compress_inited = 1;
+       }
+       return 0;
+}
+
+/* Set the read and write slave IDs. The "slave" argument is the write slave,
+ * and the read slave will be set to (slave + 1).
+ * This should not be called from outside the i2c I/O functions.
+ * Sets I2C read and write slave IDs. Returns <0 for error
+ */
+static int ov51x_set_slave_ids(struct sd *sd,
+                               __u8 slave)
+{
+       int rc;
+
+       rc = reg_w(sd, R51x_I2C_W_SID, slave);
+       if (rc < 0)
+               return rc;
+       return reg_w(sd, R51x_I2C_R_SID, slave + 1);
+}
+
+struct ov_regvals {
+       __u8 reg;
+       __u8 val;
+};
+struct ov_i2c_regvals {
+       __u8 reg;
+       __u8 val;
+};
+
+static int write_regvals(struct sd *sd,
+                        struct ov_regvals *regvals,
+                        int n)
+{
+       int rc;
+
+       while (--n >= 0) {
+               rc = reg_w(sd, regvals->reg, regvals->val);
+               if (rc < 0)
+                       return rc;
+               regvals++;
+       }
+       return 0;
+}
+
+static int write_i2c_regvals(struct sd *sd,
+                            struct ov_i2c_regvals *regvals,
+                            int n)
+{
+       int rc;
+
+       while (--n >= 0) {
+               rc = i2c_w(sd, regvals->reg, regvals->val);
+               if (rc < 0)
+                       return rc;
+               regvals++;
+       }
+       return 0;
+}
+
+/****************************************************************************
+ *
+ * OV511 and sensor configuration
+ *
+ ***************************************************************************/
+
+/* This initializes the OV8110, OV8610 sensor. The OV8110 uses
+ * the same register settings as the OV8610, since they are very similar.
+ */
+static int ov8xx0_configure(struct sd *sd)
+{
+       int rc;
+       static struct ov_i2c_regvals norm_8610[] = {
+               { 0x12, 0x80 },
+               { 0x00, 0x00 },
+               { 0x01, 0x80 },
+               { 0x02, 0x80 },
+               { 0x03, 0xc0 },
+               { 0x04, 0x30 },
+               { 0x05, 0x30 }, /* was 0x10, new from windrv 090403 */
+               { 0x06, 0x70 }, /* was 0x80, new from windrv 090403 */
+               { 0x0a, 0x86 },
+               { 0x0b, 0xb0 },
+               { 0x0c, 0x20 },
+               { 0x0d, 0x20 },
+               { 0x11, 0x01 },
+               { 0x12, 0x25 },
+               { 0x13, 0x01 },
+               { 0x14, 0x04 },
+               { 0x15, 0x01 }, /* Lin and Win think different about UV order */
+               { 0x16, 0x03 },
+               { 0x17, 0x38 }, /* was 0x2f, new from windrv 090403 */
+               { 0x18, 0xea }, /* was 0xcf, new from windrv 090403 */
+               { 0x19, 0x02 }, /* was 0x06, new from windrv 090403 */
+               { 0x1a, 0xf5 },
+               { 0x1b, 0x00 },
+               { 0x20, 0xd0 }, /* was 0x90, new from windrv 090403 */
+               { 0x23, 0xc0 }, /* was 0x00, new from windrv 090403 */
+               { 0x24, 0x30 }, /* was 0x1d, new from windrv 090403 */
+               { 0x25, 0x50 }, /* was 0x57, new from windrv 090403 */
+               { 0x26, 0xa2 },
+               { 0x27, 0xea },
+               { 0x28, 0x00 },
+               { 0x29, 0x00 },
+               { 0x2a, 0x80 },
+               { 0x2b, 0xc8 }, /* was 0xcc, new from windrv 090403 */
+               { 0x2c, 0xac },
+               { 0x2d, 0x45 }, /* was 0xd5, new from windrv 090403 */
+               { 0x2e, 0x80 },
+               { 0x2f, 0x14 }, /* was 0x01, new from windrv 090403 */
+               { 0x4c, 0x00 },
+               { 0x4d, 0x30 }, /* was 0x10, new from windrv 090403 */
+               { 0x60, 0x02 }, /* was 0x01, new from windrv 090403 */
+               { 0x61, 0x00 }, /* was 0x09, new from windrv 090403 */
+               { 0x62, 0x5f }, /* was 0xd7, new from windrv 090403 */
+               { 0x63, 0xff },
+               { 0x64, 0x53 }, /* new windrv 090403 says 0x57,
+                                * maybe thats wrong */
+               { 0x65, 0x00 },
+               { 0x66, 0x55 },
+               { 0x67, 0xb0 },
+               { 0x68, 0xc0 }, /* was 0xaf, new from windrv 090403 */
+               { 0x69, 0x02 },
+               { 0x6a, 0x22 },
+               { 0x6b, 0x00 },
+               { 0x6c, 0x99 }, /* was 0x80, old windrv says 0x00, but
+                                  deleting bit7 colors the first images red */
+               { 0x6d, 0x11 }, /* was 0x00, new from windrv 090403 */
+               { 0x6e, 0x11 }, /* was 0x00, new from windrv 090403 */
+               { 0x6f, 0x01 },
+               { 0x70, 0x8b },
+               { 0x71, 0x00 },
+               { 0x72, 0x14 },
+               { 0x73, 0x54 },
+               { 0x74, 0x00 },/* 0x60? - was 0x00, new from windrv 090403 */
+               { 0x75, 0x0e },
+               { 0x76, 0x02 }, /* was 0x02, new from windrv 090403 */
+               { 0x77, 0xff },
+               { 0x78, 0x80 },
+               { 0x79, 0x80 },
+               { 0x7a, 0x80 },
+               { 0x7b, 0x10 }, /* was 0x13, new from windrv 090403 */
+               { 0x7c, 0x00 },
+               { 0x7d, 0x08 }, /* was 0x09, new from windrv 090403 */
+               { 0x7e, 0x08 }, /* was 0xc0, new from windrv 090403 */
+               { 0x7f, 0xfb },
+               { 0x80, 0x28 },
+               { 0x81, 0x00 },
+               { 0x82, 0x23 },
+               { 0x83, 0x0b },
+               { 0x84, 0x00 },
+               { 0x85, 0x62 }, /* was 0x61, new from windrv 090403 */
+               { 0x86, 0xc9 },
+               { 0x87, 0x00 },
+               { 0x88, 0x00 },
+               { 0x89, 0x01 },
+               { 0x12, 0x20 },
+               { 0x12, 0x25 }, /* was 0x24, new from windrv 090403 */
+       };
+
+       PDEBUG(D_PROBE, "starting ov8xx0 configuration");
+
+       if (init_ov_sensor(sd) < 0)
+               PDEBUG(D_ERR|D_PROBE, "Failed to read sensor ID");
+       else
+               PDEBUG(D_PROBE, "OV86x0 initialized");
+
+       /* Detect sensor (sub)type */
+       rc = i2c_r(sd, OV7610_REG_COM_I);
+       if (rc < 0) {
+               PDEBUG(D_ERR, "Error detecting sensor type");
+               return -1;
+       }
+       if ((rc & 3) == 1) {
+               PDEBUG(D_PROBE, "Sensor is an OV8610");
+               sd->sensor = SEN_OV8610;
+       } else {
+               PDEBUG(D_ERR, "Unknown image sensor version: %d", rc & 3);
+               return -1;
+       }
+       PDEBUG(D_PROBE, "Writing 8610 registers");
+       if (write_i2c_regvals(sd,
+                       norm_8610,
+                       sizeof norm_8610 / sizeof norm_8610[0]))
+               return -1;
+
+       /* Set sensor-specific vars */
+       sd->maxwidth = 640;
+       sd->maxheight = 480;
+       return 0;
+}
+
+/* This initializes the OV7610, OV7620, or OV76BE sensor. The OV76BE uses
+ * the same register settings as the OV7610, since they are very similar.
+ */
+static int ov7xx0_configure(struct sd *sd)
+{
+       int rc, high, low;
+
+       /* Lawrence Glaister <lg@jfm.bc.ca> reports:
+        *
+        * Register 0x0f in the 7610 has the following effects:
+        *
+        * 0x85 (AEC method 1): Best overall, good contrast range
+        * 0x45 (AEC method 2): Very overexposed
+        * 0xa5 (spec sheet default): Ok, but the black level is
+        *      shifted resulting in loss of contrast
+        * 0x05 (old driver setting): very overexposed, too much
+        *      contrast
+        */
+       static struct ov_i2c_regvals norm_7610[] = {
+               { 0x10, 0xff },
+               { 0x16, 0x06 },
+               { 0x28, 0x24 },
+               { 0x2b, 0xac },
+               { 0x12, 0x00 },
+               { 0x38, 0x81 },
+               { 0x28, 0x24 }, /* 0c */
+               { 0x0f, 0x85 }, /* lg's setting */
+               { 0x15, 0x01 },
+               { 0x20, 0x1c },
+               { 0x23, 0x2a },
+               { 0x24, 0x10 },
+               { 0x25, 0x8a },
+               { 0x26, 0xa2 },
+               { 0x27, 0xc2 },
+               { 0x2a, 0x04 },
+               { 0x2c, 0xfe },
+               { 0x2d, 0x93 },
+               { 0x30, 0x71 },
+               { 0x31, 0x60 },
+               { 0x32, 0x26 },
+               { 0x33, 0x20 },
+               { 0x34, 0x48 },
+               { 0x12, 0x24 },
+               { 0x11, 0x01 },
+               { 0x0c, 0x24 },
+               { 0x0d, 0x24 },
+       };
+
+       static struct ov_i2c_regvals norm_7620[] = {
+               { 0x00, 0x00 },         /* gain */
+               { 0x01, 0x80 },         /* blue gain */
+               { 0x02, 0x80 },         /* red gain */
+               { 0x03, 0xc0 },         /* OV7670_REG_VREF */
+               { 0x06, 0x60 },
+               { 0x07, 0x00 },
+               { 0x0c, 0x24 },
+               { 0x0c, 0x24 },
+               { 0x0d, 0x24 },
+               { 0x11, 0x01 },
+               { 0x12, 0x24 },
+               { 0x13, 0x01 },
+               { 0x14, 0x84 },
+               { 0x15, 0x01 },
+               { 0x16, 0x03 },
+               { 0x17, 0x2f },
+               { 0x18, 0xcf },
+               { 0x19, 0x06 },
+               { 0x1a, 0xf5 },
+               { 0x1b, 0x00 },
+               { 0x20, 0x18 },
+               { 0x21, 0x80 },
+               { 0x22, 0x80 },
+               { 0x23, 0x00 },
+               { 0x26, 0xa2 },
+               { 0x27, 0xea },
+               { 0x28, 0x20 },
+               { 0x29, 0x00 },
+               { 0x2a, 0x10 },
+               { 0x2b, 0x00 },
+               { 0x2c, 0x88 },
+               { 0x2d, 0x91 },
+               { 0x2e, 0x80 },
+               { 0x2f, 0x44 },
+               { 0x60, 0x27 },
+               { 0x61, 0x02 },
+               { 0x62, 0x5f },
+               { 0x63, 0xd5 },
+               { 0x64, 0x57 },
+               { 0x65, 0x83 },
+               { 0x66, 0x55 },
+               { 0x67, 0x92 },
+               { 0x68, 0xcf },
+               { 0x69, 0x76 },
+               { 0x6a, 0x22 },
+               { 0x6b, 0x00 },
+               { 0x6c, 0x02 },
+               { 0x6d, 0x44 },
+               { 0x6e, 0x80 },
+               { 0x6f, 0x1d },
+               { 0x70, 0x8b },
+               { 0x71, 0x00 },
+               { 0x72, 0x14 },
+               { 0x73, 0x54 },
+               { 0x74, 0x00 },
+               { 0x75, 0x8e },
+               { 0x76, 0x00 },
+               { 0x77, 0xff },
+               { 0x78, 0x80 },
+               { 0x79, 0x80 },
+               { 0x7a, 0x80 },
+               { 0x7b, 0xe2 },
+               { 0x7c, 0x00 },
+       };
+
+       /* 7640 and 7648. The defaults should be OK for most registers. */
+       static struct ov_i2c_regvals norm_7640[] = {
+               { 0x12, 0x80 },
+               { 0x12, 0x14 },
+       };
+
+       /* 7670. Defaults taken from OmniVision provided data,
+       *  as provided by Jonathan Corbet of OLPC               */
+       static struct ov_i2c_regvals norm_7670[] = {
+               { OV7670_REG_COM7, OV7670_COM7_RESET },
+               { OV7670_REG_TSLB, 0x04 },              /* OV */
+               { OV7670_REG_COM7, OV7670_COM7_FMT_VGA }, /* VGA */
+               { OV7670_REG_CLKRC, 0x1 },
+       /*
+        * Set the hardware window.  These values from OV don't entirely
+        * make sense - hstop is less than hstart.  But they work...
+        */
+               { OV7670_REG_HSTART, 0x13 },    { OV7670_REG_HSTOP, 0x01 },
+               { OV7670_REG_HREF, 0xb6 },      { OV7670_REG_VSTART, 0x02 },
+               { OV7670_REG_VSTOP, 0x7a },     { OV7670_REG_VREF, 0x0a },
+
+               { OV7670_REG_COM3, 0 }, { OV7670_REG_COM14, 0 },
+       /* Mystery scaling numbers */
+               { 0x70, 0x3a },         { 0x71, 0x35 },
+               { 0x72, 0x11 },         { 0x73, 0xf0 },
+               { 0xa2, 0x02 },
+/* jfm */
+/* { OV7670_REG_COM10, 0x0 }, */
+
+       /* Gamma curve values */
+               { 0x7a, 0x20 },
+/* jfm:win 7b=1c */
+               { 0x7b, 0x10 },
+/* jfm:win 7c=28 */
+               { 0x7c, 0x1e },
+/* jfm:win 7d=3c */
+               { 0x7d, 0x35 },
+               { 0x7e, 0x5a },         { 0x7f, 0x69 },
+               { 0x80, 0x76 },         { 0x81, 0x80 },
+               { 0x82, 0x88 },         { 0x83, 0x8f },
+               { 0x84, 0x96 },         { 0x85, 0xa3 },
+               { 0x86, 0xaf },         { 0x87, 0xc4 },
+               { 0x88, 0xd7 },         { 0x89, 0xe8 },
+
+       /* AGC and AEC parameters.  Note we start by disabling those features,
+          then turn them only after tweaking the values. */
+               { OV7670_REG_COM8, OV7670_COM8_FASTAEC
+                                | OV7670_COM8_AECSTEP
+                                | OV7670_COM8_BFILT },
+               { OV7670_REG_GAIN, 0 }, { OV7670_REG_AECH, 0 },
+               { OV7670_REG_COM4, 0x40 }, /* magic reserved bit */
+/* jfm:win 14=38 */
+               { OV7670_REG_COM9, 0x18 }, /* 4x gain + magic rsvd bit */
+               { OV7670_REG_BD50MAX, 0x05 },   { OV7670_REG_BD60MAX, 0x07 },
+               { OV7670_REG_AEW, 0x95 },       { OV7670_REG_AEB, 0x33 },
+               { OV7670_REG_VPT, 0xe3 },       { OV7670_REG_HAECC1, 0x78 },
+               { OV7670_REG_HAECC2, 0x68 },
+/* jfm:win a1=0b */
+               { 0xa1, 0x03 }, /* magic */
+               { OV7670_REG_HAECC3, 0xd8 },    { OV7670_REG_HAECC4, 0xd8 },
+               { OV7670_REG_HAECC5, 0xf0 },    { OV7670_REG_HAECC6, 0x90 },
+               { OV7670_REG_HAECC7, 0x94 },
+               { OV7670_REG_COM8, OV7670_COM8_FASTAEC
+                               | OV7670_COM8_AECSTEP
+                               | OV7670_COM8_BFILT
+                               | OV7670_COM8_AGC
+                               | OV7670_COM8_AEC },
+
+       /* Almost all of these are magic "reserved" values.  */
+               { OV7670_REG_COM5, 0x61 },      { OV7670_REG_COM6, 0x4b },
+               { 0x16, 0x02 },
+/* jfm */
+/*             { OV7670_REG_MVFP, 0x07|OV7670_MVFP_MIRROR }, */
+               { OV7670_REG_MVFP, 0x07 },
+               { 0x21, 0x02 },         { 0x22, 0x91 },
+               { 0x29, 0x07 },         { 0x33, 0x0b },
+               { 0x35, 0x0b },         { 0x37, 0x1d },
+               { 0x38, 0x71 },         { 0x39, 0x2a },
+               { OV7670_REG_COM12, 0x78 },     { 0x4d, 0x40 },
+               { 0x4e, 0x20 },         { OV7670_REG_GFIX, 0 },
+               { 0x6b, 0x4a },         { 0x74, 0x10 },
+               { 0x8d, 0x4f },         { 0x8e, 0 },
+               { 0x8f, 0 },            { 0x90, 0 },
+               { 0x91, 0 },            { 0x96, 0 },
+               { 0x9a, 0 },            { 0xb0, 0x84 },
+               { 0xb1, 0x0c },         { 0xb2, 0x0e },
+               { 0xb3, 0x82 },         { 0xb8, 0x0a },
+
+       /* More reserved magic, some of which tweaks white balance */
+               { 0x43, 0x0a },         { 0x44, 0xf0 },
+               { 0x45, 0x34 },         { 0x46, 0x58 },
+               { 0x47, 0x28 },         { 0x48, 0x3a },
+               { 0x59, 0x88 },         { 0x5a, 0x88 },
+               { 0x5b, 0x44 },         { 0x5c, 0x67 },
+               { 0x5d, 0x49 },         { 0x5e, 0x0e },
+               { 0x6c, 0x0a },         { 0x6d, 0x55 },
+               { 0x6e, 0x11 },         { 0x6f, 0x9f },
+                                               /* "9e for advance AWB" */
+               { 0x6a, 0x40 },         { OV7670_REG_BLUE, 0x40 },
+               { OV7670_REG_RED, 0x60 },
+               { OV7670_REG_COM8, OV7670_COM8_FASTAEC
+                               | OV7670_COM8_AECSTEP
+                               | OV7670_COM8_BFILT
+                               | OV7670_COM8_AGC
+                               | OV7670_COM8_AEC
+                               | OV7670_COM8_AWB },
+
+       /* Matrix coefficients */
+               { 0x4f, 0x80 },         { 0x50, 0x80 },
+               { 0x51, 0 },            { 0x52, 0x22 },
+               { 0x53, 0x5e },         { 0x54, 0x80 },
+               { 0x58, 0x9e },
+
+               { OV7670_REG_COM16, OV7670_COM16_AWBGAIN },
+               { OV7670_REG_EDGE, 0 },
+               { 0x75, 0x05 },         { 0x76, 0xe1 },
+               { 0x4c, 0 },            { 0x77, 0x01 },
+               { OV7670_REG_COM13, 0xc3 },     { 0x4b, 0x09 },
+               { 0xc9, 0x60 },         { OV7670_REG_COM16, 0x38 },
+               { 0x56, 0x40 },
+
+               { 0x34, 0x11 },
+               { OV7670_REG_COM11, OV7670_COM11_EXP|OV7670_COM11_HZAUTO },
+               { 0xa4, 0x88 },         { 0x96, 0 },
+               { 0x97, 0x30 },         { 0x98, 0x20 },
+               { 0x99, 0x30 },         { 0x9a, 0x84 },
+               { 0x9b, 0x29 },         { 0x9c, 0x03 },
+               { 0x9d, 0x4c },         { 0x9e, 0x3f },
+               { 0x78, 0x04 },
+
+       /* Extra-weird stuff.  Some sort of multiplexor register */
+               { 0x79, 0x01 },         { 0xc8, 0xf0 },
+               { 0x79, 0x0f },         { 0xc8, 0x00 },
+               { 0x79, 0x10 },         { 0xc8, 0x7e },
+               { 0x79, 0x0a },         { 0xc8, 0x80 },
+               { 0x79, 0x0b },         { 0xc8, 0x01 },
+               { 0x79, 0x0c },         { 0xc8, 0x0f },
+               { 0x79, 0x0d },         { 0xc8, 0x20 },
+               { 0x79, 0x09 },         { 0xc8, 0x80 },
+               { 0x79, 0x02 },         { 0xc8, 0xc0 },
+               { 0x79, 0x03 },         { 0xc8, 0x40 },
+               { 0x79, 0x05 },         { 0xc8, 0x30 },
+               { 0x79, 0x26 },
+
+       /* Format YUV422 */
+               { OV7670_REG_COM7, OV7670_COM7_YUV },  /* Selects YUV mode */
+               { OV7670_REG_RGB444, 0 },       /* No RGB444 please */
+               { OV7670_REG_COM1, 0 },
+               { OV7670_REG_COM15, OV7670_COM15_R00FF },
+               { OV7670_REG_COM9, 0x18 },
+                               /* 4x gain ceiling; 0x8 is reserved bit */
+               { 0x4f, 0x80 },         /* "matrix coefficient 1" */
+               { 0x50, 0x80 },         /* "matrix coefficient 2" */
+               { 0x52, 0x22 },         /* "matrix coefficient 4" */
+               { 0x53, 0x5e },         /* "matrix coefficient 5" */
+               { 0x54, 0x80 },         /* "matrix coefficient 6" */
+               { OV7670_REG_COM13, OV7670_COM13_GAMMA|OV7670_COM13_UVSAT },
+};
+
+       PDEBUG(D_PROBE, "starting OV7xx0 configuration");
+
+/* jfm:already done? */
+       if (init_ov_sensor(sd) < 0)
+               PDEBUG(D_ERR, "Failed to read sensor ID");
+       else
+               PDEBUG(D_PROBE, "OV7xx0 initialized");
+
+       /* Detect sensor (sub)type */
+       rc = i2c_r(sd, OV7610_REG_COM_I);
+
+       /* add OV7670 here
+        * it appears to be wrongly detected as a 7610 by default */
+       if (rc < 0) {
+               PDEBUG(D_ERR, "Error detecting sensor type");
+               return -1;
+       }
+       if ((rc & 3) == 3) {
+               /* quick hack to make OV7670s work */
+               high = i2c_r(sd, 0x0a);
+               low = i2c_r(sd, 0x0b);
+               /* info("%x, %x", high, low); */
+               if (high == 0x76 && low == 0x73) {
+                       PDEBUG(D_PROBE, "Sensor is an OV7670");
+                       sd->sensor = SEN_OV7670;
+               } else {
+                       PDEBUG(D_PROBE, "Sensor is an OV7610");
+                       sd->sensor = SEN_OV7610;
+               }
+       } else if ((rc & 3) == 1) {
+               /* I don't know what's different about the 76BE yet. */
+               if (i2c_r(sd, 0x15) & 1)
+                       PDEBUG(D_PROBE, "Sensor is an OV7620AE");
+               else
+                       PDEBUG(D_PROBE, "Sensor is an OV76BE");
+
+               /* OV511+ will return all zero isoc data unless we
+                * configure the sensor as a 7620. Someone needs to
+                * find the exact reg. setting that causes this. */
+               sd->sensor = SEN_OV76BE;
+       } else if ((rc & 3) == 0) {
+               /* try to read product id registers */
+               high = i2c_r(sd, 0x0a);
+               if (high < 0) {
+                       PDEBUG(D_ERR, "Error detecting camera chip PID");
+                       return high;
+               }
+               low = i2c_r(sd, 0x0b);
+               if (low < 0) {
+                       PDEBUG(D_ERR, "Error detecting camera chip VER");
+                       return low;
+               }
+               if (high == 0x76) {
+                       if (low == 0x30) {
+                               PDEBUG(D_PROBE, "Sensor is an OV7630/OV7635");
+                               sd->sensor = SEN_OV7630;
+                       } else if (low == 0x40) {
+                               PDEBUG(D_PROBE, "Sensor is an OV7645");
+                               sd->sensor = SEN_OV7640; /* FIXME */
+                       } else if (low == 0x45) {
+                               PDEBUG(D_PROBE, "Sensor is an OV7645B");
+                               sd->sensor = SEN_OV7640; /* FIXME */
+                       } else if (low == 0x48) {
+                               PDEBUG(D_PROBE, "Sensor is an OV7648");
+                               sd->sensor = SEN_OV7640; /* FIXME */
+                       } else {
+                               PDEBUG(D_PROBE, "Unknown sensor: 0x76%X", low);
+                               return -1;
+                       }
+               } else {
+                       PDEBUG(D_PROBE, "Sensor is an OV7620");
+                       sd->sensor = SEN_OV7620;
+               }
+       } else {
+               PDEBUG(D_ERR, "Unknown image sensor version: %d", rc & 3);
+               return -1;
+       }
+
+       if (sd->sensor == SEN_OV7620) {
+               PDEBUG(D_PROBE, "Writing 7620 registers");
+               if (write_i2c_regvals(sd, norm_7620,
+                               sizeof norm_7620 / sizeof norm_7620[0]))
+                       return -1;
+       } else if (sd->sensor == SEN_OV7630) {
+               PDEBUG(D_ERR, "7630 is not supported by this driver version");
+               return -1;
+       } else if (sd->sensor == SEN_OV7640) {
+               PDEBUG(D_PROBE, "Writing 7640 registers");
+               if (write_i2c_regvals(sd, norm_7640,
+                               sizeof norm_7640 / sizeof norm_7640[0]))
+                       return -1;
+       } else if (sd->sensor == SEN_OV7670) {
+               PDEBUG(D_PROBE, "Writing 7670 registers");
+               if (write_i2c_regvals(sd, norm_7670,
+                               sizeof norm_7670 / sizeof norm_7670[0]))
+                       return -1;
+       } else {
+               PDEBUG(D_PROBE, "Writing 7610 registers");
+               if (write_i2c_regvals(sd, norm_7610,
+                               sizeof norm_7610 / sizeof norm_7610[0]))
+                       return -1;
+       }
+
+       /* Set sensor-specific vars */
+       sd->maxwidth = 640;
+       sd->maxheight = 480;
+       return 0;
+}
+
+/* This initializes the OV6620, OV6630, OV6630AE, or OV6630AF sensor. */
+static int ov6xx0_configure(struct sd *sd)
+{
+       int rc;
+       static struct ov_i2c_regvals norm_6x20[] = {
+               { 0x12, 0x80 }, /* reset */
+               { 0x11, 0x01 },
+               { 0x03, 0x60 },
+               { 0x05, 0x7f }, /* For when autoadjust is off */
+               { 0x07, 0xa8 },
+               /* The ratio of 0x0c and 0x0d  controls the white point */
+               { 0x0c, 0x24 },
+               { 0x0d, 0x24 },
+               { 0x0f, 0x15 }, /* COMS */
+               { 0x10, 0x75 }, /* AEC Exposure time */
+               { 0x12, 0x24 }, /* Enable AGC */
+               { 0x14, 0x04 },
+               /* 0x16: 0x06 helps frame stability with moving objects */
+               { 0x16, 0x06 },
+/*             { 0x20, 0x30 },  * Aperture correction enable */
+               { 0x26, 0xb2 }, /* BLC enable */
+               /* 0x28: 0x05 Selects RGB format if RGB on */
+               { 0x28, 0x05 },
+               { 0x2a, 0x04 }, /* Disable framerate adjust */
+/*             { 0x2b, 0xac },  * Framerate; Set 2a[7] first */
+               { 0x2d, 0x99 },
+               { 0x33, 0xa0 }, /* Color Processing Parameter */
+               { 0x34, 0xd2 }, /* Max A/D range */
+               { 0x38, 0x8b },
+               { 0x39, 0x40 },
+
+               { 0x3c, 0x39 }, /* Enable AEC mode changing */
+               { 0x3c, 0x3c }, /* Change AEC mode */
+               { 0x3c, 0x24 }, /* Disable AEC mode changing */
+
+               { 0x3d, 0x80 },
+               /* These next two registers (0x4a, 0x4b) are undocumented.
+                * They control the color balance */
+               { 0x4a, 0x80 },
+               { 0x4b, 0x80 },
+               { 0x4d, 0xd2 }, /* This reduces noise a bit */
+               { 0x4e, 0xc1 },
+               { 0x4f, 0x04 },
+/* Do 50-53 have any effect? */
+/* Toggle 0x12[2] off and on here? */
+       };
+
+       static struct ov_i2c_regvals norm_6x30[] = {
+               { 0x12, 0x80 }, /* Reset */
+               { 0x00, 0x1f }, /* Gain */
+               { 0x01, 0x99 }, /* Blue gain */
+               { 0x02, 0x7c }, /* Red gain */
+               { 0x03, 0xc0 }, /* Saturation */
+               { 0x05, 0x0a }, /* Contrast */
+               { 0x06, 0x95 }, /* Brightness */
+               { 0x07, 0x2d }, /* Sharpness */
+               { 0x0c, 0x20 },
+               { 0x0d, 0x20 },
+               { 0x0e, 0x20 },
+               { 0x0f, 0x05 },
+               { 0x10, 0x9a },
+               { 0x11, 0x00 }, /* Pixel clock = fastest */
+               { 0x12, 0x24 }, /* Enable AGC and AWB */
+               { 0x13, 0x21 },
+               { 0x14, 0x80 },
+               { 0x15, 0x01 },
+               { 0x16, 0x03 },
+               { 0x17, 0x38 },
+               { 0x18, 0xea },
+               { 0x19, 0x04 },
+               { 0x1a, 0x93 },
+               { 0x1b, 0x00 },
+               { 0x1e, 0xc4 },
+               { 0x1f, 0x04 },
+               { 0x20, 0x20 },
+               { 0x21, 0x10 },
+               { 0x22, 0x88 },
+               { 0x23, 0xc0 }, /* Crystal circuit power level */
+               { 0x25, 0x9a }, /* Increase AEC black ratio */
+               { 0x26, 0xb2 }, /* BLC enable */
+               { 0x27, 0xa2 },
+               { 0x28, 0x00 },
+               { 0x29, 0x00 },
+               { 0x2a, 0x84 }, /* 60 Hz power */
+               { 0x2b, 0xa8 }, /* 60 Hz power */
+               { 0x2c, 0xa0 },
+               { 0x2d, 0x95 }, /* Enable auto-brightness */
+               { 0x2e, 0x88 },
+               { 0x33, 0x26 },
+               { 0x34, 0x03 },
+               { 0x36, 0x8f },
+               { 0x37, 0x80 },
+               { 0x38, 0x83 },
+               { 0x39, 0x80 },
+               { 0x3a, 0x0f },
+               { 0x3b, 0x3c },
+               { 0x3c, 0x1a },
+               { 0x3d, 0x80 },
+               { 0x3e, 0x80 },
+               { 0x3f, 0x0e },
+               { 0x40, 0x00 }, /* White bal */
+               { 0x41, 0x00 }, /* White bal */
+               { 0x42, 0x80 },
+               { 0x43, 0x3f }, /* White bal */
+               { 0x44, 0x80 },
+               { 0x45, 0x20 },
+               { 0x46, 0x20 },
+               { 0x47, 0x80 },
+               { 0x48, 0x7f },
+               { 0x49, 0x00 },
+               { 0x4a, 0x00 },
+               { 0x4b, 0x80 },
+               { 0x4c, 0xd0 },
+               { 0x4d, 0x10 }, /* U = 0.563u, V = 0.714v */
+               { 0x4e, 0x40 },
+               { 0x4f, 0x07 }, /* UV avg., col. killer: max */
+               { 0x50, 0xff },
+               { 0x54, 0x23 }, /* Max AGC gain: 18dB */
+               { 0x55, 0xff },
+               { 0x56, 0x12 },
+               { 0x57, 0x81 },
+               { 0x58, 0x75 },
+               { 0x59, 0x01 }, /* AGC dark current comp.: +1 */
+               { 0x5a, 0x2c },
+               { 0x5b, 0x0f }, /* AWB chrominance levels */
+               { 0x5c, 0x10 },
+               { 0x3d, 0x80 },
+               { 0x27, 0xa6 },
+               { 0x12, 0x20 }, /* Toggle AWB */
+               { 0x12, 0x24 },
+       };
+
+       PDEBUG(D_PROBE, "starting sensor configuration");
+
+       if (init_ov_sensor(sd) < 0) {
+               PDEBUG(D_ERR, "Failed to read sensor ID.");
+               return -1;
+       }
+       PDEBUG(D_PROBE, "OV6xx0 sensor detected");
+
+       /* Detect sensor (sub)type */
+       rc = i2c_r(sd, OV7610_REG_COM_I);
+       if (rc < 0) {
+               PDEBUG(D_ERR, "Error detecting sensor type");
+               return -1;
+       }
+
+       /* Ugh. The first two bits are the version bits, but
+        * the entire register value must be used. I guess OVT
+        * underestimated how many variants they would make. */
+       if (rc == 0x00) {
+               sd->sensor = SEN_OV6630;
+               PDEBUG(D_ERR,
+                       "WARNING: Sensor is an OV66308. Your camera may have");
+               PDEBUG(D_ERR, "been misdetected in previous driver versions.");
+       } else if (rc == 0x01) {
+               sd->sensor = SEN_OV6620;
+               PDEBUG(D_PROBE, "Sensor is an OV6620");
+       } else if (rc == 0x02) {
+               sd->sensor = SEN_OV6630;
+               PDEBUG(D_PROBE, "Sensor is an OV66308AE");
+       } else if (rc == 0x03) {
+               sd->sensor = SEN_OV6630;
+               PDEBUG(D_PROBE, "Sensor is an OV66308AF");
+       } else if (rc == 0x90) {
+               sd->sensor = SEN_OV6630;
+               PDEBUG(D_ERR,
+                       "WARNING: Sensor is an OV66307. Your camera may have");
+               PDEBUG(D_ERR, "been misdetected in previous driver versions.");
+       } else {
+               PDEBUG(D_ERR, "FATAL: Unknown sensor version: 0x%02x", rc);
+               return -1;
+       }
+
+       /* Set sensor-specific vars */
+       sd->maxwidth = 352;
+       sd->maxheight = 288;
+
+       if (sd->sensor == SEN_OV6620) {
+               PDEBUG(D_PROBE, "Writing 6x20 registers");
+               if (write_i2c_regvals(sd, norm_6x20,
+                               sizeof norm_6x20 / sizeof norm_6x20[0]))
+                       return -1;
+       } else {
+               PDEBUG(D_PROBE, "Writing 6x30 registers");
+               if (write_i2c_regvals(sd, norm_6x30,
+                               sizeof norm_6x30 / sizeof norm_6x30[0]))
+                       return -1;
+       }
+       return 0;
+}
+
+/* Turns on or off the LED. Only has an effect with OV511+/OV518(+)/OV519 */
+static void ov51x_led_control(struct sd *sd, int on)
+{
+       PDEBUG(D_STREAM, "LED (%s)", on ? "on" : "off");
+
+/*     if (sd->bridge == BRG_OV511PLUS) */
+/*             reg_w(sd, R511_SYS_LED_CTL, on ? 1 : 0); */
+/*     else if (sd->bridge == BRG_OV519) */
+               reg_w_mask(sd, OV519_GPIO_DATA_OUT0, !on, 1);   /* 0 / 1 */
+/*     else if (sd->bclass == BCL_OV518) */
+/*             reg_w_mask(sd, R518_GPIO_OUT, on ? 0x02 : 0x00, 0x02); */
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+                       const struct usb_device_id *id)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct cam *cam;
+
+/* (from ov519_configure) */
+       static struct ov_regvals init_519[] = {
+               { 0x5a,  0x6d }, /* EnableSystem */
+/* jfm trace usbsnoop3-1.txt */
+/* jfm 53 = fb */
+               { 0x53,  0x9b },
+               { 0x54,  0xff }, /* set bit2 to enable jpeg */
+               { 0x5d,  0x03 },
+               { 0x49,  0x01 },
+               { 0x48,  0x00 },
+               /* Set LED pin to output mode. Bit 4 must be cleared or sensor
+                * detection will fail. This deserves further investigation. */
+               { OV519_GPIO_IO_CTRL0,   0xee },
+               { 0x51,  0x0f }, /* SetUsbInit */
+               { 0x51,  0x00 },
+               { 0x22,  0x00 },
+               /* windows reads 0x55 at this point*/
+       };
+
+       if (write_regvals(sd, init_519,
+                       sizeof init_519 / sizeof init_519[0]))
+               goto error;
+/* jfm: not seen in windows trace */
+       if (ov519_init_compression(sd))
+               goto error;
+       ov51x_led_control(sd, 0);       /* turn LED off */
+
+       /* Test for 76xx */
+       sd->primary_i2c_slave = OV7xx0_SID;
+       if (ov51x_set_slave_ids(sd, OV7xx0_SID) < 0)
+               goto error;
+
+       /* The OV519 must be more aggressive about sensor detection since
+        * I2C write will never fail if the sensor is not present. We have
+        * to try to initialize the sensor to detect its presence */
+       if (init_ov_sensor(sd) < 0) {
+               /* Test for 6xx0 */
+               sd->primary_i2c_slave = OV6xx0_SID;
+               if (ov51x_set_slave_ids(sd, OV6xx0_SID) < 0)
+                       goto error;
+
+               if (init_ov_sensor(sd) < 0) {
+                       /* Test for 8xx0 */
+                       sd->primary_i2c_slave = OV8xx0_SID;
+                       if (ov51x_set_slave_ids(sd, OV8xx0_SID) < 0)
+                               goto error;
+
+                       if (init_ov_sensor(sd) < 0) {
+                               PDEBUG(D_ERR,
+                                       "Can't determine sensor slave IDs");
+                               goto error;
+                       } else {
+                               if (ov8xx0_configure(sd) < 0) {
+                                       PDEBUG(D_ERR,
+                                          "Failed to configure OV8xx0 sensor");
+                                       goto error;
+                               }
+                       }
+               } else {
+                       if (ov6xx0_configure(sd) < 0) {
+                               PDEBUG(D_ERR, "Failed to configure OV6xx0");
+                               goto error;
+                       }
+               }
+       } else {
+               if (ov7xx0_configure(sd) < 0) {
+                       PDEBUG(D_ERR, "Failed to configure OV7xx0");
+                       goto error;
+               }
+       }
+
+       cam = &gspca_dev->cam;
+       cam->epaddr = OV511_ENDPOINT_ADDRESS;
+       if (sd->maxwidth == 640) {
+               cam->cam_mode = vga_mode;
+               cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+       } else {
+               cam->cam_mode = sif_mode;
+               cam->nmodes = sizeof sif_mode / sizeof sif_mode[0];
+       }
+       cam->dev_name = (char *) id->driver_info;
+       sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
+       sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
+       sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value;
+       return 0;
+error:
+       PDEBUG(D_ERR, "OV519 Config failed");
+       return -EBUSY;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+       return 0;
+}
+
+/* Sets up the OV519 with the given image parameters
+ *
+ * OV519 needs a completely different approach, until we can figure out what
+ * the individual registers do.
+ *
+ * Do not put any sensor-specific code in here (including I2C I/O functions)
+ */
+static int ov519_mode_init_regs(struct sd *sd,
+                               int width, int height)
+{
+       static struct ov_regvals mode_init_519_ov7670[] = {
+               { 0x5d, 0x03 }, /* Turn off suspend mode */
+               { 0x53, 0x9f }, /* was 9b in 1.65-1.08 */
+               { 0x54, 0x0f }, /* bit2 (jpeg enable) */
+               { 0xa2, 0x20 }, /* a2-a5 are undocumented */
+               { 0xa3, 0x18 },
+               { 0xa4, 0x04 },
+               { 0xa5, 0x28 },
+               { 0x37, 0x00 }, /* SetUsbInit */
+               { 0x55, 0x02 }, /* 4.096 Mhz audio clock */
+               /* Enable both fields, YUV Input, disable defect comp (why?) */
+               { 0x20, 0x0c },
+               { 0x21, 0x38 },
+               { 0x22, 0x1d },
+               { 0x17, 0x50 }, /* undocumented */
+               { 0x37, 0x00 }, /* undocumented */
+               { 0x40, 0xff }, /* I2C timeout counter */
+               { 0x46, 0x00 }, /* I2C clock prescaler */
+               { 0x59, 0x04 }, /* new from windrv 090403 */
+               { 0xff, 0x00 }, /* undocumented */
+               /* windows reads 0x55 at this point, why? */
+       };
+
+       static struct ov_regvals mode_init_519[] = {
+               { 0x5d, 0x03 }, /* Turn off suspend mode */
+               { 0x53, 0x9f }, /* was 9b in 1.65-1.08 */
+               { 0x54, 0x0f }, /* bit2 (jpeg enable) */
+               { 0xa2, 0x20 }, /* a2-a5 are undocumented */
+               { 0xa3, 0x18 },
+               { 0xa4, 0x04 },
+               { 0xa5, 0x28 },
+               { 0x37, 0x00 }, /* SetUsbInit */
+               { 0x55, 0x02 }, /* 4.096 Mhz audio clock */
+               /* Enable both fields, YUV Input, disable defect comp (why?) */
+               { 0x22, 0x1d },
+               { 0x17, 0x50 }, /* undocumented */
+               { 0x37, 0x00 }, /* undocumented */
+               { 0x40, 0xff }, /* I2C timeout counter */
+               { 0x46, 0x00 }, /* I2C clock prescaler */
+               { 0x59, 0x04 }, /* new from windrv 090403 */
+               { 0xff, 0x00 }, /* undocumented */
+               /* windows reads 0x55 at this point, why? */
+       };
+
+/* int hi_res; */
+
+       PDEBUG(D_CONF, "mode init %dx%d", width, height);
+
+/*     if (width >= 800 && height >= 600)
+               hi_res = 1;
+       else
+               hi_res = 0; */
+
+/*     if (ov51x_stop(sd) < 0)
+               return -EIO; */
+
+       /******** Set the mode ********/
+       if (sd->sensor != SEN_OV7670) {
+               if (write_regvals(sd, mode_init_519,
+                           sizeof mode_init_519 / sizeof mode_init_519[0]))
+                       return -EIO;
+       } else {
+               if (write_regvals(sd, mode_init_519_ov7670,
+                               sizeof mode_init_519_ov7670
+                                       / sizeof mode_init_519_ov7670[0]))
+                       return -EIO;
+       }
+
+       if (sd->sensor == SEN_OV7640) {
+               /* Select 8-bit input mode */
+               reg_w_mask(sd, OV519_CAM_DFR, 0x10, 0x10);
+       }
+
+       reg_w(sd, OV519_CAM_H_SIZE,     width >> 4);
+       reg_w(sd, OV519_CAM_V_SIZE,     height >> 3);
+       reg_w(sd, OV519_CAM_X_OFFSETL,  0x00);
+       reg_w(sd, OV519_CAM_X_OFFSETH,  0x00);
+       reg_w(sd, OV519_CAM_Y_OFFSETL,  0x00);
+       reg_w(sd, OV519_CAM_Y_OFFSETH,  0x00);
+       reg_w(sd, OV519_CAM_DIVIDER,    0x00);
+       reg_w(sd, OV519_CAM_FORMAT,     0x03); /* YUV422 */
+       reg_w(sd, 0x26,                 0x00); /* Undocumented */
+
+       /******** Set the framerate ********/
+       if (frame_rate > 0)
+               sd->frame_rate = frame_rate;
+
+/* FIXME: These are only valid at the max resolution. */
+       sd->clockdiv = 0;
+       if (sd->sensor == SEN_OV7640) {
+               switch (sd->frame_rate) {
+/*jfm: default was 30 fps */
+               case 30:
+                       reg_w(sd, 0xa4, 0x0c);
+                       reg_w(sd, 0x23, 0xff);
+                       break;
+               case 25:
+                       reg_w(sd, 0xa4, 0x0c);
+                       reg_w(sd, 0x23, 0x1f);
+                       break;
+               case 20:
+                       reg_w(sd, 0xa4, 0x0c);
+                       reg_w(sd, 0x23, 0x1b);
+                       break;
+               default:
+/*             case 15: */
+                       reg_w(sd, 0xa4, 0x04);
+                       reg_w(sd, 0x23, 0xff);
+                       sd->clockdiv = 1;
+                       break;
+               case 10:
+                       reg_w(sd, 0xa4, 0x04);
+                       reg_w(sd, 0x23, 0x1f);
+                       sd->clockdiv = 1;
+                       break;
+               case 5:
+                       reg_w(sd, 0xa4, 0x04);
+                       reg_w(sd, 0x23, 0x1b);
+                       sd->clockdiv = 1;
+                       break;
+               }
+       } else if (sd->sensor == SEN_OV8610) {
+               switch (sd->frame_rate) {
+               default:        /* 15 fps */
+/*             case 15: */
+                       reg_w(sd, 0xa4, 0x06);
+                       reg_w(sd, 0x23, 0xff);
+                       break;
+               case 10:
+                       reg_w(sd, 0xa4, 0x06);
+                       reg_w(sd, 0x23, 0x1f);
+                       break;
+               case 5:
+                       reg_w(sd, 0xa4, 0x06);
+                       reg_w(sd, 0x23, 0x1b);
+                       break;
+               }
+               sd->clockdiv = 0;
+       } else if (sd->sensor == SEN_OV7670) { /* guesses, based on 7640 */
+               PDEBUG(D_STREAM, "Setting framerate to %d fps",
+                                (sd->frame_rate == 0) ? 15 : sd->frame_rate);
+               switch (sd->frame_rate) {
+               case 30:
+                       reg_w(sd, 0xa4, 0x10);
+                       reg_w(sd, 0x23, 0xff);
+                       break;
+               case 20:
+                       reg_w(sd, 0xa4, 0x10);
+                       reg_w(sd, 0x23, 0x1b);
+                       break;
+               default: /* 15 fps */
+/*                     case 15: */
+                       reg_w(sd, 0xa4, 0x10);
+                       reg_w(sd, 0x23, 0xff);
+                       sd->clockdiv = 1;
+                       break;
+               }
+       }
+
+/*     if (ov51x_restart(sd) < 0)
+               return -EIO; */
+
+       /* Reset it just for good measure */
+/*     if (ov51x_reset(sd, OV511_RESET_NOREGS) < 0)
+               return -EIO; */
+       return 0;
+}
+
+static int mode_init_ov_sensor_regs(struct sd *sd,
+                               struct ovsensor_window *win)
+{
+       int qvga = win->quarter;
+
+       /******** Mode (VGA/QVGA) and sensor specific regs ********/
+       switch (sd->sensor) {
+       case SEN_OV8610:
+               /* For OV8610 qvga means qsvga */
+               i2c_w_mask(sd, OV7610_REG_COM_C, qvga ? (1 << 5) : 0, 1 << 5);
+               break;
+       case SEN_OV7610:
+               i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);
+               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);
+               break;
+       case SEN_OV7640:
+/*             i2c_w(sd, 0x2b, 0x00); */
+               i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);
+               i2c_w_mask(sd, 0x28, qvga ? 0x00 : 0x20, 0x20);
+/*             i2c_w(sd, 0x24, qvga ? 0x20 : 0x3a); */
+/*             i2c_w(sd, 0x25, qvga ? 0x30 : 0x60); */
+/*             i2c_w_mask(sd, 0x2d, qvga ? 0x40 : 0x00, 0x40); */
+/*             i2c_w_mask(sd, 0x67, qvga ? 0xf0 : 0x90, 0xf0); */
+/*             i2c_w_mask(sd, 0x74, qvga ? 0x20 : 0x00, 0x20); */
+               break;
+       case SEN_OV7670:
+               /* set COM7_FMT_VGA or COM7_FMT_QVGA
+                * do we need to set anything else?
+                *      HSTART etc are set in set_ov_sensor_window itself */
+               i2c_w_mask(sd, OV7670_REG_COM7,
+                        qvga ? OV7670_COM7_FMT_QVGA : OV7670_COM7_FMT_VGA,
+                        OV7670_COM7_FMT_MASK);
+               break;
+       case SEN_OV6620:
+               i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);
+               break;
+       case SEN_OV6630:
+               i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /******** Palette-specific regs ********/
+/* Need to do work here for the OV7670 */
+
+               if (sd->sensor == SEN_OV7610 || sd->sensor == SEN_OV76BE) {
+                       /* not valid on the OV6620/OV7620/6630? */
+                       i2c_w_mask(sd, 0x0e, 0x00, 0x40);
+               }
+
+               /* The OV518 needs special treatment. Although both the OV518
+                * and the OV6630 support a 16-bit video bus, only the 8 bit Y
+                * bus is actually used. The UV bus is tied to ground.
+                * Therefore, the OV6630 needs to be in 8-bit multiplexed
+                * output mode */
+
+               /* OV7640 is 8-bit only */
+
+               if (sd->sensor != SEN_OV6630 && sd->sensor != SEN_OV7640)
+                       i2c_w_mask(sd, 0x13, 0x00, 0x20);
+/*     } */
+
+       /******** Clock programming ********/
+       /* The OV6620 needs special handling. This prevents the
+        * severe banding that normally occurs */
+       if (sd->sensor == SEN_OV6620) {
+
+               /* Clock down */
+               i2c_w(sd, 0x2a, 0x04);
+               i2c_w(sd, 0x11, win->clockdiv);
+               i2c_w(sd, 0x2a, 0x84);
+               /* This next setting is critical. It seems to improve
+                * the gain or the contrast. The "reserved" bits seem
+                * to have some effect in this case. */
+               i2c_w(sd, 0x2d, 0x85);
+       } else if (win->clockdiv >= 0) {
+               i2c_w(sd, 0x11, win->clockdiv);
+       }
+
+       /******** Special Features ********/
+/* no evidence this is possible with OV7670, either */
+       /* Test Pattern */
+       if (sd->sensor != SEN_OV7640 && sd->sensor != SEN_OV7670)
+               i2c_w_mask(sd, 0x12, 0x00, 0x02);
+
+       /* Enable auto white balance */
+       if (sd->sensor == SEN_OV7670)
+               i2c_w_mask(sd, OV7670_REG_COM8, OV7670_COM8_AWB,
+                               OV7670_COM8_AWB);
+       else
+               i2c_w_mask(sd, 0x12, 0x04, 0x04);
+
+       /* This will go away as soon as ov51x_mode_init_sensor_regs() */
+       /* is fully tested. */
+       /* 7620/6620/6630? don't have register 0x35, so play it safe */
+       if (sd->sensor == SEN_OV7610 || sd->sensor == SEN_OV76BE) {
+               if (win->width == 640 /*&& win->height == 480*/)
+                       i2c_w(sd, 0x35, 0x9e);
+               else
+                       i2c_w(sd, 0x35, 0x1e);
+       }
+       return 0;
+}
+
+static int set_ov_sensor_window(struct sd *sd,
+                               struct ovsensor_window *win)
+{
+       int hwsbase, hwebase, vwsbase, vwebase, hwscale, vwscale;
+       int ret, hstart, hstop, vstop, vstart;
+       __u8 v;
+
+       /* The different sensor ICs handle setting up of window differently.
+        * IF YOU SET IT WRONG, YOU WILL GET ALL ZERO ISOC DATA FROM OV51x!! */
+       switch (sd->sensor) {
+       case SEN_OV8610:
+               hwsbase = 0x1e;
+               hwebase = 0x1e;
+               vwsbase = 0x02;
+               vwebase = 0x02;
+               break;
+       case SEN_OV7610:
+       case SEN_OV76BE:
+               hwsbase = 0x38;
+               hwebase = 0x3a;
+               vwsbase = vwebase = 0x05;
+               break;
+       case SEN_OV6620:
+       case SEN_OV6630:
+               hwsbase = 0x38;
+               hwebase = 0x3a;
+               vwsbase = 0x05;
+               vwebase = 0x06;
+               break;
+       case SEN_OV7620:
+               hwsbase = 0x2f;         /* From 7620.SET (spec is wrong) */
+               hwebase = 0x2f;
+               vwsbase = vwebase = 0x05;
+               break;
+       case SEN_OV7640:
+               hwsbase = 0x1a;
+               hwebase = 0x1a;
+               vwsbase = vwebase = 0x03;
+               break;
+       case SEN_OV7670:
+               /*handling of OV7670 hardware sensor start and stop values
+                * is very odd, compared to the other OV sensors */
+               vwsbase = vwebase = hwebase = hwsbase = 0x00;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (sd->sensor) {
+       case SEN_OV6620:
+       case SEN_OV6630:
+               if (win->quarter) {     /* QCIF */
+                       hwscale = 0;
+                       vwscale = 0;
+               } else {                /* CIF */
+                       hwscale = 1;
+                       vwscale = 1;    /* The datasheet says 0;
+                                        * it's wrong */
+               }
+               break;
+       case SEN_OV8610:
+               if (win->quarter) {     /* QSVGA */
+                       hwscale = 1;
+                       vwscale = 1;
+               } else {                /* SVGA */
+                       hwscale = 2;
+                       vwscale = 2;
+               }
+               break;
+       default:                        /* SEN_OV7xx0 */
+               if (win->quarter) {     /* QVGA */
+                       hwscale = 1;
+                       vwscale = 0;
+               } else {                /* VGA */
+                       hwscale = 2;
+                       vwscale = 1;
+               }
+       }
+
+       ret = mode_init_ov_sensor_regs(sd, win);
+       if (ret < 0)
+               return ret;
+
+       if (sd->sensor == SEN_OV8610) {
+               i2c_w_mask(sd, 0x2d, 0x05, 0x40);
+                               /* old 0x95, new 0x05 from windrv 090403 */
+                                               /* bits 5-7: reserved */
+               i2c_w_mask(sd, 0x28, 0x20, 0x20);
+                                       /* bit 5: progressive mode on */
+       }
+
+       /* The below is wrong for OV7670s because their window registers
+        * only store the high bits in 0x17 to 0x1a */
+
+       /* SRH Use sd->max values instead of requested win values */
+       /* SCS Since we're sticking with only the max hardware widths
+        * for a given mode */
+       /* I can hard code this for OV7670s */
+       /* Yes, these numbers do look odd, but they're tested and work! */
+       if (sd->sensor == SEN_OV7670) {
+               if (win->quarter) {     /* QVGA from ov7670.c by
+                                        * Jonathan Corbet */
+                       hstart = 164;
+                       hstop = 20;
+                       vstart = 14;
+                       vstop = 494;
+               } else {                /* VGA */
+                       hstart = 158;
+                       hstop = 14;
+                       vstart = 10;
+                       vstop = 490;
+               }
+               /* OV7670 hardware window registers are split across
+                * multiple locations */
+               i2c_w(sd, OV7670_REG_HSTART, (hstart >> 3) & 0xff);
+               i2c_w(sd, OV7670_REG_HSTOP, (hstop >> 3) & 0xff);
+               v = i2c_r(sd, OV7670_REG_HREF);
+               v = (v & 0xc0) | ((hstop & 0x7) << 3) | (hstart & 0x07);
+               msleep(10);     /* need to sleep between read and write to
+                                * same reg! */
+               i2c_w(sd, OV7670_REG_HREF, v);
+
+               i2c_w(sd, OV7670_REG_VSTART, (vstart >> 2) & 0xff);
+               i2c_w(sd, OV7670_REG_VSTOP, (vstop >> 2) & 0xff);
+               v = i2c_r(sd, OV7670_REG_VREF);
+               v = (v & 0xc0) | ((vstop & 0x3) << 2) | (vstart & 0x03);
+               msleep(10);     /* need to sleep between read and write to
+                                * same reg! */
+               i2c_w(sd, OV7670_REG_VREF, v);
+
+       } else {
+               i2c_w(sd, 0x17, hwsbase + (win->x >> hwscale));
+               i2c_w(sd, 0x18, hwebase + ((win->x + win->width) >> hwscale));
+               i2c_w(sd, 0x19, vwsbase + (win->y >> vwscale));
+               i2c_w(sd, 0x1a, vwebase + ((win->y + win->height) >> vwscale));
+       }
+       return 0;
+}
+
+static int ov_sensor_mode_setup(struct sd *sd,
+                               int width, int height)
+{
+       struct ovsensor_window win;
+
+/*     win.format = mode; */
+
+       /* Unless subcapture is enabled,
+        * center the image window and downsample
+        * if possible to increase the field of view */
+       /* NOTE: OV518(+) and OV519 does downsampling on its own */
+       win.width = width;
+       win.height = height;
+       if (width == sd->maxwidth)
+               win.quarter = 0;
+       else
+               win.quarter = 1;
+
+       /* Center it */
+       win.x = (win.width - width) / 2;
+       win.y = (win.height - height) / 2;
+
+       /* Clock is determined by OV519 frame rate code */
+       win.clockdiv = sd->clockdiv;
+
+       PDEBUG(D_CONF, "Setting clock divider to %d", win.clockdiv);
+       return set_ov_sensor_window(sd, &win);
+}
+
+/* -- start the camera -- */
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int ret;
+
+
+       ret = ov519_mode_init_regs(sd, gspca_dev->width, gspca_dev->height);
+       if (ret < 0)
+               goto out;
+       ret = ov_sensor_mode_setup(sd, gspca_dev->width, gspca_dev->height);
+       if (ret < 0)
+               goto out;
+
+       ret = ov51x_restart((struct sd *) gspca_dev);
+       if (ret < 0)
+               goto out;
+       PDEBUG(D_STREAM, "camera started alt: 0x%02x", gspca_dev->alt);
+       ov51x_led_control(sd, 1);
+       return;
+out:
+       PDEBUG(D_ERR, "camera start error:%d", ret);
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+       ov51x_stop((struct sd *) gspca_dev);
+       ov51x_led_control((struct sd *) gspca_dev, 0);
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+                       struct gspca_frame *frame,      /* target */
+                       unsigned char *data,            /* isoc packet */
+                       int len)                        /* iso packet length */
+{
+       /* Header of ov519 is 16 bytes:
+        *     Byte     Value      Description
+        *      0       0xff    magic
+        *      1       0xff    magic
+        *      2       0xff    magic
+        *      3       0xXX    0x50 = SOF, 0x51 = EOF
+        *      9       0xXX    0x01 initial frame without data,
+        *                      0x00 standard frame with image
+        *      14      Lo      in EOF: length of image data / 8
+        *      15      Hi
+        */
+
+       if (data[0] == 0xff && data[1] == 0xff && data[2] == 0xff) {
+               switch (data[3]) {
+               case 0x50:              /* start of frame */
+#define HDRSZ 16
+                       data += HDRSZ;
+                       len -= HDRSZ;
+#undef HDRSZ
+                       if (data[0] == 0xff || data[1] == 0xd8)
+                               gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+                                               data, len);
+                       else
+                               gspca_dev->last_packet_type = DISCARD_PACKET;
+                       return;
+               case 0x51:              /* end of frame */
+                       if (data[9] != 0)
+                               gspca_dev->last_packet_type = DISCARD_PACKET;
+                       gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+                                       data, 0);
+                       return;
+               }
+       }
+
+       /* intermediate packet */
+       gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+                       data, len);
+}
+
+/* -- management routines -- */
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int val;
+/*     int was_streaming; */
+
+       val = sd->brightness;
+       PDEBUG(D_CONF, "brightness:%d", val);
+/*     was_streaming = gspca_dev->streaming;
+ *     if (was_streaming)
+ *             ov51x_stop(sd); */
+       switch (sd->sensor) {
+       case SEN_OV8610:
+       case SEN_OV7610:
+       case SEN_OV76BE:
+       case SEN_OV6620:
+       case SEN_OV6630:
+       case SEN_OV7640:
+               i2c_w(sd, OV7610_REG_BRT, val);
+               break;
+       case SEN_OV7620:
+               /* 7620 doesn't like manual changes when in auto mode */
+/*fixme
+ *             if (!sd->auto_brt) */
+                       i2c_w(sd, OV7610_REG_BRT, val);
+               break;
+       case SEN_OV7670:
+/*jfm - from windblows
+ *             i2c_w_mask(sd, OV7670_REG_COM8, 0, OV7670_COM8_AEC); */
+               i2c_w(sd, OV7670_REG_BRIGHT, ov7670_abs_to_sm(val));
+               break;
+       }
+/*     if (was_streaming)
+ *             ov51x_restart(sd); */
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int val;
+/*     int was_streaming; */
+
+       val = sd->contrast;
+       PDEBUG(D_CONF, "contrast:%d", val);
+/*     was_streaming = gspca_dev->streaming;
+       if (was_streaming)
+               ov51x_stop(sd); */
+       switch (sd->sensor) {
+       case SEN_OV7610:
+       case SEN_OV6620:
+               i2c_w(sd, OV7610_REG_CNT, val);
+               break;
+       case SEN_OV6630:
+               i2c_w_mask(sd, OV7610_REG_CNT, val >> 4, 0x0f);
+       case SEN_OV8610: {
+               static __u8 ctab[] = {
+                       0x03, 0x09, 0x0b, 0x0f, 0x53, 0x6f, 0x35, 0x7f
+               };
+
+               /* Use Y gamma control instead. Bit 0 enables it. */
+               i2c_w(sd, 0x64, ctab[val >> 5]);
+               break;
+           }
+       case SEN_OV7620: {
+               static __u8 ctab[] = {
+                       0x01, 0x05, 0x09, 0x11, 0x15, 0x35, 0x37, 0x57,
+                       0x5b, 0xa5, 0xa7, 0xc7, 0xc9, 0xcf, 0xef, 0xff
+               };
+
+               /* Use Y gamma control instead. Bit 0 enables it. */
+               i2c_w(sd, 0x64, ctab[val >> 4]);
+               break;
+           }
+       case SEN_OV7640:
+               /* Use gain control instead. */
+               i2c_w(sd, OV7610_REG_GAIN, val >> 2);
+               break;
+       case SEN_OV7670:
+               /* check that this isn't just the same as ov7610 */
+               i2c_w(sd, OV7670_REG_CONTRAS, val >> 1);
+               break;
+       }
+/*     if (was_streaming)
+               ov51x_restart(sd); */
+}
+
+static void setcolors(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int val;
+/*     int was_streaming; */
+
+       val = sd->colors;
+       PDEBUG(D_CONF, "saturation:%d", val);
+/*     was_streaming = gspca_dev->streaming;
+       if (was_streaming)
+               ov51x_stop(sd); */
+       switch (sd->sensor) {
+       case SEN_OV8610:
+       case SEN_OV7610:
+       case SEN_OV76BE:
+       case SEN_OV6620:
+       case SEN_OV6630:
+               i2c_w(sd, OV7610_REG_SAT, val);
+               break;
+       case SEN_OV7620:
+               /* Use UV gamma control instead. Bits 0 & 7 are reserved. */
+/*             rc = ov_i2c_write(sd->dev, 0x62, (val >> 9) & 0x7e);
+               if (rc < 0)
+                       goto out; */
+               i2c_w(sd, OV7610_REG_SAT, val);
+               break;
+       case SEN_OV7640:
+               i2c_w(sd, OV7610_REG_SAT, val & 0xf0);
+               break;
+       case SEN_OV7670:
+               /* supported later once I work out how to do it
+                * transparently fail now! */
+               /* set REG_COM13 values for UV sat auto mode */
+               break;
+       }
+/*     if (was_streaming)
+               ov51x_restart(sd); */
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->brightness = val;
+       setbrightness(gspca_dev);
+       return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->brightness;
+       return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->contrast = val;
+       setcontrast(gspca_dev);
+       return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->contrast;
+       return 0;
+}
+
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->colors = val;
+       setcolors(gspca_dev);
+       return 0;
+}
+
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->colors;
+       return 0;
+}
+
+/* sub-driver description */
+static struct sd_desc sd_desc = {
+       .name = MODULE_NAME,
+       .ctrls = sd_ctrls,
+       .nctrls = ARRAY_SIZE(sd_ctrls),
+       .config = sd_config,
+       .open = sd_open,
+       .start = sd_start,
+       .stopN = sd_stopN,
+       .stop0 = sd_stop0,
+       .close = sd_close,
+       .pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static __devinitdata struct usb_device_id device_table[] = {
+       {USB_DEVICE(0x041e, 0x4052), DVNM("Creative Live! VISTA IM")},
+       {USB_DEVICE(0x041e, 0x405f), DVNM("Creative Live! VISTA VF0330")},
+       {USB_DEVICE(0x041e, 0x4060), DVNM("Creative Live! VISTA VF0350")},
+       {USB_DEVICE(0x041e, 0x4061), DVNM("Creative Live! VISTA VF0400")},
+       {USB_DEVICE(0x041e, 0x4064), DVNM("Creative Live! VISTA VF0420")},
+       {USB_DEVICE(0x041e, 0x4068), DVNM("Creative Live! VISTA VF0470")},
+       {USB_DEVICE(0x045e, 0x028c), DVNM("Microsoft xbox cam")},
+       {USB_DEVICE(0x054c, 0x0154), DVNM("Sonny toy4")},
+       {USB_DEVICE(0x054c, 0x0155), DVNM("Sonny toy5")},
+       {USB_DEVICE(0x05a9, 0x0519), DVNM("OmniVision")},
+       {USB_DEVICE(0x05a9, 0x0530), DVNM("OmniVision")},
+       {USB_DEVICE(0x05a9, 0x4519), DVNM("OmniVision")},
+       {USB_DEVICE(0x05a9, 0x8519), DVNM("OmniVision")},
+       {}
+};
+#undef DVNAME
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+                       const struct usb_device_id *id)
+{
+       return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+                               THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+       .name = MODULE_NAME,
+       .id_table = device_table,
+       .probe = sd_probe,
+       .disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+       if (usb_register(&sd_driver) < 0)
+               return -1;
+       PDEBUG(D_PROBE, "v%s registered", version);
+       return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+       usb_deregister(&sd_driver);
+       PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
+
+module_param(frame_rate, int, 0644);
+MODULE_PARM_DESC(frame_rate, "Frame rate (5, 10, 15, 20 or 30 fps)");
index 482ef4a6afc0ff014f669407c774726f7091a6e4..72a5b89cd59daca0c39ae0aa43c172ebc78596a4 100644 (file)
@@ -27,8 +27,8 @@
 
 #include "gspca.h"
 
-#define DRIVER_VERSION_NUMBER  KERNEL_VERSION(0, 2, 15)
-static const char version[] = "0.2.15";
+#define DRIVER_VERSION_NUMBER  KERNEL_VERSION(2, 1, 0)
+static const char version[] = "2.1.0";
 
 MODULE_AUTHOR("Hans de Goede <j.w.r.degoede@hhs.nl>");
 MODULE_DESCRIPTION("Pixart PAC207");
@@ -297,7 +297,6 @@ static int sd_open(struct gspca_dev *gspca_dev)
        struct sd *sd = (struct sd *) gspca_dev;
 
        sd->autogain = 1;
-
        return 0;
 }
 
@@ -338,7 +337,7 @@ static void sd_start(struct gspca_dev *gspca_dev)
 
        pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */
        pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */
-       udelay(1000); /* taken from gspca */
+       msleep(10);
        pac207_write_reg(gspca_dev, 0x40, 0x01); /* Start ISO pipe */
 
        sd->sof_read = 0;
@@ -743,8 +742,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                                PDEBUG(D_STREAM, "Incomplete frame");
                }
                pac207_decode_frame_init(gspca_dev);
-               gspca_frame_add(gspca_dev, FIRST_PACKET, frame, NULL,
-                               0);
+               gspca_frame_add(gspca_dev, FIRST_PACKET, frame, NULL, 0);
                len -= sof - data;
                data = sof;
        }
diff --git a/drivers/media/video/gspca/pac7311.c b/drivers/media/video/gspca/pac7311.c
new file mode 100644 (file)
index 0000000..8f51976
--- /dev/null
@@ -0,0 +1,754 @@
+/*
+ *             Pixart PAC7311 library
+ *             Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define MODULE_NAME "pac7311"
+
+#include "gspca.h"
+
+#define DRIVER_VERSION_NUMBER  KERNEL_VERSION(2, 1, 0)
+static const char version[] = "2.1.0";
+
+MODULE_AUTHOR("Thomas Kaiser thomas@kaiser-linux.li");
+MODULE_DESCRIPTION("Pixart PAC7311");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+       struct gspca_dev gspca_dev;             /* !! must be the first item */
+
+       int avg_lum;
+
+       unsigned char brightness;
+#define BRIGHTNESS_MAX 0x20
+       unsigned char contrast;
+       unsigned char colors;
+       unsigned char autogain;
+
+       char ffseq;
+       signed char ag_cnt;
+#define AG_CNT_START 13
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+#define SD_BRIGHTNESS 0
+       {
+           {
+               .id      = V4L2_CID_BRIGHTNESS,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Brightness",
+               .minimum = 0,
+               .maximum = BRIGHTNESS_MAX,
+               .step    = 1,
+               .default_value = 0x10,
+           },
+           .set = sd_setbrightness,
+           .get = sd_getbrightness,
+       },
+#define SD_CONTRAST 1
+       {
+           {
+               .id      = V4L2_CID_CONTRAST,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Contrast",
+               .minimum = 0,
+               .maximum = 255,
+               .step    = 1,
+               .default_value = 127,
+           },
+           .set = sd_setcontrast,
+           .get = sd_getcontrast,
+       },
+#define SD_COLOR 2
+       {
+           {
+               .id      = V4L2_CID_SATURATION,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Color",
+               .minimum = 0,
+               .maximum = 255,
+               .step    = 1,
+               .default_value = 127,
+           },
+           .set = sd_setcolors,
+           .get = sd_getcolors,
+       },
+#define SD_AUTOGAIN 3
+       {
+           {
+               .id      = V4L2_CID_AUTOGAIN,
+               .type    = V4L2_CTRL_TYPE_BOOLEAN,
+               .name    = "Auto Gain",
+               .minimum = 0,
+               .maximum = 1,
+               .step    = 1,
+               .default_value = 1,
+           },
+           .set = sd_setautogain,
+           .get = sd_getautogain,
+       },
+};
+
+static struct cam_mode vga_mode[] = {
+       {V4L2_PIX_FMT_JPEG, 160, 120, 2},
+       {V4L2_PIX_FMT_JPEG, 320, 240, 1},
+       {V4L2_PIX_FMT_JPEG, 640, 480, 0},
+};
+
+#define PAC7311_JPEG_HEADER_SIZE (sizeof pac7311_jpeg_header)  /* (594) */
+
+const unsigned char pac7311_jpeg_header[] = {
+       0xff, 0xd8,
+       0xff, 0xe0, 0x00, 0x03, 0x20,
+       0xff, 0xc0, 0x00, 0x11, 0x08,
+               0x01, 0xe0,                     /* 12: height */
+               0x02, 0x80,                     /* 14: width */
+               0x03,                           /* 16 */
+                       0x01, 0x21, 0x00,
+                       0x02, 0x11, 0x01,
+                       0x03, 0x11, 0x01,
+       0xff, 0xdb, 0x00, 0x84,
+       0x00, 0x10, 0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e, 0x0d,
+       0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28, 0x1a, 0x18, 0x16,
+       0x16, 0x18, 0x31, 0x23, 0x25, 0x1d, 0x28, 0x3a, 0x33, 0x3d,
+       0x3c, 0x39, 0x33, 0x38, 0x37, 0x40, 0x48, 0x5c, 0x4e, 0x40,
+       0x44, 0x57, 0x45, 0x37, 0x38, 0x50, 0x6d, 0x51, 0x57, 0x5f,
+       0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71, 0x79, 0x70, 0x64,
+       0x78, 0x5c, 0x65, 0x67, 0x63, 0x01, 0x11, 0x12, 0x12, 0x18,
+       0x15, 0x18, 0x2f, 0x1a, 0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42,
+       0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+       0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+       0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+       0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+       0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+       0xff, 0xc4, 0x01, 0xa2, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01,
+       0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+       0x09, 0x0a, 0x0b, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02,
+       0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d,
+       0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31,
+       0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32,
+       0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52,
+       0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
+       0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a,
+       0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45,
+       0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57,
+       0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+       0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83,
+       0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94,
+       0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
+       0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
+       0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+       0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
+       0xd9, 0xda, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8,
+       0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+       0xf9, 0xfa, 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01,
+       0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
+       0x0b, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04,
+       0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01,
+       0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41,
+       0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14,
+       0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
+       0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25,
+       0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a,
+       0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46,
+       0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+       0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a,
+       0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83,
+       0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94,
+       0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
+       0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
+       0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+       0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
+       0xd9, 0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
+       0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa,
+       0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03,
+       0x11, 0x00, 0x3f, 0x00
+};
+
+static void reg_w(struct usb_device *dev,
+                           __u16 req,
+                           __u16 value,
+                           __u16 index,
+                           __u8 *buffer, __u16 length)
+{
+       usb_control_msg(dev,
+                       usb_sndctrlpipe(dev, 0),
+                       req,
+                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       value, index, buffer, length,
+                       500);
+}
+
+static void pac7311_reg_read(struct usb_device *dev, __u16 index,
+                           __u8 *buffer)
+{
+       usb_control_msg(dev,
+                       usb_rcvctrlpipe(dev, 0),
+                       0,                      /* request */
+                       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       0,                      /* value */
+                       index, buffer, 1,
+                       500);
+}
+
+static void pac7311_reg_write(struct usb_device *dev,
+                             __u16 index,
+                             __u8 value)
+{
+       __u8 buf;
+
+       buf = value;
+       reg_w(dev, 0x00, value, index, &buf, 1);
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+                       const struct usb_device_id *id)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct usb_device *dev = gspca_dev->dev;
+       struct cam *cam;
+
+       PDEBUG(D_CONF, "Find Sensor PAC7311");
+       pac7311_reg_write(dev, 0x78, 0x40); /* Bit_0=start stream, Bit_7=LED */
+       pac7311_reg_write(dev, 0x78, 0x40); /* Bit_0=start stream, Bit_7=LED */
+       pac7311_reg_write(dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
+       pac7311_reg_write(dev, 0xff, 0x04);
+       pac7311_reg_write(dev, 0x27, 0x80);
+       pac7311_reg_write(dev, 0x28, 0xca);
+       pac7311_reg_write(dev, 0x29, 0x53);
+       pac7311_reg_write(dev, 0x2a, 0x0e);
+       pac7311_reg_write(dev, 0xff, 0x01);
+       pac7311_reg_write(dev, 0x3e, 0x20);
+
+       cam = &gspca_dev->cam;
+       cam->dev_name = (char *) id->driver_info;
+       cam->epaddr = 0x05;
+       cam->cam_mode = vga_mode;
+       cam->nmodes = ARRAY_SIZE(vga_mode);
+
+       sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
+       sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
+       sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value;
+       sd->autogain = sd_ctrls[SD_AUTOGAIN].qctrl.default_value;
+       return 0;
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int brightness;
+
+/*jfm: inverted?*/
+       brightness = BRIGHTNESS_MAX - sd->brightness;
+       pac7311_reg_write(gspca_dev->dev, 0xff, 0x04);
+       /* pac7311_reg_write(gspca_dev->dev, 0x0e, 0x00); */
+       pac7311_reg_write(gspca_dev->dev, 0x0f, brightness);
+       /* load registers to sensor (Bit 0, auto clear) */
+       pac7311_reg_write(gspca_dev->dev, 0x11, 0x01);
+       PDEBUG(D_CONF|D_STREAM, "brightness: %i", brightness);
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       pac7311_reg_write(gspca_dev->dev, 0xff, 0x01);
+       pac7311_reg_write(gspca_dev->dev, 0x80, sd->contrast);
+       /* load registers to sensor (Bit 0, auto clear) */
+       pac7311_reg_write(gspca_dev->dev, 0x11, 0x01);
+       PDEBUG(D_CONF|D_STREAM, "contrast: %i", sd->contrast);
+}
+
+static void setcolors(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       pac7311_reg_write(gspca_dev->dev, 0xff, 0x01);
+       pac7311_reg_write(gspca_dev->dev, 0x10, sd->colors);
+       /* load registers to sensor (Bit 0, auto clear) */
+       pac7311_reg_write(gspca_dev->dev, 0x11, 0x01);
+       PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors);
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+       pac7311_reg_write(gspca_dev->dev, 0x78, 0x00);  /* Turn on LED */
+       return 0;
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+       struct usb_device *dev = gspca_dev->dev;
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       pac7311_reg_write(dev, 0xff, 0x01);
+       reg_w(dev, 0x01, 0, 0x0002, "\x48\x0a\x40\x08\x00\x00\x08\x00", 8);
+       reg_w(dev, 0x01, 0, 0x000a, "\x06\xff\x11\xff\x5a\x30\x90\x4c", 8);
+       reg_w(dev, 0x01, 0, 0x0012, "\x00\x07\x00\x0a\x10\x00\xa0\x10", 8);
+       reg_w(dev, 0x01, 0, 0x001a, "\x02\x00\x00\x00\x00\x0b\x01\x00", 8);
+       reg_w(dev, 0x01, 0, 0x0022, "\x00\x00\x00\x00\x00\x00\x00\x00", 8);
+       reg_w(dev, 0x01, 0, 0x002a, "\x00\x00\x00", 3);
+       reg_w(dev, 0x01, 0, 0x003e, "\x00\x00\x78\x52\x4a\x52\x78\x6e", 8);
+       reg_w(dev, 0x01, 0, 0x0046, "\x48\x46\x48\x6e\x5f\x49\x42\x49", 8);
+       reg_w(dev, 0x01, 0, 0x004e, "\x5f\x5f\x49\x42\x49\x5f\x6e\x48", 8);
+       reg_w(dev, 0x01, 0, 0x0056, "\x46\x48\x6e\x78\x52\x4a\x52\x78", 8);
+       reg_w(dev, 0x01, 0, 0x005e, "\x00\x00\x09\x1b\x34\x49\x5c\x9b", 8);
+       reg_w(dev, 0x01, 0, 0x0066, "\xd0\xff", 2);
+       reg_w(dev, 0x01, 0, 0x0078, "\x44\x00\xf2\x01\x01\x80", 6);
+       reg_w(dev, 0x01, 0, 0x007f, "\x2a\x1c\x00\xc8\x02\x58\x03\x84", 8);
+       reg_w(dev, 0x01, 0, 0x0087, "\x12\x00\x1a\x04\x08\x0c\x10\x14", 8);
+       reg_w(dev, 0x01, 0, 0x008f, "\x18\x20", 2);
+       reg_w(dev, 0x01, 0, 0x0096, "\x01\x08\x04", 3);
+       reg_w(dev, 0x01, 0, 0x00a0, "\x44\x44\x44\x04", 4);
+       reg_w(dev, 0x01, 0, 0x00f0, "\x01\x00\x00\x00\x22\x00\x20\x00", 8);
+       reg_w(dev, 0x01, 0, 0x00f8, "\x3f\x00\x0a\x01\x00", 5);
+
+       pac7311_reg_write(dev, 0xff, 0x04);
+       pac7311_reg_write(dev, 0x02, 0x04);
+       pac7311_reg_write(dev, 0x03, 0x54);
+       pac7311_reg_write(dev, 0x04, 0x07);
+       pac7311_reg_write(dev, 0x05, 0x2b);
+       pac7311_reg_write(dev, 0x06, 0x09);
+       pac7311_reg_write(dev, 0x07, 0x0f);
+       pac7311_reg_write(dev, 0x08, 0x09);
+       pac7311_reg_write(dev, 0x09, 0x00);
+       pac7311_reg_write(dev, 0x0c, 0x07);
+       pac7311_reg_write(dev, 0x0d, 0x00);
+       pac7311_reg_write(dev, 0x0e, 0x00);
+       pac7311_reg_write(dev, 0x0f, 0x62);
+       pac7311_reg_write(dev, 0x10, 0x08);
+       pac7311_reg_write(dev, 0x12, 0x07);
+       pac7311_reg_write(dev, 0x13, 0x00);
+       pac7311_reg_write(dev, 0x14, 0x00);
+       pac7311_reg_write(dev, 0x15, 0x00);
+       pac7311_reg_write(dev, 0x16, 0x00);
+       pac7311_reg_write(dev, 0x17, 0x00);
+       pac7311_reg_write(dev, 0x18, 0x00);
+       pac7311_reg_write(dev, 0x19, 0x00);
+       pac7311_reg_write(dev, 0x1a, 0x00);
+       pac7311_reg_write(dev, 0x1b, 0x03);
+       pac7311_reg_write(dev, 0x1c, 0xa0);
+       pac7311_reg_write(dev, 0x1d, 0x01);
+       pac7311_reg_write(dev, 0x1e, 0xf4);
+       pac7311_reg_write(dev, 0x21, 0x00);
+       pac7311_reg_write(dev, 0x22, 0x08);
+       pac7311_reg_write(dev, 0x24, 0x03);
+       pac7311_reg_write(dev, 0x26, 0x00);
+       pac7311_reg_write(dev, 0x27, 0x01);
+       pac7311_reg_write(dev, 0x28, 0xca);
+       pac7311_reg_write(dev, 0x29, 0x10);
+       pac7311_reg_write(dev, 0x2a, 0x06);
+       pac7311_reg_write(dev, 0x2b, 0x78);
+       pac7311_reg_write(dev, 0x2c, 0x00);
+       pac7311_reg_write(dev, 0x2d, 0x00);
+       pac7311_reg_write(dev, 0x2e, 0x00);
+       pac7311_reg_write(dev, 0x2f, 0x00);
+       pac7311_reg_write(dev, 0x30, 0x23);
+       pac7311_reg_write(dev, 0x31, 0x28);
+       pac7311_reg_write(dev, 0x32, 0x04);
+       pac7311_reg_write(dev, 0x33, 0x11);
+       pac7311_reg_write(dev, 0x34, 0x00);
+       pac7311_reg_write(dev, 0x35, 0x00);
+       pac7311_reg_write(dev, 0x11, 0x01);
+       setcontrast(gspca_dev);
+       setbrightness(gspca_dev);
+       setcolors(gspca_dev);
+
+       /* set correct resolution */
+       switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].mode) {
+       case 2:                                 /* 160x120 */
+               pac7311_reg_write(dev, 0xff, 0x04);
+               pac7311_reg_write(dev, 0x02, 0x03);
+               pac7311_reg_write(dev, 0xff, 0x01);
+               pac7311_reg_write(dev, 0x08, 0x09);
+               pac7311_reg_write(dev, 0x17, 0x20);
+               pac7311_reg_write(dev, 0x1b, 0x00);
+/*             pac7311_reg_write(dev, 0x80, 0x69); */
+               pac7311_reg_write(dev, 0x87, 0x10);
+               break;
+       case 1:                                 /* 320x240 */
+               pac7311_reg_write(dev, 0xff, 0x04);
+               pac7311_reg_write(dev, 0x02, 0x03);
+               pac7311_reg_write(dev, 0xff, 0x01);
+               pac7311_reg_write(dev, 0x08, 0x09);
+               pac7311_reg_write(dev, 0x17, 0x30);
+/*             pac7311_reg_write(dev, 0x80, 0x3f); */
+               pac7311_reg_write(dev, 0x87, 0x11);
+               break;
+       case 0:                                 /* 640x480 */
+               pac7311_reg_write(dev, 0xff, 0x04);
+               pac7311_reg_write(dev, 0x02, 0x03);
+               pac7311_reg_write(dev, 0xff, 0x01);
+               pac7311_reg_write(dev, 0x08, 0x08);
+               pac7311_reg_write(dev, 0x17, 0x00);
+/*             pac7311_reg_write(dev, 0x80, 0x1c); */
+               pac7311_reg_write(dev, 0x87, 0x12);
+               break;
+       }
+
+       /* start stream */
+       pac7311_reg_write(dev, 0xff, 0x01);
+       pac7311_reg_write(dev, 0x78, 0x04);
+       pac7311_reg_write(dev, 0x78, 0x05);
+
+       if (sd->autogain) {
+               sd->ag_cnt = AG_CNT_START;
+               sd->avg_lum = 0;
+       } else {
+               sd->ag_cnt = -1;
+       }
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+       struct usb_device *dev = gspca_dev->dev;
+
+       pac7311_reg_write(dev, 0xff, 0x04);
+       pac7311_reg_write(dev, 0x27, 0x80);
+       pac7311_reg_write(dev, 0x28, 0xca);
+       pac7311_reg_write(dev, 0x29, 0x53);
+       pac7311_reg_write(dev, 0x2a, 0x0e);
+       pac7311_reg_write(dev, 0xff, 0x01);
+       pac7311_reg_write(dev, 0x3e, 0x20);
+       pac7311_reg_write(dev, 0x78, 0x04); /* Bit_0=start stream, Bit_7=LED */
+       pac7311_reg_write(dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
+       pac7311_reg_write(dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+/* this function is called at close time */
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+       struct usb_device *dev = gspca_dev->dev;
+
+       pac7311_reg_write(dev, 0xff, 0x04);
+       pac7311_reg_write(dev, 0x27, 0x80);
+       pac7311_reg_write(dev, 0x28, 0xca);
+       pac7311_reg_write(dev, 0x29, 0x53);
+       pac7311_reg_write(dev, 0x2a, 0x0e);
+       pac7311_reg_write(dev, 0xff, 0x01);
+       pac7311_reg_write(dev, 0x3e, 0x20);
+       pac7311_reg_write(dev, 0x78, 0x04); /* Bit_0=start stream, Bit_7=LED */
+       pac7311_reg_write(dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
+       pac7311_reg_write(dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
+}
+
+static void setautogain(struct gspca_dev *gspca_dev, int luma)
+{
+       int luma_mean = 128;
+       int luma_delta = 20;
+       __u8 spring = 5;
+       __u8 Pxclk;
+       int Gbright;
+
+       pac7311_reg_read(gspca_dev->dev, 0x02, &Pxclk);
+       Gbright = Pxclk;
+       PDEBUG(D_FRAM, "luma mean %d", luma);
+       if (luma < luma_mean - luma_delta ||
+           luma > luma_mean + luma_delta) {
+               Gbright += (luma_mean - luma) >> spring;
+               if (Gbright > 0x1a)
+                       Gbright = 0x1a;
+               else if (Gbright < 4)
+                       Gbright = 4;
+               PDEBUG(D_FRAM, "gbright %d", Gbright);
+               pac7311_reg_write(gspca_dev->dev, 0xff, 0x04);
+               pac7311_reg_write(gspca_dev->dev, 0x0f, Gbright);
+               /* load registers to sensor (Bit 0, auto clear) */
+               pac7311_reg_write(gspca_dev->dev, 0x11, 0x01);
+       }
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+                       struct gspca_frame *frame,      /* target */
+                       unsigned char *data,            /* isoc packet */
+                       int len)                        /* iso packet length */
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       unsigned char tmpbuf[4];
+       int i, p, ffseq;
+
+/*     if (len < 5) { */
+       if (len < 6) {
+/*             gspca_dev->last_packet_type = DISCARD_PACKET; */
+               return;
+       }
+
+       ffseq = sd->ffseq;
+
+       for (p = 0; p < len - 6; p++) {
+               if ((data[0 + p] == 0xff)
+                   && (data[1 + p] == 0xff)
+                   && (data[2 + p] == 0x00)
+                   && (data[3 + p] == 0xff)
+                   && (data[4 + p] == 0x96)) {
+
+                       /* start of frame */
+                       if (sd->ag_cnt >= 0 && p > 28) {
+                               sd->avg_lum += data[p - 23];
+                               if (--sd->ag_cnt < 0) {
+                                       sd->ag_cnt = AG_CNT_START;
+                                       setautogain(gspca_dev,
+                                               sd->avg_lum / AG_CNT_START);
+                                       sd->avg_lum = 0;
+                               }
+                       }
+
+                       /* copy the end of data to the current frame */
+                       frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+                                               data, p);
+
+                       /* put the JPEG header in the new frame */
+                       gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+                                       (unsigned char *) pac7311_jpeg_header,
+                                       12);
+                       tmpbuf[0] = gspca_dev->height >> 8;
+                       tmpbuf[1] = gspca_dev->height & 0xff;
+                       tmpbuf[2] = gspca_dev->width >> 8;
+                       tmpbuf[3] = gspca_dev->width & 0xff;
+                       gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+                                       tmpbuf, 4);
+                       gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+                               (unsigned char *) &pac7311_jpeg_header[16],
+                               PAC7311_JPEG_HEADER_SIZE - 16);
+
+                       data += p + 7;
+                       len -= p + 7;
+                       ffseq = 0;
+                       break;
+               }
+       }
+
+       /* remove the 'ff ff ff xx' sequences */
+       switch (ffseq) {
+       case 3:
+               data += 1;
+               len -= 1;
+               break;
+       case 2:
+               if (data[0] == 0xff) {
+                       data += 2;
+                       len -= 2;
+                       frame->data_end -= 2;
+               }
+               break;
+       case 1:
+               if (data[0] == 0xff
+                   && data[1] == 0xff) {
+                       data += 3;
+                       len -= 3;
+                       frame->data_end -= 1;
+               }
+               break;
+       }
+       for (i = 0; i < len - 4; i++) {
+               if (data[i] == 0xff
+                   && data[i + 1] == 0xff
+                   && data[i + 2] == 0xff) {
+                       memmove(&data[i], &data[i + 4], len - i - 4);
+                       len -= 4;
+               }
+       }
+       ffseq = 0;
+       if (data[len - 4] == 0xff) {
+               if (data[len - 3] == 0xff
+                   && data[len - 2] == 0xff) {
+                       len -= 4;
+               }
+       } else if (data[len - 3] == 0xff) {
+               if (data[len - 2] == 0xff
+                   && data[len - 1] == 0xff)
+                       ffseq = 3;
+       } else if (data[len - 2] == 0xff) {
+               if (data[len - 1] == 0xff)
+                       ffseq = 2;
+       } else if (data[len - 1] == 0xff)
+               ffseq = 1;
+       sd->ffseq = ffseq;
+       gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+}
+
+static void getbrightness(struct gspca_dev *gspca_dev)
+{
+/*     __u8 brightness = 0;
+
+       pac7311_reg_read(gspca_dev->dev, 0x0008, &brightness);
+       spca50x->brightness = brightness;
+       return spca50x->brightness;     */
+/*     PDEBUG(D_CONF, "Called pac7311_getbrightness: Not implemented yet"); */
+}
+
+
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->brightness = val;
+       if (gspca_dev->streaming)
+               setbrightness(gspca_dev);
+       return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       getbrightness(gspca_dev);
+       *val = sd->brightness;
+       return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->contrast = val;
+       if (gspca_dev->streaming)
+               setcontrast(gspca_dev);
+       return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+/*     getcontrast(gspca_dev); */
+       *val = sd->contrast;
+       return 0;
+}
+
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->colors = val;
+       if (gspca_dev->streaming)
+               setcolors(gspca_dev);
+       return 0;
+}
+
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+/*     getcolors(gspca_dev); */
+       *val = sd->colors;
+       return 0;
+}
+
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->autogain = val;
+       if (val) {
+               sd->ag_cnt = AG_CNT_START;
+               sd->avg_lum = 0;
+       } else {
+               sd->ag_cnt = -1;
+       }
+       return 0;
+}
+
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->autogain;
+       return 0;
+}
+
+/* sub-driver description */
+static struct sd_desc sd_desc = {
+       .name = MODULE_NAME,
+       .ctrls = sd_ctrls,
+       .nctrls = ARRAY_SIZE(sd_ctrls),
+       .config = sd_config,
+       .open = sd_open,
+       .start = sd_start,
+       .stopN = sd_stopN,
+       .stop0 = sd_stop0,
+       .close = sd_close,
+       .pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static __devinitdata struct usb_device_id device_table[] = {
+       {USB_DEVICE(0x093a, 0x2600), DVNM("Typhoon")},
+       {USB_DEVICE(0x093a, 0x2601), DVNM("Philips SPC610NC")},
+       {USB_DEVICE(0x093a, 0x2603), DVNM("PAC7312")},
+       {USB_DEVICE(0x093a, 0x2608), DVNM("Trust WB-3300p")},
+       {USB_DEVICE(0x093a, 0x260e), DVNM("Gigaware VGA PC Camera, Trust WB-3350p, SIGMA cam 2350")},
+       {USB_DEVICE(0x093a, 0x260f), DVNM("SnakeCam")},
+       {USB_DEVICE(0x093a, 0x2621), DVNM("PAC731x")},
+       {}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+                       const struct usb_device_id *id)
+{
+       return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+                               THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+       .name = MODULE_NAME,
+       .id_table = device_table,
+       .probe = sd_probe,
+       .disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+       if (usb_register(&sd_driver) < 0)
+               return -1;
+       PDEBUG(D_PROBE, "v%s registered", version);
+       return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+       usb_deregister(&sd_driver);
+       PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/video/gspca/sonixb.c
new file mode 100644 (file)
index 0000000..d26255d
--- /dev/null
@@ -0,0 +1,879 @@
+/*
+ *             sonix sn9c102 (bayer) library
+ *             Copyright (C) 2003 2004 Michel Xhaard mxhaard@magic.fr
+ * Add Pas106 Stefano Mozzi (C) 2004
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define MODULE_NAME "sonixb"
+
+#include "gspca.h"
+
+#define DRIVER_VERSION_NUMBER  KERNEL_VERSION(2, 1, 0)
+static const char version[] = "2.1.0";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("GSPCA/SN9C102 USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+       struct gspca_dev gspca_dev;     /* !! must be the first item */
+
+       unsigned char brightness;
+       unsigned char contrast;
+
+       char sensor;                    /* Type of image sensor chip */
+#define SENSOR_HV7131R 0
+#define SENSOR_OV6650 1
+#define SENSOR_OV7630 2
+#define SENSOR_OV7630_3 3
+#define SENSOR_PAS106 4
+#define SENSOR_PAS202 5
+#define SENSOR_TAS5110 6
+#define SENSOR_TAS5130CXX 7
+};
+
+#define COMP2 0x8f
+#define COMP 0xc7              /* 0x87 //0x07 */
+#define COMP1 0xc9             /* 0x89 //0x09 */
+
+#define MCK_INIT 0x63
+#define MCK_INIT1 0x20         /*fixme: Bayer - 0x50 for JPEG ??*/
+
+#define SYS_CLK 0x04
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+#define SD_BRIGHTNESS 0
+       {
+           {
+               .id      = V4L2_CID_BRIGHTNESS,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Brightness",
+               .minimum = 0,
+               .maximum = 255,
+               .step    = 1,
+               .default_value = 127,
+           },
+           .set = sd_setbrightness,
+           .get = sd_getbrightness,
+       },
+#define SD_CONTRAST 1
+       {
+           {
+               .id      = V4L2_CID_CONTRAST,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Contrast",
+               .minimum = 0,
+               .maximum = 255,
+               .step    = 1,
+               .default_value = 127,
+           },
+           .set = sd_setcontrast,
+           .get = sd_getcontrast,
+       },
+};
+
+/* fixme: should have V4L2_PIX_FMT_SN9C10X */
+static struct cam_mode vga_mode[] = {
+       {V4L2_PIX_FMT_SN9C10X, 160, 120, 2},
+       {V4L2_PIX_FMT_SN9C10X, 320, 240, 1},
+       {V4L2_PIX_FMT_SN9C10X, 640, 480, 0},
+};
+static struct cam_mode sif_mode[] = {
+       {V4L2_PIX_FMT_SN9C10X, 176, 144, 1},
+       {V4L2_PIX_FMT_SN9C10X, 352, 288, 0},
+};
+
+static const __u8 probe_ov7630[] = {0x08, 0x44};
+
+static const __u8 initHv7131[] = {
+       0x46, 0x77, 0x00, 0x04, 0x00, 0x00, 0x00, 0x80, 0x11, 0x00, 0x00, 0x00,
+       0x00, 0x00,
+       0x00, 0x00, 0x00, 0x03, 0x01, 0x00,     /* shift from 0x02 0x01 0x00 */
+       0x28, 0x1e, 0x60, 0x8a, 0x20,
+       0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c
+};
+static const __u8 hv7131_sensor_init[][8] = {
+       {0xc0, 0x11, 0x31, 0x38, 0x2a, 0x2e, 0x00, 0x10},
+       {0xa0, 0x11, 0x01, 0x08, 0x2a, 0x2e, 0x00, 0x10},
+       {0xb0, 0x11, 0x20, 0x00, 0xd0, 0x2e, 0x00, 0x10},
+       {0xc0, 0x11, 0x25, 0x03, 0x0e, 0x28, 0x00, 0x16},
+       {0xa0, 0x11, 0x30, 0x10, 0x0e, 0x28, 0x00, 0x15},
+};
+static const __u8 initOv6650[] = {
+       0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+       0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x02, 0x01, 0x0a, 0x16, 0x12, 0x68, 0x0b,
+       0x10, 0x1d, 0x10, 0x00, 0x06, 0x1f, 0x00
+};
+static const __u8 ov6650_sensor_init[][8] =
+{
+       /* Bright, contrast, etc are set througth SCBB interface.
+        * AVCAP on win2 do not send any data on this   controls. */
+       /* Anyway, some registers appears to alter bright and constrat */
+       {0xa0, 0x60, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10},
+       {0xd0, 0x60, 0x11, 0xc0, 0x1b, 0x18, 0xc1, 0x10},
+       {0xb0, 0x60, 0x15, 0x00, 0x02, 0x18, 0xc1, 0x10},
+/*     {0xa0, 0x60, 0x1b, 0x01, 0x02, 0x18, 0xc1, 0x10},
+                * THIS SET GREEN SCREEN
+                * (pixels could be innverted in decode kind of "brg",
+                * but blue wont be there. Avoid this data ... */
+       {0xd0, 0x60, 0x26, 0x01, 0x14, 0xd8, 0xa4, 0x10}, /* format out? */
+       {0xd0, 0x60, 0x26, 0x01, 0x14, 0xd8, 0xa4, 0x10},
+       {0xa0, 0x60, 0x30, 0x3d, 0x0A, 0xd8, 0xa4, 0x10},
+       {0xb0, 0x60, 0x60, 0x66, 0x68, 0xd8, 0xa4, 0x10},
+       {0xa0, 0x60, 0x68, 0x04, 0x68, 0xd8, 0xa4, 0x10},
+       {0xd0, 0x60, 0x17, 0x24, 0xd6, 0x04, 0x94, 0x10}, /* Clipreg */
+       {0xa0, 0x60, 0x10, 0x5d, 0x99, 0x04, 0x94, 0x16},
+       {0xa0, 0x60, 0x2d, 0x0a, 0x99, 0x04, 0x94, 0x16},
+       {0xa0, 0x60, 0x32, 0x00, 0x99, 0x04, 0x94, 0x16},
+       {0xa0, 0x60, 0x33, 0x40, 0x99, 0x04, 0x94, 0x16},
+       {0xa0, 0x60, 0x11, 0xc0, 0x99, 0x04, 0x94, 0x16},
+       {0xa0, 0x60, 0x00, 0x16, 0x99, 0x04, 0x94, 0x15}, /* bright / Lumino */
+       {0xa0, 0x60, 0x2b, 0xab, 0x99, 0x04, 0x94, 0x15},
+                                                       /* ?flicker o brillo */
+       {0xa0, 0x60, 0x2d, 0x2a, 0x99, 0x04, 0x94, 0x15},
+       {0xa0, 0x60, 0x2d, 0x2b, 0x99, 0x04, 0x94, 0x16},
+       {0xa0, 0x60, 0x32, 0x00, 0x99, 0x04, 0x94, 0x16},
+       {0xa0, 0x60, 0x33, 0x00, 0x99, 0x04, 0x94, 0x16},
+       {0xa0, 0x60, 0x10, 0x57, 0x99, 0x04, 0x94, 0x16},
+       {0xa0, 0x60, 0x2d, 0x2b, 0x99, 0x04, 0x94, 0x16},
+       {0xa0, 0x60, 0x32, 0x00, 0x99, 0x04, 0x94, 0x16},
+               /* Low Light (Enabled: 0x32 0x1 | Disabled: 0x32 0x00) */
+       {0xa0, 0x60, 0x33, 0x29, 0x99, 0x04, 0x94, 0x16},
+               /* Low Ligth (Enabled: 0x33 0x13 | Disabled: 0x33 0x29) */
+/*     {0xa0, 0x60, 0x11, 0xc1, 0x99, 0x04, 0x94, 0x16}, */
+       {0xa0, 0x60, 0x00, 0x17, 0x99, 0x04, 0x94, 0x15}, /* clip? r */
+       {0xa0, 0x60, 0x00, 0x18, 0x99, 0x04, 0x94, 0x15}, /* clip? r */
+};
+static const __u8 initOv7630[] = {
+       0x04, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, /* r01 .. r08 */
+       0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* r09 .. r10 */
+       0x00, 0x02, 0x01, 0x0a,                         /* r11 .. r14 */
+       0x28, 0x1e,                     /* H & V sizes     r15 .. r16 */
+       0x68, COMP1, MCK_INIT1,                         /* r17 .. r19 */
+       0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c              /* r1a .. r1f */
+};
+static const __u8 initOv7630_3[] = {
+       0x44, 0x44, 0x00, 0x1a, 0x20, 0x20, 0x20, 0x80, /* r01 .. r08 */
+       0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, /* r09 .. r10 */
+       0x00, 0x02, 0x01, 0x0a,                         /* r11 .. r14 */
+       0x28, 0x1e,                     /* H & V sizes     r15 .. r16 */
+       0x68, COMP1, MCK_INIT1,                         /* r17 .. r19 */
+       0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c              /* r1a .. r1f */
+};
+static const __u8 ov7630_sensor_init_com[][8] = {
+       {0xa0, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10},
+       {0xb0, 0x21, 0x01, 0x77, 0x3a, 0x00, 0x00, 0x10},
+/*     {0xd0, 0x21, 0x12, 0x7c, 0x01, 0x80, 0x34, 0x10},          jfm */
+       {0xd0, 0x21, 0x12, 0x78, 0x00, 0x80, 0x34, 0x10},       /* jfm */
+       {0xa0, 0x21, 0x1b, 0x04, 0x00, 0x80, 0x34, 0x10},
+       {0xa0, 0x21, 0x20, 0x44, 0x00, 0x80, 0x34, 0x10},
+       {0xa0, 0x21, 0x23, 0xee, 0x00, 0x80, 0x34, 0x10},
+       {0xd0, 0x21, 0x26, 0xa0, 0x9a, 0xa0, 0x30, 0x10},
+       {0xb0, 0x21, 0x2a, 0x80, 0x00, 0xa0, 0x30, 0x10},
+       {0xb0, 0x21, 0x2f, 0x3d, 0x24, 0xa0, 0x30, 0x10},
+       {0xa0, 0x21, 0x32, 0x86, 0x24, 0xa0, 0x30, 0x10},
+/*     {0xb0, 0x21, 0x60, 0xa9, 0x4a, 0xa0, 0x30, 0x10},          jfm */
+       {0xb0, 0x21, 0x60, 0xa9, 0x42, 0xa0, 0x30, 0x10},       /* jfm */
+       {0xa0, 0x21, 0x65, 0x00, 0x42, 0xa0, 0x30, 0x10},
+       {0xa0, 0x21, 0x69, 0x38, 0x42, 0xa0, 0x30, 0x10},
+       {0xc0, 0x21, 0x6f, 0x88, 0x0b, 0x00, 0x30, 0x10},
+       {0xc0, 0x21, 0x74, 0x21, 0x8e, 0x00, 0x30, 0x10},
+       {0xa0, 0x21, 0x7d, 0xf7, 0x8e, 0x00, 0x30, 0x10},
+       {0xd0, 0x21, 0x17, 0x1c, 0xbd, 0x06, 0xf6, 0x10},
+};
+static const __u8 ov7630_sensor_init[][8] = {
+       {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 200ms */
+       {0xa0, 0x21, 0x11, 0x01, 0xbd, 0x06, 0xf6, 0x10},       /* jfm */
+       {0xa0, 0x21, 0x10, 0x57, 0xbd, 0x06, 0xf6, 0x16},
+       {0xa0, 0x21, 0x76, 0x02, 0xbd, 0x06, 0xf6, 0x16},
+       {0xa0, 0x21, 0x00, 0x10, 0xbd, 0x06, 0xf6, 0x15},       /* gain */
+};
+static const __u8 ov7630_sensor_init_3[][8] = {
+       {0xa0, 0x21, 0x10, 0x36, 0xbd, 0x06, 0xf6, 0x16},       /* exposure */
+       {0xa0, 0x21, 0x76, 0x03, 0xbd, 0x06, 0xf6, 0x16},
+       {0xa0, 0x21, 0x11, 0x01, 0xbd, 0x06, 0xf6, 0x16},
+       {0xa0, 0x21, 0x00, 0x10, 0xbd, 0x06, 0xf6, 0x15},       /* gain */
+/*     {0xb0, 0x21, 0x2a, 0xc0, 0x3c, 0x06, 0xf6, 0x1d},
+               * a0 1c,a0 1f,c0 3c frame rate ?line interval from ov6630 */
+/*     {0xb0, 0x21, 0x2a, 0xa0, 0x1f, 0x06, 0xf6, 0x1d},        * from win */
+       {0xb0, 0x21, 0x2a, 0xa0, 0x1c, 0x06, 0xf6, 0x1d},
+};
+
+static const __u8 initPas106[] = {
+       0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x40, 0x00, 0x00, 0x00,
+       0x00, 0x00,
+       0x00, 0x00, 0x00, 0x05, 0x01, 0x00,
+       0x16, 0x12, 0x28, COMP1, MCK_INIT1,
+       0x18, 0x10, 0x04, 0x03, 0x11, 0x0c
+};
+/* compression 0x86 mckinit1 0x2b */
+static const __u8 pas106_data[][2] = {
+       {0x02, 0x04},           /* Pixel Clock Divider 6 */
+       {0x03, 0x13},           /* Frame Time MSB */
+/*     {0x03, 0x12},            * Frame Time MSB */
+       {0x04, 0x06},           /* Frame Time LSB */
+/*     {0x04, 0x05},            * Frame Time LSB */
+       {0x05, 0x65},           /* Shutter Time Line Offset */
+/*     {0x05, 0x6d},            * Shutter Time Line Offset */
+/*     {0x06, 0xb1},            * Shutter Time Pixel Offset */
+       {0x06, 0xcd},           /* Shutter Time Pixel Offset */
+       {0x07, 0xc1},           /* Black Level Subtract Sign */
+/*     {0x07, 0x00},            * Black Level Subtract Sign */
+       {0x08, 0x06},           /* Black Level Subtract Level */
+       {0x08, 0x06},           /* Black Level Subtract Level */
+/*     {0x08, 0x01},            * Black Level Subtract Level */
+       {0x09, 0x05},           /* Color Gain B Pixel 5 a */
+       {0x0a, 0x04},           /* Color Gain G1 Pixel 1 5 */
+       {0x0b, 0x04},           /* Color Gain G2 Pixel 1 0 5 */
+       {0x0c, 0x05},           /* Color Gain R Pixel 3 1 */
+       {0x0d, 0x00},           /* Color GainH  Pixel */
+       {0x0e, 0x0e},           /* Global Gain */
+       {0x0f, 0x00},           /* Contrast */
+       {0x10, 0x06},           /* H&V synchro polarity */
+       {0x11, 0x06},           /* ?default */
+       {0x12, 0x06},           /* DAC scale */
+       {0x14, 0x02},           /* ?default */
+       {0x13, 0x01},           /* Validate Settings */
+};
+static const __u8 initPas202[] = {
+       0x44, 0x44, 0x21, 0x30, 0x00, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, 0x00,
+       0x00, 0x00,
+       0x00, 0x00, 0x00, 0x07, 0x03, 0x0a,     /* 6 */
+       0x28, 0x1e, 0x28, 0x89, 0x30,
+       0x00, 0x00, 0x02, 0x03, 0x0f, 0x0c
+};
+static const __u8 pas202_sensor_init[][8] = {
+       {0xa0, 0x40, 0x02, 0x03, 0x00, 0x00, 0x00, 0x10},
+       {0xd0, 0x40, 0x04, 0x07, 0x34, 0x00, 0x09, 0x10},
+       {0xd0, 0x40, 0x08, 0x01, 0x00, 0x00, 0x01, 0x10},
+       {0xd0, 0x40, 0x0C, 0x00, 0x0C, 0x00, 0x32, 0x10},
+       {0xd0, 0x40, 0x10, 0x00, 0x01, 0x00, 0x63, 0x10},
+       {0xa0, 0x40, 0x15, 0x70, 0x01, 0x00, 0x63, 0x10},
+       {0xa0, 0x40, 0x18, 0x00, 0x01, 0x00, 0x63, 0x10},
+       {0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10},
+       {0xa0, 0x40, 0x03, 0x56, 0x01, 0x00, 0x63, 0x10},
+       {0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10},
+       {0xb0, 0x40, 0x04, 0x07, 0x2a, 0x00, 0x63, 0x10},
+       {0xb0, 0x40, 0x0e, 0x00, 0x3d, 0x00, 0x63, 0x10},
+
+       {0xa0, 0x40, 0x11, 0x01, 0x3d, 0x00, 0x63, 0x16},
+       {0xa0, 0x40, 0x10, 0x08, 0x3d, 0x00, 0x63, 0x15},
+       {0xa0, 0x40, 0x02, 0x04, 0x3d, 0x00, 0x63, 0x16},
+       {0xa0, 0x40, 0x11, 0x01, 0x3d, 0x00, 0x63, 0x16},
+       {0xb0, 0x40, 0x0e, 0x00, 0x31, 0x00, 0x63, 0x16},
+       {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16},
+       {0xa0, 0x40, 0x10, 0x0e, 0x31, 0x00, 0x63, 0x15},
+       {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16},
+};
+
+static const __u8 initTas5110[] = {
+       0x44, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00,
+       0x00, 0x00,
+       0x00, 0x01, 0x00, 0x46, 0x09, 0x0a,     /* shift from 0x45 0x09 0x0a */
+       0x16, 0x12, 0x60, 0x86, 0x2b,
+       0x14, 0x0a, 0x02, 0x02, 0x09, 0x07
+};
+static const __u8 tas5110_sensor_init[][8] = {
+       {0x30, 0x11, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x10},
+       {0x30, 0x11, 0x02, 0x20, 0xa9, 0x00, 0x00, 0x10},
+       {0xa0, 0x61, 0x9a, 0xca, 0x00, 0x00, 0x00, 0x17},
+};
+
+static const __u8 initTas5130[] = {
+       0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00,
+       0x00, 0x00,
+       0x00, 0x01, 0x00, 0x69, 0x0c, 0x0a,
+       0x28, 0x1e, 0x60, COMP, MCK_INIT,
+       0x18, 0x10, 0x04, 0x03, 0x11, 0x0c
+};
+static const __u8 tas5130_sensor_init[][8] = {
+/*     {0x30, 0x11, 0x00, 0x40, 0x47, 0x00, 0x00, 0x10},
+                                       * shutter 0x47 short exposure? */
+       {0x30, 0x11, 0x00, 0x40, 0x01, 0x00, 0x00, 0x10},
+                                       /* shutter 0x01 long exposure */
+       {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10},
+};
+
+static void reg_r(struct usb_device *dev,
+                        __u16 value, __u8 *buffer)
+{
+       usb_control_msg(dev,
+                       usb_rcvctrlpipe(dev, 0),
+                       0,                      /* request */
+                       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+                       value,
+                       0,                      /* index */
+                       buffer, 1,
+                       500);
+}
+
+static void reg_w(struct usb_device *dev,
+                         __u16 value,
+                         const __u8 *buffer,
+                         __u16 len)
+{
+       usb_control_msg(dev,
+                       usb_sndctrlpipe(dev, 0),
+                       0x08,                   /* request */
+                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+                       value,
+                       0,                      /* index */
+                       (__u8 *) buffer, len,
+                       500);
+}
+
+static int i2c_w(struct usb_device *dev, const __u8 *buffer)
+{
+       int retry = 60;
+       __u8 ByteReceive;
+
+       /* is i2c ready */
+       reg_w(dev, 0x08, buffer, 8);
+       while (retry--) {
+               msleep(10);
+               reg_r(dev, 0x08, &ByteReceive);
+               if (ByteReceive == 4)
+                       return 0;
+       }
+       return -1;
+}
+
+static void i2c_w_vector(struct usb_device *dev,
+                       const __u8 buffer[][8], int len)
+{
+       for (;;) {
+               reg_w(dev, 0x08, *buffer, 8);
+               len -= 8;
+               if (len <= 0)
+                       break;
+               buffer++;
+       }
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       __u8 value;
+
+       switch (sd->sensor) {
+       case SENSOR_OV6650: {
+               __u8 i2cOV6650[] =
+                       {0xa0, 0x60, 0x06, 0x11, 0x99, 0x04, 0x94, 0x15};
+
+               i2cOV6650[3] = sd->brightness;
+               if (i2c_w(gspca_dev->dev, i2cOV6650) < 0)
+                        goto err;
+               break;
+           }
+       case  SENSOR_OV7630: {
+               __u8 i2cOV[] =
+                       {0xa0, 0x21, 0x06, 0x36, 0xbd, 0x06, 0xf6, 0x16};
+
+               /* change reg 0x06 */
+               i2cOV[3] = sd->brightness;
+               if (i2c_w(gspca_dev->dev, i2cOV) < 0)
+                       goto err;
+               break;
+           }
+       case SENSOR_PAS106: {
+               __u8 i2c1[] =
+                       {0xa1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14};
+
+               i2c1[3] = sd->brightness >> 3;
+               i2c1[2] = 0x0e;
+               if (i2c_w(gspca_dev->dev, i2c1) < 0)
+                       goto err;
+               i2c1[3] = 0x01;
+               i2c1[2] = 0x13;
+               if (i2c_w(gspca_dev->dev, i2c1) < 0)
+                       goto err;
+               break;
+           }
+       case SENSOR_PAS202: {
+               /* __u8 i2cpexpo1[] =
+                       {0xb0, 0x40, 0x04, 0x07, 0x2a, 0x00, 0x63, 0x16}; */
+               __u8 i2cpexpo[] =
+                       {0xb0, 0x40, 0x0e, 0x01, 0xab, 0x00, 0x63, 0x16};
+               __u8 i2cp202[] =
+                       {0xa0, 0x40, 0x10, 0x0e, 0x31, 0x00, 0x63, 0x15};
+               static __u8 i2cpdoit[] =
+                       {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16};
+
+               /* change reg 0x10 */
+               i2cpexpo[4] = 0xff - sd->brightness;
+/*             if(i2c_w(gspca_dev->dev,i2cpexpo1) < 0)
+                       goto err; */
+/*             if(i2c_w(gspca_dev->dev,i2cpdoit) < 0)
+                       goto err; */
+               if (i2c_w(gspca_dev->dev, i2cpexpo) < 0)
+                       goto err;
+               if (i2c_w(gspca_dev->dev, i2cpdoit) < 0)
+                       goto err;
+               i2cp202[3] = sd->brightness >> 3;
+               if (i2c_w(gspca_dev->dev, i2cp202) < 0)
+                       goto err;
+               if (i2c_w(gspca_dev->dev, i2cpdoit) < 0)
+                       goto err;
+               break;
+           }
+       case SENSOR_TAS5130CXX:
+       case SENSOR_TAS5110: {
+               __u8 i2c[] =
+                       {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10};
+
+               value = 0xff - sd->brightness;
+               i2c[4] = value;
+               PDEBUG(D_CONF, "brightness %d : %d", value, i2c[4]);
+               if (i2c_w(gspca_dev->dev, i2c) < 0)
+                       goto err;
+               break;
+           }
+       }
+       return;
+err:
+       PDEBUG(D_ERR, "i2c error brightness");
+}
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       __u8 gain;
+       __u8 rgb_value;
+
+       gain = sd->contrast >> 4;
+       /* red and blue gain */
+       rgb_value = gain << 4 | gain;
+       reg_w(gspca_dev->dev, 0x10, &rgb_value, 1);
+       /* green gain */
+       rgb_value = gain;
+       reg_w(gspca_dev->dev, 0x11, &rgb_value, 1);
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+                       const struct usb_device_id *id)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct cam *cam;
+/*     __u16 vendor; */
+       __u16 product;
+       int sif = 0;
+
+/*     vendor = id->idVendor; */
+       product = id->idProduct;
+/*     switch (vendor) { */
+/*     case 0x0c45:                             * Sonix */
+               switch (product) {
+               case 0x6001:                    /* SN9C102 */
+               case 0x6005:                    /* SN9C101 */
+               case 0x6007:                    /* SN9C101 */
+                       sd->sensor = SENSOR_TAS5110;
+                       sif = 1;
+                       break;
+               case 0x6009:                    /* SN9C101 */
+               case 0x600d:                    /* SN9C101 */
+               case 0x6029:                    /* SN9C101 */
+                       sd->sensor = SENSOR_PAS106;
+                       sif = 1;
+                       break;
+               case 0x6011:                    /* SN9C101 - SN9C101G */
+                       sd->sensor = SENSOR_OV6650;
+                       sif = 1;
+                       break;
+               case 0x6019:                    /* SN9C101 */
+               case 0x602c:                    /* SN9C102 */
+               case 0x602e:                    /* SN9C102 */
+                       sd->sensor = SENSOR_OV7630;
+                       break;
+               case 0x60b0:                    /* SN9C103 */
+                       sd->sensor = SENSOR_OV7630_3;
+                       break;
+               case 0x6024:                    /* SN9C102 */
+               case 0x6025:                    /* SN9C102 */
+                       sd->sensor = SENSOR_TAS5130CXX;
+                       break;
+               case 0x6028:                    /* SN9C102 */
+                       sd->sensor = SENSOR_PAS202;
+                       break;
+               case 0x602d:                    /* SN9C102 */
+                       sd->sensor = SENSOR_HV7131R;
+                       break;
+               case 0x60af:                    /* SN9C103 */
+                       sd->sensor = SENSOR_PAS202;
+                       break;
+               }
+/*             break; */
+/*     } */
+
+       cam = &gspca_dev->cam;
+       cam->dev_name = (char *) id->driver_info;
+       cam->epaddr = 0x01;
+       if (!sif) {
+               cam->cam_mode = vga_mode;
+               cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+       } else {
+               cam->cam_mode = sif_mode;
+               cam->nmodes = sizeof sif_mode / sizeof sif_mode[0];
+       }
+       sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
+       sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
+       if (sd->sensor == SENSOR_OV7630_3)      /* jfm: from win trace */
+               reg_w(gspca_dev->dev, 0x01, probe_ov7630, sizeof probe_ov7630);
+       return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+       __u8 ByteReceive;
+
+       reg_r(gspca_dev->dev, 0x00, &ByteReceive);
+       if (ByteReceive != 0x10)
+               return -ENODEV;
+       return 0;
+}
+
+static void pas106_i2cinit(struct usb_device *dev)
+{
+       int i;
+       const __u8 *data;
+       __u8 i2c1[] = { 0xa1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14 };
+
+       i = ARRAY_SIZE(pas106_data);
+       data = pas106_data[0];
+       while (--i >= 0) {
+               memcpy(&i2c1[2], data, 2);
+                                       /* copy 2 bytes from the template */
+               if (i2c_w(dev, i2c1) < 0)
+                       PDEBUG(D_ERR, "i2c error pas106");
+               data += 2;
+       }
+}
+
+/* -- start the camera -- */
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct usb_device *dev = gspca_dev->dev;
+       int mode, l;
+       const __u8 *sn9c10x;
+       __u8 reg01, reg17;
+       __u8 reg17_19[3];
+
+       mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].mode;
+       switch (sd->sensor) {
+       case SENSOR_HV7131R:
+               sn9c10x = initHv7131;
+               reg17_19[0] = 0x60;
+               reg17_19[1] = (mode << 4) | 0x8a;
+               reg17_19[2] = 0x20;
+               break;
+       case SENSOR_OV6650:
+               sn9c10x = initOv6650;
+               reg17_19[0] = 0x68;
+               reg17_19[1] = (mode << 4) | 0x8b;
+               reg17_19[2] = 0x20;
+               break;
+       case SENSOR_OV7630:
+               sn9c10x = initOv7630;
+               reg17_19[0] = 0x68;
+               reg17_19[1] = (mode << 4) | COMP2;
+               reg17_19[2] = MCK_INIT1;
+               break;
+       case SENSOR_OV7630_3:
+               sn9c10x = initOv7630_3;
+               reg17_19[0] = 0x68;
+               reg17_19[1] = (mode << 4) | COMP2;
+               reg17_19[2] = MCK_INIT1;
+               break;
+       case SENSOR_PAS106:
+               sn9c10x = initPas106;
+               reg17_19[0] = 0x24;             /* 0x28 */
+               reg17_19[1] = (mode << 4) | COMP1;
+               reg17_19[2] = MCK_INIT1;
+               break;
+       case SENSOR_PAS202:
+               sn9c10x = initPas202;
+               reg17_19[0] = mode ? 0x24 : 0x20;
+               reg17_19[1] = (mode << 4) | 0x89;
+               reg17_19[2] = 0x20;
+               break;
+       case SENSOR_TAS5110:
+               sn9c10x = initTas5110;
+               reg17_19[0] = 0x60;
+               reg17_19[1] = (mode << 4) | 0x86;
+               reg17_19[2] = 0x2b;             /* 0xf3; */
+               break;
+       default:
+/*     case SENSOR_TAS5130CXX: */
+               sn9c10x = initTas5130;
+               reg17_19[0] = 0x60;
+               reg17_19[1] = (mode << 4) | COMP;
+               reg17_19[2] = mode ? 0x23 : 0x43;
+               break;
+       }
+       switch (sd->sensor) {
+       case SENSOR_OV7630:
+               reg01 = 0x06;
+               reg17 = 0x29;
+               l = 0x10;
+               break;
+       case SENSOR_OV7630_3:
+               reg01 = 0x44;
+               reg17 = 0x68;
+               l = 0x10;
+               break;
+       default:
+               reg01 = sn9c10x[0];
+               reg17 = sn9c10x[0x17 - 1];
+               l = 0x1f;
+               break;
+       }
+
+       /* reg 0x01 bit 2 video transfert on */
+       reg_w(dev, 0x01, &reg01, 1);
+       /* reg 0x17 SensorClk enable inv Clk 0x60 */
+       reg_w(dev, 0x17, &reg17, 1);
+/*fixme: for ov7630 102
+       reg_w(dev, 0x01, {0x06, sn9c10x[1]}, 2); */
+       /* Set the registers from the template */
+       reg_w(dev, 0x01, sn9c10x, l);
+       switch (sd->sensor) {
+       case SENSOR_HV7131R:
+               i2c_w_vector(dev, hv7131_sensor_init,
+                               sizeof hv7131_sensor_init);
+               break;
+       case SENSOR_OV6650:
+               i2c_w_vector(dev, ov6650_sensor_init,
+                               sizeof ov6650_sensor_init);
+               break;
+       case SENSOR_OV7630:
+               i2c_w_vector(dev, ov7630_sensor_init_com,
+                               sizeof ov7630_sensor_init_com);
+               msleep(200);
+               i2c_w_vector(dev, ov7630_sensor_init,
+                               sizeof ov7630_sensor_init);
+               break;
+       case SENSOR_OV7630_3:
+               i2c_w_vector(dev, ov7630_sensor_init_com,
+                               sizeof ov7630_sensor_init_com);
+               msleep(200);
+               i2c_w_vector(dev, ov7630_sensor_init_3,
+                               sizeof ov7630_sensor_init_3);
+               break;
+       case SENSOR_PAS106:
+               pas106_i2cinit(dev);
+               break;
+       case SENSOR_PAS202:
+               i2c_w_vector(dev, pas202_sensor_init,
+                               sizeof pas202_sensor_init);
+               break;
+       case SENSOR_TAS5110:
+               i2c_w_vector(dev, tas5110_sensor_init,
+                               sizeof tas5110_sensor_init);
+               break;
+       default:
+/*     case SENSOR_TAS5130CXX: */
+               i2c_w_vector(dev, tas5130_sensor_init,
+                               sizeof tas5130_sensor_init);
+               break;
+       }
+       /* H_size V_size  0x28, 0x1e maybe 640x480 */
+       reg_w(dev, 0x15, &sn9c10x[0x15 - 1], 2);
+       /* compression register */
+       reg_w(dev, 0x18, &reg17_19[1], 1);
+       /* H_start */           /*fixme: not ov7630*/
+       reg_w(dev, 0x12, &sn9c10x[0x12 - 1], 1);
+       /* V_START */           /*fixme: not ov7630*/
+       reg_w(dev, 0x13, &sn9c10x[0x13 - 1], 1);
+       /* reset 0x17 SensorClk enable inv Clk 0x60 */
+                               /*fixme: ov7630 [17]=68 8f (+20 if 102)*/
+       reg_w(dev, 0x17, &reg17_19[0], 1);
+       /*MCKSIZE ->3 */        /*fixme: not ov7630*/
+       reg_w(dev, 0x19, &reg17_19[2], 1);
+       /* AE_STRX AE_STRY AE_ENDX AE_ENDY */
+       reg_w(dev, 0x1c, &sn9c10x[0x1c - 1], 4);
+       /* Enable video transfert */
+       reg_w(dev, 0x01, &sn9c10x[0], 1);
+       /* Compression */
+       reg_w(dev, 0x18, &reg17_19[1], 2);
+       msleep(20);
+
+       setcontrast(gspca_dev);
+       setbrightness(gspca_dev);
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+       __u8 ByteSend = 0;
+
+       ByteSend = 0x09;        /* 0X00 */
+       reg_w(gspca_dev->dev, 0x01, &ByteSend, 1);
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+                       struct gspca_frame *frame,      /* target */
+                       unsigned char *data,            /* isoc packet */
+                       int len)                        /* iso packet length */
+{
+       int p;
+
+       if (len > 6 && len < 24) {
+               for (p = 0; p < len - 6; p++) {
+                       if (data[0 + p] == 0xff
+                           && data[1 + p] == 0xff
+                           && data[2 + p] == 0x00
+                           && data[3 + p] == 0xc4
+                           && data[4 + p] == 0xc4
+                           && data[5 + p] == 0x96) {   /* start of frame */
+                               frame = gspca_frame_add(gspca_dev,
+                                                       LAST_PACKET,
+                                                       frame,
+                                                       data, 0);
+                               data += 12;
+                               len -= 12;
+                               gspca_frame_add(gspca_dev, FIRST_PACKET,
+                                               frame, data, len);
+                               return;
+                       }
+               }
+       }
+       gspca_frame_add(gspca_dev, INTER_PACKET,
+                       frame, data, len);
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->brightness = val;
+       if (gspca_dev->streaming)
+               setbrightness(gspca_dev);
+       return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->brightness;
+       return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->contrast = val;
+       if (gspca_dev->streaming)
+               setcontrast(gspca_dev);
+       return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->contrast;
+       return 0;
+}
+
+/* sub-driver description */
+static struct sd_desc sd_desc = {
+       .name = MODULE_NAME,
+       .ctrls = sd_ctrls,
+       .nctrls = ARRAY_SIZE(sd_ctrls),
+       .config = sd_config,
+       .open = sd_open,
+       .start = sd_start,
+       .stopN = sd_stopN,
+       .stop0 = sd_stop0,
+       .close = sd_close,
+       .pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static __devinitdata struct usb_device_id device_table[] = {
+       {USB_DEVICE(0x0c45, 0x6001), DVNM("Genius VideoCAM NB")},
+       {USB_DEVICE(0x0c45, 0x6005), DVNM("Sweex Tas5110")},
+       {USB_DEVICE(0x0c45, 0x6007), DVNM("Sonix sn9c101 + Tas5110D")},
+       {USB_DEVICE(0x0c45, 0x6009), DVNM("spcaCam@120")},
+       {USB_DEVICE(0x0c45, 0x600d), DVNM("spcaCam@120")},
+       {USB_DEVICE(0x0c45, 0x6011), DVNM("MAX Webcam Microdia-OV6650-SN9C101G")},
+       {USB_DEVICE(0x0c45, 0x6019), DVNM("Generic Sonix OV7630")},
+       {USB_DEVICE(0x0c45, 0x6024), DVNM("Generic Sonix Tas5130c")},
+       {USB_DEVICE(0x0c45, 0x6025), DVNM("Xcam Shanga")},
+       {USB_DEVICE(0x0c45, 0x6028), DVNM("Sonix Btc Pc380")},
+       {USB_DEVICE(0x0c45, 0x6029), DVNM("spcaCam@150")},
+       {USB_DEVICE(0x0c45, 0x602c), DVNM("Generic Sonix OV7630")},
+       {USB_DEVICE(0x0c45, 0x602d), DVNM("LIC-200 LG")},
+       {USB_DEVICE(0x0c45, 0x602e), DVNM("Genius VideoCam Messenger")},
+       {USB_DEVICE(0x0c45, 0x60af), DVNM("Trust WB3100P")},
+       {USB_DEVICE(0x0c45, 0x60b0), DVNM("Genius VideoCam Look")},
+       {}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+                       const struct usb_device_id *id)
+{
+       return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+                               THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+       .name = MODULE_NAME,
+       .id_table = device_table,
+       .probe = sd_probe,
+       .disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+       if (usb_register(&sd_driver) < 0)
+               return -1;
+       PDEBUG(D_PROBE, "v%s registered", version);
+       return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+       usb_deregister(&sd_driver);
+       PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c
new file mode 100644 (file)
index 0000000..6180bc5
--- /dev/null
@@ -0,0 +1,1629 @@
+/*
+ *             Sonix sn9c102p sn9c105 sn9c120 (jpeg) library
+ *             Copyright (C) 2005 Michel Xhaard mxhaard@magic.fr
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define MODULE_NAME "sonixj"
+
+#include "gspca.h"
+#include "jpeg.h"
+
+#define DRIVER_VERSION_NUMBER  KERNEL_VERSION(2, 1, 0)
+static const char version[] = "2.1.0";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("GSPCA/SONIX JPEG USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+       struct gspca_dev gspca_dev;     /* !! must be the first item */
+
+       int avg_lum;
+       unsigned int exposure;
+
+       unsigned short brightness;
+       unsigned char contrast;
+       unsigned char colors;
+       unsigned char autogain;
+
+       signed char ag_cnt;
+#define AG_CNT_START 13
+
+       char qindex;
+       char sensor;                    /* Type of image sensor chip */
+#define SENSOR_HV7131R 0
+#define SENSOR_MI0360 1
+#define SENSOR_MO4000 2
+#define SENSOR_OV7648 3
+#define SENSOR_OV7660 4
+       unsigned char customid;
+#define SN9C102P 0
+#define SN9C105 1
+#define SN9C110 2
+#define SN9C120 3
+#define SN9C325 4
+       unsigned char i2c_base;
+       unsigned char i2c_ctrl_reg;
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+#define SD_BRIGHTNESS 0
+       {
+           {
+               .id      = V4L2_CID_BRIGHTNESS,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Brightness",
+               .minimum = 0,
+               .maximum = 0xffff,
+               .step    = 1,
+               .default_value = 0x7fff,
+           },
+           .set = sd_setbrightness,
+           .get = sd_getbrightness,
+       },
+#define SD_CONTRAST 1
+       {
+           {
+               .id      = V4L2_CID_CONTRAST,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Contrast",
+               .minimum = 0,
+               .maximum = 127,
+               .step    = 1,
+               .default_value = 63,
+           },
+           .set = sd_setcontrast,
+           .get = sd_getcontrast,
+       },
+#define SD_COLOR 2
+       {
+           {
+               .id      = V4L2_CID_SATURATION,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Color",
+               .minimum = 0,
+               .maximum = 255,
+               .step    = 1,
+               .default_value = 127,
+           },
+           .set = sd_setcolors,
+           .get = sd_getcolors,
+       },
+#define SD_AUTOGAIN 3
+       {
+           {
+               .id      = V4L2_CID_AUTOGAIN,
+               .type    = V4L2_CTRL_TYPE_BOOLEAN,
+               .name    = "Auto Gain",
+               .minimum = 0,
+               .maximum = 1,
+               .step    = 1,
+               .default_value = 1,
+           },
+           .set = sd_setautogain,
+           .get = sd_getautogain,
+       },
+};
+
+static struct cam_mode vga_mode[] = {
+       {V4L2_PIX_FMT_JPEG, 160, 120, 2},
+       {V4L2_PIX_FMT_JPEG, 320, 240, 1},
+       {V4L2_PIX_FMT_JPEG, 640, 480, 0},
+};
+
+/*Data from sn9c102p+hv71331r */
+static __u8 sn_hv7131[] = {
+       0x00, 0x03, 0x64, 0x00, 0x1A, 0x20, 0x20, 0x20, 0xA1, 0x11,
+/*     reg0  reg1  reg2  reg3  reg4  reg5  reg6  reg7  reg8  reg9 */
+       0x02, 0x09, 0x00, 0x00, 0x00, 0x10, 0x03, 0x00,         /* 00 */
+/*     rega  regb  regc  regd  rege  regf  reg10 reg11 */
+       0x00, 0x01, 0x03, 0x28, 0x1e, 0x41, 0x0a, 0x00, 0x00, 0x00,
+/*     reg12 reg13 reg14 reg15 reg16 reg17 reg18 reg19 reg1a reg1b */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+/*     reg1c reg1d reg1e reg1f reg20 reg21 reg22 reg23 */
+};
+
+static __u8 sn_mi0360[] = {
+       0x00, 0x61, 0x44, 0x00, 0x1a, 0x20, 0x20, 0x20, 0xb1, 0x5d,
+/*     reg0  reg1  reg2  reg3  reg4  reg5  reg6  reg7  reg8  reg9 */
+       0x07, 0x00, 0x00, 0x00, 0x00, 0x10, 0x03, 0x00,
+/*     rega  regb  regc  regd  rege  regf  reg10 reg11 */
+       0x00, 0x02, 0x0a, 0x28, 0x1e, 0x61, 0x06, 0x00, 0x00, 0x00,
+/*     reg12 reg13 reg14 reg15 reg16 reg17 reg18 reg19 reg1a reg1b */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+/*     reg1c reg1d reg1e reg1f reg20 reg21 reg22 reg23 */
+};
+
+static __u8 sn_mo4000[] = {
+       0x12,   0x23,   0x60,   0x00,   0x1A,   0x00,   0x20,   0x18,   0x81,
+/*     reg0    reg1    reg2    reg3    reg4    reg5    reg6    reg7    reg8 */
+       0x21,   0x00,   0x00,   0x00,   0x00,   0x00,   0x00,   0x03,   0x00,
+/*     reg9    rega    regb    regc    regd    rege    regf    reg10   reg11*/
+       0x0b,   0x0f,   0x14,   0x28,   0x1e,   0x40,   0x08,   0x00,   0x00,
+/*     reg12   reg13   reg14   reg15   reg16   reg17   reg18   reg19   reg1a*/
+       0x00,   0x00,   0x00,   0x00,   0x00,   0x08,   0x25,   0x39,   0x4b,
+/*     reg1b   reg1c   reg1d   reg1e   reg1f   reg20   reg21   reg22   reg23*/
+       0x5c,   0x6b,   0x79,   0x87,   0x95,   0xa2,   0xaf,   0xbb,   0xc7,
+       0xd3,   0xdf,   0xea,   0xf5
+};
+
+static __u8 sn_ov7648[] = {
+       0x00, 0x21, 0x62, 0x00, 0x1a, 0x20, 0x20, 0x20, 0xA1, 0x6E, 0x18, 0x65,
+       0x00, 0x00, 0x00, 0x10, 0x03, 0x00, 0x00, 0x06, 0x06, 0x28, 0x1E, 0x82,
+       0x07, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static __u8 sn_ov7660[]        = {
+/*     reg0    reg1    reg2    reg3    reg4    reg5    reg6    reg7    reg8 */
+       0x00,   0x61,   0x40,   0x00,   0x1a,   0x00,   0x00,   0x00,   0x81,
+/*     reg9    rega    regb    regc    regd    rege    regf    reg10   reg11*/
+       0x21,   0x00,   0x00,   0x00,   0x00,   0x00,   0x00,   0x03,   0x00,
+/*     reg12   reg13   reg14   reg15   reg16   reg17   reg18   reg19   reg1a*/
+       0x01,   0x01,   0x08,   0x28,   0x1e,   0x20,   0x07,   0x00,   0x00,
+/*     reg1b   reg1c   reg1d   reg1e   reg1f   reg20   reg21   reg22   reg23*/
+       0x00,   0x00,   0x00,   0x00,   0x00,   0x00,   0x00,   0x00,   0x00
+};
+
+/* sequence specific to the sensors - !! index = SENSOR_xxx */
+static __u8 *sn_tb[] = {
+       sn_hv7131,
+       sn_mi0360,
+       sn_mo4000,
+       sn_ov7648,
+       sn_ov7660
+};
+
+static __u8 regsn20[] = {
+       0x00, 0x2d, 0x46, 0x5a, 0x6c, 0x7c, 0x8b, 0x99,
+       0xa6, 0xb2, 0xbf, 0xca, 0xd5, 0xe0, 0xeb, 0xf5, 0xff
+};
+static __u8 regsn20_sn9c325[] = {
+       0x0a, 0x3a, 0x56, 0x6c, 0x7e, 0x8d, 0x9a, 0xa4,
+       0xaf, 0xbb, 0xc5, 0xcd, 0xd5, 0xde, 0xe8, 0xed, 0xf5
+};
+
+static __u8 reg84[] = {
+       0x14, 0x00, 0x27, 0x00, 0x07, 0x00, 0xe5, 0x0f,
+       0xe4, 0x0f, 0x38, 0x00, 0x3e, 0x00, 0xc3, 0x0f,
+/*     0x00, 0x00, 0x00, 0x00, 0x00 */
+       0xf7, 0x0f, 0x0a, 0x00, 0x00
+};
+static __u8 reg84_sn9c325[] = {
+       0x14, 0x00, 0x27, 0x00, 0x07, 0x00, 0xe4, 0x0f,
+       0xd3, 0x0f, 0x4b, 0x00, 0x48, 0x00, 0xc0, 0x0f,
+       0xf8, 0x0f, 0x00, 0x00, 0x00
+};
+
+static __u8 hv7131r_sensor_init[][8] = {
+       {0xC1, 0x11, 0x01, 0x08, 0x01, 0x00, 0x00, 0x10},
+       {0xB1, 0x11, 0x34, 0x17, 0x7F, 0x00, 0x00, 0x10},
+       {0xD1, 0x11, 0x40, 0xFF, 0x7F, 0x7F, 0x7F, 0x10},
+       {0x91, 0x11, 0x44, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xD1, 0x11, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xD1, 0x11, 0x14, 0x01, 0xE2, 0x02, 0x82, 0x10},
+       {0x91, 0x11, 0x18, 0x00, 0x00, 0x00, 0x00, 0x10},
+
+       {0xA1, 0x11, 0x01, 0x08, 0x00, 0x00, 0x00, 0x10},
+       {0xA1, 0x11, 0x01, 0x08, 0x00, 0x00, 0x00, 0x10},
+       {0xC1, 0x11, 0x25, 0x00, 0x61, 0xA8, 0x00, 0x10},
+       {0xA1, 0x11, 0x30, 0x22, 0x00, 0x00, 0x00, 0x10},
+       {0xC1, 0x11, 0x31, 0x20, 0x2E, 0x20, 0x00, 0x10},
+       {0xC1, 0x11, 0x25, 0x00, 0xC3, 0x50, 0x00, 0x10},
+       {0xA1, 0x11, 0x30, 0x07, 0x00, 0x00, 0x00, 0x10}, /* gain14 */
+       {0xC1, 0x11, 0x31, 0x10, 0x10, 0x10, 0x00, 0x10}, /* r g b 101a10 */
+
+       {0xA1, 0x11, 0x01, 0x08, 0x00, 0x00, 0x00, 0x10},
+       {0xA1, 0x11, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xA1, 0x11, 0x21, 0xD0, 0x00, 0x00, 0x00, 0x10},
+       {0xA1, 0x11, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xA1, 0x11, 0x23, 0x09, 0x00, 0x00, 0x00, 0x10},
+
+       {0xA1, 0x11, 0x01, 0x08, 0x00, 0x00, 0x00, 0x10},
+       {0xA1, 0x11, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xA1, 0x11, 0x21, 0xD0, 0x00, 0x00, 0x00, 0x10},
+       {0xA1, 0x11, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xA1, 0x11, 0x23, 0x10, 0x00, 0x00, 0x00, 0x10},
+       {0, 0, 0, 0, 0, 0, 0, 0}
+};
+static __u8 mi0360_sensor_init[][8] = {
+       {0xB1, 0x5D, 0x07, 0x00, 0x02, 0x00, 0x00, 0x10},
+       {0xB1, 0x5D, 0x0D, 0x00, 0x01, 0x00, 0x00, 0x10},
+       {0xB1, 0x5D, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xD1, 0x5D, 0x01, 0x00, 0x08, 0x00, 0x16, 0x10},
+       {0xD1, 0x5D, 0x03, 0x01, 0xE2, 0x02, 0x82, 0x10},
+       {0xD1, 0x5D, 0x05, 0x00, 0x09, 0x00, 0x53, 0x10},
+       {0xB1, 0x5D, 0x0D, 0x00, 0x02, 0x00, 0x00, 0x10},
+       {0xD1, 0x5D, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xD1, 0x5D, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xD1, 0x5D, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xD1, 0x5D, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xD1, 0x5D, 0x12, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xD1, 0x5D, 0x14, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xD1, 0x5D, 0x16, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xD1, 0x5D, 0x18, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xD1, 0x5D, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xD1, 0x5D, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xB1, 0x5D, 0x32, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xD1, 0x5D, 0x20, 0x91, 0x01, 0x00, 0x00, 0x10},
+       {0xD1, 0x5D, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xD1, 0x5D, 0x24, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xD1, 0x5D, 0x26, 0x00, 0x00, 0x00, 0x24, 0x10},
+       {0xD1, 0x5D, 0x2F, 0xF7, 0xB0, 0x00, 0x04, 0x10},
+       {0xD1, 0x5D, 0x31, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xD1, 0x5D, 0x33, 0x00, 0x00, 0x01, 0x00, 0x10},
+       {0xB1, 0x5D, 0x3D, 0x06, 0x8F, 0x00, 0x00, 0x10},
+       {0xD1, 0x5D, 0x40, 0x01, 0xE0, 0x00, 0xD1, 0x10},
+       {0xB1, 0x5D, 0x44, 0x00, 0x82, 0x00, 0x00, 0x10},
+       {0xD1, 0x5D, 0x58, 0x00, 0x78, 0x00, 0x43, 0x10},
+       {0xD1, 0x5D, 0x5A, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xD1, 0x5D, 0x5C, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xD1, 0x5D, 0x5E, 0x00, 0x00, 0xA3, 0x1D, 0x10},
+       {0xB1, 0x5D, 0x62, 0x04, 0x11, 0x00, 0x00, 0x10},
+
+       {0xB1, 0x5D, 0x20, 0x91, 0x01, 0x00, 0x00, 0x10},
+       {0xB1, 0x5D, 0x20, 0x11, 0x01, 0x00, 0x00, 0x10},
+       {0xB1, 0x5D, 0x09, 0x00, 0x64, 0x00, 0x00, 0x10},
+       {0xD1, 0x5D, 0x2B, 0x00, 0xA0, 0x00, 0xB0, 0x10},
+       {0xD1, 0x5D, 0x2D, 0x00, 0xA0, 0x00, 0xA0, 0x10},
+
+       {0xB1, 0x5D, 0x0A, 0x00, 0x02, 0x00, 0x00, 0x10}, /* sensor clck ?2 */
+       {0xB1, 0x5D, 0x06, 0x00, 0x30, 0x00, 0x00, 0x10},
+       {0xB1, 0x5D, 0x05, 0x00, 0x0A, 0x00, 0x00, 0x10},
+       {0xB1, 0x5D, 0x09, 0x02, 0x35, 0x00, 0x00, 0x10}, /* exposure 2 */
+
+       {0xD1, 0x5D, 0x2B, 0x00, 0xB9, 0x00, 0xE3, 0x10},
+       {0xD1, 0x5D, 0x2D, 0x00, 0x5f, 0x00, 0xB9, 0x10}, /* 42 */
+/*     {0xB1, 0x5D, 0x35, 0x00, 0x67, 0x00, 0x00, 0x10}, * gain orig */
+/*     {0xB1, 0x5D, 0x35, 0x00, 0x20, 0x00, 0x00, 0x10}, * gain */
+       {0xB1, 0x5D, 0x07, 0x00, 0x03, 0x00, 0x00, 0x10}, /* update */
+       {0xB1, 0x5D, 0x07, 0x00, 0x02, 0x00, 0x00, 0x10}, /* sensor on */
+       {0, 0, 0, 0, 0, 0, 0, 0}
+};
+static __u8 mo4000_sensor_init[][8] = {
+       {0xa1, 0x21, 0x01, 0x02, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x21, 0x02, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x21, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x21, 0x04, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x21, 0x05, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x21, 0x05, 0x04, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x21, 0x06, 0x80, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x21, 0x06, 0x81, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x21, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x21, 0x11, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x21, 0x11, 0x20, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x21, 0x11, 0x30, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x21, 0x11, 0x38, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x21, 0x11, 0x38, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x21, 0x12, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x21, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x21, 0x0f, 0x20, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x21, 0x10, 0x20, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x21, 0x11, 0x38, 0x00, 0x00, 0x00, 0x10},
+       {0, 0, 0, 0, 0, 0, 0, 0}
+};
+static __u8 ov7660_sensor_init[][8] = {
+       {0xa1, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10}, /* reset SCCB */
+       {0xa1, 0x21, 0x12, 0x05, 0x00, 0x00, 0x00, 0x10},
+                                               /* Outformat ?? rawRGB */
+       {0xa1, 0x21, 0x13, 0xb8, 0x00, 0x00, 0x00, 0x10}, /* init COM8 */
+/*     {0xd1, 0x21, 0x00, 0x01, 0x74, 0x92, 0x00, 0x10},
+                                                * GAIN BLUE RED VREF */
+       {0xd1, 0x21, 0x00, 0x01, 0x74, 0x74, 0x00, 0x10},
+                                               /* GAIN BLUE RED VREF */
+       {0xd1, 0x21, 0x04, 0x00, 0x7d, 0x62, 0x00, 0x10},
+                                               /* COM 1 BAVE GEAVE AECHH */
+       {0xb1, 0x21, 0x08, 0x83, 0x01, 0x00, 0x00, 0x10}, /* RAVE COM2 */
+       {0xd1, 0x21, 0x0c, 0x00, 0x08, 0x04, 0x4f, 0x10}, /* COM 3 4 5 6 */
+/*     {0xd1, 0x21, 0x10, 0x7f, 0x40, 0x05, 0xf8, 0x10},
+                                                * AECH CLKRC COM7 COM8 */
+       {0xd1, 0x21, 0x10, 0x7f, 0x40, 0x05, 0xff, 0x10},
+                                               /* AECH CLKRC COM7 COM8 */
+       {0xc1, 0x21, 0x14, 0x2c, 0x00, 0x02, 0x00, 0x10}, /* COM9 COM10 */
+       {0xd1, 0x21, 0x17, 0x10, 0x60, 0x02, 0x7b, 0x10},
+                                               /* HSTART HSTOP VSTRT VSTOP */
+       {0xa1, 0x21, 0x1b, 0x02, 0x00, 0x00, 0x00, 0x10}, /* PSHFT */
+       {0xb1, 0x21, 0x1e, 0x01, 0x0e, 0x00, 0x00, 0x10}, /* MVFP LAEC */
+       {0xd1, 0x21, 0x20, 0x07, 0x07, 0x07, 0x07, 0x10},
+                                       /* BOS GBOS GROS ROS (BGGR offset) */
+/*     {0xd1, 0x21, 0x24, 0x68, 0x58, 0xd4, 0x80, 0x10},
+                                                * AEW AEB VPT BBIAS */
+       {0xd1, 0x21, 0x24, 0x78, 0x68, 0xd4, 0x80, 0x10},
+                                               /* AEW AEB VPT BBIAS */
+       {0xd1, 0x21, 0x28, 0x80, 0x30, 0x00, 0x00, 0x10},
+                                               /* GbBIAS RSVD EXHCH EXHCL */
+       {0xd1, 0x21, 0x2c, 0x80, 0x00, 0x00, 0x62, 0x10},
+                                               /* RBIAS ADVFL ASDVFH YAVE */
+       {0xc1, 0x21, 0x30, 0x08, 0x30, 0xb4, 0x00, 0x10},
+                                               /* HSYST HSYEN HREF */
+       {0xd1, 0x21, 0x33, 0x00, 0x07, 0x84, 0x00, 0x10}, /* reserved */
+       {0xd1, 0x21, 0x37, 0x0c, 0x02, 0x43, 0x00, 0x10},
+                                               /* ADC ACOM OFON TSLB */
+       {0xd1, 0x21, 0x3b, 0x02, 0x6c, 0x19, 0x0e, 0x10},
+                                               /* COM11 COM12 COM13 COM14 */
+       {0xd1, 0x21, 0x3f, 0x41, 0xc1, 0x22, 0x08, 0x10},
+                                               /* EDGE COM15 COM16 COM17 */
+       {0xd1, 0x21, 0x43, 0xf0, 0x10, 0x78, 0xa8, 0x10}, /* reserved */
+       {0xd1, 0x21, 0x47, 0x60, 0x80, 0x00, 0x00, 0x10}, /* reserved */
+       {0xd1, 0x21, 0x4b, 0x00, 0x00, 0x00, 0x00, 0x10}, /* reserved */
+       {0xd1, 0x21, 0x4f, 0x46, 0x36, 0x0f, 0x17, 0x10}, /* MTX 1 2 3 4 */
+       {0xd1, 0x21, 0x53, 0x7f, 0x96, 0x40, 0x40, 0x10}, /* MTX 5 6 7 8 */
+       {0xb1, 0x21, 0x57, 0x40, 0x0f, 0x00, 0x00, 0x10}, /* MTX9 MTXS */
+       {0xd1, 0x21, 0x59, 0xba, 0x9a, 0x22, 0xb9, 0x10}, /* reserved */
+       {0xd1, 0x21, 0x5d, 0x9b, 0x10, 0xf0, 0x05, 0x10}, /* reserved */
+       {0xa1, 0x21, 0x61, 0x60, 0x00, 0x00, 0x00, 0x10}, /* reserved */
+       {0xd1, 0x21, 0x62, 0x00, 0x00, 0x50, 0x30, 0x10},
+                                               /* LCC1 LCC2 LCC3 LCC4 */
+       {0xa1, 0x21, 0x66, 0x00, 0x00, 0x00, 0x00, 0x10}, /* LCC5 */
+       {0xd1, 0x21, 0x67, 0x80, 0x7a, 0x90, 0x80, 0x10},
+       {0xa1, 0x21, 0x6b, 0x0a, 0x00, 0x00, 0x00, 0x10},
+                                       /* band gap reference [0..3] DBLV */
+       {0xd1, 0x21, 0x6c, 0x30, 0x48, 0x80, 0x74, 0x10}, /* gamma curve */
+       {0xd1, 0x21, 0x70, 0x64, 0x60, 0x5c, 0x58, 0x10}, /* gamma curve */
+       {0xd1, 0x21, 0x74, 0x54, 0x4c, 0x40, 0x38, 0x10}, /* gamma curve */
+       {0xd1, 0x21, 0x78, 0x34, 0x30, 0x2f, 0x2b, 0x10}, /* gamma curve */
+       {0xd1, 0x21, 0x7c, 0x03, 0x07, 0x17, 0x34, 0x10}, /* gamma curve */
+       {0xd1, 0x21, 0x80, 0x41, 0x4d, 0x58, 0x63, 0x10}, /* gamma curve */
+       {0xd1, 0x21, 0x84, 0x6e, 0x77, 0x87, 0x95, 0x10}, /* gamma curve */
+       {0xc1, 0x21, 0x88, 0xaf, 0xc7, 0xdf, 0x00, 0x10}, /* gamma curve */
+       {0xc1, 0x21, 0x8b, 0x99, 0x99, 0xcf, 0x00, 0x10}, /* reserved */
+       {0xb1, 0x21, 0x92, 0x00, 0x00, 0x00, 0x00, 0x10},
+/****** (some exchanges in the win trace) ******/
+       {0xa1, 0x21, 0x1e, 0x01, 0x00, 0x00, 0x00, 0x10},
+                                               /* bits[3..0]reserved */
+       {0xa1, 0x21, 0x1e, 0x01, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x21, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10},
+                                               /* VREF vertical frame ctrl */
+       {0xa1, 0x21, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x21, 0x10, 0x20, 0x00, 0x00, 0x00, 0x10}, /* 0x20 */
+       {0xa1, 0x21, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x21, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x21, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x10},
+/*     {0xb1, 0x21, 0x01, 0x78, 0x78, 0x00, 0x00, 0x10}, */
+/****** (some exchanges in the win trace) ******/
+       {0xa1, 0x21, 0x93, 0x00, 0x00, 0x00, 0x00, 0x10},/* dummy line hight */
+       {0xa1, 0x21, 0x92, 0x25, 0x00, 0x00, 0x00, 0x10},/* dummy line low */
+       {0xa1, 0x21, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x21, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x10},
+/*     {0xa1, 0x21, 0x02, 0x90, 0x00, 0x00, 0x00, 0x10}, */
+/****** (some exchanges in the win trace) ******/
+/**********startsensor KO if changed !!****/
+       {0xa1, 0x21, 0x93, 0x01, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x21, 0x92, 0xff, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x21, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x21, 0x2b, 0xc3, 0x00, 0x00, 0x00, 0x10},
+/* here may start the isoc exchanges */
+       {0, 0, 0, 0, 0, 0, 0, 0}
+};
+/* reg0x04             reg0x07         reg 0x10 */
+/* expo  = (COM1 & 0x02) | (AECHH & 0x2f <<10) [ (AECh << 2) */
+
+static __u8 ov7648_sensor_init[][8] = {
+       {0xC1, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00},
+       {0xC1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00},
+       {0xC1, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00},
+       {0xA1, 0x6E, 0x3F, 0x20, 0x00, 0x00, 0x00, 0x10},
+       {0xA1, 0x6E, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xA1, 0x6E, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xD1, 0x6E, 0x04, 0x02, 0xB1, 0x02, 0x39, 0x10},
+       {0xD1, 0x6E, 0x08, 0x00, 0x01, 0x00, 0x00, 0x10},
+       {0xD1, 0x6E, 0x0C, 0x02, 0x7F, 0x01, 0xE0, 0x10},
+       {0xD1, 0x6E, 0x12, 0x03, 0x02, 0x00, 0x03, 0x10},
+       {0xD1, 0x6E, 0x16, 0x85, 0x40, 0x4A, 0x40, 0x10},
+       {0xC1, 0x6E, 0x1A, 0x00, 0x80, 0x00, 0x00, 0x10},
+       {0xD1, 0x6E, 0x1D, 0x08, 0x03, 0x00, 0x00, 0x10},
+       {0xD1, 0x6E, 0x23, 0x00, 0xB0, 0x00, 0x94, 0x10},
+       {0xD1, 0x6E, 0x27, 0x58, 0x00, 0x00, 0x00, 0x10},
+       {0xD1, 0x6E, 0x2D, 0x14, 0x35, 0x61, 0x84, 0x10},
+       {0xD1, 0x6E, 0x31, 0xA2, 0xBD, 0xD8, 0xFF, 0x10},
+       {0xD1, 0x6E, 0x35, 0x06, 0x1E, 0x12, 0x02, 0x10},
+       {0xD1, 0x6E, 0x39, 0xAA, 0x53, 0x37, 0xD5, 0x10},
+       {0xA1, 0x6E, 0x3D, 0xF2, 0x00, 0x00, 0x00, 0x10},
+       {0xD1, 0x6E, 0x3E, 0x00, 0x00, 0x80, 0x03, 0x10},
+       {0xD1, 0x6E, 0x42, 0x03, 0x00, 0x00, 0x00, 0x10},
+       {0xC1, 0x6E, 0x46, 0x00, 0x80, 0x80, 0x00, 0x10},
+       {0xD1, 0x6E, 0x4B, 0x02, 0xEF, 0x08, 0xCD, 0x10},
+       {0xD1, 0x6E, 0x4F, 0x00, 0xD0, 0x00, 0xA0, 0x10},
+       {0xD1, 0x6E, 0x53, 0x01, 0xAA, 0x01, 0x40, 0x10},
+       {0xD1, 0x6E, 0x5A, 0x50, 0x04, 0x30, 0x03, 0x10},
+       {0xA1, 0x6E, 0x5E, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xD1, 0x6E, 0x5F, 0x10, 0x40, 0xFF, 0x00, 0x10},
+  /*   {0xD1, 0x6E, 0x63, 0x40, 0x40, 0x00, 0x00, 0x10},
+       {0xD1, 0x6E, 0x67, 0x00, 0x00, 0x00, 0x00, 0x10},
+ * This is currently setting a
+ * blue tint, and some things more , i leave it here for future test if
+ * somene is having problems with color on this sensor
+       {0xD1, 0x6E, 0x6B, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xD1, 0x6E, 0x6F, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xC1, 0x6E, 0x73, 0x10, 0x80, 0xEB, 0x00, 0x10},
+       {0xA1, 0x6E, 0x1E, 0x03, 0x00, 0x00, 0x00, 0x10},
+       {0xA1, 0x6E, 0x15, 0x01, 0x00, 0x00, 0x00, 0x10},
+       {0xC1, 0x6E, 0x16, 0x40, 0x40, 0x40, 0x00, 0x10},
+       {0xA1, 0x6E, 0x1D, 0x08, 0x00, 0x00, 0x00, 0x10},
+       {0xA1, 0x6E, 0x06, 0x02, 0x00, 0x00, 0x00, 0x10},
+       {0xA1, 0x6E, 0x07, 0xB5, 0x00, 0x00, 0x00, 0x10},
+       {0xA1, 0x6E, 0x18, 0x6B, 0x00, 0x00, 0x00, 0x10},
+       {0xA1, 0x6E, 0x1D, 0x08, 0x00, 0x00, 0x00, 0x10},
+       {0xA1, 0x6E, 0x06, 0x02, 0x00, 0x00, 0x00, 0x10},
+       {0xA1, 0x6E, 0x07, 0xB8, 0x00, 0x00, 0x00, 0x10},  */
+       {0xC1, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00},
+       {0xA1, 0x6E, 0x06, 0x03, 0x00, 0x00, 0x00, 0x10}, /* Bright... */
+       {0xA1, 0x6E, 0x07, 0x66, 0x00, 0x00, 0x00, 0x10}, /* B.. */
+       {0xC1, 0x6E, 0x1A, 0x03, 0x65, 0x90, 0x00, 0x10}, /* Bright/Witen....*/
+/*     {0xC1, 0x6E, 0x16, 0x45, 0x40, 0x60, 0x00, 0x10},  * Bright/Witene */
+       {0, 0, 0, 0, 0, 0, 0, 0}
+};
+
+static __u8 qtable4[] = {
+       0x06, 0x04, 0x04, 0x06, 0x04, 0x04, 0x06, 0x06, 0x06, 0x06, 0x08, 0x06,
+       0x06, 0x08, 0x0A, 0x11,
+       0x0A, 0x0A, 0x08, 0x08, 0x0A, 0x15, 0x0F, 0x0F, 0x0C, 0x11, 0x19, 0x15,
+       0x19, 0x19, 0x17, 0x15,
+       0x17, 0x17, 0x1B, 0x1D, 0x25, 0x21, 0x1B, 0x1D, 0x23, 0x1D, 0x17, 0x17,
+       0x21, 0x2E, 0x21, 0x23,
+       0x27, 0x29, 0x2C, 0x2C, 0x2C, 0x19, 0x1F, 0x30, 0x32, 0x2E, 0x29, 0x32,
+       0x25, 0x29, 0x2C, 0x29,
+       0x06, 0x08, 0x08, 0x0A, 0x08, 0x0A, 0x13, 0x0A, 0x0A, 0x13, 0x29, 0x1B,
+       0x17, 0x1B, 0x29, 0x29,
+       0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
+       0x29, 0x29, 0x29, 0x29,
+       0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
+       0x29, 0x29, 0x29, 0x29,
+       0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
+       0x29, 0x29, 0x29, 0x29
+};
+
+static void reg_r(struct usb_device *dev,
+                 __u16 value,
+                 __u8 *buffer, int len)
+{
+       usb_control_msg(dev,
+                       usb_rcvctrlpipe(dev, 0),
+                       0,
+                       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+                       value, 0,
+                       buffer, len,
+                       500);
+}
+
+static void reg_w(struct usb_device *dev,
+                         __u16 value,
+                         __u8 *buffer,
+                         int len)
+{
+       usb_control_msg(dev,
+                       usb_sndctrlpipe(dev, 0),
+                       0x08,
+                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+                       value, 0,
+                       buffer, len,
+                       500);
+}
+
+/* write 2 bytes */
+static void i2c_w2(struct gspca_dev *gspca_dev,
+                  __u8 *buffer)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct usb_device *dev = gspca_dev->dev;
+       __u8 mode[8];
+
+       /* is i2c ready */
+       mode[0] = sd->i2c_ctrl_reg | (2 << 4);
+       mode[1] = sd->i2c_base;
+       mode[2] = buffer[0];
+       mode[3] = buffer[1];
+       mode[4] = 0;
+       mode[5] = 0;
+       mode[6] = 0;
+       mode[7] = 0x10;
+       reg_w(dev, 0x08, mode, 8);
+}
+
+/* write 8 bytes */
+static void i2c_w8(struct usb_device *dev, __u8 *buffer)
+{
+       reg_w(dev, 0x08, buffer, 8);
+       msleep(1);
+}
+
+/* read 5 bytes */
+static void i2c_r5(struct gspca_dev *gspca_dev, __u8 reg,
+                            __u8 *buffer)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct usb_device *dev = gspca_dev->dev;
+       __u8 mode[8];
+
+       mode[0] = sd->i2c_ctrl_reg | 0x10;
+       mode[1] = sd->i2c_base;
+       mode[2] = reg;
+       mode[3] = 0;
+       mode[4] = 0;
+       mode[5] = 0;
+       mode[6] = 0;
+       mode[7] = 0x10;
+       i2c_w8(dev, mode);
+       mode[0] = sd->i2c_ctrl_reg | (5 << 4) | 0x02;
+       mode[2] = 0;
+       i2c_w8(dev, mode);
+       reg_r(dev, 0x0a, buffer, 5);
+}
+
+static int probesensor(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct usb_device *dev = gspca_dev->dev;
+       __u8 reg02;
+       static __u8 datasend[] = { 2, 0 };
+       /* reg val1 val2 val3 val4 */
+       __u8 datarecd[6];
+
+       i2c_w2(gspca_dev, datasend);
+/* should write 0xa1 0x11 0x02 0x00 0x00 0x00 0x00 the 0x10 is add by i2cw */
+       msleep(10);
+       reg02 = 0x66;
+       reg_w(dev, 0x02, &reg02, 1);            /* Gpio on */
+       msleep(10);
+       i2c_r5(gspca_dev, 0, datarecd);         /* read sensor id */
+       if (datarecd[0] == 0x02
+           && datarecd[1] == 0x09
+           && datarecd[2] == 0x01
+           && datarecd[3] == 0x00
+           && datarecd[4] == 0x00) {
+               PDEBUG(D_PROBE, "Find Sensor sn9c102P HV7131R");
+               sd->sensor = SENSOR_HV7131R;
+               return SENSOR_HV7131R;
+       }
+       PDEBUG(D_PROBE, "Find Sensor %d %d %d",
+               datarecd[0], datarecd[1], datarecd[2]);
+       PDEBUG(D_PROBE, "Sensor sn9c102P Not found");
+       return -ENODEV;
+}
+
+static int configure_gpio(struct gspca_dev *gspca_dev,
+                         __u8 *sn9c1xx)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct usb_device *dev = gspca_dev->dev;
+       __u8 data;
+       __u8 regF1;
+       __u8 *reg9a;
+       static __u8 reg9a_def[] =
+               {0x08, 0x40, 0x20, 0x10, 0x00, 0x04};
+       static __u8 reg9a_sn9c120[] =                   /* from win trace */
+               {0x00, 0x40, 0x38, 0x30, 0x00, 0x20};
+       static __u8 reg9a_sn9c325[] =
+               {0x0a, 0x40, 0x38, 0x30, 0x00, 0x20};
+
+
+       regF1 = 0x00;
+       reg_w(dev, 0xf1, &regF1, 1);
+
+       reg_w(dev, 0x01, &sn9c1xx[0], 1);       /*fixme:jfm was [1] en v1*/
+
+       /* configure gpio */
+       reg_w(dev, 0x01, &sn9c1xx[1], 2);
+       reg_w(dev, 0x08, &sn9c1xx[8], 2);
+       reg_w(dev, 0x17, &sn9c1xx[0x17], 3);
+       switch (sd->customid) {
+       case SN9C325:
+               reg9a = reg9a_sn9c325;
+               break;
+       case SN9C120:
+               reg9a = reg9a_sn9c120;
+               break;
+       default:
+               reg9a = reg9a_def;
+               break;
+       }
+       reg_w(dev, 0x9a, reg9a, 6);
+
+       data = 0x60;                            /*fixme:jfm 60 00 00 (3) */
+       reg_w(dev, 0xd4, &data, 1);
+
+       reg_w(dev, 0x03, &sn9c1xx[3], 0x0f);
+
+       switch (sd->customid) {
+       case SN9C120:                           /* from win trace */
+               data = 0x61;
+               reg_w(dev, 0x01, &data, 1);
+               data = 0x20;
+               reg_w(dev, 0x17, &data, 1);
+               data = 0x60;
+               reg_w(dev, 0x01, &data, 1);
+               break;
+       case SN9C325:
+               data = 0x43;
+               reg_w(dev, 0x01, &data, 1);
+               data = 0xae;
+               reg_w(dev, 0x17, &data, 1);
+               data = 0x42;
+               reg_w(dev, 0x01, &data, 1);
+               break;
+       default:
+               data = 0x43;
+               reg_w(dev, 0x01, &data, 1);
+               data = 0x61;
+               reg_w(dev, 0x17, &data, 1);
+               data = 0x42;
+               reg_w(dev, 0x01, &data, 1);
+       }
+
+       if (sd->sensor == SENSOR_HV7131R) {
+               if (probesensor(gspca_dev) < 0)
+                       return -ENODEV;
+       }
+       return 0;
+}
+
+static void hv7131R_InitSensor(struct gspca_dev *gspca_dev)
+{
+       int i = 0;
+       struct usb_device *dev = gspca_dev->dev;
+       static __u8 SetSensorClk[] =            /* 0x08 Mclk */
+               { 0xa1, 0x11, 0x01, 0x18, 0x00, 0x00, 0x00, 0x10 };
+
+       while (hv7131r_sensor_init[i][0]) {
+               i2c_w8(dev, hv7131r_sensor_init[i]);
+               i++;
+       }
+       i2c_w8(dev, SetSensorClk);
+}
+
+static void mi0360_InitSensor(struct gspca_dev *gspca_dev)
+{
+       int i = 0;
+       struct usb_device *dev = gspca_dev->dev;
+
+       while (mi0360_sensor_init[i][0]) {
+               i2c_w8(dev, mi0360_sensor_init[i]);
+               i++;
+       }
+}
+
+static void mo4000_InitSensor(struct gspca_dev *gspca_dev)
+{
+       int i = 0;
+       struct usb_device *dev = gspca_dev->dev;
+
+       while (mo4000_sensor_init[i][0]) {
+               i2c_w8(dev, mo4000_sensor_init[i]);
+               i++;
+       }
+}
+
+static void ov7648_InitSensor(struct gspca_dev *gspca_dev)
+{
+       struct usb_device *dev = gspca_dev->dev;
+       int i = 0;
+
+       while (ov7648_sensor_init[i][0]) {
+               i2c_w8(dev, ov7648_sensor_init[i]);
+               i++;
+       }
+}
+
+static void ov7660_InitSensor(struct gspca_dev *gspca_dev)
+{
+       int i = 0;
+       struct usb_device *dev = gspca_dev->dev;
+
+       while (ov7660_sensor_init[i][0]) {
+               i2c_w8(dev, ov7660_sensor_init[i]);
+               i++;
+       }
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+                       const struct usb_device_id *id)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct cam *cam;
+       __u16 vendor;
+       __u16 product;
+
+       vendor = id->idVendor;
+       product = id->idProduct;
+       sd->sensor = -1;
+       switch (vendor) {
+       case 0x0458:                            /* Genius */
+/*             switch (product) {
+               case 0x7025: */
+                       sd->customid = SN9C120;
+                       sd->sensor = SENSOR_MI0360;
+                       sd->i2c_ctrl_reg = 0x81;
+                       sd->i2c_base = 0x5d;
+/*                     break;
+               } */
+               break;
+       case 0x045e:
+/*             switch (product) {
+               case 0x00f5:
+               case 0x00f7: */
+                       sd->customid = SN9C105;
+                       sd->sensor = SENSOR_OV7660;
+                       sd->i2c_ctrl_reg = 0x81;
+                       sd->i2c_base = 0x21;
+/*                     break;
+               } */
+               break;
+       case 0x0471:                            /* Philips */
+/*             switch (product) {
+               case 0x0327:
+               case 0x0328:
+               case 0x0330: */
+                       sd->customid = SN9C105;
+                       sd->sensor = SENSOR_MI0360;
+                       sd->i2c_ctrl_reg = 0x81;
+                       sd->i2c_base = 0x5d;
+/*                     break;
+               } */
+               break;
+       case 0x0c45:                            /* Sonix */
+               switch (product) {
+               case 0x6040:
+                       sd->customid = SN9C102P;
+                       sd->sensor = SENSOR_MI0360;     /* from BW600.inf */
+/*                     sd->sensor = SENSOR_HV7131R;     * gspcav1 value */
+                       sd->i2c_ctrl_reg = 0x81;
+                       sd->i2c_base = 0x11;
+                       break;
+/*             case 0x607a:                            * from BW600.inf
+                       sd->customid = SN9C102P;
+                       sd->sensor = SENSOR_OV7648;
+                       sd->i2c_ctrl_reg = 0x??;
+                       sd->i2c_base = 0x??;
+                       break; */
+               case 0x607c:
+                       sd->customid = SN9C102P;
+                       sd->sensor = SENSOR_HV7131R;
+                       sd->i2c_ctrl_reg = 0x81;
+                       sd->i2c_base = 0x11;
+                       break;
+/*             case 0x607e:                            * from BW600.inf
+                       sd->customid = SN9C102P;
+                       sd->sensor = SENSOR_OV7630;
+                       sd->i2c_ctrl_reg = 0x??;
+                       sd->i2c_base = 0x??;
+                       break; */
+               case 0x60c0:
+                       sd->customid = SN9C105;
+                       sd->sensor = SENSOR_MI0360;
+                       sd->i2c_ctrl_reg = 0x81;
+                       sd->i2c_base = 0x5d;
+                       break;
+/*             case 0x60c8:                            * from BW600.inf
+                       sd->customid = SN9C105;
+                       sd->sensor = SENSOR_OM6801;
+                       sd->i2c_ctrl_reg = 0x??;
+                       sd->i2c_base = 0x??;
+                       break; */
+/*             case 0x60cc:                            * from BW600.inf
+                       sd->customid = SN9C105;
+                       sd->sensor = SENSOR_HV7131GP;
+                       sd->i2c_ctrl_reg = 0x??;
+                       sd->i2c_base = 0x??;
+                       break; */
+               case 0x60ec:
+                       sd->customid = SN9C105;
+                       sd->sensor = SENSOR_MO4000;
+                       sd->i2c_ctrl_reg = 0x81;
+                       sd->i2c_base = 0x21;
+                       break;
+/*             case 0x60ef:                            * from BW600.inf
+                       sd->customid = SN9C105;
+                       sd->sensor = SENSOR_ICM105C;
+                       sd->i2c_ctrl_reg = 0x??;
+                       sd->i2c_base = 0x??;
+                       break; */
+/*             case 0x60fa:                            * from BW600.inf
+                       sd->customid = SN9C105;
+                       sd->sensor = SENSOR_OV7648;
+                       sd->i2c_ctrl_reg = 0x??;
+                       sd->i2c_base = 0x??;
+                       break; */
+               case 0x60fb:
+                       sd->customid = SN9C105;
+                       sd->sensor = SENSOR_OV7660;
+                       sd->i2c_ctrl_reg = 0x81;
+                       sd->i2c_base = 0x21;
+                       break;
+               case 0x60fc:
+                       sd->customid = SN9C105;
+                       sd->sensor = SENSOR_HV7131R;
+                       sd->i2c_ctrl_reg = 0x81;
+                       sd->i2c_base = 0x11;
+                       break;
+/*             case 0x60fe:                            * from BW600.inf
+                       sd->customid = SN9C105;
+                       sd->sensor = SENSOR_OV7630;
+                       sd->i2c_ctrl_reg = 0x??;
+                       sd->i2c_base = 0x??;
+                       break; */
+/*             case 0x6108:                            * from BW600.inf
+                       sd->customid = SN9C120;
+                       sd->sensor = SENSOR_OM6801;
+                       sd->i2c_ctrl_reg = 0x??;
+                       sd->i2c_base = 0x??;
+                       break; */
+/*             case 0x6122:                            * from BW600.inf
+                       sd->customid = SN9C110;
+                       sd->sensor = SENSOR_ICM105C;
+                       sd->i2c_ctrl_reg = 0x??;
+                       sd->i2c_base = 0x??;
+                       break; */
+               case 0x612a:
+/*                     sd->customid = SN9C110;          * in BW600.inf */
+                       sd->customid = SN9C325;
+                       sd->sensor = SENSOR_OV7648;
+                       sd->i2c_ctrl_reg = 0x81;
+                       sd->i2c_base = 0x21;
+                       break;
+/*             case 0x6123:                            * from BW600.inf
+                       sd->customid = SN9C110;
+                       sd->sensor = SENSOR_SanyoCCD;
+                       sd->i2c_ctrl_reg = 0x??;
+                       sd->i2c_base = 0x??;
+                       break; */
+               case 0x612c:
+                       sd->customid = SN9C110;
+                       sd->sensor = SENSOR_MO4000;
+                       sd->i2c_ctrl_reg = 0x81;
+                       sd->i2c_base = 0x21;
+                       break;
+/*             case 0x612e:                            * from BW600.inf
+                       sd->customid = SN9C110;
+                       sd->sensor = SENSOR_OV7630;
+                       sd->i2c_ctrl_reg = 0x??;
+                       sd->i2c_base = 0x??;
+                       break; */
+/*             case 0x612f:                            * from BW600.inf
+                       sd->customid = SN9C110;
+                       sd->sensor = SENSOR_ICM105C;
+                       sd->i2c_ctrl_reg = 0x??;
+                       sd->i2c_base = 0x??;
+                       break; */
+               case 0x6130:
+                       sd->customid = SN9C120;
+                       sd->sensor = SENSOR_MI0360;
+                       sd->i2c_ctrl_reg = 0x81;
+                       sd->i2c_base = 0x5d;
+                       break;
+               case 0x6138:
+                       sd->customid = SN9C120;
+                       sd->sensor = SENSOR_MO4000;
+                       sd->i2c_ctrl_reg = 0x81;
+                       sd->i2c_base = 0x21;
+                       break;
+/*             case 0x613a:                            * from BW600.inf
+                       sd->customid = SN9C120;
+                       sd->sensor = SENSOR_OV7648;
+                       sd->i2c_ctrl_reg = 0x??;
+                       sd->i2c_base = 0x??;
+                       break; */
+               case 0x613b:
+                       sd->customid = SN9C120;
+                       sd->sensor = SENSOR_OV7660;
+                       sd->i2c_ctrl_reg = 0x81;
+                       sd->i2c_base = 0x21;
+                       break;
+               case 0x613c:
+                       sd->customid = SN9C120;
+                       sd->sensor = SENSOR_HV7131R;
+                       sd->i2c_ctrl_reg = 0x81;
+                       sd->i2c_base = 0x11;
+                       break;
+/*             case 0x613e:                            * from BW600.inf
+                       sd->customid = SN9C120;
+                       sd->sensor = SENSOR_OV7630;
+                       sd->i2c_ctrl_reg = 0x??;
+                       sd->i2c_base = 0x??;
+                       break; */
+               }
+               break;
+       }
+       if (sd->sensor < 0) {
+               PDEBUG(D_ERR, "Invalid vendor/product %04x:%04x",
+                       vendor, product);
+               return -EINVAL;
+       }
+
+       cam = &gspca_dev->cam;
+       cam->dev_name = (char *) id->driver_info;
+       cam->epaddr = 0x01;
+       cam->cam_mode = vga_mode;
+       cam->nmodes = ARRAY_SIZE(vga_mode);
+       sd->qindex = 4;                 /* set the quantization table */
+       sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
+       sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
+       sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value;
+       sd->autogain = sd_ctrls[SD_AUTOGAIN].qctrl.default_value;
+       return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct usb_device *dev = gspca_dev->dev;
+/*     __u8 *sn9c1xx; */
+       __u8 regF1;
+       __u8 regGpio[] = { 0x29, 0x74 };
+
+       /* setup a selector by customid */
+       regF1 = 0x01;
+       reg_w(dev, 0xf1, &regF1, 1);
+       reg_r(dev, 0x00, &regF1, 1);    /* -> regF1 = 0x00 */
+       reg_w(dev, 0xf1, &regF1, 1);
+       reg_r(dev, 0x00, &regF1, 1);
+       switch (sd->customid) {
+       case SN9C102P:
+               if (regF1 != 0x11)
+                       return -ENODEV;
+               reg_w(dev, 0x02, &regGpio[1], 1);
+               break;
+       case SN9C105:
+               if (regF1 != 0x11)
+                       return -ENODEV;
+               reg_w(dev, 0x02, regGpio, 2);
+               break;
+       case SN9C110:
+               if (regF1 != 0x12)
+                       return -ENODEV;
+               regGpio[1] = 0x62;
+               reg_w(dev, 0x02, &regGpio[1], 1);
+               break;
+       case SN9C120:
+               if (regF1 != 0x12)
+                       return -ENODEV;
+               regGpio[1] = 0x70;
+               reg_w(dev, 0x02, regGpio, 2);
+               break;
+       default:
+/*     case SN9C325: */
+               if (regF1 != 0x12)
+                       return -ENODEV;
+               regGpio[1] = 0x62;
+               reg_w(dev, 0x02, &regGpio[1], 1);
+               break;
+       }
+
+       regF1 = 0x01;
+       reg_w(dev, 0xf1, &regF1, 1);
+
+       return 0;
+}
+
+static unsigned int setexposure(struct gspca_dev *gspca_dev,
+                               unsigned int expo)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       static __u8 doit[] =                    /* update sensor */
+               { 0xb1, 0x5d, 0x07, 0x00, 0x03, 0x00, 0x00, 0x10 };
+       static __u8 sensorgo[] =                /* sensor on */
+               { 0xb1, 0x5d, 0x07, 0x00, 0x02, 0x00, 0x00, 0x10 };
+       static __u8 gainMo[] =
+               { 0xa1, 0x21, 0x00, 0x10, 0x00, 0x00, 0x00, 0x1d };
+
+       switch (sd->sensor) {
+       case SENSOR_HV7131R: {
+               __u8 Expodoit[] =
+                       { 0xc1, 0x11, 0x25, 0x07, 0x27, 0xc0, 0x00, 0x16 };
+
+               Expodoit[3] = expo >> 16;
+               Expodoit[4] = expo >> 8;
+               Expodoit[5] = expo;
+               i2c_w8(gspca_dev->dev, Expodoit);
+               break;
+           }
+       case SENSOR_MI0360: {
+               __u8 expoMi[] =  /* exposure 0x0635 -> 4 fp/s 0x10 */
+                       { 0xb1, 0x5d, 0x09, 0x06, 0x35, 0x00, 0x00, 0x16 };
+
+               if (expo > 0x0635)
+                       expo = 0x0635;
+               else if (expo < 0x0001)
+                       expo = 0x0001;
+               expoMi[3] = expo >> 8;
+               expoMi[4] = expo;
+               i2c_w8(gspca_dev->dev, expoMi);
+               i2c_w8(gspca_dev->dev, doit);
+               i2c_w8(gspca_dev->dev, sensorgo);
+               break;
+           }
+       case SENSOR_MO4000: {
+               __u8 expoMof[] =
+                       { 0xa1, 0x21, 0x0f, 0x20, 0x00, 0x00, 0x00, 0x10 };
+               __u8 expoMo10[] =
+                       { 0xa1, 0x21, 0x10, 0x20, 0x00, 0x00, 0x00, 0x10 };
+
+               if (expo > 0x1fff)
+                       expo = 0x1fff;
+               else if (expo < 0x0001)
+                       expo = 0x0001;
+               expoMof[3] = (expo & 0x03fc) >> 2;
+               i2c_w8(gspca_dev->dev, expoMof);
+               expoMo10[3] = ((expo & 0x1c00) >> 10)
+                               | ((expo & 0x0003) << 4);
+               i2c_w8(gspca_dev->dev, expoMo10);
+               i2c_w8(gspca_dev->dev, gainMo);
+               PDEBUG(D_CONF," set exposure %d",
+                       ((expoMo10[3] & 0x07) << 10)
+                       | (expoMof[3] << 2)
+                       | ((expoMo10[3] & 0x30) >> 4));
+               break;
+           }
+       }
+       return expo;
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       unsigned int expo;
+       __u8 k2;
+
+       switch (sd->sensor) {
+       case SENSOR_HV7131R:
+               expo = sd->brightness << 4;
+               if (expo > 0x002dc6c0)
+                       expo = 0x002dc6c0;
+               else if (expo < 0x02a0)
+                       expo = 0x02a0;
+               sd->exposure = setexposure(gspca_dev, expo);
+               break;
+       case SENSOR_MI0360:
+               expo = sd->brightness >> 4;
+               sd->exposure = setexposure(gspca_dev, expo);
+               break;
+       case SENSOR_MO4000:
+               expo = sd->brightness >> 4;
+               sd->exposure = setexposure(gspca_dev, expo);
+               break;
+       case SENSOR_OV7660:
+               return;                         /*jfm??*/
+       }
+
+       k2 = sd->brightness >> 10;
+       reg_w(gspca_dev->dev, 0x96, &k2, 1);
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       __u8 k2;
+       __u8 contrast[] = { 0x00, 0x00, 0x28, 0x00, 0x07, 0x00 };
+
+       if (sd->sensor == SENSOR_OV7660)
+               return;                         /*jfm??*/
+       k2 = sd->contrast;
+       contrast[2] = k2;
+       contrast[0] = (k2 + 1) >> 1;
+       contrast[4] = (k2 + 1) / 5;
+       reg_w(gspca_dev->dev, 0x84, contrast, 6);
+}
+
+static void setcolors(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       __u8 data;
+       int colour;
+
+       colour = sd->colors - 128;
+       if (colour > 0)
+               data = (colour + 32) & 0x7f;    /* blue */
+       else
+               data = (-colour + 32) & 0x7f;   /* red */
+       reg_w(gspca_dev->dev, 0x05, &data, 1);
+}
+
+/* -- start the camera -- */
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct usb_device *dev = gspca_dev->dev;
+       int i;
+       __u8 data;
+       __u8 reg1;
+       __u8 reg17;
+       __u8 *sn9c1xx;
+       int mode;
+       static __u8 DC29[] = { 0x6a, 0x50, 0x00, 0x00, 0x50, 0x3c };
+       static __u8 C0[] = { 0x2d, 0x2d, 0x3a, 0x05, 0x04, 0x3f };
+       static __u8 CA[] = { 0x28, 0xd8, 0x14, 0xec };
+       static __u8 CA_sn9c120[] = { 0x14, 0xec, 0x0a, 0xf6 }; /* SN9C120 */
+       static __u8 CE[] = { 0x32, 0xdd, 0x2d, 0xdd };  /* MI0360 */
+       static __u8 CE_sn9c325[] =
+                       { 0x32, 0xdd, 0x32, 0xdd };     /* OV7648 - SN9C325 */
+
+       sn9c1xx = sn_tb[(int) sd->sensor];
+       configure_gpio(gspca_dev, sn9c1xx);
+
+/*fixme:jfm this sequence should appear at end of sd_start */
+/* with
+       data = 0x44;
+       reg_w(dev, 0x01, &data, 1); */
+       reg_w(dev, 0x15, &sn9c1xx[0x15], 1);
+       reg_w(dev, 0x16, &sn9c1xx[0x16], 1);
+       reg_w(dev, 0x12, &sn9c1xx[0x12], 1);
+       reg_w(dev, 0x13, &sn9c1xx[0x13], 1);
+       reg_w(dev, 0x18, &sn9c1xx[0x18], 1);
+       reg_w(dev, 0xd2, &DC29[0], 1);
+       reg_w(dev, 0xd3, &DC29[1], 1);
+       reg_w(dev, 0xc6, &DC29[2], 1);
+       reg_w(dev, 0xc7, &DC29[3], 1);
+       reg_w(dev, 0xc8, &DC29[4], 1);
+       reg_w(dev, 0xc9, &DC29[5], 1);
+/*fixme:jfm end of ending sequence */
+       reg_w(dev, 0x18, &sn9c1xx[0x18], 1);
+       if (sd->customid == SN9C325)
+               data = 0xae;
+       else
+               data = 0x60;
+       reg_w(dev, 0x17, &data, 1);
+       reg_w(dev, 0x05, &sn9c1xx[5], 1);
+       reg_w(dev, 0x07, &sn9c1xx[7], 1);
+       reg_w(dev, 0x06, &sn9c1xx[6], 1);
+       reg_w(dev, 0x14, &sn9c1xx[0x14], 1);
+       if (sd->customid == SN9C325) {
+               reg_w(dev, 0x20, regsn20_sn9c325, 0x11);
+               for (i = 0; i < 8; i++)
+                       reg_w(dev, 0x84, reg84_sn9c325, 0x15);
+               data = 0x0a;
+               reg_w(dev, 0x9a, &data, 1);
+               data = 0x60;
+               reg_w(dev, 0x99, &data, 1);
+       } else {
+               reg_w(dev, 0x20, regsn20, 0x11);
+               for (i = 0; i < 8; i++)
+                       reg_w(dev, 0x84, reg84, 0x15);
+               data = 0x08;
+               reg_w(dev, 0x9a, &data, 1);
+               data = 0x59;
+               reg_w(dev, 0x99, &data, 1);
+       }
+
+       mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].mode;
+       reg1 = 0x02;
+       reg17 = 0x61;
+       switch (sd->sensor) {
+       case SENSOR_HV7131R:
+               hv7131R_InitSensor(gspca_dev);
+               if (mode)
+                       reg1 = 0x46;    /* 320 clk 48Mhz */
+               else
+                       reg1 = 0x06;    /* 640 clk 24Mz */
+               break;
+       case SENSOR_MI0360:
+               mi0360_InitSensor(gspca_dev);
+               if (mode)
+                       reg1 = 0x46;    /* 320 clk 48Mhz */
+               else
+                       reg1 = 0x06;    /* 640 clk 24Mz */
+               break;
+       case SENSOR_MO4000:
+               mo4000_InitSensor(gspca_dev);
+               if (mode) {
+/*                     reg1 = 0x46;     * 320 clk 48Mhz 60fp/s */
+                       reg1 = 0x06;    /* clk 24Mz */
+               } else {
+                       reg17 = 0x22;   /* 640 MCKSIZE */
+                       reg1 = 0x06;    /* 640 clk 24Mz */
+               }
+               break;
+       case SENSOR_OV7648:
+               reg17 = 0xa2;
+               reg1 = 0x44;
+               ov7648_InitSensor(gspca_dev);
+/*             if (mode)
+                       ;                * 320x2...
+               else
+                       ;                * 640x... */
+               break;
+       default:
+/*     case SENSOR_OV7660: */
+               ov7660_InitSensor(gspca_dev);
+               if (mode) {
+/*                     reg17 = 0x21;    * 320 */
+/*                     reg1 = 0x44; */
+                       reg1 = 0x46;
+               } else {
+                       reg17 = 0xa2;   /* 640 */
+                       reg1 = 0x40;
+               }
+               break;
+       }
+       reg_w(dev, 0xc0, C0, 6);
+       switch (sd->customid) {
+       case SN9C120:                   /*jfm ?? */
+               reg_w(dev, 0xca, CA_sn9c120, 4);
+               break;
+       default:
+               reg_w(dev, 0xca, CA, 4);
+               break;
+       }
+       switch (sd->customid) {
+       case SN9C120:                   /*jfm ?? */
+       case SN9C325:
+               reg_w(dev, 0xce, CE_sn9c325, 4);
+               break;
+       default:
+               reg_w(dev, 0xce, CE, 4);
+                                       /* ?? {0x1e, 0xdd, 0x2d, 0xe7} */
+               break;
+       }
+
+       /* here change size mode 0 -> VGA; 1 -> CIF */
+       data = 0x40 | sn9c1xx[0x18] | (mode << 4);
+       reg_w(dev, 0x18, &data, 1);
+
+       reg_w(dev, 0x100, qtable4, 0x40);
+       reg_w(dev, 0x140, qtable4 + 0x40, 0x40);
+
+       data = sn9c1xx[0x18] | (mode << 4);
+       reg_w(dev, 0x18, &data, 1);
+
+       reg_w(dev, 0x17, &reg17, 1);
+       reg_w(dev, 0x01, &reg1, 1);
+       setbrightness(gspca_dev);
+       setcontrast(gspca_dev);
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct usb_device *dev = gspca_dev->dev;
+       static __u8 stophv7131[] =
+               { 0xa1, 0x11, 0x02, 0x09, 0x00, 0x00, 0x00, 0x10 };
+       static __u8 stopmi0360[] =
+               { 0xb1, 0x5d, 0x07, 0x00, 0x00, 0x00, 0x00, 0x10 };
+       __u8 regF1;
+       __u8 data;
+       __u8 *sn9c1xx;
+
+       data = 0x0b;
+       switch (sd->sensor) {
+       case SENSOR_HV7131R:
+               i2c_w8(dev, stophv7131);
+               data = 0x2b;
+               break;
+       case SENSOR_MI0360:
+               i2c_w8(dev, stopmi0360);
+               data = 0x29;
+               break;
+       case SENSOR_MO4000:
+               break;
+       case SENSOR_OV7648:
+               data = 0x29;
+               break;
+       default:
+/*     case SENSOR_OV7660: */
+               break;
+       }
+       sn9c1xx = sn_tb[(int) sd->sensor];
+       reg_w(dev, 0x01, &sn9c1xx[1], 1);
+       reg_w(dev, 0x17, &sn9c1xx[0x17], 1);
+       reg_w(dev, 0x01, &sn9c1xx[1], 1);
+       reg_w(dev, 0x01, &data, 1);
+       regF1 = 0x01;
+       reg_w(dev, 0xf1, &regF1, 1);
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+static void setautogain(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       /* Thanks S., without your advice, autobright should not work :) */
+       int delta;
+       int expotimes = 0;
+       __u8 luma_mean = 130;
+       __u8 luma_delta = 20;
+
+       delta = sd->avg_lum;
+       if (delta < luma_mean - luma_delta ||
+           delta > luma_mean + luma_delta) {
+               switch (sd->sensor) {
+               case SENSOR_HV7131R:
+                       expotimes = sd->exposure >> 8;
+                       expotimes += (luma_mean - delta) >> 4;
+                       if (expotimes < 0)
+                               expotimes = 0;
+                       sd->exposure = setexposure(gspca_dev,
+                                       (unsigned int) (expotimes << 8));
+                       break;
+               case SENSOR_MO4000:
+               case SENSOR_MI0360:
+                       expotimes = sd->exposure;
+                       expotimes += (luma_mean - delta) >> 6;
+                       if (expotimes < 0)
+                               expotimes = 0;
+                       sd->exposure = setexposure(gspca_dev,
+                                                  (unsigned int) expotimes);
+                       setcolors(gspca_dev);
+                       break;
+               }
+       }
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+                       struct gspca_frame *frame,      /* target */
+                       unsigned char *data,            /* isoc packet */
+                       int len)                        /* iso packet length */
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int sof, avg_lum;
+
+       sof = len - 64;
+       if (sof >= 0 && data[sof] == 0xff && data[sof + 1] == 0xd9) {
+
+               /* end of frame */
+               gspca_frame_add(gspca_dev, LAST_PACKET,
+                               frame, data, sof + 2);
+               if (sd->ag_cnt < 0)
+                       return;
+               if (--sd->ag_cnt >= 0)
+                       return;
+               sd->ag_cnt = AG_CNT_START;
+/* w1 w2 w3 */
+/* w4 w5 w6 */
+/* w7 w8 */
+/* w4 */
+               avg_lum = ((data[sof + 29] << 8) | data[sof + 30]) >> 6;
+/* w6 */
+               avg_lum += ((data[sof + 33] << 8) | data[sof + 34]) >> 6;
+/* w2 */
+               avg_lum += ((data[sof + 25] << 8) | data[sof + 26]) >> 6;
+/* w8 */
+               avg_lum += ((data[sof + 37] << 8) | data[sof + 38]) >> 6;
+/* w5 */
+               avg_lum += ((data[sof + 31] << 8) | data[sof + 32]) >> 4;
+               avg_lum >>= 4;
+               sd->avg_lum = avg_lum;
+               PDEBUG(D_PACK, "mean lum %d", avg_lum);
+               setautogain(gspca_dev);
+               return;
+       }
+       if (gspca_dev->last_packet_type == LAST_PACKET) {
+
+               /* put the JPEG 422 header */
+               jpeg_put_header(gspca_dev, frame, sd->qindex, 0x21);
+       }
+       gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+}
+
+static unsigned int getexposure(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       __u8 hexpo, mexpo, lexpo;
+       __u8 expo[6];
+
+       switch (sd->sensor) {
+       case SENSOR_HV7131R:
+               /* read sensor exposure */
+               i2c_r5(gspca_dev, 0x25, expo);
+               return (expo[0] << 16) | (expo[1] << 8) | expo[2];
+       case SENSOR_MI0360:
+               /* read sensor exposure */
+               i2c_r5(gspca_dev, 0x09, expo);
+               return (expo[0] << 8) | expo[1];
+       case SENSOR_MO4000:
+               i2c_r5(gspca_dev, 0x0e, expo);
+               hexpo = 0;              /* expo[1] & 0x07; */
+               mexpo = 0x40;           /* expo[2] &0xff; */
+               lexpo = (expo[1] & 0x30) >> 4;
+               PDEBUG(D_CONF, "exposure %d",
+                       (hexpo << 10) | (mexpo << 2) | lexpo);
+               return (hexpo << 10) | (mexpo << 2) | lexpo;
+       default:
+/*     case SENSOR_OV7660: */
+               /* read sensor exposure */
+               i2c_r5(gspca_dev, 0x04, expo);
+               hexpo = expo[3] & 0x2f;
+               lexpo = expo[0] & 0x02;
+               i2c_r5(gspca_dev, 0x08, expo);
+               mexpo = expo[2];
+               return (hexpo << 10) | (mexpo << 2) | lexpo;
+       }
+}
+
+static void getbrightness(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       /* hardcoded registers seem not readable */
+       switch (sd->sensor) {
+       case SENSOR_HV7131R:
+/*             sd->brightness = 0x7fff; */
+               sd->brightness = getexposure(gspca_dev) >> 4;
+               break;
+       case SENSOR_MI0360:
+               sd->brightness = getexposure(gspca_dev) << 4;
+               break;
+       case SENSOR_MO4000:
+/*             sd->brightness = 0x1fff; */
+               sd->brightness = getexposure(gspca_dev) << 4;
+               break;
+       }
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->brightness = val;
+       if (gspca_dev->streaming)
+               setbrightness(gspca_dev);
+       return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       getbrightness(gspca_dev);
+       *val = sd->brightness;
+       return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->contrast = val;
+       if (gspca_dev->streaming)
+               setcontrast(gspca_dev);
+       return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->contrast;
+       return 0;
+}
+
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->colors = val;
+       if (gspca_dev->streaming)
+               setcolors(gspca_dev);
+       return 0;
+}
+
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->colors;
+       return 0;
+}
+
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->autogain = val;
+       if (val)
+               sd->ag_cnt = AG_CNT_START;
+       else
+               sd->ag_cnt = -1;
+       return 0;
+}
+
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->autogain;
+       return 0;
+}
+
+/* sub-driver description */
+static struct sd_desc sd_desc = {
+       .name = MODULE_NAME,
+       .ctrls = sd_ctrls,
+       .nctrls = ARRAY_SIZE(sd_ctrls),
+       .config = sd_config,
+       .open = sd_open,
+       .start = sd_start,
+       .stopN = sd_stopN,
+       .stop0 = sd_stop0,
+       .close = sd_close,
+       .pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static __devinitdata struct usb_device_id device_table[] = {
+       {USB_DEVICE(0x0458, 0x7025), DVNM("Genius Eye 311Q")},
+       {USB_DEVICE(0x045e, 0x00f5), DVNM("MicroSoft VX3000")},
+       {USB_DEVICE(0x045e, 0x00f7), DVNM("MicroSoft VX1000")},
+       {USB_DEVICE(0x0471, 0x0327), DVNM("Philips SPC 600 NC")},
+       {USB_DEVICE(0x0471, 0x0328), DVNM("Philips SPC 700 NC")},
+       {USB_DEVICE(0x0471, 0x0330), DVNM("Philips SPC 710NC")},
+       {USB_DEVICE(0x0c45, 0x6040), DVNM("Speed NVC 350K")},
+       {USB_DEVICE(0x0c45, 0x607c), DVNM("Sonix sn9c102p Hv7131R")},
+       {USB_DEVICE(0x0c45, 0x60c0), DVNM("Sangha Sn535")},
+       {USB_DEVICE(0x0c45, 0x60ec), DVNM("SN9C105+MO4000")},
+       {USB_DEVICE(0x0c45, 0x60fb), DVNM("Surfer NoName")},
+       {USB_DEVICE(0x0c45, 0x60fc), DVNM("LG-LIC300")},
+       {USB_DEVICE(0x0c45, 0x612a), DVNM("Avant Camera")},
+       {USB_DEVICE(0x0c45, 0x612c), DVNM("Typhoon Rasy Cam 1.3MPix")},
+       {USB_DEVICE(0x0c45, 0x6130), DVNM("Sonix Pccam")},
+       {USB_DEVICE(0x0c45, 0x6138), DVNM("Sn9c120 Mo4000")},
+       {USB_DEVICE(0x0c45, 0x613b), DVNM("Surfer SN-206")},
+       {USB_DEVICE(0x0c45, 0x613c), DVNM("Sonix Pccam168")},
+       {}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+                   const struct usb_device_id *id)
+{
+       return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+                               THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+       .name = MODULE_NAME,
+       .id_table = device_table,
+       .probe = sd_probe,
+       .disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+       if (usb_register(&sd_driver) < 0)
+               return -1;
+       info("v%s registered", version);
+       return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+       usb_deregister(&sd_driver);
+       info("deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/spca500.c b/drivers/media/video/gspca/spca500.c
new file mode 100644 (file)
index 0000000..c0dd969
--- /dev/null
@@ -0,0 +1,1195 @@
+/*
+ * SPCA500 chip based cameras initialization data
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#define MODULE_NAME "spca500"
+
+#include "gspca.h"
+#include "jpeg.h"
+
+#define DRIVER_VERSION_NUMBER  KERNEL_VERSION(2, 1, 0)
+static const char version[] = "2.1.0";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("GSPCA/SPCA500 USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+       struct gspca_dev gspca_dev;             /* !! must be the first item */
+
+       unsigned char packet[ISO_MAX_SIZE + 128];
+                                /* !! no more than 128 ff in an ISO packet */
+
+       unsigned char brightness;
+       unsigned char contrast;
+       unsigned char colors;
+
+       char qindex;
+       char subtype;
+#define AgfaCl20 0
+#define AiptekPocketDV 1
+#define BenqDC1016 2
+#define CreativePCCam300 3
+#define DLinkDSC350 4
+#define Gsmartmini 5
+#define IntelPocketPCCamera 6
+#define KodakEZ200 7
+#define LogitechClickSmart310 8
+#define LogitechClickSmart510 9
+#define LogitechTraveler 10
+#define MustekGsmart300 11
+#define Optimedia 12
+#define PalmPixDC85 13
+#define ToptroIndus 14
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+#define SD_BRIGHTNESS 0
+       {
+           {
+               .id      = V4L2_CID_BRIGHTNESS,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Brightness",
+               .minimum = 0,
+               .maximum = 0xff,
+               .step    = 1,
+               .default_value = 0x7f,
+           },
+           .set = sd_setbrightness,
+           .get = sd_getbrightness,
+       },
+#define SD_CONTRAST 1
+       {
+           {
+               .id      = V4L2_CID_CONTRAST,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Contrast",
+               .minimum = 0,
+               .maximum = 255,
+               .step    = 1,
+               .default_value = 127,
+           },
+           .set = sd_setcontrast,
+           .get = sd_getcontrast,
+       },
+#define SD_COLOR 2
+       {
+           {
+               .id      = V4L2_CID_SATURATION,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Color",
+               .minimum = 0,
+               .maximum = 255,
+               .step    = 1,
+               .default_value = 127,
+           },
+           .set = sd_setcolors,
+           .get = sd_getcolors,
+       },
+};
+
+static struct cam_mode vga_mode[] = {
+       {V4L2_PIX_FMT_JPEG, 320, 240, 1},
+       {V4L2_PIX_FMT_JPEG, 640, 480, 0},
+};
+
+static struct cam_mode sif_mode[] = {
+       {V4L2_PIX_FMT_JPEG, 176, 144, 1},
+       {V4L2_PIX_FMT_JPEG, 352, 288, 0},
+};
+
+/* Frame packet header offsets for the spca500 */
+#define SPCA500_OFFSET_PADDINGLB 2
+#define SPCA500_OFFSET_PADDINGHB 3
+#define SPCA500_OFFSET_MODE      4
+#define SPCA500_OFFSET_IMGWIDTH  5
+#define SPCA500_OFFSET_IMGHEIGHT 6
+#define SPCA500_OFFSET_IMGMODE   7
+#define SPCA500_OFFSET_QTBLINDEX 8
+#define SPCA500_OFFSET_FRAMSEQ   9
+#define SPCA500_OFFSET_CDSPINFO  10
+#define SPCA500_OFFSET_GPIO      11
+#define SPCA500_OFFSET_AUGPIO    12
+#define SPCA500_OFFSET_DATA      16
+
+
+static __u16 spca500_visual_defaults[][3] = {
+       {0x00, 0x0003, 0x816b}, /* SSI not active sync with vsync,
+                                * hue (H byte) = 0,
+                                * saturation/hue enable,
+                                * brightness/contrast enable.
+                                */
+       {0x00, 0x0000, 0x8167}, /* brightness = 0 */
+       {0x00, 0x0020, 0x8168}, /* contrast = 0 */
+       {0x00, 0x0003, 0x816b}, /* SSI not active sync with vsync,
+                                * hue (H byte) = 0, saturation/hue enable,
+                                * brightness/contrast enable.
+                                * was 0x0003, now 0x0000.
+                                */
+       {0x00, 0x0000, 0x816a}, /* hue (L byte) = 0 */
+       {0x00, 0x0020, 0x8169}, /* saturation = 0x20 */
+       {0x00, 0x0050, 0x8157}, /* edge gain high threshold */
+       {0x00, 0x0030, 0x8158}, /* edge gain low threshold */
+       {0x00, 0x0028, 0x8159}, /* edge bandwidth high threshold */
+       {0x00, 0x000a, 0x815a}, /* edge bandwidth low threshold */
+       {0x00, 0x0001, 0x8202}, /* clock rate compensation = 1/25 sec/frame */
+       {0x0c, 0x0004, 0x0000},
+       /* set interface */
+
+       {0, 0, 0}
+};
+static __u16 Clicksmart510_defaults[][3] = {
+       {0x00, 0x00, 0x8211},
+       {0x00, 0x01, 0x82c0},
+       {0x00, 0x10, 0x82cb},
+       {0x00, 0x0f, 0x800d},
+       {0x00, 0x82, 0x8225},
+       {0x00, 0x21, 0x8228},
+       {0x00, 0x00, 0x8203},
+       {0x00, 0x00, 0x8204},
+       {0x00, 0x08, 0x8205},
+       {0x00, 0xf8, 0x8206},
+       {0x00, 0x28, 0x8207},
+       {0x00, 0xa0, 0x8208},
+       {0x00, 0x08, 0x824a},
+       {0x00, 0x08, 0x8214},
+       {0x00, 0x80, 0x82c1},
+       {0x00, 0x00, 0x82c2},
+       {0x00, 0x00, 0x82ca},
+       {0x00, 0x80, 0x82c1},
+       {0x00, 0x04, 0x82c2},
+       {0x00, 0x00, 0x82ca},
+       {0x00, 0xfc, 0x8100},
+       {0x00, 0xfc, 0x8105},
+       {0x00, 0x30, 0x8101},
+       {0x00, 0x00, 0x8102},
+       {0x00, 0x00, 0x8103},
+       {0x00, 0x66, 0x8107},
+       {0x00, 0x00, 0x816b},
+       {0x00, 0x00, 0x8155},
+       {0x00, 0x01, 0x8156},
+       {0x00, 0x60, 0x8157},
+       {0x00, 0x40, 0x8158},
+       {0x00, 0x0a, 0x8159},
+       {0x00, 0x06, 0x815a},
+       {0x00, 0x00, 0x813f},
+       {0x00, 0x00, 0x8200},
+       {0x00, 0x19, 0x8201},
+       {0x00, 0x00, 0x82c1},
+       {0x00, 0xa0, 0x82c2},
+       {0x00, 0x00, 0x82ca},
+       {0x00, 0x00, 0x8117},
+       {0x00, 0x00, 0x8118},
+       {0x00, 0x65, 0x8119},
+       {0x00, 0x00, 0x811a},
+       {0x00, 0x00, 0x811b},
+       {0x00, 0x55, 0x811c},
+       {0x00, 0x65, 0x811d},
+       {0x00, 0x55, 0x811e},
+       {0x00, 0x16, 0x811f},
+       {0x00, 0x19, 0x8120},
+       {0x00, 0x80, 0x8103},
+       {0x00, 0x83, 0x816b},
+       {0x00, 0x25, 0x8168},
+       {0x00, 0x01, 0x820f},
+       {0x00, 0xff, 0x8115},
+       {0x00, 0x48, 0x8116},
+       {0x00, 0x50, 0x8151},
+       {0x00, 0x40, 0x8152},
+       {0x00, 0x78, 0x8153},
+       {0x00, 0x40, 0x8154},
+       {0x00, 0x00, 0x8167},
+       {0x00, 0x20, 0x8168},
+       {0x00, 0x00, 0x816a},
+       {0x00, 0x03, 0x816b},
+       {0x00, 0x20, 0x8169},
+       {0x00, 0x60, 0x8157},
+       {0x00, 0x00, 0x8190},
+       {0x00, 0x00, 0x81a1},
+       {0x00, 0x00, 0x81b2},
+       {0x00, 0x27, 0x8191},
+       {0x00, 0x27, 0x81a2},
+       {0x00, 0x27, 0x81b3},
+       {0x00, 0x4b, 0x8192},
+       {0x00, 0x4b, 0x81a3},
+       {0x00, 0x4b, 0x81b4},
+       {0x00, 0x66, 0x8193},
+       {0x00, 0x66, 0x81a4},
+       {0x00, 0x66, 0x81b5},
+       {0x00, 0x79, 0x8194},
+       {0x00, 0x79, 0x81a5},
+       {0x00, 0x79, 0x81b6},
+       {0x00, 0x8a, 0x8195},
+       {0x00, 0x8a, 0x81a6},
+       {0x00, 0x8a, 0x81b7},
+       {0x00, 0x9b, 0x8196},
+       {0x00, 0x9b, 0x81a7},
+       {0x00, 0x9b, 0x81b8},
+       {0x00, 0xa6, 0x8197},
+       {0x00, 0xa6, 0x81a8},
+       {0x00, 0xa6, 0x81b9},
+       {0x00, 0xb2, 0x8198},
+       {0x00, 0xb2, 0x81a9},
+       {0x00, 0xb2, 0x81ba},
+       {0x00, 0xbe, 0x8199},
+       {0x00, 0xbe, 0x81aa},
+       {0x00, 0xbe, 0x81bb},
+       {0x00, 0xc8, 0x819a},
+       {0x00, 0xc8, 0x81ab},
+       {0x00, 0xc8, 0x81bc},
+       {0x00, 0xd2, 0x819b},
+       {0x00, 0xd2, 0x81ac},
+       {0x00, 0xd2, 0x81bd},
+       {0x00, 0xdb, 0x819c},
+       {0x00, 0xdb, 0x81ad},
+       {0x00, 0xdb, 0x81be},
+       {0x00, 0xe4, 0x819d},
+       {0x00, 0xe4, 0x81ae},
+       {0x00, 0xe4, 0x81bf},
+       {0x00, 0xed, 0x819e},
+       {0x00, 0xed, 0x81af},
+       {0x00, 0xed, 0x81c0},
+       {0x00, 0xf7, 0x819f},
+       {0x00, 0xf7, 0x81b0},
+       {0x00, 0xf7, 0x81c1},
+       {0x00, 0xff, 0x81a0},
+       {0x00, 0xff, 0x81b1},
+       {0x00, 0xff, 0x81c2},
+       {0x00, 0x03, 0x8156},
+       {0x00, 0x00, 0x8211},
+       {0x00, 0x20, 0x8168},
+       {0x00, 0x01, 0x8202},
+       {0x00, 0x30, 0x8101},
+       {0x00, 0x00, 0x8111},
+       {0x00, 0x00, 0x8112},
+       {0x00, 0x00, 0x8113},
+       {0x00, 0x00, 0x8114},
+       {}
+};
+
+static unsigned char qtable_creative_pccam[2][64] = {
+       {                               /* Q-table Y-components */
+        0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
+        0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
+        0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11,
+        0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13,
+        0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17,
+        0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c,
+        0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e,
+        0x16, 0x1c, 0x1d, 0x1d, 0x22, 0x1e, 0x1f, 0x1e},
+       {                               /* Q-table C-components */
+        0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e,
+        0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e,
+        0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+        0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+        0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+        0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+        0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+        0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
+};
+
+static unsigned char qtable_kodak_ez200[2][64] = {
+       {                               /* Q-table Y-components */
+        0x02, 0x01, 0x01, 0x02, 0x02, 0x04, 0x05, 0x06,
+        0x01, 0x01, 0x01, 0x02, 0x03, 0x06, 0x06, 0x06,
+        0x01, 0x01, 0x02, 0x02, 0x04, 0x06, 0x07, 0x06,
+        0x01, 0x02, 0x02, 0x03, 0x05, 0x09, 0x08, 0x06,
+        0x02, 0x02, 0x04, 0x06, 0x07, 0x0b, 0x0a, 0x08,
+        0x02, 0x04, 0x06, 0x06, 0x08, 0x0a, 0x0b, 0x09,
+        0x05, 0x06, 0x08, 0x09, 0x0a, 0x0c, 0x0c, 0x0a,
+        0x07, 0x09, 0x0a, 0x0a, 0x0b, 0x0a, 0x0a, 0x0a},
+       {                               /* Q-table C-components */
+        0x02, 0x02, 0x02, 0x05, 0x0a, 0x0a, 0x0a, 0x0a,
+        0x02, 0x02, 0x03, 0x07, 0x0a, 0x0a, 0x0a, 0x0a,
+        0x02, 0x03, 0x06, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+        0x05, 0x07, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+        0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+        0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+        0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+        0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a}
+};
+
+static unsigned char qtable_pocketdv[2][64] = {
+       {                       /* Q-table Y-components start registers 0x8800 */
+        0x06, 0x04, 0x04, 0x06, 0x0a, 0x10, 0x14, 0x18,
+        0x05, 0x05, 0x06, 0x08, 0x0a, 0x17, 0x18, 0x16,
+        0x06, 0x05, 0x06, 0x0a, 0x10, 0x17, 0x1c, 0x16,
+        0x06, 0x07, 0x09, 0x0c, 0x14, 0x23, 0x20, 0x19,
+        0x07, 0x09, 0x0f, 0x16, 0x1b, 0x2c, 0x29, 0x1f,
+        0x0a, 0x0e, 0x16, 0x1a, 0x20, 0x2a, 0x2d, 0x25,
+        0x14, 0x1a, 0x1f, 0x23, 0x29, 0x30, 0x30, 0x28,
+        0x1d, 0x25, 0x26, 0x27, 0x2d, 0x28, 0x29, 0x28,
+        },
+       {                       /* Q-table C-components start registers 0x8840 */
+        0x07, 0x07, 0x0a, 0x13, 0x28, 0x28, 0x28, 0x28,
+        0x07, 0x08, 0x0a, 0x1a, 0x28, 0x28, 0x28, 0x28,
+        0x0a, 0x0a, 0x16, 0x28, 0x28, 0x28, 0x28, 0x28,
+        0x13, 0x1a, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
+        0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
+        0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
+        0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
+        0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28}
+};
+
+static void spca5xxRegRead(struct usb_device *dev,
+                          __u16 index,
+                          __u8 *buffer, __u16 length)
+{
+       usb_control_msg(dev,
+                       usb_rcvctrlpipe(dev, 0),
+                       0,
+                       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       0,              /* value */
+                       index, buffer, length, 500);
+}
+
+static int reg_write(struct usb_device *dev,
+                    __u16 req, __u16 index, __u16 value)
+{
+       int ret;
+
+       ret = usb_control_msg(dev,
+                       usb_sndctrlpipe(dev, 0),
+                       req,
+                       USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       value, index, NULL, 0, 500);
+       PDEBUG(D_USBO, "reg write: [0x%02x] = 0x%02x, 0x%x",
+               index, value, ret);
+       if (ret < 0)
+               PDEBUG(D_ERR, "reg write: error %d", ret);
+       return ret;
+}
+
+/* returns: negative is error, pos or zero is data */
+static int reg_read(struct usb_device *dev,
+                       __u16 req,      /* bRequest */
+                       __u16 index,    /* wIndex */
+                       __u16 length)   /* wLength (1 or 2 only) */
+{
+       int ret;
+       __u8 buf[2];
+
+       buf[1] = 0;
+       ret = usb_control_msg(dev,
+                       usb_rcvctrlpipe(dev, 0),
+                       req,
+                       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       0,              /* value */
+                       index,
+                       buf, length,
+                       500);           /* timeout */
+       if (ret < 0) {
+               PDEBUG(D_ERR, "reg_read err %d", ret);
+               return -1;
+       }
+       return (buf[1] << 8) + buf[0];
+}
+
+/*
+ * Simple function to wait for a given 8-bit value to be returned from
+ * a reg_read call.
+ * Returns: negative is error or timeout, zero is success.
+ */
+static int reg_readwait(struct usb_device *dev,
+                       __u16 reg, __u16 index, __u16 value)
+{
+       int ret, cnt = 20;
+
+       while (--cnt > 0) {
+               ret = reg_read(dev, reg, index, 1);
+               if (ret == value)
+                       return 0;
+               msleep(50);
+       }
+       return -EIO;
+}
+
+static int write_vector(struct gspca_dev *gspca_dev,
+                               __u16 data[][3])
+{
+       struct usb_device *dev = gspca_dev->dev;
+       int ret, i = 0;
+
+       while (data[i][0] != 0 || data[i][1] != 0 || data[i][2] != 0) {
+               ret = reg_write(dev, data[i][0], data[i][2], data[i][1]);
+               if (ret < 0)
+                       return ret;
+               i++;
+       }
+       return 0;
+}
+
+static int spca50x_setup_qtable(struct gspca_dev *gspca_dev,
+                               unsigned int request,
+                               unsigned int ybase,
+                               unsigned int cbase,
+                               unsigned char qtable[2][64])
+{
+       struct usb_device *dev = gspca_dev->dev;
+       int i, err;
+
+       /* loop over y components */
+       for (i = 0; i < 64; i++) {
+               err = reg_write(dev, request, ybase + i, qtable[0][i]);
+               if (err < 0)
+                       return err;
+       }
+
+       /* loop over c components */
+       for (i = 0; i < 64; i++) {
+               err = reg_write(dev, request, cbase + i, qtable[1][i]);
+               if (err < 0)
+                       return err;
+       }
+       return 0;
+}
+
+static void spca500_ping310(struct gspca_dev *gspca_dev)
+{
+       __u8 Data[2];
+
+       spca5xxRegRead(gspca_dev->dev, 0x0d04, Data, 2);
+       PDEBUG(D_PACK, "ClickSmart310 ping 0x0d04 0x%02x 0x%02x",
+               Data[0], Data[1]);
+}
+
+static void spca500_clksmart310_init(struct gspca_dev *gspca_dev)
+{
+       __u8 Data[2];
+
+       spca5xxRegRead(gspca_dev->dev, 0x0d05, Data, 2);
+       PDEBUG(D_PACK, "ClickSmart310 init 0x0d05 0x%02x 0x%02x", Data[0],
+               Data[1]);
+       reg_write(gspca_dev->dev, 0x00, 0x8167, 0x5a);
+       spca500_ping310(gspca_dev);
+
+       reg_write(gspca_dev->dev, 0x00, 0x8168, 0x22);
+       reg_write(gspca_dev->dev, 0x00, 0x816a, 0xc0);
+       reg_write(gspca_dev->dev, 0x00, 0x816b, 0x0b);
+       reg_write(gspca_dev->dev, 0x00, 0x8169, 0x25);
+       reg_write(gspca_dev->dev, 0x00, 0x8157, 0x5b);
+       reg_write(gspca_dev->dev, 0x00, 0x8158, 0x5b);
+       reg_write(gspca_dev->dev, 0x00, 0x813f, 0x03);
+       reg_write(gspca_dev->dev, 0x00, 0x8151, 0x4a);
+       reg_write(gspca_dev->dev, 0x00, 0x8153, 0x78);
+       reg_write(gspca_dev->dev, 0x00, 0x0d01, 0x04);
+                                               /* 00 for adjust shutter */
+       reg_write(gspca_dev->dev, 0x00, 0x0d02, 0x01);
+       reg_write(gspca_dev->dev, 0x00, 0x8169, 0x25);
+       reg_write(gspca_dev->dev, 0x00, 0x0d01, 0x02);
+}
+
+static void spca500_setmode(struct gspca_dev *gspca_dev,
+                       __u8 xmult, __u8 ymult)
+{
+       int mode;
+
+       /* set x multiplier */
+       reg_write(gspca_dev->dev, 0, 0x8001, xmult);
+
+       /* set y multiplier */
+       reg_write(gspca_dev->dev, 0, 0x8002, ymult);
+
+       /* use compressed mode, VGA, with mode specific subsample */
+       mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].mode;
+       reg_write(gspca_dev->dev, 0, 0x8003, mode << 4);
+}
+
+static int spca500_full_reset(struct gspca_dev *gspca_dev)
+{
+       int err;
+
+       /* send the reset command */
+       err = reg_write(gspca_dev->dev, 0xe0, 0x0001, 0x0000);
+       if (err < 0)
+               return err;
+
+       /* wait for the reset to complete */
+       err = reg_readwait(gspca_dev->dev, 0x06, 0x0000, 0x0000);
+       if (err < 0)
+               return err;
+       err = reg_write(gspca_dev->dev, 0xe0, 0x0000, 0x0000);
+       if (err < 0)
+               return err;
+       err = reg_readwait(gspca_dev->dev, 0x06, 0, 0);
+       if (err < 0) {
+               PDEBUG(D_ERR, "reg_readwait() failed");
+               return err;
+       }
+       /* all ok */
+       return 0;
+}
+
+/* Synchro the Bridge with sensor */
+/* Maybe that will work on all spca500 chip */
+/* because i only own a clicksmart310 try for that chip */
+/* using spca50x_set_packet_size() cause an Ooops here */
+/* usb_set_interface from kernel 2.6.x clear all the urb stuff */
+/* up-port the same feature as in 2.4.x kernel */
+static int spca500_synch310(struct gspca_dev *gspca_dev)
+{
+       __u8 Data;
+
+       if (usb_set_interface(gspca_dev->dev, gspca_dev->iface, 0) < 0) {
+               PDEBUG(D_ERR, "Set packet size: set interface error");
+               goto error;
+       }
+       spca500_ping310(gspca_dev);
+
+       spca5xxRegRead(gspca_dev->dev, 0x0d00, &Data, 1);
+
+       /* need alt setting here */
+       PDEBUG(D_PACK, "ClickSmart310 sync alt: %d", gspca_dev->alt);
+
+       /* Windoze use pipe with altsetting 6 why 7 here */
+       if (usb_set_interface(gspca_dev->dev,
+                               gspca_dev->iface,
+                               gspca_dev->alt) < 0) {
+               PDEBUG(D_ERR, "Set packet size: set interface error");
+               goto error;
+       }
+       return 0;
+error:
+       return -EBUSY;
+}
+
+static void spca500_reinit(struct gspca_dev *gspca_dev)
+{
+       int err;
+       __u8 Data;
+
+       /* some unknow command from Aiptek pocket dv and family300 */
+
+       reg_write(gspca_dev->dev, 0x00, 0x0d01, 0x01);
+       reg_write(gspca_dev->dev, 0x00, 0x0d03, 0x00);
+       reg_write(gspca_dev->dev, 0x00, 0x0d02, 0x01);
+
+       /* enable drop packet */
+       reg_write(gspca_dev->dev, 0x00, 0x850a, 0x0001);
+
+       err = spca50x_setup_qtable(gspca_dev, 0x00, 0x8800, 0x8840,
+                                qtable_pocketdv);
+       if (err < 0)
+               PDEBUG(D_ERR|D_STREAM, "spca50x_setup_qtable failed on init");
+
+       /* set qtable index */
+       reg_write(gspca_dev->dev, 0x00, 0x8880, 2);
+       /* family cam Quicksmart stuff */
+       reg_write(gspca_dev->dev, 0x00, 0x800a, 0x00);
+       /* Set agc transfer: synced inbetween frames */
+       reg_write(gspca_dev->dev, 0x00, 0x820f, 0x01);
+       /* Init SDRAM - needed for SDRAM access */
+       reg_write(gspca_dev->dev, 0x00, 0x870a, 0x04);
+       /*Start init sequence or stream */
+
+       reg_write(gspca_dev->dev, 0, 0x8003, 0x00);
+       /* switch to video camera mode */
+       reg_write(gspca_dev->dev, 0x00, 0x8000, 0x0004);
+       msleep(2000);
+       if (reg_readwait(gspca_dev->dev, 0, 0x8000, 0x44) != 0)
+               spca5xxRegRead(gspca_dev->dev, 0x816b, &Data, 1);
+       reg_write(gspca_dev->dev, 0x00, 0x816b, Data);
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+                       const struct usb_device_id *id)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct cam *cam;
+       __u16 vendor;
+       __u16 product;
+
+       vendor = id->idVendor;
+       product = id->idProduct;
+       switch (vendor) {
+       case 0x040a:            /* Kodak cameras */
+/*             switch (product) { */
+/*             case 0x0300: */
+                       sd->subtype = KodakEZ200;
+/*                     break; */
+/*             } */
+               break;
+       case 0x041e:            /* Creative cameras */
+/*             switch (product) { */
+/*             case 0x400a: */
+                       sd->subtype = CreativePCCam300;
+/*                     break; */
+/*             } */
+               break;
+       case 0x046d:            /* Logitech Labtec */
+               switch (product) {
+               case 0x0890:
+                       sd->subtype = LogitechTraveler;
+                       break;
+               case 0x0900:
+                       sd->subtype = LogitechClickSmart310;
+                       break;
+               case 0x0901:
+                       sd->subtype = LogitechClickSmart510;
+                       break;
+               }
+               break;
+       case 0x04a5:            /* Benq */
+/*             switch (product) { */
+/*             case 0x300c: */
+                       sd->subtype = BenqDC1016;
+/*                     break; */
+/*             } */
+               break;
+       case 0x04fc:            /* SunPlus */
+/*             switch (product) { */
+/*             case 0x7333: */
+                       sd->subtype = PalmPixDC85;
+/*                     break; */
+/*             } */
+               break;
+       case 0x055f:            /* Mustek cameras */
+               switch (product) {
+               case 0xc200:
+                       sd->subtype = MustekGsmart300;
+                       break;
+               case 0xc220:
+                       sd->subtype = Gsmartmini;
+                       break;
+               }
+               break;
+       case 0x06bd:            /* Agfa Cl20 */
+/*             switch (product) { */
+/*             case 0x0404: */
+                       sd->subtype = AgfaCl20;
+/*                     break; */
+/*             } */
+               break;
+       case 0x06be:            /* Optimedia */
+/*             switch (product) { */
+/*             case 0x0800: */
+                       sd->subtype = Optimedia;
+/*                     break; */
+/*             } */
+               break;
+       case 0x084d:            /* D-Link / Minton */
+/*             switch (product) { */
+/*             case 0x0003:     * DSC-350 / S-Cam F5 */
+                       sd->subtype = DLinkDSC350;
+/*                     break; */
+/*             } */
+               break;
+       case 0x08ca:            /* Aiptek */
+/*             switch (product) { */
+/*             case 0x0103: */
+                       sd->subtype = AiptekPocketDV;
+/*                     break; */
+/*             } */
+               break;
+       case 0x2899:            /* ToptroIndustrial */
+/*             switch (product) { */
+/*             case 0x012c: */
+                       sd->subtype = ToptroIndus;
+/*                     break; */
+/*             } */
+               break;
+       case 0x8086:            /* Intel */
+/*             switch (product) { */
+/*             case 0x0630:     * Pocket PC Camera */
+                       sd->subtype = IntelPocketPCCamera;
+/*                     break; */
+/*             } */
+               break;
+       }
+       cam = &gspca_dev->cam;
+       cam->dev_name = (char *) id->driver_info;
+       cam->epaddr = 0x01;
+       if (sd->subtype != LogitechClickSmart310) {
+               cam->cam_mode = vga_mode;
+               cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+       } else {
+               cam->cam_mode = sif_mode;
+               cam->nmodes = sizeof sif_mode / sizeof sif_mode[0];
+       }
+       sd->qindex = 5;
+       sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
+       sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
+       sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value;
+       return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       /* initialisation of spca500 based cameras is deferred */
+       PDEBUG(D_STREAM, "SPCA500 init");
+       if (sd->subtype == LogitechClickSmart310)
+               spca500_clksmart310_init(gspca_dev);
+/*     else
+               spca500_initialise(gspca_dev); */
+       PDEBUG(D_STREAM, "SPCA500 init done");
+       return 0;
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int err;
+       __u8 Data;
+       __u8 xmult, ymult;
+
+       if (sd->subtype == LogitechClickSmart310) {
+               xmult = 0x16;
+               ymult = 0x12;
+       } else {
+               xmult = 0x28;
+               ymult = 0x1e;
+       }
+
+       /* is there a sensor here ? */
+       spca5xxRegRead(gspca_dev->dev, 0x8a04, &Data, 1);
+       PDEBUG(D_STREAM, "Spca500 Sensor Address 0x%02X", Data);
+       PDEBUG(D_STREAM, "Spca500 curr_mode: %d Xmult: 0x%02X, Ymult: 0x%02X",
+               gspca_dev->curr_mode, xmult, ymult);
+
+       /* setup qtable */
+       switch (sd->subtype) {
+       case LogitechClickSmart310:
+                spca500_setmode(gspca_dev, xmult, ymult);
+
+               /* enable drop packet */
+               reg_write(gspca_dev->dev, 0x00, 0x850a, 0x0001);
+               reg_write(gspca_dev->dev, 0x00, 0x8880, 3);
+               err = spca50x_setup_qtable(gspca_dev,
+                                          0x00, 0x8800, 0x8840,
+                                          qtable_creative_pccam);
+               if (err < 0)
+                       PDEBUG(D_ERR, "spca50x_setup_qtable failed");
+               /* Init SDRAM - needed for SDRAM access */
+               reg_write(gspca_dev->dev, 0x00, 0x870a, 0x04);
+
+               /* switch to video camera mode */
+               reg_write(gspca_dev->dev, 0x00, 0x8000, 0x0004);
+               msleep(500);
+               if (reg_readwait(gspca_dev->dev, 0, 0x8000, 0x44) != 0)
+                       PDEBUG(D_ERR, "reg_readwait() failed");
+
+               spca5xxRegRead(gspca_dev->dev, 0x816b, &Data, 1);
+               reg_write(gspca_dev->dev, 0x00, 0x816b, Data);
+
+               spca500_synch310(gspca_dev);
+
+               write_vector(gspca_dev, spca500_visual_defaults);
+               spca500_setmode(gspca_dev, xmult, ymult);
+               /* enable drop packet */
+               reg_write(gspca_dev->dev, 0x00, 0x850a, 0x0001);
+                       PDEBUG(D_ERR, "failed to enable drop packet");
+               reg_write(gspca_dev->dev, 0x00, 0x8880, 3);
+               err = spca50x_setup_qtable(gspca_dev,
+                                          0x00, 0x8800, 0x8840,
+                                          qtable_creative_pccam);
+               if (err < 0)
+                       PDEBUG(D_ERR, "spca50x_setup_qtable failed");
+
+               /* Init SDRAM - needed for SDRAM access */
+               reg_write(gspca_dev->dev, 0x00, 0x870a, 0x04);
+
+               /* switch to video camera mode */
+               reg_write(gspca_dev->dev, 0x00, 0x8000, 0x0004);
+
+               if (reg_readwait(gspca_dev->dev, 0, 0x8000, 0x44) != 0)
+                       PDEBUG(D_ERR, "reg_readwait() failed");
+
+               spca5xxRegRead(gspca_dev->dev, 0x816b, &Data, 1);
+               reg_write(gspca_dev->dev, 0x00, 0x816b, Data);
+               break;
+       case CreativePCCam300:          /* Creative PC-CAM 300 640x480 CCD */
+       case IntelPocketPCCamera:       /* FIXME: Temporary fix for
+                                        *      Intel Pocket PC Camera
+                                        *      - NWG (Sat 29th March 2003) */
+
+               /* do a full reset */
+               if ((err = spca500_full_reset(gspca_dev)) < 0)
+                       PDEBUG(D_ERR, "spca500_full_reset failed");
+
+               /* enable drop packet */
+               err = reg_write(gspca_dev->dev, 0x00, 0x850a, 0x0001);
+               if (err < 0)
+                       PDEBUG(D_ERR, "failed to enable drop packet");
+               reg_write(gspca_dev->dev, 0x00, 0x8880, 3);
+               err = spca50x_setup_qtable(gspca_dev,
+                                          0x00, 0x8800, 0x8840,
+                                          qtable_creative_pccam);
+               if (err < 0)
+                       PDEBUG(D_ERR, "spca50x_setup_qtable failed");
+
+               spca500_setmode(gspca_dev, xmult, ymult);
+               reg_write(gspca_dev->dev, 0x20, 0x0001, 0x0004);
+
+               /* switch to video camera mode */
+               reg_write(gspca_dev->dev, 0x00, 0x8000, 0x0004);
+
+               if (reg_readwait(gspca_dev->dev, 0, 0x8000, 0x44) != 0)
+                       PDEBUG(D_ERR, "reg_readwait() failed");
+
+               spca5xxRegRead(gspca_dev->dev, 0x816b, &Data, 1);
+               reg_write(gspca_dev->dev, 0x00, 0x816b, Data);
+
+               /* write_vector(gspca_dev, spca500_visual_defaults); */
+               break;
+       case KodakEZ200:                /* Kodak EZ200 */
+
+               /* do a full reset */
+               err = spca500_full_reset(gspca_dev);
+               if (err < 0)
+                       PDEBUG(D_ERR, "spca500_full_reset failed");
+               /* enable drop packet */
+               reg_write(gspca_dev->dev, 0x00, 0x850a, 0x0001);
+               reg_write(gspca_dev->dev, 0x00, 0x8880, 0);
+               err = spca50x_setup_qtable(gspca_dev,
+                                          0x00, 0x8800, 0x8840,
+                                          qtable_kodak_ez200);
+               if (err < 0)
+                       PDEBUG(D_ERR, "spca50x_setup_qtable failed");
+               spca500_setmode(gspca_dev, xmult, ymult);
+
+               reg_write(gspca_dev->dev, 0x20, 0x0001, 0x0004);
+
+               /* switch to video camera mode */
+               reg_write(gspca_dev->dev, 0x00, 0x8000, 0x0004);
+
+               if (reg_readwait(gspca_dev->dev, 0, 0x8000, 0x44) != 0)
+                       PDEBUG(D_ERR, "reg_readwait() failed");
+
+               spca5xxRegRead(gspca_dev->dev, 0x816b, &Data, 1);
+               reg_write(gspca_dev->dev, 0x00, 0x816b, Data);
+
+               /* write_vector(gspca_dev, spca500_visual_defaults); */
+               break;
+
+       case BenqDC1016:
+       case DLinkDSC350:               /* FamilyCam 300 */
+       case AiptekPocketDV:            /* Aiptek PocketDV */
+       case Gsmartmini:                /*Mustek Gsmart Mini */
+       case MustekGsmart300:           /* Mustek Gsmart 300 */
+       case PalmPixDC85:
+       case Optimedia:
+       case ToptroIndus:
+       case AgfaCl20:
+               spca500_reinit(gspca_dev);
+               reg_write(gspca_dev->dev, 0x00, 0x0d01, 0x01);
+               /* enable drop packet */
+               reg_write(gspca_dev->dev, 0x00, 0x850a, 0x0001);
+
+               err = spca50x_setup_qtable(gspca_dev,
+                                  0x00, 0x8800, 0x8840, qtable_pocketdv);
+               if (err < 0)
+                       PDEBUG(D_ERR, "spca50x_setup_qtable failed");
+               reg_write(gspca_dev->dev, 0x00, 0x8880, 2);
+
+               /* familycam Quicksmart pocketDV stuff */
+               reg_write(gspca_dev->dev, 0x00, 0x800a, 0x00);
+               /* Set agc transfer: synced inbetween frames */
+               reg_write(gspca_dev->dev, 0x00, 0x820f, 0x01);
+               /* Init SDRAM - needed for SDRAM access */
+               reg_write(gspca_dev->dev, 0x00, 0x870a, 0x04);
+
+               spca500_setmode(gspca_dev,xmult,ymult);
+               /* switch to video camera mode */
+               reg_write(gspca_dev->dev, 0x00, 0x8000, 0x0004);
+
+               reg_readwait(gspca_dev->dev, 0, 0x8000, 0x44);
+
+               spca5xxRegRead(gspca_dev->dev, 0x816b, &Data, 1);
+               reg_write(gspca_dev->dev, 0x00, 0x816b, Data);
+               break;
+       case LogitechTraveler:
+       case LogitechClickSmart510:
+               reg_write(gspca_dev->dev, 0x02, 0x00, 0x00);
+               /* enable drop packet */
+               reg_write(gspca_dev->dev, 0x00, 0x850a, 0x0001);
+
+               err = spca50x_setup_qtable(gspca_dev,
+                                       0x00, 0x8800,
+                                       0x8840, qtable_creative_pccam);
+               if (err < 0)
+                       PDEBUG(D_ERR, "spca50x_setup_qtable failed");
+               reg_write(gspca_dev->dev, 0x00, 0x8880, 3);
+               reg_write(gspca_dev->dev, 0x00, 0x800a, 0x00);
+               /* Init SDRAM - needed for SDRAM access */
+               reg_write(gspca_dev->dev, 0x00, 0x870a, 0x04);
+
+               spca500_setmode(gspca_dev, xmult, ymult);
+
+               /* switch to video camera mode */
+               reg_write(gspca_dev->dev, 0x00, 0x8000, 0x0004);
+               reg_readwait(gspca_dev->dev, 0, 0x8000, 0x44);
+
+               spca5xxRegRead(gspca_dev->dev, 0x816b, &Data, 1);
+               reg_write(gspca_dev->dev, 0x00, 0x816b, Data);
+               write_vector(gspca_dev, Clicksmart510_defaults);
+               break;
+       }
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+       __u8 data = 0;
+
+       reg_write(gspca_dev->dev, 0, 0x8003, 0x00);
+
+       /* switch to video camera mode */
+       reg_write(gspca_dev->dev, 0x00, 0x8000, 0x0004);
+       spca5xxRegRead(gspca_dev->dev, 0x8000, &data, 1);
+       PDEBUG(D_STREAM, "stop SPCA500 done reg8000: 0x%2x", data);
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+                       struct gspca_frame *frame,      /* target */
+                       unsigned char *data,            /* isoc packet */
+                       int len)                        /* iso packet length */
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int i;
+       unsigned char *s, *d;
+       static unsigned char ffd9[] = {0xff, 0xd9};
+
+/* frames are jpeg 4.1.1 without 0xff escape */
+       if (data[0] == 0xff) {
+               if (data[1] != 0x01) {  /* drop packet */
+/*                     gspca_dev->last_packet_type = DISCARD_PACKET; */
+                       return;
+               }
+               frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+                                       ffd9, 2);
+
+               /* put the JPEG header in the new frame */
+               jpeg_put_header(gspca_dev, frame,
+                               ((struct sd *) gspca_dev)->qindex,
+                               0x22);
+
+               data += SPCA500_OFFSET_DATA;
+               len -= SPCA500_OFFSET_DATA;
+       } else {
+               data += 1;
+               len -= 1;
+       }
+
+       /* add 0x00 after 0xff */
+       for (i = len; --i >= 0; )
+               if (data[i] == 0xff)
+                       break;
+       if (i < 0) {                    /* no 0xff */
+               gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+               return;
+       }
+       s = data;
+       d = sd->packet;
+       for (i = 0; i < len; i++) {
+               *d++ = *s++;
+               if (s[-1] == 0xff)
+                       *d++ = 0x00;
+       }
+       gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+                       sd->packet, d - sd->packet);
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       reg_write(gspca_dev->dev, 0x00, 0x8167,
+                       (__u8) (sd->brightness - 128));
+}
+
+static void getbrightness(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->brightness = reg_read(gspca_dev->dev, 0x00, 0x8167, 1) + 128;
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       reg_write(gspca_dev->dev, 0x00, 0x8168, sd->contrast >> 2);
+}
+
+static void getcontrast(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->contrast = reg_read(gspca_dev->dev, 0x0, 0x8168, 1) << 2;
+}
+
+static void setcolors(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       reg_write(gspca_dev->dev, 0x00, 0x8169, sd->colors >> 2);
+}
+
+static void getcolors(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->colors = reg_read(gspca_dev->dev, 0x0, 0x8169, 1) << 2;
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->brightness = val;
+       if (gspca_dev->streaming)
+               setbrightness(gspca_dev);
+       return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       getbrightness(gspca_dev);
+       *val = sd->brightness;
+       return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->contrast = val;
+       if (gspca_dev->streaming)
+               setcontrast(gspca_dev);
+       return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       getcontrast(gspca_dev);
+       *val = sd->contrast;
+       return 0;
+}
+
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->colors = val;
+       if (gspca_dev->streaming)
+               setcolors(gspca_dev);
+       return 0;
+}
+
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       getcolors(gspca_dev);
+       *val = sd->colors;
+       return 0;
+}
+
+/* sub-driver description */
+static struct sd_desc sd_desc = {
+       .name = MODULE_NAME,
+       .ctrls = sd_ctrls,
+       .nctrls = sizeof sd_ctrls / sizeof sd_ctrls[0],
+       .config = sd_config,
+       .open = sd_open,
+       .start = sd_start,
+       .stopN = sd_stopN,
+       .stop0 = sd_stop0,
+       .close = sd_close,
+       .pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static __devinitdata struct usb_device_id device_table[] = {
+       {USB_DEVICE(0x040a, 0x0300), DVNM("Kodak EZ200")},
+       {USB_DEVICE(0x041e, 0x400a), DVNM("Creative PC-CAM 300")},
+       {USB_DEVICE(0x046d, 0x0890), DVNM("Logitech QuickCam traveler")},
+       {USB_DEVICE(0x046d, 0x0900), DVNM("Logitech Inc. ClickSmart 310")},
+       {USB_DEVICE(0x046d, 0x0901), DVNM("Logitech Inc. ClickSmart 510")},
+       {USB_DEVICE(0x04a5, 0x300c), DVNM("Benq DC1016")},
+       {USB_DEVICE(0x04fc, 0x7333), DVNM("PalmPixDC85")},
+       {USB_DEVICE(0x055f, 0xc200), DVNM("Mustek Gsmart 300")},
+       {USB_DEVICE(0x055f, 0xc220), DVNM("Gsmart Mini")},
+       {USB_DEVICE(0x06bd, 0x0404), DVNM("Agfa CL20")},
+       {USB_DEVICE(0x06be, 0x0800), DVNM("Optimedia")},
+       {USB_DEVICE(0x084d, 0x0003), DVNM("D-Link DSC-350")},
+       {USB_DEVICE(0x08ca, 0x0103), DVNM("Aiptek PocketDV")},
+       {USB_DEVICE(0x2899, 0x012c), DVNM("Toptro Industrial")},
+       {USB_DEVICE(0x8086, 0x0630), DVNM("Intel Pocket PC Camera")},
+       {}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+                       const struct usb_device_id *id)
+{
+       return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+                               THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+       .name = MODULE_NAME,
+       .id_table = device_table,
+       .probe = sd_probe,
+       .disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+       if (usb_register(&sd_driver) < 0)
+               return -1;
+       PDEBUG(D_PROBE, "v%s registered", version);
+       return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+       usb_deregister(&sd_driver);
+       PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/spca501.c b/drivers/media/video/gspca/spca501.c
new file mode 100644 (file)
index 0000000..c6468cf
--- /dev/null
@@ -0,0 +1,2219 @@
+/*
+ * SPCA501 chip based cameras initialization data
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#define MODULE_NAME "spca501"
+
+#include "gspca.h"
+
+#define DRIVER_VERSION_NUMBER  KERNEL_VERSION(2, 1, 0)
+static const char version[] = "2.1.0";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("GSPCA/SPCA501 USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+       struct gspca_dev gspca_dev;     /* !! must be the first item */
+
+       unsigned short contrast;
+       __u8 brightness;
+       __u8 colors;
+
+       char subtype;
+#define Arowana300KCMOSCamera 0
+#define IntelCreateAndShare 1
+#define KodakDVC325 2
+#define MystFromOriUnknownCamera 3
+#define SmileIntlCamera 4
+#define ThreeComHomeConnectLite 5
+#define ViewQuestM318B 6
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+#define MY_BRIGHTNESS 0
+       {
+           {
+               .id      = V4L2_CID_BRIGHTNESS,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Brightness",
+               .minimum = 0,
+               .maximum = 127,
+               .step    = 1,
+               .default_value = 63,
+           },
+           .set = sd_setbrightness,
+           .get = sd_getbrightness,
+       },
+#define MY_CONTRAST 1
+       {
+           {
+               .id      = V4L2_CID_CONTRAST,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Contrast",
+               .minimum = 0,
+               .maximum = 0xffff,
+               .step    = 1,
+               .default_value = 0xaa00,
+           },
+           .set = sd_setcontrast,
+           .get = sd_getcontrast,
+       },
+#define MY_COLOR 2
+       {
+           {
+               .id      = V4L2_CID_SATURATION,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Color",
+               .minimum = 0,
+               .maximum = 63,
+               .step    = 1,
+               .default_value = 31,
+           },
+           .set = sd_setcolors,
+           .get = sd_getcolors,
+       },
+};
+
+static struct cam_mode vga_mode[] = {
+       {V4L2_PIX_FMT_SPCA501, 160, 120, 2},
+       {V4L2_PIX_FMT_SPCA501, 320, 240, 1},
+       {V4L2_PIX_FMT_SPCA501, 640, 480, 0},
+};
+
+#define SPCA50X_REG_USB 0x2    /* spca505 501 */
+/*
+ * Data to initialize a SPCA501. From a capture file provided by Bill Roehl
+ * With SPCA501 chip description
+ */
+#define CCDSP_SET              /* set CCDSP parameters */
+#define TG_SET                 /* set time generator set */
+#undef DSPWIN_SET              /* set DSP windows parameters */
+#undef ALTER_GAMA      /* Set alternate set to YUV transform coeffs. */
+#define SPCA501_SNAPBIT 0x80
+#define SPCA501_SNAPCTRL 0x10
+/* Frame packet header offsets for the spca501 */
+#define SPCA501_OFFSET_GPIO   1
+#define SPCA501_OFFSET_TYPE   2
+#define SPCA501_OFFSET_TURN3A 3
+#define SPCA501_OFFSET_FRAMSEQ 4
+#define SPCA501_OFFSET_COMPRESS 5
+#define SPCA501_OFFSET_QUANT 6
+#define SPCA501_OFFSET_QUANT2 7
+#define SPCA501_OFFSET_DATA 8
+
+#define SPCA501_PROP_COMP_ENABLE(d) ((d) & 1)
+#define SPCA501_PROP_SNAP(d) ((d) & 0x40)
+#define SPCA501_PROP_SNAP_CTRL(d) ((d) & 0x10)
+#define SPCA501_PROP_COMP_THRESH(d) (((d) & 0x0e) >> 1)
+#define SPCA501_PROP_COMP_QUANT(d) (((d) & 0x70) >> 4)
+
+/* SPCA501 CCDSP control */
+#define SPCA501_REG_CCDSP 0x01
+/* SPCA501 control/status registers */
+#define SPCA501_REG_CTLRL 0x02
+
+/* registers for color correction and YUV transformation */
+#define SPCA501_A11 0x08
+#define SPCA501_A12 0x09
+#define SPCA501_A13 0x0A
+#define SPCA501_A21 0x0B
+#define SPCA501_A22 0x0C
+#define SPCA501_A23 0x0D
+#define SPCA501_A31 0x0E
+#define SPCA501_A32 0x0F
+#define SPCA501_A33 0x10
+
+/* Data for video camera initialization before capturing */
+static __u16 spca501_open_data[][3] = {
+       /* bmRequest,value,index */
+
+       {0x2, 0x50, 0x00},      /* C/S enable soft reset */
+       {0x2, 0x40, 0x00},      /* C/S disable soft reset */
+       {0x2, 0x02, 0x05},      /* C/S general purpose I/O data */
+       {0x2, 0x03, 0x05},      /* C/S general purpose I/O data */
+
+#ifdef CCDSP_SET
+       {0x1, 0x38, 0x01},      /* CCDSP options */
+       {0x1, 0x05, 0x02}, /* CCDSP Optical black level for user settings */
+       {0x1, 0xC0, 0x03},      /* CCDSP Optical black settings */
+
+       {0x1, 0x67, 0x07},
+       {0x1, 0x63, 0x3f},      /* CCDSP CCD gamma enable */
+       {0x1, 0x03, 0x56},      /* Add gamma correction */
+
+       {0x1, 0xFF, 0x15},      /* CCDSP High luminance for white balance */
+       {0x1, 0x01, 0x16},      /* CCDSP Low luminance for white balance */
+
+/* Color correction and RGB-to-YUV transformation coefficients changing */
+#ifdef ALTER_GAMA
+       {0x0, 0x00, 0x08},      /* A11 */
+       {0x0, 0x00, 0x09},      /* A12 */
+       {0x0, 0x90, 0x0A},      /* A13 */
+       {0x0, 0x12, 0x0B},      /* A21 */
+       {0x0, 0x00, 0x0C},      /* A22 */
+       {0x0, 0x00, 0x0D},      /* A23 */
+       {0x0, 0x00, 0x0E},      /* A31 */
+       {0x0, 0x02, 0x0F},      /* A32 */
+       {0x0, 0x00, 0x10},      /* A33 */
+#else
+       {0x1, 0x2a, 0x08},      /* A11 0x31 */
+       {0x1, 0xf8, 0x09},      /* A12 f8 */
+       {0x1, 0xf8, 0x0A},      /* A13 f8 */
+       {0x1, 0xf8, 0x0B},      /* A21 f8 */
+       {0x1, 0x14, 0x0C},      /* A22 0x14 */
+       {0x1, 0xf8, 0x0D},      /* A23 f8 */
+       {0x1, 0xf8, 0x0E},      /* A31 f8 */
+       {0x1, 0xf8, 0x0F},      /* A32 f8 */
+       {0x1, 0x20, 0x10},      /* A33 0x20 */
+#endif
+       {0x1, 0x00, 0x11},      /* R offset */
+       {0x1, 0x00, 0x12},      /* G offset */
+       {0x1, 0x00, 0x13},      /* B offset */
+       {0x1, 0x00, 0x14},      /* GB offset */
+
+#endif
+
+#ifdef TG_SET
+       /* Time generator manipulations */
+       {0x0, 0xfc, 0x0},       /* Set up high bits of shutter speed */
+       {0x0, 0x01, 0x1},       /* Set up low bits of shutter speed */
+
+       {0x0, 0xe4, 0x04},      /* DCLK*2 clock phase adjustment */
+       {0x0, 0x08, 0x05},      /* ADCK phase adjustment, inv. ext. VB */
+       {0x0, 0x03, 0x06},      /* FR phase adjustment */
+       {0x0, 0x01, 0x07},      /* FCDS phase adjustment */
+       {0x0, 0x39, 0x08},      /* FS phase adjustment */
+       {0x0, 0x88, 0x0a},      /* FH1 phase and delay adjustment */
+       {0x0, 0x03, 0x0f},      /* pixel identification */
+       {0x0, 0x00, 0x11},      /* clock source selection (default) */
+
+       /*VERY strange manipulations with
+        * select DMCLP or OBPX to be ADCLP output (0x0C)
+        * OPB always toggle or not (0x0D) but they allow
+        * us to set up brightness
+        */
+       {0x0, 0x01, 0x0c},
+       {0x0, 0xe0, 0x0d},
+       /* Done */
+#endif
+
+#ifdef DSPWIN_SET
+       {0x1, 0xa0, 0x01},      /* Setting image processing parameters */
+       {0x1, 0x1c, 0x17},      /* Changing Windows positions X1 */
+       {0x1, 0xe2, 0x19},      /* X2 */
+       {0x1, 0x1c, 0x1b},      /* X3 */
+       {0x1, 0xe2, 0x1d},      /* X4 */
+       {0x1, 0x5f, 0x1f},      /* X5 */
+       {0x1, 0x32, 0x20},      /* Y5 */
+       {0x1, 0x01, 0x10},      /* Changing A33 */
+#endif
+
+       {0x2, 0x204a, 0x07},/* Setting video compression & resolution 160x120 */
+       {0x2, 0x94, 0x06},      /* Setting video no compression */
+       {}
+};
+
+/*
+   The SPCAxxx docs from Sunplus document these values
+   in tables, one table per register number.  In the data
+   below, dmRequest is the register number, index is the Addr,
+   and value is a combination of Bit values.
+   Bit  Value (hex)
+   0    01
+   1    02
+   2    04
+   3    08
+   4    10
+   5    20
+   6    40
+   7    80
+ */
+
+/* Data for chip initialization (set default values) */
+static __u16 spca501_init_data[][3] = {
+       /* Set all the values to powerup defaults */
+       /* bmRequest,value,index */
+       {0x0, 0xAA, 0x00},
+       {0x0, 0x02, 0x01},
+       {0x0, 0x01, 0x02},
+       {0x0, 0x02, 0x03},
+       {0x0, 0xCE, 0x04},
+       {0x0, 0x00, 0x05},
+       {0x0, 0x00, 0x06},
+       {0x0, 0x00, 0x07},
+       {0x0, 0x00, 0x08},
+       {0x0, 0x00, 0x09},
+       {0x0, 0x90, 0x0A},
+       {0x0, 0x12, 0x0B},
+       {0x0, 0x00, 0x0C},
+       {0x0, 0x00, 0x0D},
+       {0x0, 0x00, 0x0E},
+       {0x0, 0x02, 0x0F},
+       {0x0, 0x00, 0x10},
+       {0x0, 0x00, 0x11},
+       {0x0, 0x00, 0x12},
+       {0x0, 0x00, 0x13},
+       {0x0, 0x00, 0x14},
+       {0x0, 0x00, 0x15},
+       {0x0, 0x00, 0x16},
+       {0x0, 0x00, 0x17},
+       {0x0, 0x00, 0x18},
+       {0x0, 0x00, 0x19},
+       {0x0, 0x00, 0x1A},
+       {0x0, 0x00, 0x1B},
+       {0x0, 0x00, 0x1C},
+       {0x0, 0x00, 0x1D},
+       {0x0, 0x00, 0x1E},
+       {0x0, 0x00, 0x1F},
+       {0x0, 0x00, 0x20},
+       {0x0, 0x00, 0x21},
+       {0x0, 0x00, 0x22},
+       {0x0, 0x00, 0x23},
+       {0x0, 0x00, 0x24},
+       {0x0, 0x00, 0x25},
+       {0x0, 0x00, 0x26},
+       {0x0, 0x00, 0x27},
+       {0x0, 0x00, 0x28},
+       {0x0, 0x00, 0x29},
+       {0x0, 0x00, 0x2A},
+       {0x0, 0x00, 0x2B},
+       {0x0, 0x00, 0x2C},
+       {0x0, 0x00, 0x2D},
+       {0x0, 0x00, 0x2E},
+       {0x0, 0x00, 0x2F},
+       {0x0, 0x00, 0x30},
+       {0x0, 0x00, 0x31},
+       {0x0, 0x00, 0x32},
+       {0x0, 0x00, 0x33},
+       {0x0, 0x00, 0x34},
+       {0x0, 0x00, 0x35},
+       {0x0, 0x00, 0x36},
+       {0x0, 0x00, 0x37},
+       {0x0, 0x00, 0x38},
+       {0x0, 0x00, 0x39},
+       {0x0, 0x00, 0x3A},
+       {0x0, 0x00, 0x3B},
+       {0x0, 0x00, 0x3C},
+       {0x0, 0x00, 0x3D},
+       {0x0, 0x00, 0x3E},
+       {0x0, 0x00, 0x3F},
+       {0x0, 0x00, 0x40},
+       {0x0, 0x00, 0x41},
+       {0x0, 0x00, 0x42},
+       {0x0, 0x00, 0x43},
+       {0x0, 0x00, 0x44},
+       {0x0, 0x00, 0x45},
+       {0x0, 0x00, 0x46},
+       {0x0, 0x00, 0x47},
+       {0x0, 0x00, 0x48},
+       {0x0, 0x00, 0x49},
+       {0x0, 0x00, 0x4A},
+       {0x0, 0x00, 0x4B},
+       {0x0, 0x00, 0x4C},
+       {0x0, 0x00, 0x4D},
+       {0x0, 0x00, 0x4E},
+       {0x0, 0x00, 0x4F},
+       {0x0, 0x00, 0x50},
+       {0x0, 0x00, 0x51},
+       {0x0, 0x00, 0x52},
+       {0x0, 0x00, 0x53},
+       {0x0, 0x00, 0x54},
+       {0x0, 0x00, 0x55},
+       {0x0, 0x00, 0x56},
+       {0x0, 0x00, 0x57},
+       {0x0, 0x00, 0x58},
+       {0x0, 0x00, 0x59},
+       {0x0, 0x00, 0x5A},
+       {0x0, 0x00, 0x5B},
+       {0x0, 0x00, 0x5C},
+       {0x0, 0x00, 0x5D},
+       {0x0, 0x00, 0x5E},
+       {0x0, 0x00, 0x5F},
+       {0x0, 0x00, 0x60},
+       {0x0, 0x00, 0x61},
+       {0x0, 0x00, 0x62},
+       {0x0, 0x00, 0x63},
+       {0x0, 0x00, 0x64},
+       {0x0, 0x00, 0x65},
+       {0x0, 0x00, 0x66},
+       {0x0, 0x00, 0x67},
+       {0x0, 0x00, 0x68},
+       {0x0, 0x00, 0x69},
+       {0x0, 0x00, 0x6A},
+       {0x0, 0x00, 0x6B},
+       {0x0, 0x00, 0x6C},
+       {0x0, 0x00, 0x6D},
+       {0x0, 0x00, 0x6E},
+       {0x0, 0x00, 0x6F},
+       {0x0, 0x00, 0x70},
+       {0x0, 0x00, 0x71},
+       {0x0, 0x00, 0x72},
+       {0x0, 0x00, 0x73},
+       {0x0, 0x00, 0x74},
+       {0x0, 0x00, 0x75},
+       {0x0, 0x00, 0x76},
+       {0x0, 0x00, 0x77},
+       {0x0, 0x00, 0x78},
+       {0x0, 0x00, 0x79},
+       {0x0, 0x00, 0x7A},
+       {0x0, 0x00, 0x7B},
+       {0x0, 0x00, 0x7C},
+       {0x0, 0x00, 0x7D},
+       {0x0, 0x00, 0x7E},
+       {0x0, 0x00, 0x7F},
+       {0x0, 0x00, 0x80},
+       {0x0, 0x00, 0x81},
+       {0x0, 0x00, 0x82},
+       {0x0, 0x00, 0x83},
+       {0x0, 0x00, 0x84},
+       {0x0, 0x00, 0x85},
+       {0x0, 0x00, 0x86},
+       {0x0, 0x00, 0x87},
+       {0x0, 0x00, 0x88},
+       {0x0, 0x00, 0x89},
+       {0x0, 0x00, 0x8A},
+       {0x0, 0x00, 0x8B},
+       {0x0, 0x00, 0x8C},
+       {0x0, 0x00, 0x8D},
+       {0x0, 0x00, 0x8E},
+       {0x0, 0x00, 0x8F},
+       {0x0, 0x00, 0x90},
+       {0x0, 0x00, 0x91},
+       {0x0, 0x00, 0x92},
+       {0x0, 0x00, 0x93},
+       {0x0, 0x00, 0x94},
+       {0x0, 0x00, 0x95},
+       {0x0, 0x00, 0x96},
+       {0x0, 0x00, 0x97},
+       {0x0, 0x00, 0x98},
+       {0x0, 0x00, 0x99},
+       {0x0, 0x00, 0x9A},
+       {0x0, 0x00, 0x9B},
+       {0x0, 0x00, 0x9C},
+       {0x0, 0x00, 0x9D},
+       {0x0, 0x00, 0x9E},
+       {0x0, 0x00, 0x9F},
+       {0x0, 0x00, 0xA0},
+       {0x0, 0x00, 0xA1},
+       {0x0, 0x00, 0xA2},
+       {0x0, 0x00, 0xA3},
+       {0x0, 0x00, 0xA4},
+       {0x0, 0x00, 0xA5},
+       {0x0, 0x00, 0xA6},
+       {0x0, 0x00, 0xA7},
+       {0x0, 0x00, 0xA8},
+       {0x0, 0x00, 0xA9},
+       {0x0, 0x00, 0xAA},
+       {0x0, 0x00, 0xAB},
+       {0x0, 0x00, 0xAC},
+       {0x0, 0x00, 0xAD},
+       {0x0, 0x00, 0xAE},
+       {0x0, 0x00, 0xAF},
+       {0x0, 0x00, 0xB0},
+       {0x0, 0x00, 0xB1},
+       {0x0, 0x00, 0xB2},
+       {0x0, 0x00, 0xB3},
+       {0x0, 0x00, 0xB4},
+       {0x0, 0x00, 0xB5},
+       {0x0, 0x00, 0xB6},
+       {0x0, 0x00, 0xB7},
+       {0x0, 0x00, 0xB8},
+       {0x0, 0x00, 0xB9},
+       {0x0, 0x00, 0xBA},
+       {0x0, 0x00, 0xBB},
+       {0x0, 0x00, 0xBC},
+       {0x0, 0x00, 0xBD},
+       {0x0, 0x00, 0xBE},
+       {0x0, 0x00, 0xBF},
+       {0x0, 0x00, 0xC0},
+       {0x0, 0x00, 0xC1},
+       {0x0, 0x00, 0xC2},
+       {0x0, 0x00, 0xC3},
+       {0x0, 0x00, 0xC4},
+       {0x0, 0x00, 0xC5},
+       {0x0, 0x00, 0xC6},
+       {0x0, 0x00, 0xC7},
+       {0x0, 0x00, 0xC8},
+       {0x0, 0x00, 0xC9},
+       {0x0, 0x00, 0xCA},
+       {0x0, 0x00, 0xCB},
+       {0x0, 0x00, 0xCC},
+       {0x1, 0xF4, 0x00},
+       {0x1, 0x38, 0x01},
+       {0x1, 0x40, 0x02},
+       {0x1, 0x0A, 0x03},
+       {0x1, 0x40, 0x04},
+       {0x1, 0x40, 0x05},
+       {0x1, 0x40, 0x06},
+       {0x1, 0x67, 0x07},
+       {0x1, 0x31, 0x08},
+       {0x1, 0x00, 0x09},
+       {0x1, 0x00, 0x0A},
+       {0x1, 0x00, 0x0B},
+       {0x1, 0x14, 0x0C},
+       {0x1, 0x00, 0x0D},
+       {0x1, 0x00, 0x0E},
+       {0x1, 0x00, 0x0F},
+       {0x1, 0x1E, 0x10},
+       {0x1, 0x00, 0x11},
+       {0x1, 0x00, 0x12},
+       {0x1, 0x00, 0x13},
+       {0x1, 0x00, 0x14},
+       {0x1, 0xFF, 0x15},
+       {0x1, 0x01, 0x16},
+       {0x1, 0x32, 0x17},
+       {0x1, 0x23, 0x18},
+       {0x1, 0xCE, 0x19},
+       {0x1, 0x23, 0x1A},
+       {0x1, 0x32, 0x1B},
+       {0x1, 0x8D, 0x1C},
+       {0x1, 0xCE, 0x1D},
+       {0x1, 0x8D, 0x1E},
+       {0x1, 0x00, 0x1F},
+       {0x1, 0x00, 0x20},
+       {0x1, 0xFF, 0x3E},
+       {0x1, 0x02, 0x3F},
+       {0x1, 0x00, 0x40},
+       {0x1, 0x00, 0x41},
+       {0x1, 0x00, 0x42},
+       {0x1, 0x00, 0x43},
+       {0x1, 0x00, 0x44},
+       {0x1, 0x00, 0x45},
+       {0x1, 0x00, 0x46},
+       {0x1, 0x00, 0x47},
+       {0x1, 0x00, 0x48},
+       {0x1, 0x00, 0x49},
+       {0x1, 0x00, 0x4A},
+       {0x1, 0x00, 0x4B},
+       {0x1, 0x00, 0x4C},
+       {0x1, 0x00, 0x4D},
+       {0x1, 0x00, 0x4E},
+       {0x1, 0x00, 0x4F},
+       {0x1, 0x00, 0x50},
+       {0x1, 0x00, 0x51},
+       {0x1, 0x00, 0x52},
+       {0x1, 0x00, 0x53},
+       {0x1, 0x00, 0x54},
+       {0x1, 0x00, 0x55},
+       {0x1, 0x00, 0x56},
+       {0x1, 0x00, 0x57},
+       {0x1, 0x00, 0x58},
+       {0x1, 0x00, 0x59},
+       {0x1, 0x00, 0x5A},
+       {0x2, 0x03, 0x00},
+       {0x2, 0x00, 0x01},
+       {0x2, 0x00, 0x05},
+       {0x2, 0x00, 0x06},
+       {0x2, 0x00, 0x07},
+       {0x2, 0x00, 0x10},
+       {0x2, 0x00, 0x11},
+       /* Strange - looks like the 501 driver doesn't do anything
+        * at insert time except read the EEPROM
+        */
+       {}
+};
+
+/* Data for video camera init before capture.
+ * Capture and decoding by Colin Peart.
+ * This is is for the 3com HomeConnect Lite which is spca501a based.
+ */
+static __u16 spca501_3com_open_data[][3] = {
+       /* bmRequest,value,index */
+       {0x2, 0x0050, 0x0000},  /* C/S Enable TG soft reset, timing mode=010 */
+       {0x2, 0x0043, 0x0000},  /* C/S Disable TG soft reset, timing mode=010 */
+       {0x2, 0x0002, 0x0005},  /* C/S GPIO */
+       {0x2, 0x0003, 0x0005},  /* C/S GPIO */
+
+#ifdef CCDSP_SET
+       {0x1, 0x0020, 0x0001},  /* CCDSP Options */
+
+       {0x1, 0x0020, 0x0002},  /* CCDSP Black Level */
+       {0x1, 0x006e, 0x0007},  /* CCDSP Gamma options */
+       {0x1, 0x0090, 0x0015},  /* CCDSP Luminance Low */
+       {0x1, 0x00ff, 0x0016},  /* CCDSP Luminance High */
+       {0x1, 0x0003, 0x003F},  /* CCDSP Gamma correction toggle */
+
+#ifdef ALTER_GAMMA
+       {0x1, 0x0010, 0x0008},  /* CCDSP YUV A11 */
+       {0x1, 0x0000, 0x0009},  /* CCDSP YUV A12 */
+       {0x1, 0x0000, 0x000a},  /* CCDSP YUV A13 */
+       {0x1, 0x0000, 0x000b},  /* CCDSP YUV A21 */
+       {0x1, 0x0010, 0x000c},  /* CCDSP YUV A22 */
+       {0x1, 0x0000, 0x000d},  /* CCDSP YUV A23 */
+       {0x1, 0x0000, 0x000e},  /* CCDSP YUV A31 */
+       {0x1, 0x0000, 0x000f},  /* CCDSP YUV A32 */
+       {0x1, 0x0010, 0x0010},  /* CCDSP YUV A33 */
+       {0x1, 0x0000, 0x0011},  /* CCDSP R Offset */
+       {0x1, 0x0000, 0x0012},  /* CCDSP G Offset */
+       {0x1, 0x0001, 0x0013},  /* CCDSP B Offset */
+       {0x1, 0x0001, 0x0014},  /* CCDSP BG Offset */
+       {0x1, 0x003f, 0x00C1},  /* CCDSP Gamma Correction Enable */
+#endif
+#endif
+
+#ifdef TG_SET
+       {0x0, 0x00fc, 0x0000},  /* TG Shutter Speed High Bits */
+       {0x0, 0x0000, 0x0001},  /* TG Shutter Speed Low Bits */
+       {0x0, 0x00e4, 0x0004},  /* TG DCLK*2 Adjust */
+       {0x0, 0x0008, 0x0005},  /* TG ADCK Adjust */
+       {0x0, 0x0003, 0x0006},  /* TG FR Phase Adjust */
+       {0x0, 0x0001, 0x0007},  /* TG FCDS Phase Adjust */
+       {0x0, 0x0039, 0x0008},  /* TG FS Phase Adjust */
+       {0x0, 0x0088, 0x000a},  /* TG MH1 */
+       {0x0, 0x0003, 0x000f},  /* TG Pixel ID */
+
+       /* Like below, unexplained toglleing */
+       {0x0, 0x0080, 0x000c},
+       {0x0, 0x0000, 0x000d},
+       {0x0, 0x0080, 0x000c},
+       {0x0, 0x0004, 0x000d},
+       {0x0, 0x0000, 0x000c},
+       {0x0, 0x0000, 0x000d},
+       {0x0, 0x0040, 0x000c},
+       {0x0, 0x0017, 0x000d},
+       {0x0, 0x00c0, 0x000c},
+       {0x0, 0x0000, 0x000d},
+       {0x0, 0x0080, 0x000c},
+       {0x0, 0x0006, 0x000d},
+       {0x0, 0x0080, 0x000c},
+       {0x0, 0x0004, 0x000d},
+       {0x0, 0x0002, 0x0003},
+#endif
+
+#ifdef DSPWIN_SET
+       {0x1, 0x001c, 0x0017},  /* CCDSP W1 Start X */
+       {0x1, 0x00e2, 0x0019},  /* CCDSP W2 Start X */
+       {0x1, 0x001c, 0x001b},  /* CCDSP W3 Start X */
+       {0x1, 0x00e2, 0x001d},  /* CCDSP W4 Start X */
+       {0x1, 0x00aa, 0x001f},  /* CCDSP W5 Start X */
+       {0x1, 0x0070, 0x0020},  /* CCDSP W5 Start Y */
+#endif
+       {0x0, 0x0001, 0x0010},  /* TG Start Clock */
+
+/*     {0x2, 0x006a, 0x0001},   * C/S Enable ISOSYNCH Packet Engine */
+       {0x2, 0x0068, 0x0001},  /* C/S Diable ISOSYNCH Packet Engine */
+       {0x2, 0x0000, 0x0005},
+       {0x2, 0x0043, 0x0000},  /* C/S Set Timing Mode, Disable TG soft reset */
+       {0x2, 0x0043, 0x0000},  /* C/S Set Timing Mode, Disable TG soft reset */
+       {0x2, 0x0002, 0x0005},  /* C/S GPIO */
+       {0x2, 0x0003, 0x0005},  /* C/S GPIO */
+
+       {0x2, 0x006a, 0x0001},  /* C/S Enable ISOSYNCH Packet Engine */
+       {}
+};
+
+/*
+ * Data used to initialize a SPCA501C with HV7131B sensor.
+ * From a capture file taken with USBSnoop v 1.5
+ * I have a "SPCA501C pc camera chipset" manual by sunplus, but some
+ * of the value meanings are obscure or simply "reserved".
+ * to do list:
+ * 1) Understand what every value means
+ * 2) Understand why some values seem to appear more than once
+ * 3) Write a small comment for each line of the following arrays.
+ */
+static __u16 spca501c_arowana_open_data[][3] = {
+       /* bmRequest,value,index */
+       {0x02, 0x0007, 0x0005},
+       {0x02, 0xa048, 0x0000},
+       {0x05, 0x0022, 0x0004},
+       {0x01, 0x0006, 0x0011},
+       {0x01, 0x00ff, 0x0012},
+       {0x01, 0x0014, 0x0013},
+       {0x01, 0x0000, 0x0014},
+       {0x01, 0x0042, 0x0051},
+       {0x01, 0x0040, 0x0052},
+       {0x01, 0x0051, 0x0053},
+       {0x01, 0x0040, 0x0054},
+       {0x01, 0x0000, 0x0055},
+       {0x00, 0x0025, 0x0000},
+       {0x00, 0x0026, 0x0000},
+       {0x00, 0x0001, 0x0000},
+       {0x00, 0x0027, 0x0000},
+       {0x00, 0x008a, 0x0000},
+       {}
+};
+
+static __u16 spca501c_arowana_init_data[][3] = {
+       /* bmRequest,value,index */
+       {0x02, 0x0007, 0x0005},
+       {0x02, 0xa048, 0x0000},
+       {0x05, 0x0022, 0x0004},
+       {0x01, 0x0006, 0x0011},
+       {0x01, 0x00ff, 0x0012},
+       {0x01, 0x0014, 0x0013},
+       {0x01, 0x0000, 0x0014},
+       {0x01, 0x0042, 0x0051},
+       {0x01, 0x0040, 0x0052},
+       {0x01, 0x0051, 0x0053},
+       {0x01, 0x0040, 0x0054},
+       {0x01, 0x0000, 0x0055},
+       {0x00, 0x0025, 0x0000},
+       {0x00, 0x0026, 0x0000},
+       {0x00, 0x0001, 0x0000},
+       {0x00, 0x0027, 0x0000},
+       {0x00, 0x008a, 0x0000},
+       {0x02, 0x0000, 0x0005},
+       {0x02, 0x0007, 0x0005},
+       {0x02, 0x2000, 0x0000},
+       {0x05, 0x0022, 0x0004},
+       {0x05, 0x0015, 0x0001},
+       {0x05, 0x00ea, 0x0000},
+       {0x05, 0x0021, 0x0001},
+       {0x05, 0x00d2, 0x0000},
+       {0x05, 0x0023, 0x0001},
+       {0x05, 0x0003, 0x0000},
+       {0x05, 0x0030, 0x0001},
+       {0x05, 0x002b, 0x0000},
+       {0x05, 0x0031, 0x0001},
+       {0x05, 0x0023, 0x0000},
+       {0x05, 0x0032, 0x0001},
+       {0x05, 0x0023, 0x0000},
+       {0x05, 0x0033, 0x0001},
+       {0x05, 0x0023, 0x0000},
+       {0x05, 0x0034, 0x0001},
+       {0x05, 0x0002, 0x0000},
+       {0x05, 0x0050, 0x0001},
+       {0x05, 0x0000, 0x0000},
+       {0x05, 0x0051, 0x0001},
+       {0x05, 0x0000, 0x0000},
+       {0x05, 0x0052, 0x0001},
+       {0x05, 0x0000, 0x0000},
+       {0x05, 0x0054, 0x0001},
+       {0x05, 0x0001, 0x0000},
+       {0x00, 0x0000, 0x0001},
+       {0x00, 0x0000, 0x0002},
+       {0x00, 0x000c, 0x0003},
+       {0x00, 0x0000, 0x0004},
+       {0x00, 0x0090, 0x0005},
+       {0x00, 0x0000, 0x0006},
+       {0x00, 0x0040, 0x0007},
+       {0x00, 0x00c0, 0x0008},
+       {0x00, 0x004a, 0x0009},
+       {0x00, 0x0000, 0x000a},
+       {0x00, 0x0000, 0x000b},
+       {0x00, 0x0001, 0x000c},
+       {0x00, 0x0001, 0x000d},
+       {0x00, 0x0000, 0x000e},
+       {0x00, 0x0002, 0x000f},
+       {0x00, 0x0001, 0x0010},
+       {0x00, 0x0000, 0x0011},
+       {0x00, 0x0000, 0x0012},
+       {0x00, 0x0002, 0x0020},
+       {0x00, 0x0080, 0x0021},
+       {0x00, 0x0001, 0x0022},
+       {0x00, 0x00e0, 0x0023},
+       {0x00, 0x0000, 0x0024},
+       {0x00, 0x00d5, 0x0025},
+       {0x00, 0x0000, 0x0026},
+       {0x00, 0x000b, 0x0027},
+       {0x00, 0x0000, 0x0046},
+       {0x00, 0x0000, 0x0047},
+       {0x00, 0x0000, 0x0048},
+       {0x00, 0x0000, 0x0049},
+       {0x00, 0x0008, 0x004a},
+       {0xff, 0x0000, 0x00d0},
+       {0xff, 0x00d8, 0x00d1},
+       {0xff, 0x0000, 0x00d4},
+       {0xff, 0x0000, 0x00d5},
+       {0x01, 0x00a6, 0x0000},
+       {0x01, 0x0028, 0x0001},
+       {0x01, 0x0000, 0x0002},
+       {0x01, 0x000a, 0x0003},
+       {0x01, 0x0040, 0x0004},
+       {0x01, 0x0066, 0x0007},
+       {0x01, 0x0011, 0x0008},
+       {0x01, 0x0032, 0x0009},
+       {0x01, 0x00fd, 0x000a},
+       {0x01, 0x0038, 0x000b},
+       {0x01, 0x00d1, 0x000c},
+       {0x01, 0x00f7, 0x000d},
+       {0x01, 0x00ed, 0x000e},
+       {0x01, 0x00d8, 0x000f},
+       {0x01, 0x0038, 0x0010},
+       {0x01, 0x00ff, 0x0015},
+       {0x01, 0x0001, 0x0016},
+       {0x01, 0x0032, 0x0017},
+       {0x01, 0x0023, 0x0018},
+       {0x01, 0x00ce, 0x0019},
+       {0x01, 0x0023, 0x001a},
+       {0x01, 0x0032, 0x001b},
+       {0x01, 0x008d, 0x001c},
+       {0x01, 0x00ce, 0x001d},
+       {0x01, 0x008d, 0x001e},
+       {0x01, 0x0000, 0x001f},
+       {0x01, 0x0000, 0x0020},
+       {0x01, 0x00ff, 0x003e},
+       {0x01, 0x0003, 0x003f},
+       {0x01, 0x0000, 0x0040},
+       {0x01, 0x0035, 0x0041},
+       {0x01, 0x0053, 0x0042},
+       {0x01, 0x0069, 0x0043},
+       {0x01, 0x007c, 0x0044},
+       {0x01, 0x008c, 0x0045},
+       {0x01, 0x009a, 0x0046},
+       {0x01, 0x00a8, 0x0047},
+       {0x01, 0x00b4, 0x0048},
+       {0x01, 0x00bf, 0x0049},
+       {0x01, 0x00ca, 0x004a},
+       {0x01, 0x00d4, 0x004b},
+       {0x01, 0x00dd, 0x004c},
+       {0x01, 0x00e7, 0x004d},
+       {0x01, 0x00ef, 0x004e},
+       {0x01, 0x00f8, 0x004f},
+       {0x01, 0x00ff, 0x0050},
+       {0x01, 0x0001, 0x0056},
+       {0x01, 0x0060, 0x0057},
+       {0x01, 0x0040, 0x0058},
+       {0x01, 0x0011, 0x0059},
+       {0x01, 0x0001, 0x005a},
+       {0x02, 0x0007, 0x0005},
+       {0x02, 0xa048, 0x0000},
+       {0x02, 0x0007, 0x0005},
+       {0x02, 0x0015, 0x0006},
+       {0x02, 0x100a, 0x0007},
+       {0x02, 0xa048, 0x0000},
+       {0x02, 0xc002, 0x0001},
+       {0x02, 0x000f, 0x0005},
+       {0x02, 0xa048, 0x0000},
+       {0x05, 0x0022, 0x0004},
+       {0x05, 0x0025, 0x0001},
+       {0x05, 0x0000, 0x0000},
+       {0x05, 0x0026, 0x0001},
+       {0x05, 0x0001, 0x0000},
+       {0x05, 0x0027, 0x0001},
+       {0x05, 0x0000, 0x0000},
+       {0x05, 0x0001, 0x0001},
+       {0x05, 0x0000, 0x0000},
+       {0x05, 0x0021, 0x0001},
+       {0x05, 0x00d2, 0x0000},
+       {0x05, 0x0020, 0x0001},
+       {0x05, 0x0000, 0x0000},
+       {0x00, 0x0090, 0x0005},
+       {0x01, 0x00a6, 0x0000},
+       {0x02, 0x0007, 0x0005},
+       {0x02, 0x2000, 0x0000},
+       {0x05, 0x0022, 0x0004},
+       {0x05, 0x0015, 0x0001},
+       {0x05, 0x00ea, 0x0000},
+       {0x05, 0x0021, 0x0001},
+       {0x05, 0x00d2, 0x0000},
+       {0x05, 0x0023, 0x0001},
+       {0x05, 0x0003, 0x0000},
+       {0x05, 0x0030, 0x0001},
+       {0x05, 0x002b, 0x0000},
+       {0x05, 0x0031, 0x0001},
+       {0x05, 0x0023, 0x0000},
+       {0x05, 0x0032, 0x0001},
+       {0x05, 0x0023, 0x0000},
+       {0x05, 0x0033, 0x0001},
+       {0x05, 0x0023, 0x0000},
+       {0x05, 0x0034, 0x0001},
+       {0x05, 0x0002, 0x0000},
+       {0x05, 0x0050, 0x0001},
+       {0x05, 0x0000, 0x0000},
+       {0x05, 0x0051, 0x0001},
+       {0x05, 0x0000, 0x0000},
+       {0x05, 0x0052, 0x0001},
+       {0x05, 0x0000, 0x0000},
+       {0x05, 0x0054, 0x0001},
+       {0x05, 0x0001, 0x0000},
+       {0x00, 0x0000, 0x0001},
+       {0x00, 0x0000, 0x0002},
+       {0x00, 0x000c, 0x0003},
+       {0x00, 0x0000, 0x0004},
+       {0x00, 0x0090, 0x0005},
+       {0x00, 0x0000, 0x0006},
+       {0x00, 0x0040, 0x0007},
+       {0x00, 0x00c0, 0x0008},
+       {0x00, 0x004a, 0x0009},
+       {0x00, 0x0000, 0x000a},
+       {0x00, 0x0000, 0x000b},
+       {0x00, 0x0001, 0x000c},
+       {0x00, 0x0001, 0x000d},
+       {0x00, 0x0000, 0x000e},
+       {0x00, 0x0002, 0x000f},
+       {0x00, 0x0001, 0x0010},
+       {0x00, 0x0000, 0x0011},
+       {0x00, 0x0000, 0x0012},
+       {0x00, 0x0002, 0x0020},
+       {0x00, 0x0080, 0x0021},
+       {0x00, 0x0001, 0x0022},
+       {0x00, 0x00e0, 0x0023},
+       {0x00, 0x0000, 0x0024},
+       {0x00, 0x00d5, 0x0025},
+       {0x00, 0x0000, 0x0026},
+       {0x00, 0x000b, 0x0027},
+       {0x00, 0x0000, 0x0046},
+       {0x00, 0x0000, 0x0047},
+       {0x00, 0x0000, 0x0048},
+       {0x00, 0x0000, 0x0049},
+       {0x00, 0x0008, 0x004a},
+       {0xff, 0x0000, 0x00d0},
+       {0xff, 0x00d8, 0x00d1},
+       {0xff, 0x0000, 0x00d4},
+       {0xff, 0x0000, 0x00d5},
+       {0x01, 0x00a6, 0x0000},
+       {0x01, 0x0028, 0x0001},
+       {0x01, 0x0000, 0x0002},
+       {0x01, 0x000a, 0x0003},
+       {0x01, 0x0040, 0x0004},
+       {0x01, 0x0066, 0x0007},
+       {0x01, 0x0011, 0x0008},
+       {0x01, 0x0032, 0x0009},
+       {0x01, 0x00fd, 0x000a},
+       {0x01, 0x0038, 0x000b},
+       {0x01, 0x00d1, 0x000c},
+       {0x01, 0x00f7, 0x000d},
+       {0x01, 0x00ed, 0x000e},
+       {0x01, 0x00d8, 0x000f},
+       {0x01, 0x0038, 0x0010},
+       {0x01, 0x00ff, 0x0015},
+       {0x01, 0x0001, 0x0016},
+       {0x01, 0x0032, 0x0017},
+       {0x01, 0x0023, 0x0018},
+       {0x01, 0x00ce, 0x0019},
+       {0x01, 0x0023, 0x001a},
+       {0x01, 0x0032, 0x001b},
+       {0x01, 0x008d, 0x001c},
+       {0x01, 0x00ce, 0x001d},
+       {0x01, 0x008d, 0x001e},
+       {0x01, 0x0000, 0x001f},
+       {0x01, 0x0000, 0x0020},
+       {0x01, 0x00ff, 0x003e},
+       {0x01, 0x0003, 0x003f},
+       {0x01, 0x0000, 0x0040},
+       {0x01, 0x0035, 0x0041},
+       {0x01, 0x0053, 0x0042},
+       {0x01, 0x0069, 0x0043},
+       {0x01, 0x007c, 0x0044},
+       {0x01, 0x008c, 0x0045},
+       {0x01, 0x009a, 0x0046},
+       {0x01, 0x00a8, 0x0047},
+       {0x01, 0x00b4, 0x0048},
+       {0x01, 0x00bf, 0x0049},
+       {0x01, 0x00ca, 0x004a},
+       {0x01, 0x00d4, 0x004b},
+       {0x01, 0x00dd, 0x004c},
+       {0x01, 0x00e7, 0x004d},
+       {0x01, 0x00ef, 0x004e},
+       {0x01, 0x00f8, 0x004f},
+       {0x01, 0x00ff, 0x0050},
+       {0x01, 0x0001, 0x0056},
+       {0x01, 0x0060, 0x0057},
+       {0x01, 0x0040, 0x0058},
+       {0x01, 0x0011, 0x0059},
+       {0x01, 0x0001, 0x005a},
+       {0x02, 0x0007, 0x0005},
+       {0x02, 0xa048, 0x0000},
+       {0x02, 0x0007, 0x0005},
+       {0x02, 0x0015, 0x0006},
+       {0x02, 0x100a, 0x0007},
+       {0x02, 0xa048, 0x0000},
+       {0x02, 0xc002, 0x0001},
+       {0x02, 0x000f, 0x0005},
+       {0x02, 0xa048, 0x0000},
+       {0x05, 0x0022, 0x0004},
+       {0x05, 0x0025, 0x0001},
+       {0x05, 0x0000, 0x0000},
+       {0x05, 0x0026, 0x0001},
+       {0x05, 0x0001, 0x0000},
+       {0x05, 0x0027, 0x0001},
+       {0x05, 0x0000, 0x0000},
+       {0x05, 0x0001, 0x0001},
+       {0x05, 0x0000, 0x0000},
+       {0x05, 0x0021, 0x0001},
+       {0x05, 0x00d2, 0x0000},
+       {0x05, 0x0020, 0x0001},
+       {0x05, 0x0000, 0x0000},
+       {0x00, 0x0090, 0x0005},
+       {0x01, 0x00a6, 0x0000},
+       {0x01, 0x0003, 0x003f},
+       {0x01, 0x0001, 0x0056},
+       {0x01, 0x0011, 0x0008},
+       {0x01, 0x0032, 0x0009},
+       {0x01, 0xfffd, 0x000a},
+       {0x01, 0x0023, 0x000b},
+       {0x01, 0xffea, 0x000c},
+       {0x01, 0xfff4, 0x000d},
+       {0x01, 0xfffc, 0x000e},
+       {0x01, 0xffe3, 0x000f},
+       {0x01, 0x001f, 0x0010},
+       {0x01, 0x00a8, 0x0001},
+       {0x01, 0x0067, 0x0007},
+       {0x01, 0x0032, 0x0017},
+       {0x01, 0x0023, 0x0018},
+       {0x01, 0x00ce, 0x0019},
+       {0x01, 0x0023, 0x001a},
+       {0x01, 0x0032, 0x001b},
+       {0x01, 0x008d, 0x001c},
+       {0x01, 0x00ce, 0x001d},
+       {0x01, 0x008d, 0x001e},
+       {0x01, 0x00c8, 0x0015},
+       {0x01, 0x0032, 0x0016},
+       {0x01, 0x0000, 0x0011},
+       {0x01, 0x0000, 0x0012},
+       {0x01, 0x0000, 0x0013},
+       {0x01, 0x000a, 0x0003},
+       {0x02, 0xc002, 0x0001},
+       {0x02, 0x0007, 0x0005},
+       {0x02, 0xc000, 0x0001},
+       {0x02, 0x0000, 0x0005},
+       {0x02, 0x0007, 0x0005},
+       {0x02, 0x2000, 0x0000},
+       {0x05, 0x0022, 0x0004},
+       {0x05, 0x0015, 0x0001},
+       {0x05, 0x00ea, 0x0000},
+       {0x05, 0x0021, 0x0001},
+       {0x05, 0x00d2, 0x0000},
+       {0x05, 0x0023, 0x0001},
+       {0x05, 0x0003, 0x0000},
+       {0x05, 0x0030, 0x0001},
+       {0x05, 0x002b, 0x0000},
+       {0x05, 0x0031, 0x0001},
+       {0x05, 0x0023, 0x0000},
+       {0x05, 0x0032, 0x0001},
+       {0x05, 0x0023, 0x0000},
+       {0x05, 0x0033, 0x0001},
+       {0x05, 0x0023, 0x0000},
+       {0x05, 0x0034, 0x0001},
+       {0x05, 0x0002, 0x0000},
+       {0x05, 0x0050, 0x0001},
+       {0x05, 0x0000, 0x0000},
+       {0x05, 0x0051, 0x0001},
+       {0x05, 0x0000, 0x0000},
+       {0x05, 0x0052, 0x0001},
+       {0x05, 0x0000, 0x0000},
+       {0x05, 0x0054, 0x0001},
+       {0x05, 0x0001, 0x0000},
+       {0x00, 0x0000, 0x0001},
+       {0x00, 0x0000, 0x0002},
+       {0x00, 0x000c, 0x0003},
+       {0x00, 0x0000, 0x0004},
+       {0x00, 0x0090, 0x0005},
+       {0x00, 0x0000, 0x0006},
+       {0x00, 0x0040, 0x0007},
+       {0x00, 0x00c0, 0x0008},
+       {0x00, 0x004a, 0x0009},
+       {0x00, 0x0000, 0x000a},
+       {0x00, 0x0000, 0x000b},
+       {0x00, 0x0001, 0x000c},
+       {0x00, 0x0001, 0x000d},
+       {0x00, 0x0000, 0x000e},
+       {0x00, 0x0002, 0x000f},
+       {0x00, 0x0001, 0x0010},
+       {0x00, 0x0000, 0x0011},
+       {0x00, 0x0000, 0x0012},
+       {0x00, 0x0002, 0x0020},
+       {0x00, 0x0080, 0x0021},
+       {0x00, 0x0001, 0x0022},
+       {0x00, 0x00e0, 0x0023},
+       {0x00, 0x0000, 0x0024},
+       {0x00, 0x00d5, 0x0025},
+       {0x00, 0x0000, 0x0026},
+       {0x00, 0x000b, 0x0027},
+       {0x00, 0x0000, 0x0046},
+       {0x00, 0x0000, 0x0047},
+       {0x00, 0x0000, 0x0048},
+       {0x00, 0x0000, 0x0049},
+       {0x00, 0x0008, 0x004a},
+       {0xff, 0x0000, 0x00d0},
+       {0xff, 0x00d8, 0x00d1},
+       {0xff, 0x0000, 0x00d4},
+       {0xff, 0x0000, 0x00d5},
+       {0x01, 0x00a6, 0x0000},
+       {0x01, 0x0028, 0x0001},
+       {0x01, 0x0000, 0x0002},
+       {0x01, 0x000a, 0x0003},
+       {0x01, 0x0040, 0x0004},
+       {0x01, 0x0066, 0x0007},
+       {0x01, 0x0011, 0x0008},
+       {0x01, 0x0032, 0x0009},
+       {0x01, 0x00fd, 0x000a},
+       {0x01, 0x0038, 0x000b},
+       {0x01, 0x00d1, 0x000c},
+       {0x01, 0x00f7, 0x000d},
+       {0x01, 0x00ed, 0x000e},
+       {0x01, 0x00d8, 0x000f},
+       {0x01, 0x0038, 0x0010},
+       {0x01, 0x00ff, 0x0015},
+       {0x01, 0x0001, 0x0016},
+       {0x01, 0x0032, 0x0017},
+       {0x01, 0x0023, 0x0018},
+       {0x01, 0x00ce, 0x0019},
+       {0x01, 0x0023, 0x001a},
+       {0x01, 0x0032, 0x001b},
+       {0x01, 0x008d, 0x001c},
+       {0x01, 0x00ce, 0x001d},
+       {0x01, 0x008d, 0x001e},
+       {0x01, 0x0000, 0x001f},
+       {0x01, 0x0000, 0x0020},
+       {0x01, 0x00ff, 0x003e},
+       {0x01, 0x0003, 0x003f},
+       {0x01, 0x0000, 0x0040},
+       {0x01, 0x0035, 0x0041},
+       {0x01, 0x0053, 0x0042},
+       {0x01, 0x0069, 0x0043},
+       {0x01, 0x007c, 0x0044},
+       {0x01, 0x008c, 0x0045},
+       {0x01, 0x009a, 0x0046},
+       {0x01, 0x00a8, 0x0047},
+       {0x01, 0x00b4, 0x0048},
+       {0x01, 0x00bf, 0x0049},
+       {0x01, 0x00ca, 0x004a},
+       {0x01, 0x00d4, 0x004b},
+       {0x01, 0x00dd, 0x004c},
+       {0x01, 0x00e7, 0x004d},
+       {0x01, 0x00ef, 0x004e},
+       {0x01, 0x00f8, 0x004f},
+       {0x01, 0x00ff, 0x0050},
+       {0x01, 0x0001, 0x0056},
+       {0x01, 0x0060, 0x0057},
+       {0x01, 0x0040, 0x0058},
+       {0x01, 0x0011, 0x0059},
+       {0x01, 0x0001, 0x005a},
+       {0x02, 0x0007, 0x0005},
+       {0x02, 0xa048, 0x0000},
+       {0x02, 0x0007, 0x0005},
+       {0x02, 0x0015, 0x0006},
+       {0x02, 0x100a, 0x0007},
+       {0x02, 0xa048, 0x0000},
+       {0x02, 0xc002, 0x0001},
+       {0x02, 0x000f, 0x0005},
+       {0x02, 0xa048, 0x0000},
+       {0x05, 0x0022, 0x0004},
+       {0x05, 0x0025, 0x0001},
+       {0x05, 0x0000, 0x0000},
+       {0x05, 0x0026, 0x0001},
+       {0x05, 0x0001, 0x0000},
+       {0x05, 0x0027, 0x0001},
+       {0x05, 0x0000, 0x0000},
+       {0x05, 0x0001, 0x0001},
+       {0x05, 0x0000, 0x0000},
+       {0x05, 0x0021, 0x0001},
+       {0x05, 0x00d2, 0x0000},
+       {0x05, 0x0020, 0x0001},
+       {0x05, 0x0000, 0x0000},
+       {0x00, 0x0090, 0x0005},
+       {0x01, 0x00a6, 0x0000},
+       {0x02, 0x0007, 0x0005},
+       {0x02, 0x2000, 0x0000},
+       {0x05, 0x0022, 0x0004},
+       {0x05, 0x0015, 0x0001},
+       {0x05, 0x00ea, 0x0000},
+       {0x05, 0x0021, 0x0001},
+       {0x05, 0x00d2, 0x0000},
+       {0x05, 0x0023, 0x0001},
+       {0x05, 0x0003, 0x0000},
+       {0x05, 0x0030, 0x0001},
+       {0x05, 0x002b, 0x0000},
+       {0x05, 0x0031, 0x0001},
+       {0x05, 0x0023, 0x0000},
+       {0x05, 0x0032, 0x0001},
+       {0x05, 0x0023, 0x0000},
+       {0x05, 0x0033, 0x0001},
+       {0x05, 0x0023, 0x0000},
+       {0x05, 0x0034, 0x0001},
+       {0x05, 0x0002, 0x0000},
+       {0x05, 0x0050, 0x0001},
+       {0x05, 0x0000, 0x0000},
+       {0x05, 0x0051, 0x0001},
+       {0x05, 0x0000, 0x0000},
+       {0x05, 0x0052, 0x0001},
+       {0x05, 0x0000, 0x0000},
+       {0x05, 0x0054, 0x0001},
+       {0x05, 0x0001, 0x0000},
+       {0x00, 0x0000, 0x0001},
+       {0x00, 0x0000, 0x0002},
+       {0x00, 0x000c, 0x0003},
+       {0x00, 0x0000, 0x0004},
+       {0x00, 0x0090, 0x0005},
+       {0x00, 0x0000, 0x0006},
+       {0x00, 0x0040, 0x0007},
+       {0x00, 0x00c0, 0x0008},
+       {0x00, 0x004a, 0x0009},
+       {0x00, 0x0000, 0x000a},
+       {0x00, 0x0000, 0x000b},
+       {0x00, 0x0001, 0x000c},
+       {0x00, 0x0001, 0x000d},
+       {0x00, 0x0000, 0x000e},
+       {0x00, 0x0002, 0x000f},
+       {0x00, 0x0001, 0x0010},
+       {0x00, 0x0000, 0x0011},
+       {0x00, 0x0000, 0x0012},
+       {0x00, 0x0002, 0x0020},
+       {0x00, 0x0080, 0x0021},
+       {0x00, 0x0001, 0x0022},
+       {0x00, 0x00e0, 0x0023},
+       {0x00, 0x0000, 0x0024},
+       {0x00, 0x00d5, 0x0025},
+       {0x00, 0x0000, 0x0026},
+       {0x00, 0x000b, 0x0027},
+       {0x00, 0x0000, 0x0046},
+       {0x00, 0x0000, 0x0047},
+       {0x00, 0x0000, 0x0048},
+       {0x00, 0x0000, 0x0049},
+       {0x00, 0x0008, 0x004a},
+       {0xff, 0x0000, 0x00d0},
+       {0xff, 0x00d8, 0x00d1},
+       {0xff, 0x0000, 0x00d4},
+       {0xff, 0x0000, 0x00d5},
+       {0x01, 0x00a6, 0x0000},
+       {0x01, 0x0028, 0x0001},
+       {0x01, 0x0000, 0x0002},
+       {0x01, 0x000a, 0x0003},
+       {0x01, 0x0040, 0x0004},
+       {0x01, 0x0066, 0x0007},
+       {0x01, 0x0011, 0x0008},
+       {0x01, 0x0032, 0x0009},
+       {0x01, 0x00fd, 0x000a},
+       {0x01, 0x0038, 0x000b},
+       {0x01, 0x00d1, 0x000c},
+       {0x01, 0x00f7, 0x000d},
+       {0x01, 0x00ed, 0x000e},
+       {0x01, 0x00d8, 0x000f},
+       {0x01, 0x0038, 0x0010},
+       {0x01, 0x00ff, 0x0015},
+       {0x01, 0x0001, 0x0016},
+       {0x01, 0x0032, 0x0017},
+       {0x01, 0x0023, 0x0018},
+       {0x01, 0x00ce, 0x0019},
+       {0x01, 0x0023, 0x001a},
+       {0x01, 0x0032, 0x001b},
+       {0x01, 0x008d, 0x001c},
+       {0x01, 0x00ce, 0x001d},
+       {0x01, 0x008d, 0x001e},
+       {0x01, 0x0000, 0x001f},
+       {0x01, 0x0000, 0x0020},
+       {0x01, 0x00ff, 0x003e},
+       {0x01, 0x0003, 0x003f},
+       {0x01, 0x0000, 0x0040},
+       {0x01, 0x0035, 0x0041},
+       {0x01, 0x0053, 0x0042},
+       {0x01, 0x0069, 0x0043},
+       {0x01, 0x007c, 0x0044},
+       {0x01, 0x008c, 0x0045},
+       {0x01, 0x009a, 0x0046},
+       {0x01, 0x00a8, 0x0047},
+       {0x01, 0x00b4, 0x0048},
+       {0x01, 0x00bf, 0x0049},
+       {0x01, 0x00ca, 0x004a},
+       {0x01, 0x00d4, 0x004b},
+       {0x01, 0x00dd, 0x004c},
+       {0x01, 0x00e7, 0x004d},
+       {0x01, 0x00ef, 0x004e},
+       {0x01, 0x00f8, 0x004f},
+       {0x01, 0x00ff, 0x0050},
+       {0x01, 0x0001, 0x0056},
+       {0x01, 0x0060, 0x0057},
+       {0x01, 0x0040, 0x0058},
+       {0x01, 0x0011, 0x0059},
+       {0x01, 0x0001, 0x005a},
+       {0x02, 0x0007, 0x0005},
+       {0x02, 0xa048, 0x0000},
+       {0x02, 0x0007, 0x0005},
+       {0x02, 0x0015, 0x0006},
+       {0x02, 0x100a, 0x0007},
+       {0x02, 0xa048, 0x0000},
+       {0x02, 0xc002, 0x0001},
+       {0x02, 0x000f, 0x0005},
+       {0x02, 0xa048, 0x0000},
+       {0x05, 0x0022, 0x0004},
+       {0x05, 0x0025, 0x0001},
+       {0x05, 0x0000, 0x0000},
+       {0x05, 0x0026, 0x0001},
+       {0x05, 0x0001, 0x0000},
+       {0x05, 0x0027, 0x0001},
+       {0x05, 0x0000, 0x0000},
+       {0x05, 0x0001, 0x0001},
+       {0x05, 0x0000, 0x0000},
+       {0x05, 0x0021, 0x0001},
+       {0x05, 0x00d2, 0x0000},
+       {0x05, 0x0020, 0x0001},
+       {0x05, 0x0000, 0x0000},
+       {0x00, 0x0090, 0x0005},
+       {0x01, 0x00a6, 0x0000},
+       {0x05, 0x0026, 0x0001},
+       {0x05, 0x0001, 0x0000},
+       {0x05, 0x0027, 0x0001},
+       {0x05, 0x000f, 0x0000},
+       {0x01, 0x0003, 0x003f},
+       {0x01, 0x0001, 0x0056},
+       {0x01, 0x0011, 0x0008},
+       {0x01, 0x0032, 0x0009},
+       {0x01, 0xfffd, 0x000a},
+       {0x01, 0x0023, 0x000b},
+       {0x01, 0xffea, 0x000c},
+       {0x01, 0xfff4, 0x000d},
+       {0x01, 0xfffc, 0x000e},
+       {0x01, 0xffe3, 0x000f},
+       {0x01, 0x001f, 0x0010},
+       {0x01, 0x00a8, 0x0001},
+       {0x01, 0x0067, 0x0007},
+       {0x01, 0x0042, 0x0051},
+       {0x01, 0x0051, 0x0053},
+       {0x01, 0x000a, 0x0003},
+       {0x02, 0xc002, 0x0001},
+       {0x02, 0x0007, 0x0005},
+       {0x02, 0xc000, 0x0001},
+       {0x02, 0x0000, 0x0005},
+       {0x02, 0x0007, 0x0005},
+       {0x02, 0x2000, 0x0000},
+       {0x05, 0x0022, 0x0004},
+       {0x05, 0x0015, 0x0001},
+       {0x05, 0x00ea, 0x0000},
+       {0x05, 0x0021, 0x0001},
+       {0x05, 0x00d2, 0x0000},
+       {0x05, 0x0023, 0x0001},
+       {0x05, 0x0003, 0x0000},
+       {0x05, 0x0030, 0x0001},
+       {0x05, 0x002b, 0x0000},
+       {0x05, 0x0031, 0x0001},
+       {0x05, 0x0023, 0x0000},
+       {0x05, 0x0032, 0x0001},
+       {0x05, 0x0023, 0x0000},
+       {0x05, 0x0033, 0x0001},
+       {0x05, 0x0023, 0x0000},
+       {0x05, 0x0034, 0x0001},
+       {0x05, 0x0002, 0x0000},
+       {0x05, 0x0050, 0x0001},
+       {0x05, 0x0000, 0x0000},
+       {0x05, 0x0051, 0x0001},
+       {0x05, 0x0000, 0x0000},
+       {0x05, 0x0052, 0x0001},
+       {0x05, 0x0000, 0x0000},
+       {0x05, 0x0054, 0x0001},
+       {0x05, 0x0001, 0x0000},
+       {0x00, 0x0000, 0x0001},
+       {0x00, 0x0000, 0x0002},
+       {0x00, 0x000c, 0x0003},
+       {0x00, 0x0000, 0x0004},
+       {0x00, 0x0090, 0x0005},
+       {0x00, 0x0000, 0x0006},
+       {0x00, 0x0040, 0x0007},
+       {0x00, 0x00c0, 0x0008},
+       {0x00, 0x004a, 0x0009},
+       {0x00, 0x0000, 0x000a},
+       {0x00, 0x0000, 0x000b},
+       {0x00, 0x0001, 0x000c},
+       {0x00, 0x0001, 0x000d},
+       {0x00, 0x0000, 0x000e},
+       {0x00, 0x0002, 0x000f},
+       {0x00, 0x0001, 0x0010},
+       {0x00, 0x0000, 0x0011},
+       {0x00, 0x0000, 0x0012},
+       {0x00, 0x0002, 0x0020},
+       {0x00, 0x0080, 0x0021},
+       {0x00, 0x0001, 0x0022},
+       {0x00, 0x00e0, 0x0023},
+       {0x00, 0x0000, 0x0024},
+       {0x00, 0x00d5, 0x0025},
+       {0x00, 0x0000, 0x0026},
+       {0x00, 0x000b, 0x0027},
+       {0x00, 0x0000, 0x0046},
+       {0x00, 0x0000, 0x0047},
+       {0x00, 0x0000, 0x0048},
+       {0x00, 0x0000, 0x0049},
+       {0x00, 0x0008, 0x004a},
+       {0xff, 0x0000, 0x00d0},
+       {0xff, 0x00d8, 0x00d1},
+       {0xff, 0x0000, 0x00d4},
+       {0xff, 0x0000, 0x00d5},
+       {0x01, 0x00a6, 0x0000},
+       {0x01, 0x0028, 0x0001},
+       {0x01, 0x0000, 0x0002},
+       {0x01, 0x000a, 0x0003},
+       {0x01, 0x0040, 0x0004},
+       {0x01, 0x0066, 0x0007},
+       {0x01, 0x0011, 0x0008},
+       {0x01, 0x0032, 0x0009},
+       {0x01, 0x00fd, 0x000a},
+       {0x01, 0x0038, 0x000b},
+       {0x01, 0x00d1, 0x000c},
+       {0x01, 0x00f7, 0x000d},
+       {0x01, 0x00ed, 0x000e},
+       {0x01, 0x00d8, 0x000f},
+       {0x01, 0x0038, 0x0010},
+       {0x01, 0x00ff, 0x0015},
+       {0x01, 0x0001, 0x0016},
+       {0x01, 0x0032, 0x0017},
+       {0x01, 0x0023, 0x0018},
+       {0x01, 0x00ce, 0x0019},
+       {0x01, 0x0023, 0x001a},
+       {0x01, 0x0032, 0x001b},
+       {0x01, 0x008d, 0x001c},
+       {0x01, 0x00ce, 0x001d},
+       {0x01, 0x008d, 0x001e},
+       {0x01, 0x0000, 0x001f},
+       {0x01, 0x0000, 0x0020},
+       {0x01, 0x00ff, 0x003e},
+       {0x01, 0x0003, 0x003f},
+       {0x01, 0x0000, 0x0040},
+       {0x01, 0x0035, 0x0041},
+       {0x01, 0x0053, 0x0042},
+       {0x01, 0x0069, 0x0043},
+       {0x01, 0x007c, 0x0044},
+       {0x01, 0x008c, 0x0045},
+       {0x01, 0x009a, 0x0046},
+       {0x01, 0x00a8, 0x0047},
+       {0x01, 0x00b4, 0x0048},
+       {0x01, 0x00bf, 0x0049},
+       {0x01, 0x00ca, 0x004a},
+       {0x01, 0x00d4, 0x004b},
+       {0x01, 0x00dd, 0x004c},
+       {0x01, 0x00e7, 0x004d},
+       {0x01, 0x00ef, 0x004e},
+       {0x01, 0x00f8, 0x004f},
+       {0x01, 0x00ff, 0x0050},
+       {0x01, 0x0001, 0x0056},
+       {0x01, 0x0060, 0x0057},
+       {0x01, 0x0040, 0x0058},
+       {0x01, 0x0011, 0x0059},
+       {0x01, 0x0001, 0x005a},
+       {0x02, 0x0007, 0x0005},
+       {0x02, 0xa048, 0x0000},
+       {0x02, 0x0007, 0x0005},
+       {0x02, 0x0015, 0x0006},
+       {0x02, 0x100a, 0x0007},
+       {0x02, 0xa048, 0x0000},
+       {0x02, 0xc002, 0x0001},
+       {0x02, 0x000f, 0x0005},
+       {0x02, 0xa048, 0x0000},
+       {0x05, 0x0022, 0x0004},
+       {0x05, 0x0025, 0x0001},
+       {0x05, 0x0000, 0x0000},
+       {0x05, 0x0026, 0x0001},
+       {0x05, 0x0001, 0x0000},
+       {0x05, 0x0027, 0x0001},
+       {0x05, 0x0000, 0x0000},
+       {0x05, 0x0001, 0x0001},
+       {0x05, 0x0000, 0x0000},
+       {0x05, 0x0021, 0x0001},
+       {0x05, 0x00d2, 0x0000},
+       {0x05, 0x0020, 0x0001},
+       {0x05, 0x0000, 0x0000},
+       {0x00, 0x0090, 0x0005},
+       {0x01, 0x00a6, 0x0000},
+       {0x02, 0x0007, 0x0005},
+       {0x02, 0x2000, 0x0000},
+       {0x05, 0x0022, 0x0004},
+       {0x05, 0x0015, 0x0001},
+       {0x05, 0x00ea, 0x0000},
+       {0x05, 0x0021, 0x0001},
+       {0x05, 0x00d2, 0x0000},
+       {0x05, 0x0023, 0x0001},
+       {0x05, 0x0003, 0x0000},
+       {0x05, 0x0030, 0x0001},
+       {0x05, 0x002b, 0x0000},
+       {0x05, 0x0031, 0x0001},
+       {0x05, 0x0023, 0x0000},
+       {0x05, 0x0032, 0x0001},
+       {0x05, 0x0023, 0x0000},
+       {0x05, 0x0033, 0x0001},
+       {0x05, 0x0023, 0x0000},
+       {0x05, 0x0034, 0x0001},
+       {0x05, 0x0002, 0x0000},
+       {0x05, 0x0050, 0x0001},
+       {0x05, 0x0000, 0x0000},
+       {0x05, 0x0051, 0x0001},
+       {0x05, 0x0000, 0x0000},
+       {0x05, 0x0052, 0x0001},
+       {0x05, 0x0000, 0x0000},
+       {0x05, 0x0054, 0x0001},
+       {0x05, 0x0001, 0x0000},
+       {0x00, 0x0000, 0x0001},
+       {0x00, 0x0000, 0x0002},
+       {0x00, 0x000c, 0x0003},
+       {0x00, 0x0000, 0x0004},
+       {0x00, 0x0090, 0x0005},
+       {0x00, 0x0000, 0x0006},
+       {0x00, 0x0040, 0x0007},
+       {0x00, 0x00c0, 0x0008},
+       {0x00, 0x004a, 0x0009},
+       {0x00, 0x0000, 0x000a},
+       {0x00, 0x0000, 0x000b},
+       {0x00, 0x0001, 0x000c},
+       {0x00, 0x0001, 0x000d},
+       {0x00, 0x0000, 0x000e},
+       {0x00, 0x0002, 0x000f},
+       {0x00, 0x0001, 0x0010},
+       {0x00, 0x0000, 0x0011},
+       {0x00, 0x0000, 0x0012},
+       {0x00, 0x0002, 0x0020},
+       {0x00, 0x0080, 0x0021},
+       {0x00, 0x0001, 0x0022},
+       {0x00, 0x00e0, 0x0023},
+       {0x00, 0x0000, 0x0024},
+       {0x00, 0x00d5, 0x0025},
+       {0x00, 0x0000, 0x0026},
+       {0x00, 0x000b, 0x0027},
+       {0x00, 0x0000, 0x0046},
+       {0x00, 0x0000, 0x0047},
+       {0x00, 0x0000, 0x0048},
+       {0x00, 0x0000, 0x0049},
+       {0x00, 0x0008, 0x004a},
+       {0xff, 0x0000, 0x00d0},
+       {0xff, 0x00d8, 0x00d1},
+       {0xff, 0x0000, 0x00d4},
+       {0xff, 0x0000, 0x00d5},
+       {0x01, 0x00a6, 0x0000},
+       {0x01, 0x0028, 0x0001},
+       {0x01, 0x0000, 0x0002},
+       {0x01, 0x000a, 0x0003},
+       {0x01, 0x0040, 0x0004},
+       {0x01, 0x0066, 0x0007},
+       {0x01, 0x0011, 0x0008},
+       {0x01, 0x0032, 0x0009},
+       {0x01, 0x00fd, 0x000a},
+       {0x01, 0x0038, 0x000b},
+       {0x01, 0x00d1, 0x000c},
+       {0x01, 0x00f7, 0x000d},
+       {0x01, 0x00ed, 0x000e},
+       {0x01, 0x00d8, 0x000f},
+       {0x01, 0x0038, 0x0010},
+       {0x01, 0x00ff, 0x0015},
+       {0x01, 0x0001, 0x0016},
+       {0x01, 0x0032, 0x0017},
+       {0x01, 0x0023, 0x0018},
+       {0x01, 0x00ce, 0x0019},
+       {0x01, 0x0023, 0x001a},
+       {0x01, 0x0032, 0x001b},
+       {0x01, 0x008d, 0x001c},
+       {0x01, 0x00ce, 0x001d},
+       {0x01, 0x008d, 0x001e},
+       {0x01, 0x0000, 0x001f},
+       {0x01, 0x0000, 0x0020},
+       {0x01, 0x00ff, 0x003e},
+       {0x01, 0x0003, 0x003f},
+       {0x01, 0x0000, 0x0040},
+       {0x01, 0x0035, 0x0041},
+       {0x01, 0x0053, 0x0042},
+       {0x01, 0x0069, 0x0043},
+       {0x01, 0x007c, 0x0044},
+       {0x01, 0x008c, 0x0045},
+       {0x01, 0x009a, 0x0046},
+       {0x01, 0x00a8, 0x0047},
+       {0x01, 0x00b4, 0x0048},
+       {0x01, 0x00bf, 0x0049},
+       {0x01, 0x00ca, 0x004a},
+       {0x01, 0x00d4, 0x004b},
+       {0x01, 0x00dd, 0x004c},
+       {0x01, 0x00e7, 0x004d},
+       {0x01, 0x00ef, 0x004e},
+       {0x01, 0x00f8, 0x004f},
+       {0x01, 0x00ff, 0x0050},
+       {0x01, 0x0001, 0x0056},
+       {0x01, 0x0060, 0x0057},
+       {0x01, 0x0040, 0x0058},
+       {0x01, 0x0011, 0x0059},
+       {0x01, 0x0001, 0x005a},
+       {0x02, 0x0007, 0x0005},
+       {0x02, 0xa048, 0x0000},
+       {0x02, 0x0007, 0x0005},
+       {0x02, 0x0015, 0x0006},
+       {0x02, 0x100a, 0x0007},
+       {0x02, 0xa048, 0x0000},
+       {0x02, 0xc002, 0x0001},
+       {0x02, 0x000f, 0x0005},
+       {0x02, 0xa048, 0x0000},
+       {0x05, 0x0022, 0x0004},
+       {0x05, 0x0025, 0x0001},
+       {0x05, 0x0000, 0x0000},
+       {0x05, 0x0026, 0x0001},
+       {0x05, 0x0001, 0x0000},
+       {0x05, 0x0027, 0x0001},
+       {0x05, 0x0000, 0x0000},
+       {0x05, 0x0001, 0x0001},
+       {0x05, 0x0000, 0x0000},
+       {0x05, 0x0021, 0x0001},
+       {0x05, 0x00d2, 0x0000},
+       {0x05, 0x0020, 0x0001},
+       {0x05, 0x0000, 0x0000},
+       {0x00, 0x0090, 0x0005},
+       {0x01, 0x00a6, 0x0000},
+       {0x05, 0x0026, 0x0001},
+       {0x05, 0x0001, 0x0000},
+       {0x05, 0x0027, 0x0001},
+       {0x05, 0x001e, 0x0000},
+       {0x01, 0x0003, 0x003f},
+       {0x01, 0x0001, 0x0056},
+       {0x01, 0x0011, 0x0008},
+       {0x01, 0x0032, 0x0009},
+       {0x01, 0xfffd, 0x000a},
+       {0x01, 0x0023, 0x000b},
+       {0x01, 0xffea, 0x000c},
+       {0x01, 0xfff4, 0x000d},
+       {0x01, 0xfffc, 0x000e},
+       {0x01, 0xffe3, 0x000f},
+       {0x01, 0x001f, 0x0010},
+       {0x01, 0x00a8, 0x0001},
+       {0x01, 0x0067, 0x0007},
+       {0x01, 0x0042, 0x0051},
+       {0x01, 0x0051, 0x0053},
+       {0x01, 0x000a, 0x0003},
+       {0x02, 0xc002, 0x0001},
+       {0x02, 0x0007, 0x0005},
+       {0x01, 0x0042, 0x0051},
+       {0x01, 0x0051, 0x0053},
+       {0x05, 0x0026, 0x0001},
+       {0x05, 0x0001, 0x0000},
+       {0x05, 0x0027, 0x0001},
+       {0x05, 0x002d, 0x0000},
+       {0x01, 0x0003, 0x003f},
+       {0x01, 0x0001, 0x0056},
+       {0x02, 0xc000, 0x0001},
+       {0x02, 0x0000, 0x0005},
+       {}
+};
+
+/* Unknow camera from Ori Usbid 0x0000:0x0000 */
+/* Based on snoops from Ori Cohen */
+static __u16 spca501c_mysterious_open_data[][3] = {
+       {0x02, 0x000f, 0x0005},
+       {0x02, 0xa048, 0x0000},
+       {0x05, 0x0022, 0x0004},
+/* DSP Registers */
+       {0x01, 0x0016, 0x0011}, /* RGB offset */
+       {0x01, 0x0000, 0x0012},
+       {0x01, 0x0006, 0x0013},
+       {0x01, 0x0078, 0x0051},
+       {0x01, 0x0040, 0x0052},
+       {0x01, 0x0046, 0x0053},
+       {0x01, 0x0040, 0x0054},
+       {0x00, 0x0025, 0x0000},
+/*     {0x00, 0x0000, 0x0000 }, */
+/* Part 2 */
+/* TG Registers */
+       {0x00, 0x0026, 0x0000},
+       {0x00, 0x0001, 0x0000},
+       {0x00, 0x0027, 0x0000},
+       {0x00, 0x008a, 0x0000},
+       {0x02, 0x0007, 0x0005},
+       {0x02, 0x2000, 0x0000},
+       {0x05, 0x0022, 0x0004},
+       {0x05, 0x0015, 0x0001},
+       {0x05, 0x00ea, 0x0000},
+       {0x05, 0x0021, 0x0001},
+       {0x05, 0x00d2, 0x0000},
+       {0x05, 0x0023, 0x0001},
+       {0x05, 0x0003, 0x0000},
+       {0x05, 0x0030, 0x0001},
+       {0x05, 0x002b, 0x0000},
+       {0x05, 0x0031, 0x0001},
+       {0x05, 0x0023, 0x0000},
+       {0x05, 0x0032, 0x0001},
+       {0x05, 0x0023, 0x0000},
+       {0x05, 0x0033, 0x0001},
+       {0x05, 0x0023, 0x0000},
+       {0x05, 0x0034, 0x0001},
+       {0x05, 0x0002, 0x0000},
+       {0x05, 0x0050, 0x0001},
+       {0x05, 0x0000, 0x0000},
+       {0x05, 0x0051, 0x0001},
+       {0x05, 0x0000, 0x0000},
+       {0x05, 0x0052, 0x0001},
+       {0x05, 0x0000, 0x0000},
+       {0x05, 0x0054, 0x0001},
+       {0x05, 0x0001, 0x0000},
+       {}
+};
+
+/* Based on snoops from Ori Cohen */
+static __u16 spca501c_mysterious_init_data[][3] = {
+/* Part 3 */
+/* TG registers */
+/*     {0x00, 0x0000, 0x0000}, */
+       {0x00, 0x0000, 0x0001},
+       {0x00, 0x0000, 0x0002},
+       {0x00, 0x0006, 0x0003},
+       {0x00, 0x0000, 0x0004},
+       {0x00, 0x0090, 0x0005},
+       {0x00, 0x0000, 0x0006},
+       {0x00, 0x0040, 0x0007},
+       {0x00, 0x00c0, 0x0008},
+       {0x00, 0x004a, 0x0009},
+       {0x00, 0x0000, 0x000a},
+       {0x00, 0x0000, 0x000b},
+       {0x00, 0x0001, 0x000c},
+       {0x00, 0x0001, 0x000d},
+       {0x00, 0x0000, 0x000e},
+       {0x00, 0x0002, 0x000f},
+       {0x00, 0x0001, 0x0010},
+       {0x00, 0x0000, 0x0011},
+       {0x00, 0x0001, 0x0012},
+       {0x00, 0x0002, 0x0020},
+       {0x00, 0x0080, 0x0021}, /* 640 */
+       {0x00, 0x0001, 0x0022},
+       {0x00, 0x00e0, 0x0023}, /* 480 */
+       {0x00, 0x0000, 0x0024}, /* Offset H hight */
+       {0x00, 0x00d3, 0x0025}, /* low */
+       {0x00, 0x0000, 0x0026}, /* Offset V */
+       {0x00, 0x000d, 0x0027}, /* low */
+       {0x00, 0x0000, 0x0046},
+       {0x00, 0x0000, 0x0047},
+       {0x00, 0x0000, 0x0048},
+       {0x00, 0x0000, 0x0049},
+       {0x00, 0x0008, 0x004a},
+/* DSP Registers        */
+       {0x01, 0x00a6, 0x0000},
+       {0x01, 0x0028, 0x0001},
+       {0x01, 0x0000, 0x0002},
+       {0x01, 0x000a, 0x0003}, /* Level Calc bit7 ->1 Auto */
+       {0x01, 0x0040, 0x0004},
+       {0x01, 0x0066, 0x0007},
+       {0x01, 0x000f, 0x0008}, /* A11 Color correction coeff */
+       {0x01, 0x002d, 0x0009}, /* A12 */
+       {0x01, 0x0005, 0x000a}, /* A13 */
+       {0x01, 0x0023, 0x000b}, /* A21 */
+       {0x01, 0x00e0, 0x000c}, /* A22 */
+       {0x01, 0x00fd, 0x000d}, /* A23 */
+       {0x01, 0x00f4, 0x000e}, /* A31 */
+       {0x01, 0x00e4, 0x000f}, /* A32 */
+       {0x01, 0x0028, 0x0010}, /* A33 */
+       {0x01, 0x00ff, 0x0015}, /* Reserved */
+       {0x01, 0x0001, 0x0016}, /* Reserved */
+       {0x01, 0x0032, 0x0017}, /* Win1 Start begin */
+       {0x01, 0x0023, 0x0018},
+       {0x01, 0x00ce, 0x0019},
+       {0x01, 0x0023, 0x001a},
+       {0x01, 0x0032, 0x001b},
+       {0x01, 0x008d, 0x001c},
+       {0x01, 0x00ce, 0x001d},
+       {0x01, 0x008d, 0x001e},
+       {0x01, 0x0000, 0x001f},
+       {0x01, 0x0000, 0x0020}, /* Win1 Start end */
+       {0x01, 0x00ff, 0x003e}, /* Reserved begin */
+       {0x01, 0x0002, 0x003f},
+       {0x01, 0x0000, 0x0040},
+       {0x01, 0x0035, 0x0041},
+       {0x01, 0x0053, 0x0042},
+       {0x01, 0x0069, 0x0043},
+       {0x01, 0x007c, 0x0044},
+       {0x01, 0x008c, 0x0045},
+       {0x01, 0x009a, 0x0046},
+       {0x01, 0x00a8, 0x0047},
+       {0x01, 0x00b4, 0x0048},
+       {0x01, 0x00bf, 0x0049},
+       {0x01, 0x00ca, 0x004a},
+       {0x01, 0x00d4, 0x004b},
+       {0x01, 0x00dd, 0x004c},
+       {0x01, 0x00e7, 0x004d},
+       {0x01, 0x00ef, 0x004e},
+       {0x01, 0x00f8, 0x004f},
+       {0x01, 0x00ff, 0x0050},
+       {0x01, 0x0003, 0x0056}, /* Reserved end */
+       {0x01, 0x0060, 0x0057}, /* Edge Gain */
+       {0x01, 0x0040, 0x0058},
+       {0x01, 0x0011, 0x0059}, /* Edge Bandwidth */
+       {0x01, 0x0001, 0x005a},
+       {0x02, 0x0007, 0x0005},
+       {0x02, 0xa048, 0x0000},
+       {0x02, 0x0007, 0x0005},
+       {0x02, 0x0015, 0x0006},
+       {0x02, 0x200a, 0x0007},
+       {0x02, 0xa048, 0x0000},
+       {0x02, 0xc000, 0x0001},
+       {0x02, 0x000f, 0x0005},
+       {0x02, 0xa048, 0x0000},
+       {0x05, 0x0022, 0x0004},
+       {0x05, 0x0025, 0x0001},
+       {0x05, 0x0000, 0x0000},
+/* Part 4             */
+       {0x05, 0x0026, 0x0001},
+       {0x05, 0x0001, 0x0000},
+       {0x05, 0x0027, 0x0001},
+       {0x05, 0x0000, 0x0000},
+       {0x05, 0x0001, 0x0001},
+       {0x05, 0x0000, 0x0000},
+       {0x05, 0x0021, 0x0001},
+       {0x05, 0x00d2, 0x0000},
+       {0x05, 0x0020, 0x0001},
+       {0x05, 0x0000, 0x0000},
+       {0x00, 0x0090, 0x0005},
+       {0x01, 0x00a6, 0x0000},
+       {0x02, 0x0000, 0x0005},
+       {0x05, 0x0026, 0x0001},
+       {0x05, 0x0001, 0x0000},
+       {0x05, 0x0027, 0x0001},
+       {0x05, 0x004e, 0x0000},
+/* Part 5               */
+       {0x01, 0x0003, 0x003f},
+       {0x01, 0x0001, 0x0056},
+       {0x01, 0x000f, 0x0008},
+       {0x01, 0x002d, 0x0009},
+       {0x01, 0x0005, 0x000a},
+       {0x01, 0x0023, 0x000b},
+       {0x01, 0xffe0, 0x000c},
+       {0x01, 0xfffd, 0x000d},
+       {0x01, 0xfff4, 0x000e},
+       {0x01, 0xffe4, 0x000f},
+       {0x01, 0x0028, 0x0010},
+       {0x01, 0x00a8, 0x0001},
+       {0x01, 0x0066, 0x0007},
+       {0x01, 0x0032, 0x0017},
+       {0x01, 0x0023, 0x0018},
+       {0x01, 0x00ce, 0x0019},
+       {0x01, 0x0023, 0x001a},
+       {0x01, 0x0032, 0x001b},
+       {0x01, 0x008d, 0x001c},
+       {0x01, 0x00ce, 0x001d},
+       {0x01, 0x008d, 0x001e},
+       {0x01, 0x00c8, 0x0015}, /* c8 Poids fort Luma */
+       {0x01, 0x0032, 0x0016}, /* 32 */
+       {0x01, 0x0016, 0x0011}, /* R 00 */
+       {0x01, 0x0016, 0x0012}, /* G 00 */
+       {0x01, 0x0016, 0x0013}, /* B 00 */
+       {0x01, 0x000a, 0x0003},
+       {0x02, 0xc002, 0x0001},
+       {0x02, 0x0007, 0x0005},
+       {}
+};
+
+static int reg_write(struct usb_device *dev,
+                    __u16 req, __u16 index, __u16 value)
+{
+       int ret;
+
+       ret = usb_control_msg(dev,
+                       usb_sndctrlpipe(dev, 0),
+                       req,
+                       USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       value, index, NULL, 0, 500);
+       PDEBUG(D_USBO, "reg write: 0x%02x 0x%02x 0x%02x",
+               req, index, value);
+       if (ret < 0)
+               PDEBUG(D_ERR, "reg write: error %d", ret);
+       return ret;
+}
+
+/* returns: negative is error, pos or zero is data */
+static int reg_read(struct usb_device *dev,
+                       __u16 req,      /* bRequest */
+                       __u16 index,    /* wIndex */
+                       __u16 length)   /* wLength (1 or 2 only) */
+{
+       int ret;
+       __u8 buf[2];
+
+       buf[1] = 0;
+       ret = usb_control_msg(dev,
+                       usb_rcvctrlpipe(dev, 0),
+                       req,
+                       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       0,              /* value */
+                       index,
+                       buf, length,
+                       500);                   /* timeout */
+       if (ret < 0) {
+               PDEBUG(D_ERR, "reg_read err %d", ret);
+               return -1;
+       }
+       return (buf[1] << 8) + buf[0];
+}
+
+static int write_vector(struct gspca_dev *gspca_dev,
+                               __u16 data[][3])
+{
+       struct usb_device *dev = gspca_dev->dev;
+       int ret, i = 0;
+
+       while (data[i][0] != 0 || data[i][1] != 0 || data[i][2] != 0) {
+               ret = reg_write(dev, data[i][0], data[i][2], data[i][1]);
+               if (ret < 0) {
+                       PDEBUG(D_ERR,
+                               "Reg write failed for 0x%02x,0x%02x,0x%02x",
+                               data[i][0], data[i][1], data[i][2]);
+                       return ret;
+               }
+               i++;
+       }
+       return 0;
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x11, sd->brightness);
+       reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x12, sd->brightness);
+       reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x13, sd->brightness);
+}
+
+static void getbrightness(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       __u16 brightness;
+
+       brightness = reg_read(gspca_dev->dev, SPCA501_REG_CCDSP, 0x11, 2);
+       sd->brightness = brightness << 1;
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       reg_write(gspca_dev->dev, 0x00, 0x00,
+                                 (sd->contrast >> 8) & 0xff);
+       reg_write(gspca_dev->dev, 0x00, 0x01,
+                                 sd->contrast & 0xff);
+}
+
+static void getcontrast(struct gspca_dev *gspca_dev)
+{
+/*     spca50x->contrast = 0xaa01; */
+}
+
+static void setcolors(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x0c, sd->colors);
+}
+
+static void getcolors(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->colors = reg_read(gspca_dev->dev, SPCA501_REG_CCDSP, 0x0c, 2);
+/*     sd->hue = (reg_read(gspca_dev->dev, SPCA501_REG_CCDSP, 0x13, */
+/*                     2) & 0xFF) << 8; */
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+                       const struct usb_device_id *id)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct cam *cam;
+       __u16 vendor;
+       __u16 product;
+
+       vendor = id->idVendor;
+       product = id->idProduct;
+       switch (vendor) {
+       case 0x0000:            /* Unknow Camera */
+/*             switch (product) { */
+/*             case 0x0000: */
+                       sd->subtype = MystFromOriUnknownCamera;
+/*                     break; */
+/*             } */
+               break;
+       case 0x040a:            /* Kodak cameras */
+/*             switch (product) { */
+/*             case 0x0002: */
+                       sd->subtype = KodakDVC325;
+/*                     break; */
+/*             } */
+               break;
+       case 0x0497:            /* Smile International */
+/*             switch (product) { */
+/*             case 0xc001: */
+                       sd->subtype = SmileIntlCamera;
+/*                     break; */
+/*             } */
+               break;
+       case 0x0506:            /* 3COM cameras */
+/*             switch (product) { */
+/*             case 0x00df: */
+                       sd->subtype = ThreeComHomeConnectLite;
+/*                     break; */
+/*             } */
+               break;
+       case 0x0733:    /* Rebadged ViewQuest (Intel) and ViewQuest cameras */
+               switch (product) {
+               case 0x0401:
+                       sd->subtype = IntelCreateAndShare;
+                       break;
+               case 0x0402:
+                       sd->subtype = ViewQuestM318B;
+                       break;
+               }
+               break;
+       case 0x1776:            /* Arowana */
+/*             switch (product) { */
+/*             case 0x501c: */
+                       sd->subtype = Arowana300KCMOSCamera;
+/*                     break; */
+/*             } */
+               break;
+       }
+       cam = &gspca_dev->cam;
+       cam->dev_name = (char *) id->driver_info;
+       cam->epaddr = 0x01;
+       cam->cam_mode = vga_mode;
+       cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+       sd->brightness = sd_ctrls[MY_BRIGHTNESS].qctrl.default_value;
+       sd->contrast = sd_ctrls[MY_CONTRAST].qctrl.default_value;
+       sd->colors = sd_ctrls[MY_COLOR].qctrl.default_value;
+
+       switch (sd->subtype) {
+       case Arowana300KCMOSCamera:
+       case SmileIntlCamera:
+               /* Arowana 300k CMOS Camera data */
+               if (write_vector(gspca_dev, spca501c_arowana_init_data))
+                       goto error;
+               break;
+       case MystFromOriUnknownCamera:
+               /* UnKnow Ori CMOS Camera data */
+               if (write_vector(gspca_dev, spca501c_mysterious_open_data))
+                       goto error;
+               break;
+       default:
+               /* generic spca501 init data */
+               if (write_vector(gspca_dev, spca501_init_data))
+                       goto error;
+               break;
+       }
+       return 0;
+error:
+       return -EINVAL;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       PDEBUG(D_STREAM, "SPCA501 init");
+       switch (sd->subtype) {
+       case ThreeComHomeConnectLite:
+               /* Special handling for 3com data */
+               write_vector(gspca_dev, spca501_3com_open_data);
+               break;
+       case Arowana300KCMOSCamera:
+       case SmileIntlCamera:
+               /* Arowana 300k CMOS Camera data */
+               write_vector(gspca_dev, spca501c_arowana_open_data);
+               break;
+       case MystFromOriUnknownCamera:
+               /* UnKnow  CMOS Camera data */
+               write_vector(gspca_dev, spca501c_mysterious_init_data);
+               break;
+       default:
+               /* Generic 501 open data */
+               write_vector(gspca_dev, spca501_open_data);
+       }
+       PDEBUG(D_STREAM, "Initializing SPCA501 finished");
+       return 0;
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+       struct usb_device *dev = gspca_dev->dev;
+       int mode;
+
+       /* memorize the wanted pixel format */
+       mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].mode;
+
+       /* Enable ISO packet machine CTRL reg=2,
+        * index=1 bitmask=0x2 (bit ordinal 1) */
+       reg_write(dev, SPCA50X_REG_USB, 0x6, 0x94);
+       switch (mode) {
+       case 0: /* 640x480 */
+               reg_write(dev, SPCA50X_REG_USB, 0x07, 0x004a);
+               break;
+       case 1: /* 320x240 */
+               reg_write(dev, SPCA50X_REG_USB, 0x07, 0x104a);
+               break;
+       default:
+/*     case 2:  * 160x120 */
+               reg_write(dev, SPCA50X_REG_USB, 0x07, 0x204a);
+               break;
+       }
+       reg_write(dev, SPCA501_REG_CTLRL, 0x01, 0x02);
+
+       /* HDG atleast the Intel CreateAndShare needs to have one of its
+        * brightness / contrast / color set otherwise it assumes wath seems
+        * max contrast. Note that strange enough setting any of these is
+        * enough to fix the max contrast problem, to be sure we set all 3 */
+       setbrightness(gspca_dev);
+       setcontrast(gspca_dev);
+       setcolors(gspca_dev);
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+       /* Disable ISO packet
+        * machine CTRL reg=2, index=1 bitmask=0x0 (bit ordinal 1) */
+       reg_write(gspca_dev->dev, SPCA501_REG_CTLRL, 0x01, 0x00);
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+/* this function is called at close time */
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+       reg_write(gspca_dev->dev, SPCA501_REG_CTLRL, 0x05, 0x00);
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+                       struct gspca_frame *frame,      /* target */
+                       __u8 *data,                     /* isoc packet */
+                       int len)                        /* iso packet length */
+{
+       switch (data[0]) {
+       case 0:                         /* start of frame */
+               frame = gspca_frame_add(gspca_dev,
+                                       LAST_PACKET,
+                                       frame,
+                                       data, 0);
+               data += SPCA501_OFFSET_DATA;
+               len -= SPCA501_OFFSET_DATA;
+               gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+                               data, len);
+               return;
+       case 0xff:                      /* drop */
+/*             gspca_dev->last_packet_type = DISCARD_PACKET; */
+               return;
+       }
+       data++;
+       len--;
+       gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+                       data, len);
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->brightness = val;
+       if (gspca_dev->streaming)
+               setbrightness(gspca_dev);
+       return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       getbrightness(gspca_dev);
+       *val = sd->brightness;
+       return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->contrast = val;
+       if (gspca_dev->streaming)
+               setcontrast(gspca_dev);
+       return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       getcontrast(gspca_dev);
+       *val = sd->contrast;
+       return 0;
+}
+
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->colors = val;
+       if (gspca_dev->streaming)
+               setcolors(gspca_dev);
+       return 0;
+}
+
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       getcolors(gspca_dev);
+       *val = sd->colors;
+       return 0;
+}
+
+/* sub-driver description */
+static struct sd_desc sd_desc = {
+       .name = MODULE_NAME,
+       .ctrls = sd_ctrls,
+       .nctrls = ARRAY_SIZE(sd_ctrls),
+       .config = sd_config,
+       .open = sd_open,
+       .start = sd_start,
+       .stopN = sd_stopN,
+       .stop0 = sd_stop0,
+       .close = sd_close,
+       .pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static __devinitdata struct usb_device_id device_table[] = {
+       {USB_DEVICE(0x040a, 0x0002), DVNM("Kodak DVC-325")},
+       {USB_DEVICE(0x0497, 0xc001), DVNM("Smile International")},
+       {USB_DEVICE(0x0506, 0x00df), DVNM("3Com HomeConnect Lite")},
+       {USB_DEVICE(0x0733, 0x0401), DVNM("Intel Create and Share")},
+       {USB_DEVICE(0x0733, 0x0402), DVNM("ViewQuest M318B")},
+       {USB_DEVICE(0x1776, 0x501c), DVNM("Arowana 300K CMOS Camera")},
+       {USB_DEVICE(0x0000, 0x0000), DVNM("MystFromOri Unknow Camera")},
+       {}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+                       const struct usb_device_id *id)
+{
+       return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+                               THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+       .name = MODULE_NAME,
+       .id_table = device_table,
+       .probe = sd_probe,
+       .disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+       if (usb_register(&sd_driver) < 0)
+               return -1;
+       PDEBUG(D_PROBE, "v%s registered", version);
+       return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+       usb_deregister(&sd_driver);
+       PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/spca505.c b/drivers/media/video/gspca/spca505.c
new file mode 100644 (file)
index 0000000..5b23518
--- /dev/null
@@ -0,0 +1,933 @@
+/*
+ * SPCA505 chip based cameras initialization data
+ *
+ * V4L2 by Jean-Francis Moine <http://moinejf.free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#define MODULE_NAME "spca505"
+
+#include "gspca.h"
+
+#define DRIVER_VERSION_NUMBER  KERNEL_VERSION(2, 1, 0)
+static const char version[] = "2.1.0";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("GSPCA/SPCA505 USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+       struct gspca_dev gspca_dev;             /* !! must be the first item */
+
+       int buflen;
+       unsigned char tmpbuf[640 * 480 * 3 / 2]; /* YYUV per line */
+       unsigned char tmpbuf2[640 * 480 * 2];   /* YUYV */
+
+       unsigned char brightness;
+
+       char subtype;
+#define IntelPCCameraPro 0
+#define Nxultra 1
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+#define SD_BRIGHTNESS 0
+       {
+           {
+               .id      = V4L2_CID_BRIGHTNESS,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Brightness",
+               .minimum = 0,
+               .maximum = 255,
+               .step    = 1,
+               .default_value = 127,
+           },
+           .set = sd_setbrightness,
+           .get = sd_getbrightness,
+       },
+};
+
+static struct cam_mode vga_mode[] = {
+       {V4L2_PIX_FMT_YUYV, 160, 120, 5},
+       {V4L2_PIX_FMT_YUYV, 176, 144, 4},
+       {V4L2_PIX_FMT_YUYV, 320, 240, 2},
+       {V4L2_PIX_FMT_YUYV, 352, 288, 1},
+       {V4L2_PIX_FMT_YUYV, 640, 480, 0},
+};
+
+#define SPCA50X_OFFSET_DATA 10
+
+#define SPCA50X_REG_USB 0x02   /* spca505 501 */
+
+#define SPCA50X_USB_CTRL 0x00  /* spca505 */
+#define SPCA50X_CUSB_ENABLE 0x01 /* spca505 */
+#define SPCA50X_REG_GLOBAL 0x03        /* spca505 */
+#define SPCA50X_GMISC0_IDSEL 0x01 /* Global control device ID select spca505 */
+#define SPCA50X_GLOBAL_MISC0 0x00 /* Global control miscellaneous 0 spca505 */
+
+#define SPCA50X_GLOBAL_MISC1 0x01 /* 505 */
+#define SPCA50X_GLOBAL_MISC3 0x03 /* 505 */
+#define SPCA50X_GMISC3_SAA7113RST 0x20 /* Not sure about this one spca505 */
+
+/*
+ * Data to initialize a SPCA505. Common to the CCD and external modes
+ */
+static __u16 spca505_init_data[][3] = {
+       /* line    bmRequest,value,index */
+       /* 1819 */
+       {SPCA50X_REG_GLOBAL, SPCA50X_GMISC3_SAA7113RST, SPCA50X_GLOBAL_MISC3},
+       /* Sensor reset */
+       /* 1822 */ {SPCA50X_REG_GLOBAL, 0x00, SPCA50X_GLOBAL_MISC3},
+       /* 1825 */ {SPCA50X_REG_GLOBAL, 0x00, SPCA50X_GLOBAL_MISC1},
+       /* Block USB reset */
+       /* 1828 */ {SPCA50X_REG_GLOBAL, SPCA50X_GMISC0_IDSEL,
+               SPCA50X_GLOBAL_MISC0},
+
+       /* 1831 */ {0x5, 0x01, 0x10},
+                                       /* Maybe power down some stuff */
+       /* 1834 */ {0x5, 0x0f, 0x11},
+
+       /* Setup internal CCD  ? */
+       /* 1837 */ {0x6, 0x10, 0x08},
+       /* 1840 */ {0x6, 0x00, 0x09},
+       /* 1843 */ {0x6, 0x00, 0x0a},
+       /* 1846 */ {0x6, 0x00, 0x0b},
+       /* 1849 */ {0x6, 0x10, 0x0c},
+       /* 1852 */ {0x6, 0x00, 0x0d},
+       /* 1855 */ {0x6, 0x00, 0x0e},
+       /* 1858 */ {0x6, 0x00, 0x0f},
+       /* 1861 */ {0x6, 0x10, 0x10},
+       /* 1864 */ {0x6, 0x02, 0x11},
+       /* 1867 */ {0x6, 0x00, 0x12},
+       /* 1870 */ {0x6, 0x04, 0x13},
+       /* 1873 */ {0x6, 0x02, 0x14},
+       /* 1876 */ {0x6, 0x8a, 0x51},
+       /* 1879 */ {0x6, 0x40, 0x52},
+       /* 1882 */ {0x6, 0xb6, 0x53},
+       /* 1885 */ {0x6, 0x3d, 0x54},
+       {}
+};
+
+/*
+ * Data to initialize the camera using the internal CCD
+ */
+static __u16 spca505_open_data_ccd[][3] = {
+       /* line    bmRequest,value,index */
+       /* Internal CCD data set */
+       /* 1891 */ {0x3, 0x04, 0x01},
+       /* This could be a reset */
+       /* 1894 */ {0x3, 0x00, 0x01},
+
+       /* Setup compression and image registers. 0x6 and 0x7 seem to be
+          related to H&V hold, and are resolution mode specific */
+               /* 1897 */ {0x4, 0x10, 0x01},
+               /* DIFF(0x50), was (0x10) */
+       /* 1900 */ {0x4, 0x00, 0x04},
+       /* 1903 */ {0x4, 0x00, 0x05},
+       /* 1906 */ {0x4, 0x20, 0x06},
+       /* 1909 */ {0x4, 0x20, 0x07},
+
+       /* 1912 */ {0x8, 0x0a, 0x00},
+       /* DIFF (0x4a), was (0xa) */
+
+       /* 1915 */ {0x5, 0x00, 0x10},
+       /* 1918 */ {0x5, 0x00, 0x11},
+       /* 1921 */ {0x5, 0x00, 0x00},
+       /* DIFF not written */
+       /* 1924 */ {0x5, 0x00, 0x01},
+       /* DIFF not written */
+       /* 1927 */ {0x5, 0x00, 0x02},
+       /* DIFF not written */
+       /* 1930 */ {0x5, 0x00, 0x03},
+       /* DIFF not written */
+       /* 1933 */ {0x5, 0x00, 0x04},
+       /* DIFF not written */
+               /* 1936 */ {0x5, 0x80, 0x05},
+               /* DIFF not written */
+               /* 1939 */ {0x5, 0xe0, 0x06},
+               /* DIFF not written */
+               /* 1942 */ {0x5, 0x20, 0x07},
+               /* DIFF not written */
+               /* 1945 */ {0x5, 0xa0, 0x08},
+               /* DIFF not written */
+               /* 1948 */ {0x5, 0x0, 0x12},
+               /* DIFF not written */
+       /* 1951 */ {0x5, 0x02, 0x0f},
+       /* DIFF not written */
+               /* 1954 */ {0x5, 0x10, 0x46},
+               /* DIFF not written */
+               /* 1957 */ {0x5, 0x8, 0x4a},
+               /* DIFF not written */
+
+       /* 1960 */ {0x3, 0x08, 0x03},
+       /* DIFF (0x3,0x28,0x3) */
+       /* 1963 */ {0x3, 0x08, 0x01},
+       /* 1966 */ {0x3, 0x0c, 0x03},
+       /* DIFF not written */
+               /* 1969 */ {0x3, 0x21, 0x00},
+               /* DIFF (0x39) */
+
+/* Extra block copied from init to hopefully ensure CCD is in a sane state */
+       /* 1837 */ {0x6, 0x10, 0x08},
+       /* 1840 */ {0x6, 0x00, 0x09},
+       /* 1843 */ {0x6, 0x00, 0x0a},
+       /* 1846 */ {0x6, 0x00, 0x0b},
+       /* 1849 */ {0x6, 0x10, 0x0c},
+       /* 1852 */ {0x6, 0x00, 0x0d},
+       /* 1855 */ {0x6, 0x00, 0x0e},
+       /* 1858 */ {0x6, 0x00, 0x0f},
+       /* 1861 */ {0x6, 0x10, 0x10},
+       /* 1864 */ {0x6, 0x02, 0x11},
+       /* 1867 */ {0x6, 0x00, 0x12},
+       /* 1870 */ {0x6, 0x04, 0x13},
+       /* 1873 */ {0x6, 0x02, 0x14},
+       /* 1876 */ {0x6, 0x8a, 0x51},
+       /* 1879 */ {0x6, 0x40, 0x52},
+       /* 1882 */ {0x6, 0xb6, 0x53},
+       /* 1885 */ {0x6, 0x3d, 0x54},
+       /* End of extra block */
+
+               /* 1972 */ {0x6, 0x3f, 0x1},
+               /* Block skipped */
+       /* 1975 */ {0x6, 0x10, 0x02},
+       /* 1978 */ {0x6, 0x64, 0x07},
+       /* 1981 */ {0x6, 0x10, 0x08},
+       /* 1984 */ {0x6, 0x00, 0x09},
+       /* 1987 */ {0x6, 0x00, 0x0a},
+       /* 1990 */ {0x6, 0x00, 0x0b},
+       /* 1993 */ {0x6, 0x10, 0x0c},
+       /* 1996 */ {0x6, 0x00, 0x0d},
+       /* 1999 */ {0x6, 0x00, 0x0e},
+       /* 2002 */ {0x6, 0x00, 0x0f},
+       /* 2005 */ {0x6, 0x10, 0x10},
+       /* 2008 */ {0x6, 0x02, 0x11},
+       /* 2011 */ {0x6, 0x00, 0x12},
+       /* 2014 */ {0x6, 0x04, 0x13},
+       /* 2017 */ {0x6, 0x02, 0x14},
+       /* 2020 */ {0x6, 0x8a, 0x51},
+       /* 2023 */ {0x6, 0x40, 0x52},
+       /* 2026 */ {0x6, 0xb6, 0x53},
+       /* 2029 */ {0x6, 0x3d, 0x54},
+       /* 2032 */ {0x6, 0x60, 0x57},
+       /* 2035 */ {0x6, 0x20, 0x58},
+       /* 2038 */ {0x6, 0x15, 0x59},
+       /* 2041 */ {0x6, 0x05, 0x5a},
+
+       /* 2044 */ {0x5, 0x01, 0xc0},
+       /* 2047 */ {0x5, 0x10, 0xcb},
+               /* 2050 */ {0x5, 0x80, 0xc1},
+               /* */
+               /* 2053 */ {0x5, 0x0, 0xc2},
+               /* 4 was 0 */
+       /* 2056 */ {0x5, 0x00, 0xca},
+               /* 2059 */ {0x5, 0x80, 0xc1},
+               /*  */
+       /* 2062 */ {0x5, 0x04, 0xc2},
+       /* 2065 */ {0x5, 0x00, 0xca},
+               /* 2068 */ {0x5, 0x0, 0xc1},
+               /*  */
+       /* 2071 */ {0x5, 0x00, 0xc2},
+       /* 2074 */ {0x5, 0x00, 0xca},
+               /* 2077 */ {0x5, 0x40, 0xc1},
+               /* */
+       /* 2080 */ {0x5, 0x17, 0xc2},
+       /* 2083 */ {0x5, 0x00, 0xca},
+               /* 2086 */ {0x5, 0x80, 0xc1},
+               /* */
+       /* 2089 */ {0x5, 0x06, 0xc2},
+       /* 2092 */ {0x5, 0x00, 0xca},
+               /* 2095 */ {0x5, 0x80, 0xc1},
+               /* */
+       /* 2098 */ {0x5, 0x04, 0xc2},
+       /* 2101 */ {0x5, 0x00, 0xca},
+
+       /* 2104 */ {0x3, 0x4c, 0x3},
+       /* 2107 */ {0x3, 0x18, 0x1},
+
+       /* 2110 */ {0x6, 0x70, 0x51},
+       /* 2113 */ {0x6, 0xbe, 0x53},
+       /* 2116 */ {0x6, 0x71, 0x57},
+       /* 2119 */ {0x6, 0x20, 0x58},
+       /* 2122 */ {0x6, 0x05, 0x59},
+       /* 2125 */ {0x6, 0x15, 0x5a},
+
+       /* 2128 */ {0x4, 0x00, 0x08},
+       /* Compress = OFF (0x1 to turn on) */
+       /* 2131 */ {0x4, 0x12, 0x09},
+       /* 2134 */ {0x4, 0x21, 0x0a},
+       /* 2137 */ {0x4, 0x10, 0x0b},
+       /* 2140 */ {0x4, 0x21, 0x0c},
+       /* 2143 */ {0x4, 0x05, 0x00},
+       /* was 5 (Image Type ? ) */
+       /* 2146 */ {0x4, 0x00, 0x01},
+
+       /* 2149 */ {0x6, 0x3f, 0x01},
+
+       /* 2152 */ {0x4, 0x00, 0x04},
+       /* 2155 */ {0x4, 0x00, 0x05},
+       /* 2158 */ {0x4, 0x40, 0x06},
+       /* 2161 */ {0x4, 0x40, 0x07},
+
+       /* 2164 */ {0x6, 0x1c, 0x17},
+       /* 2167 */ {0x6, 0xe2, 0x19},
+       /* 2170 */ {0x6, 0x1c, 0x1b},
+       /* 2173 */ {0x6, 0xe2, 0x1d},
+       /* 2176 */ {0x6, 0xaa, 0x1f},
+       /* 2179 */ {0x6, 0x70, 0x20},
+
+       /* 2182 */ {0x5, 0x01, 0x10},
+       /* 2185 */ {0x5, 0x00, 0x11},
+       /* 2188 */ {0x5, 0x01, 0x00},
+       /* 2191 */ {0x5, 0x05, 0x01},
+               /* 2194 */ {0x5, 0x00, 0xc1},
+               /* */
+       /* 2197 */ {0x5, 0x00, 0xc2},
+       /* 2200 */ {0x5, 0x00, 0xca},
+
+       /* 2203 */ {0x6, 0x70, 0x51},
+       /* 2206 */ {0x6, 0xbe, 0x53},
+       {}
+};
+
+/*
+   Made by Tomasz Zablocki (skalamandra@poczta.onet.pl)
+ * SPCA505b chip based cameras initialization data
+ *
+ */
+/* jfm */
+#define initial_brightness 0x7f        /* 0x0(white)-0xff(black) */
+/* #define initial_brightness 0x0      //0x0(white)-0xff(black) */
+/*
+ * Data to initialize a SPCA505. Common to the CCD and external modes
+ */
+static __u16 spca505b_init_data[][3] = {
+/* start */
+       {0x02, 0x00, 0x00},             /* init */
+       {0x02, 0x00, 0x01},
+       {0x02, 0x00, 0x02},
+       {0x02, 0x00, 0x03},
+       {0x02, 0x00, 0x04},
+       {0x02, 0x00, 0x05},
+       {0x02, 0x00, 0x06},
+       {0x02, 0x00, 0x07},
+       {0x02, 0x00, 0x08},
+       {0x02, 0x00, 0x09},
+       {0x03, 0x00, 0x00},
+       {0x03, 0x00, 0x01},
+       {0x03, 0x00, 0x02},
+       {0x03, 0x00, 0x03},
+       {0x03, 0x00, 0x04},
+       {0x03, 0x00, 0x05},
+       {0x03, 0x00, 0x06},
+       {0x04, 0x00, 0x00},
+       {0x04, 0x00, 0x02},
+       {0x04, 0x00, 0x04},
+       {0x04, 0x00, 0x05},
+       {0x04, 0x00, 0x06},
+       {0x04, 0x00, 0x07},
+       {0x04, 0x00, 0x08},
+       {0x04, 0x00, 0x09},
+       {0x04, 0x00, 0x0a},
+       {0x04, 0x00, 0x0b},
+       {0x04, 0x00, 0x0c},
+       {0x07, 0x00, 0x00},
+       {0x07, 0x00, 0x03},
+       {0x08, 0x00, 0x00},
+       {0x08, 0x00, 0x01},
+       {0x08, 0x00, 0x02},
+       {0x00, 0x01, 0x00},
+       {0x00, 0x01, 0x01},
+       {0x00, 0x01, 0x34},
+       {0x00, 0x01, 0x35},
+       {0x06, 0x18, 0x08},
+       {0x06, 0xfc, 0x09},
+       {0x06, 0xfc, 0x0a},
+       {0x06, 0xfc, 0x0b},
+       {0x06, 0x18, 0x0c},
+       {0x06, 0xfc, 0x0d},
+       {0x06, 0xfc, 0x0e},
+       {0x06, 0xfc, 0x0f},
+       {0x06, 0x18, 0x10},
+       {0x06, 0xfe, 0x12},
+       {0x06, 0x00, 0x11},
+       {0x06, 0x00, 0x14},
+       {0x06, 0x00, 0x13},
+       {0x06, 0x28, 0x51},
+       {0x06, 0xff, 0x53},
+       {0x02, 0x00, 0x08},
+
+       {0x03, 0x00, 0x03},
+       {0x03, 0x10, 0x03},
+       {}
+};
+
+/*
+ * Data to initialize the camera using the internal CCD
+ */
+static __u16 spca505b_open_data_ccd[][3] = {
+
+/* {0x02,0x00,0x00}, */
+       {0x03, 0x04, 0x01},             /* rst */
+       {0x03, 0x00, 0x01},
+       {0x03, 0x00, 0x00},
+       {0x03, 0x21, 0x00},
+       {0x03, 0x00, 0x04},
+       {0x03, 0x00, 0x03},
+       {0x03, 0x18, 0x03},
+       {0x03, 0x08, 0x01},
+       {0x03, 0x1c, 0x03},
+       {0x03, 0x5c, 0x03},
+       {0x03, 0x5c, 0x03},
+       {0x03, 0x18, 0x01},
+
+/* same as 505 */
+       {0x04, 0x10, 0x01},
+       {0x04, 0x00, 0x04},
+       {0x04, 0x00, 0x05},
+       {0x04, 0x20, 0x06},
+       {0x04, 0x20, 0x07},
+
+       {0x08, 0x0a, 0x00},
+
+       {0x05, 0x00, 0x10},
+       {0x05, 0x00, 0x11},
+       {0x05, 0x00, 0x12},
+       {0x05, 0x6f, 0x00},
+       {0x05, initial_brightness >> 6, 0x00},
+       {0x05, initial_brightness << 2, 0x01},
+       {0x05, 0x00, 0x02},
+       {0x05, 0x01, 0x03},
+       {0x05, 0x00, 0x04},
+       {0x05, 0x03, 0x05},
+       {0x05, 0xe0, 0x06},
+       {0x05, 0x20, 0x07},
+       {0x05, 0xa0, 0x08},
+       {0x05, 0x00, 0x12},
+       {0x05, 0x02, 0x0f},
+       {0x05, 128, 0x14},              /* max exposure off (0=on) */
+       {0x05, 0x01, 0xb0},
+       {0x05, 0x01, 0xbf},
+       {0x03, 0x02, 0x06},
+       {0x05, 0x10, 0x46},
+       {0x05, 0x08, 0x4a},
+
+       {0x06, 0x00, 0x01},
+       {0x06, 0x10, 0x02},
+       {0x06, 0x64, 0x07},
+       {0x06, 0x18, 0x08},
+       {0x06, 0xfc, 0x09},
+       {0x06, 0xfc, 0x0a},
+       {0x06, 0xfc, 0x0b},
+       {0x04, 0x00, 0x01},
+       {0x06, 0x18, 0x0c},
+       {0x06, 0xfc, 0x0d},
+       {0x06, 0xfc, 0x0e},
+       {0x06, 0xfc, 0x0f},
+       {0x06, 0x11, 0x10},             /* contrast */
+       {0x06, 0x00, 0x11},
+       {0x06, 0xfe, 0x12},
+       {0x06, 0x00, 0x13},
+       {0x06, 0x00, 0x14},
+       {0x06, 0x9d, 0x51},
+       {0x06, 0x40, 0x52},
+       {0x06, 0x7c, 0x53},
+       {0x06, 0x40, 0x54},
+       {0x06, 0x02, 0x57},
+       {0x06, 0x03, 0x58},
+       {0x06, 0x15, 0x59},
+       {0x06, 0x05, 0x5a},
+       {0x06, 0x03, 0x56},
+       {0x06, 0x02, 0x3f},
+       {0x06, 0x00, 0x40},
+       {0x06, 0x39, 0x41},
+       {0x06, 0x69, 0x42},
+       {0x06, 0x87, 0x43},
+       {0x06, 0x9e, 0x44},
+       {0x06, 0xb1, 0x45},
+       {0x06, 0xbf, 0x46},
+       {0x06, 0xcc, 0x47},
+       {0x06, 0xd5, 0x48},
+       {0x06, 0xdd, 0x49},
+       {0x06, 0xe3, 0x4a},
+       {0x06, 0xe8, 0x4b},
+       {0x06, 0xed, 0x4c},
+       {0x06, 0xf2, 0x4d},
+       {0x06, 0xf7, 0x4e},
+       {0x06, 0xfc, 0x4f},
+       {0x06, 0xff, 0x50},
+
+       {0x05, 0x01, 0xc0},
+       {0x05, 0x10, 0xcb},
+       {0x05, 0x40, 0xc1},
+       {0x05, 0x04, 0xc2},
+       {0x05, 0x00, 0xca},
+       {0x05, 0x40, 0xc1},
+       {0x05, 0x09, 0xc2},
+       {0x05, 0x00, 0xca},
+       {0x05, 0xc0, 0xc1},
+       {0x05, 0x09, 0xc2},
+       {0x05, 0x00, 0xca},
+       {0x05, 0x40, 0xc1},
+       {0x05, 0x59, 0xc2},
+       {0x05, 0x00, 0xca},
+       {0x04, 0x00, 0x01},
+       {0x05, 0x80, 0xc1},
+       {0x05, 0xec, 0xc2},
+       {0x05, 0x0, 0xca},
+
+       {0x06, 0x02, 0x57},
+       {0x06, 0x01, 0x58},
+       {0x06, 0x15, 0x59},
+       {0x06, 0x0a, 0x5a},
+       {0x06, 0x01, 0x57},
+       {0x06, 0x8a, 0x03},
+       {0x06, 0x0a, 0x6c},
+       {0x06, 0x30, 0x01},
+       {0x06, 0x20, 0x02},
+       {0x06, 0x00, 0x03},
+
+       {0x05, 0x8c, 0x25},
+
+       {0x06, 0x4d, 0x51},             /* maybe saturation (4d) */
+       {0x06, 0x84, 0x53},             /* making green (84) */
+       {0x06, 0x00, 0x57},             /* sharpness (1) */
+       {0x06, 0x18, 0x08},
+       {0x06, 0xfc, 0x09},
+       {0x06, 0xfc, 0x0a},
+       {0x06, 0xfc, 0x0b},
+       {0x06, 0x18, 0x0c},             /* maybe hue (18) */
+       {0x06, 0xfc, 0x0d},
+       {0x06, 0xfc, 0x0e},
+       {0x06, 0xfc, 0x0f},
+       {0x06, 0x18, 0x10},             /* maybe contrast (18) */
+
+       {0x05, 0x01, 0x02},
+
+       {0x04, 0x00, 0x08},             /* compression */
+       {0x04, 0x12, 0x09},
+       {0x04, 0x21, 0x0a},
+       {0x04, 0x10, 0x0b},
+       {0x04, 0x21, 0x0c},
+       {0x04, 0x1d, 0x00},             /* imagetype (1d) */
+       {0x04, 0x41, 0x01},             /* hardware snapcontrol */
+
+       {0x04, 0x00, 0x04},
+       {0x04, 0x00, 0x05},
+       {0x04, 0x10, 0x06},
+       {0x04, 0x10, 0x07},
+       {0x04, 0x40, 0x06},
+       {0x04, 0x40, 0x07},
+       {0x04, 0x00, 0x04},
+       {0x04, 0x00, 0x05},
+
+       {0x06, 0x1c, 0x17},
+       {0x06, 0xe2, 0x19},
+       {0x06, 0x1c, 0x1b},
+       {0x06, 0xe2, 0x1d},
+       {0x06, 0x5f, 0x1f},
+       {0x06, 0x32, 0x20},
+
+       {0x05, initial_brightness >> 6, 0x00},
+       {0x05, initial_brightness << 2, 0x01},
+       {0x05, 0x06, 0xc1},
+       {0x05, 0x58, 0xc2},
+       {0x05, 0x0, 0xca},
+       {0x05, 0x0, 0x11},
+       {}
+};
+
+static int reg_write(struct usb_device *dev,
+                    __u16 reg, __u16 index, __u16 value)
+{
+       int ret;
+
+       ret = usb_control_msg(dev,
+                       usb_sndctrlpipe(dev, 0),
+                       reg,
+                       USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       value, index, NULL, 0, 500);
+       PDEBUG(D_PACK, "reg write: 0x%02x,0x%02x:0x%02x, 0x%x",
+               reg, index, value, ret);
+       if (ret < 0)
+               PDEBUG(D_ERR, "reg write: error %d", ret);
+       return ret;
+}
+
+/* returns: negative is error, pos or zero is data */
+static int reg_read(struct usb_device *dev,
+                       __u16 reg,      /* bRequest */
+                       __u16 index,    /* wIndex */
+                       __u16 length)   /* wLength (1 or 2 only) */
+{
+       int ret;
+       unsigned char buf[4];
+
+       buf[1] = 0;
+       ret = usb_control_msg(dev,
+                       usb_rcvctrlpipe(dev, 0),
+                       reg,
+                       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       (__u16) 0,              /* value */
+                       (__u16) index,
+                       buf,
+                       length,
+                       500);                   /* timeout */
+       if (ret < 0) {
+               PDEBUG(D_ERR, "reg_read err %d", ret);
+               return -1;
+       }
+       return (buf[1] << 8) + buf[0];
+}
+
+static int write_vector(struct gspca_dev *gspca_dev,
+                               __u16 data[][3])
+{
+       struct usb_device *dev = gspca_dev->dev;
+       int ret, i = 0;
+
+       while (data[i][0] != 0 || data[i][1] != 0 || data[i][2] != 0) {
+               ret = reg_write(dev, data[i][0], data[i][2], data[i][1]);
+               if (ret < 0) {
+                       PDEBUG(D_ERR,
+                               "Register write failed for 0x%x,0x%x,0x%x",
+                               data[i][0], data[i][1], data[i][2]);
+                       return ret;
+               }
+               i++;
+       }
+       return 0;
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+                       const struct usb_device_id *id)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct cam *cam;
+       __u16 vendor;
+       __u16 product;
+
+       vendor = id->idVendor;
+       product = id->idProduct;
+       switch (vendor) {
+       case 0x041e:            /* Creative cameras */
+/*             switch (product) { */
+/*             case 0x401d:     * here505b */
+                       sd->subtype = Nxultra;
+/*                     break; */
+/*             } */
+               break;
+       case 0x0733:    /* Rebadged ViewQuest (Intel) and ViewQuest cameras */
+/*             switch (product) { */
+/*             case 0x0430: */
+/*             fixme: may be UsbGrabberPV321 BRIDGE_SPCA506 SENSOR_SAA7113 */
+                       sd->subtype = IntelPCCameraPro;
+/*                     break; */
+/*             } */
+               break;
+       }
+
+       cam = &gspca_dev->cam;
+       cam->dev_name = (char *) id->driver_info;
+       cam->epaddr = 0x01;
+       cam->cam_mode = vga_mode;
+       if (sd->subtype != IntelPCCameraPro)
+               cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+       else                    /* no 640x480 for IntelPCCameraPro */
+               cam->nmodes = sizeof vga_mode / sizeof vga_mode[0] - 1;
+       sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
+
+       if (sd->subtype == Nxultra) {
+               if (write_vector(gspca_dev, spca505b_init_data))
+                       return -EIO;
+       } else {
+               if (write_vector(gspca_dev, spca505_init_data))
+                       return -EIO;
+       }
+       return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int ret;
+
+       PDEBUG(D_STREAM, "Initializing SPCA505");
+       if (sd->subtype == Nxultra)
+               write_vector(gspca_dev, spca505b_open_data_ccd);
+       else
+               write_vector(gspca_dev, spca505_open_data_ccd);
+       ret = reg_read(gspca_dev->dev, 6, 0x16, 2);
+
+       if (ret < 0) {
+               PDEBUG(D_ERR|D_STREAM,
+                      "register read failed for after vector read err = %d",
+                      ret);
+               return -EIO;
+       }
+       PDEBUG(D_STREAM,
+               "After vector read returns : 0x%x should be 0x0101",
+               ret & 0xffff);
+
+       ret = reg_write(gspca_dev->dev, 6, 0x16, 0x0a);
+       if (ret < 0) {
+               PDEBUG(D_ERR, "register write failed for (6,0xa,0x16) err=%d",
+                      ret);
+               return -EIO;
+       }
+       reg_write(gspca_dev->dev, 5, 0xc2, 18);
+       return 0;
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+       struct usb_device *dev = gspca_dev->dev;
+       int ret;
+
+       /* necessary because without it we can see stream
+        * only once after loading module */
+       /* stopping usb registers Tomasz change */
+       reg_write(dev, 0x02, 0x0, 0x0);
+       switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].mode) {
+       case 0:
+               reg_write(dev, 0x04, 0x00, 0x00);
+               reg_write(dev, 0x04, 0x06, 0x10);
+               reg_write(dev, 0x04, 0x07, 0x10);
+               break;
+       case 1:
+               reg_write(dev, 0x04, 0x00, 0x01);
+               reg_write(dev, 0x04, 0x06, 0x1a);
+               reg_write(dev, 0x04, 0x07, 0x1a);
+               break;
+       case 2:
+               reg_write(dev, 0x04, 0x00, 0x02);
+               reg_write(dev, 0x04, 0x06, 0x1c);
+               reg_write(dev, 0x04, 0x07, 0x1d);
+               break;
+       case 4:
+               reg_write(dev, 0x04, 0x00, 0x04);
+               reg_write(dev, 0x04, 0x06, 0x34);
+               reg_write(dev, 0x04, 0x07, 0x34);
+               break;
+       default:
+/*     case 5: */
+               reg_write(dev, 0x04, 0x00, 0x05);
+               reg_write(dev, 0x04, 0x06, 0x40);
+               reg_write(dev, 0x04, 0x07, 0x40);
+               break;
+       }
+/* Enable ISO packet machine - should we do this here or in ISOC init ? */
+       ret = reg_write(dev, SPCA50X_REG_USB,
+                        SPCA50X_USB_CTRL,
+                        SPCA50X_CUSB_ENABLE);
+
+/*     reg_write(dev, 0x5, 0x0, 0x0); */
+/*     reg_write(dev, 0x5, 0x0, 0x1); */
+/*     reg_write(dev, 0x5, 0x11, 0x2); */
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+       /* Disable ISO packet machine */
+       reg_write(gspca_dev->dev, 0x02, 0x00, 0x00);
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+/* this function is called at close time */
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+       /* This maybe reset or power control */
+       reg_write(gspca_dev->dev, 0x03, 0x03, 0x20);
+       reg_write(gspca_dev->dev, 0x03, 0x01, 0x0);
+       reg_write(gspca_dev->dev, 0x03, 0x00, 0x1);
+       reg_write(gspca_dev->dev, 0x05, 0x10, 0x1);
+       reg_write(gspca_dev->dev, 0x05, 0x11, 0xf);
+}
+
+/* convert YYUV per line to YUYV (YUV 4:2:2) */
+static void yyuv_decode(unsigned char *out,
+                       unsigned char *in,
+                       int width,
+                       int height)
+{
+       unsigned char *Ui, *Vi, *yi, *yi1;
+       unsigned char *out1;
+       int i, j;
+
+       yi = in;
+       for (i = height / 2; --i >= 0; ) {
+               out1 = out + width * 2;         /* next line */
+               yi1 = yi + width;
+               Ui = yi1 + width;
+               Vi = Ui + width / 2;
+               for (j = width / 2; --j >= 0; ) {
+                       *out++ = 128 + *yi++;
+                       *out++ = 128 + *Ui;
+                       *out++ = 128 + *yi++;
+                       *out++ = 128 + *Vi;
+
+                       *out1++ = 128 + *yi1++;
+                       *out1++ = 128 + *Ui++;
+                       *out1++ = 128 + *yi1++;
+                       *out1++ = 128 + *Vi++;
+               }
+               yi += width * 2;
+               out = out1;
+       }
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+                       struct gspca_frame *frame,      /* target */
+                       unsigned char *data,            /* isoc packet */
+                       int len)                        /* iso packet length */
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       switch (data[0]) {
+       case 0:                         /* start of frame */
+               if (gspca_dev->last_packet_type == FIRST_PACKET) {
+                       yyuv_decode(sd->tmpbuf2, sd->tmpbuf,
+                                       gspca_dev->width,
+                                       gspca_dev->height);
+                       frame = gspca_frame_add(gspca_dev,
+                                               LAST_PACKET,
+                                               frame,
+                                               sd->tmpbuf2,
+                                               gspca_dev->width
+                                                       * gspca_dev->height
+                                                       * 2);
+               }
+               gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+                               data, 0);
+               data += SPCA50X_OFFSET_DATA;
+               len -= SPCA50X_OFFSET_DATA;
+               if (len > 0)
+                       memcpy(sd->tmpbuf, data, len);
+               else
+                       len = 0;
+               sd->buflen = len;
+               return;
+       case 0xff:                      /* drop */
+/*             gspca_dev->last_packet_type = DISCARD_PACKET; */
+               return;
+       }
+       data += 1;
+       len -= 1;
+       memcpy(&sd->tmpbuf[sd->buflen], data, len);
+       sd->buflen += len;
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       __u8 brightness = sd->brightness;
+       reg_write(gspca_dev->dev, 5, 0x00, (255 - brightness) >> 6);
+       reg_write(gspca_dev->dev, 5, 0x01, (255 - brightness) << 2);
+
+}
+static void getbrightness(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->brightness = 255
+               - ((reg_read(gspca_dev->dev, 5, 0x01, 1) >> 2)
+                       + (reg_read(gspca_dev->dev, 5, 0x0, 1) << 6));
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->brightness = val;
+       if (gspca_dev->streaming)
+               setbrightness(gspca_dev);
+       return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       getbrightness(gspca_dev);
+       *val = sd->brightness;
+       return 0;
+}
+
+/* sub-driver description */
+static struct sd_desc sd_desc = {
+       .name = MODULE_NAME,
+       .ctrls = sd_ctrls,
+       .nctrls = ARRAY_SIZE(sd_ctrls),
+       .config = sd_config,
+       .open = sd_open,
+       .start = sd_start,
+       .stopN = sd_stopN,
+       .stop0 = sd_stop0,
+       .close = sd_close,
+       .pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static __devinitdata struct usb_device_id device_table[] = {
+       {USB_DEVICE(0x041e, 0x401d), DVNM("Creative Webcam NX ULTRA")},
+       {USB_DEVICE(0x0733, 0x0430), DVNM("Intel PC Camera Pro")},
+       {}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+                       const struct usb_device_id *id)
+{
+       return gspca_dev_probe(intf, id, &sd_desc, sizeof (struct sd),
+                               THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+       .name = MODULE_NAME,
+       .id_table = device_table,
+       .probe = sd_probe,
+       .disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+       if (usb_register(&sd_driver) < 0)
+               return -1;
+       PDEBUG(D_PROBE, "v%s registered", version);
+       return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+       usb_deregister(&sd_driver);
+       PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/spca506.c b/drivers/media/video/gspca/spca506.c
new file mode 100644 (file)
index 0000000..614fb3a
--- /dev/null
@@ -0,0 +1,830 @@
+/*
+ * SPCA506 chip based cameras function
+ * M Xhaard 15/04/2004 based on different work Mark Taylor and others
+ * and my own snoopy file on a pv-321c donate by a german compagny
+ *                "Firma Frank Gmbh" from  Saarbruecken
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define MODULE_NAME "spca506"
+
+#include "gspca.h"
+
+#define DRIVER_VERSION_NUMBER  KERNEL_VERSION(2, 1, 0)
+static const char version[] = "2.1.0";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("GSPCA/SPCA506 USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+       struct gspca_dev gspca_dev;             /* !! must be the first item */
+
+       int buflen;
+       unsigned char tmpbuf[640 * 480 * 3];    /* YYUV per line */
+       unsigned char tmpbuf2[640 * 480 * 2];   /* YUYV */
+
+       unsigned char brightness;
+       unsigned char contrast;
+       unsigned char colors;
+       unsigned char hue;
+       char norme;
+       char channel;
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+#define SD_BRIGHTNESS 0
+       {
+           {
+               .id      = V4L2_CID_BRIGHTNESS,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Brightness",
+               .minimum = 0,
+               .maximum = 0xff,
+               .step    = 1,
+               .default_value = 0x80,
+           },
+           .set = sd_setbrightness,
+           .get = sd_getbrightness,
+       },
+#define SD_CONTRAST 1
+       {
+           {
+               .id      = V4L2_CID_CONTRAST,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Contrast",
+               .minimum = 0,
+               .maximum = 0xff,
+               .step    = 1,
+               .default_value = 0x47,
+           },
+           .set = sd_setcontrast,
+           .get = sd_getcontrast,
+       },
+#define SD_COLOR 2
+       {
+           {
+               .id      = V4L2_CID_SATURATION,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Saturation",
+               .minimum = 0,
+               .maximum = 0xff,
+               .step    = 1,
+               .default_value = 0x40,
+           },
+           .set = sd_setcolors,
+           .get = sd_getcolors,
+       },
+#define SD_HUE 3
+       {
+           {
+               .id      = V4L2_CID_HUE,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Hue",
+               .minimum = 0,
+               .maximum = 0xff,
+               .step    = 1,
+               .default_value = 0,
+           },
+           .set = sd_sethue,
+           .get = sd_gethue,
+       },
+};
+
+static struct cam_mode vga_mode[] = {
+       {V4L2_PIX_FMT_YUYV, 160, 120, 5},
+       {V4L2_PIX_FMT_YUYV, 176, 144, 4},
+       {V4L2_PIX_FMT_YUYV, 320, 240, 2},
+       {V4L2_PIX_FMT_YUYV, 352, 288, 1},
+       {V4L2_PIX_FMT_YUYV, 640, 480, 0},
+};
+
+#define SPCA50X_OFFSET_DATA 10
+
+#define SAA7113_bright 0x0a    /* defaults 0x80 */
+#define SAA7113_contrast 0x0b  /* defaults 0x47 */
+#define SAA7113_saturation 0x0c        /* defaults 0x40 */
+#define SAA7113_hue 0x0d       /* defaults 0x00 */
+#define SAA7113_I2C_BASE_WRITE 0x4a
+
+static void reg_r(struct usb_device *dev,
+                 __u16 req,
+                 __u16 index,
+                 __u8 *buffer, __u16 length)
+{
+       usb_control_msg(dev,
+                       usb_rcvctrlpipe(dev, 0),
+                       req,
+                       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       0,              /* value */
+                       index, buffer, length,
+                       500);
+}
+
+static void reg_w(struct usb_device *dev,
+                 __u16 req,
+                 __u16 value,
+                 __u16 index)
+{
+       usb_control_msg(dev,
+                       usb_sndctrlpipe(dev, 0),
+                       req,
+                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       value, index,
+                       NULL, 0, 500);
+}
+
+static void spca506_Initi2c(struct gspca_dev *gspca_dev)
+{
+       reg_w(gspca_dev->dev, 0x07, SAA7113_I2C_BASE_WRITE, 0x0004);
+}
+
+static void spca506_WriteI2c(struct gspca_dev *gspca_dev, __u16 valeur,
+                            __u16 reg)
+{
+       int retry = 60;
+       unsigned char Data[2];
+
+       reg_w(gspca_dev->dev, 0x07, reg, 0x0001);
+       reg_w(gspca_dev->dev, 0x07, valeur, 0x0000);
+       while (retry--) {
+               reg_r(gspca_dev->dev, 0x07, 0x0003, Data, 2);
+               if ((Data[0] | Data[1]) == 0x00)
+                       break;
+       }
+}
+
+static int spca506_ReadI2c(struct gspca_dev *gspca_dev, __u16 reg)
+{
+       int retry = 60;
+       unsigned char Data[2];
+       unsigned char value;
+
+       reg_w(gspca_dev->dev, 0x07, SAA7113_I2C_BASE_WRITE, 0x0004);
+       reg_w(gspca_dev->dev, 0x07, reg, 0x0001);
+       reg_w(gspca_dev->dev, 0x07, 0x01, 0x0002);
+       while (--retry) {
+               reg_r(gspca_dev->dev, 0x07, 0x0003, Data, 2);
+               if ((Data[0] | Data[1]) == 0x00)
+                       break;
+       }
+       if (retry == 0)
+               return -1;
+       reg_r(gspca_dev->dev, 0x07, 0x0000, &value, 1);
+       return value;
+}
+
+static void spca506_SetNormeInput(struct gspca_dev *gspca_dev,
+                                __u16 norme,
+                                __u16 channel)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+/* fixme: check if channel == 0..3 and 6..9 (8 values) */
+       __u8 setbit0 = 0x00;
+       __u8 setbit1 = 0x00;
+       __u8 videomask = 0x00;
+
+       PDEBUG(D_STREAM, "** Open Set Norme **");
+       spca506_Initi2c(gspca_dev);
+       /* NTSC bit0 -> 1(525 l) PAL SECAM bit0 -> 0 (625 l) */
+       /* Composite channel bit1 -> 1 S-video bit 1 -> 0 */
+       /* and exclude SAA7113 reserved channel set default 0 otherwise */
+       if (norme & V4L2_STD_NTSC)
+               setbit0 = 0x01;
+       if (channel == 4 || channel == 5 || channel > 9)
+               channel = 0;
+       if (channel < 4)
+               setbit1 = 0x02;
+       videomask = (0x48 | setbit0 | setbit1);
+       reg_w(gspca_dev->dev, 0x08, videomask, 0x0000);
+       spca506_WriteI2c(gspca_dev, (0xc0 | (channel & 0x0F)), 0x02);
+
+       if (norme & V4L2_STD_NTSC)
+               spca506_WriteI2c(gspca_dev, 0x33, 0x0e);
+                                       /* Chrominance Control NTSC N */
+       else if (norme & V4L2_STD_SECAM)
+               spca506_WriteI2c(gspca_dev, 0x53, 0x0e);
+                                       /* Chrominance Control SECAM */
+       else
+               spca506_WriteI2c(gspca_dev, 0x03, 0x0e);
+                                       /* Chrominance Control PAL BGHIV */
+
+       sd->norme = norme;
+       sd->channel = channel;
+       PDEBUG(D_STREAM, "Set Video Byte to 0x%2x", videomask);
+       PDEBUG(D_STREAM, "Set Norme: %08x Channel %d", norme, channel);
+}
+
+static void spca506_GetNormeInput(struct gspca_dev *gspca_dev,
+                                 __u16 *norme, __u16 *channel)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       /* Read the register is not so good value change so
+          we use your own copy in spca50x struct */
+       *norme = sd->norme;
+       *channel = sd->channel;
+       PDEBUG(D_STREAM, "Get Norme: %d Channel %d", *norme, *channel);
+}
+
+static void spca506_Setsize(struct gspca_dev *gspca_dev, __u16 code,
+                           __u16 xmult, __u16 ymult)
+{
+       struct usb_device *dev = gspca_dev->dev;
+
+       PDEBUG(D_STREAM, "** SetSize **");
+       reg_w(dev, 0x04, (0x18 | (code & 0x07)), 0x0000);
+       /* Soft snap 0x40 Hard 0x41 */
+       reg_w(dev, 0x04, 0x41, 0x0001);
+       reg_w(dev, 0x04, 0x00, 0x0002);
+       /* reserved */
+       reg_w(dev, 0x04, 0x00, 0x0003);
+
+       /* reserved */
+       reg_w(dev, 0x04, 0x00, 0x0004);
+       /* reserved */
+       reg_w(dev, 0x04, 0x01, 0x0005);
+       /* reserced */
+       reg_w(dev, 0x04, xmult, 0x0006);
+       /* reserved */
+       reg_w(dev, 0x04, ymult, 0x0007);
+       /* compression 1 */
+       reg_w(dev, 0x04, 0x00, 0x0008);
+       /* T=64 -> 2 */
+       reg_w(dev, 0x04, 0x00, 0x0009);
+       /* threshold2D */
+       reg_w(dev, 0x04, 0x21, 0x000a);
+       /* quantization */
+       reg_w(dev, 0x04, 0x00, 0x000b);
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+                       const struct usb_device_id *id)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct cam *cam;
+
+       cam = &gspca_dev->cam;
+       cam->dev_name = (char *) id->driver_info;
+       cam->epaddr = 0x01;
+       cam->cam_mode = vga_mode;
+       cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+       sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
+       sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
+       sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value;
+       sd->hue = sd_ctrls[SD_HUE].qctrl.default_value;
+       return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+       struct usb_device *dev = gspca_dev->dev;
+
+       reg_w(dev, 0x03, 0x00, 0x0004);
+       reg_w(dev, 0x03, 0xFF, 0x0003);
+       reg_w(dev, 0x03, 0x00, 0x0000);
+       reg_w(dev, 0x03, 0x1c, 0x0001);
+       reg_w(dev, 0x03, 0x18, 0x0001);
+       /* Init on PAL and composite input0 */
+       spca506_SetNormeInput(gspca_dev, 0, 0);
+       reg_w(dev, 0x03, 0x1c, 0x0001);
+       reg_w(dev, 0x03, 0x18, 0x0001);
+       reg_w(dev, 0x05, 0x00, 0x0000);
+       reg_w(dev, 0x05, 0xef, 0x0001);
+       reg_w(dev, 0x05, 0x00, 0x00c1);
+       reg_w(dev, 0x05, 0x00, 0x00c2);
+       reg_w(dev, 0x06, 0x18, 0x0002);
+       reg_w(dev, 0x06, 0xf5, 0x0011);
+       reg_w(dev, 0x06, 0x02, 0x0012);
+       reg_w(dev, 0x06, 0xfb, 0x0013);
+       reg_w(dev, 0x06, 0x00, 0x0014);
+       reg_w(dev, 0x06, 0xa4, 0x0051);
+       reg_w(dev, 0x06, 0x40, 0x0052);
+       reg_w(dev, 0x06, 0x71, 0x0053);
+       reg_w(dev, 0x06, 0x40, 0x0054);
+       /************************************************/
+       reg_w(dev, 0x03, 0x00, 0x0004);
+       reg_w(dev, 0x03, 0x00, 0x0003);
+       reg_w(dev, 0x03, 0x00, 0x0004);
+       reg_w(dev, 0x03, 0xFF, 0x0003);
+       reg_w(dev, 0x02, 0x00, 0x0000);
+       reg_w(dev, 0x03, 0x60, 0x0000);
+       reg_w(dev, 0x03, 0x18, 0x0001);
+       /* for a better reading mx :)     */
+       /*sdca506_WriteI2c(value,register) */
+       spca506_Initi2c(gspca_dev);
+       spca506_WriteI2c(gspca_dev, 0x08, 0x01);
+       spca506_WriteI2c(gspca_dev, 0xc0, 0x02);
+                                               /* input composite video */
+       spca506_WriteI2c(gspca_dev, 0x33, 0x03);
+       spca506_WriteI2c(gspca_dev, 0x00, 0x04);
+       spca506_WriteI2c(gspca_dev, 0x00, 0x05);
+       spca506_WriteI2c(gspca_dev, 0x0d, 0x06);
+       spca506_WriteI2c(gspca_dev, 0xf0, 0x07);
+       spca506_WriteI2c(gspca_dev, 0x98, 0x08);
+       spca506_WriteI2c(gspca_dev, 0x03, 0x09);
+       spca506_WriteI2c(gspca_dev, 0x80, 0x0a);
+       spca506_WriteI2c(gspca_dev, 0x47, 0x0b);
+       spca506_WriteI2c(gspca_dev, 0x48, 0x0c);
+       spca506_WriteI2c(gspca_dev, 0x00, 0x0d);
+       spca506_WriteI2c(gspca_dev, 0x03, 0x0e);        /* Chroma Pal adjust */
+       spca506_WriteI2c(gspca_dev, 0x2a, 0x0f);
+       spca506_WriteI2c(gspca_dev, 0x00, 0x10);
+       spca506_WriteI2c(gspca_dev, 0x0c, 0x11);
+       spca506_WriteI2c(gspca_dev, 0xb8, 0x12);
+       spca506_WriteI2c(gspca_dev, 0x01, 0x13);
+       spca506_WriteI2c(gspca_dev, 0x00, 0x14);
+       spca506_WriteI2c(gspca_dev, 0x00, 0x15);
+       spca506_WriteI2c(gspca_dev, 0x00, 0x16);
+       spca506_WriteI2c(gspca_dev, 0x00, 0x17);
+       spca506_WriteI2c(gspca_dev, 0x00, 0x18);
+       spca506_WriteI2c(gspca_dev, 0x00, 0x19);
+       spca506_WriteI2c(gspca_dev, 0x00, 0x1a);
+       spca506_WriteI2c(gspca_dev, 0x00, 0x1b);
+       spca506_WriteI2c(gspca_dev, 0x00, 0x1c);
+       spca506_WriteI2c(gspca_dev, 0x00, 0x1d);
+       spca506_WriteI2c(gspca_dev, 0x00, 0x1e);
+       spca506_WriteI2c(gspca_dev, 0xa1, 0x1f);
+       spca506_WriteI2c(gspca_dev, 0x02, 0x40);
+       spca506_WriteI2c(gspca_dev, 0xff, 0x41);
+       spca506_WriteI2c(gspca_dev, 0xff, 0x42);
+       spca506_WriteI2c(gspca_dev, 0xff, 0x43);
+       spca506_WriteI2c(gspca_dev, 0xff, 0x44);
+       spca506_WriteI2c(gspca_dev, 0xff, 0x45);
+       spca506_WriteI2c(gspca_dev, 0xff, 0x46);
+       spca506_WriteI2c(gspca_dev, 0xff, 0x47);
+       spca506_WriteI2c(gspca_dev, 0xff, 0x48);
+       spca506_WriteI2c(gspca_dev, 0xff, 0x49);
+       spca506_WriteI2c(gspca_dev, 0xff, 0x4a);
+       spca506_WriteI2c(gspca_dev, 0xff, 0x4b);
+       spca506_WriteI2c(gspca_dev, 0xff, 0x4c);
+       spca506_WriteI2c(gspca_dev, 0xff, 0x4d);
+       spca506_WriteI2c(gspca_dev, 0xff, 0x4e);
+       spca506_WriteI2c(gspca_dev, 0xff, 0x4f);
+       spca506_WriteI2c(gspca_dev, 0xff, 0x50);
+       spca506_WriteI2c(gspca_dev, 0xff, 0x51);
+       spca506_WriteI2c(gspca_dev, 0xff, 0x52);
+       spca506_WriteI2c(gspca_dev, 0xff, 0x53);
+       spca506_WriteI2c(gspca_dev, 0xff, 0x54);
+       spca506_WriteI2c(gspca_dev, 0xff, 0x55);
+       spca506_WriteI2c(gspca_dev, 0xff, 0x56);
+       spca506_WriteI2c(gspca_dev, 0xff, 0x57);
+       spca506_WriteI2c(gspca_dev, 0x00, 0x58);
+       spca506_WriteI2c(gspca_dev, 0x54, 0x59);
+       spca506_WriteI2c(gspca_dev, 0x07, 0x5a);
+       spca506_WriteI2c(gspca_dev, 0x83, 0x5b);
+       spca506_WriteI2c(gspca_dev, 0x00, 0x5c);
+       spca506_WriteI2c(gspca_dev, 0x00, 0x5d);
+       spca506_WriteI2c(gspca_dev, 0x00, 0x5e);
+       spca506_WriteI2c(gspca_dev, 0x00, 0x5f);
+       spca506_WriteI2c(gspca_dev, 0x00, 0x60);
+       spca506_WriteI2c(gspca_dev, 0x05, 0x61);
+       spca506_WriteI2c(gspca_dev, 0x9f, 0x62);
+       PDEBUG(D_STREAM, "** Close Init *");
+       return 0;
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+       struct usb_device *dev = gspca_dev->dev;
+       __u16 norme;
+       __u16 channel;
+       __u8 Data[2];
+
+       /**************************************/
+       reg_w(dev, 0x03, 0x00, 0x0004);
+       reg_w(dev, 0x03, 0x00, 0x0003);
+       reg_w(dev, 0x03, 0x00, 0x0004);
+       reg_w(dev, 0x03, 0xFF, 0x0003);
+       reg_w(dev, 0x02, 0x00, 0x0000);
+       reg_w(dev, 0x03, 0x60, 0x0000);
+       reg_w(dev, 0x03, 0x18, 0x0001);
+
+       /*sdca506_WriteI2c(value,register) */
+       spca506_Initi2c(gspca_dev);
+       spca506_WriteI2c(gspca_dev, 0x08, 0x01);        /* Increment Delay */
+/*     spca506_WriteI2c(gspca_dev, 0xc0, 0x02); * Analog Input Control 1 */
+       spca506_WriteI2c(gspca_dev, 0x33, 0x03);
+                                               /* Analog Input Control 2 */
+       spca506_WriteI2c(gspca_dev, 0x00, 0x04);
+                                               /* Analog Input Control 3 */
+       spca506_WriteI2c(gspca_dev, 0x00, 0x05);
+                                               /* Analog Input Control 4 */
+       spca506_WriteI2c(gspca_dev, 0x0d, 0x06);
+                                       /* Horizontal Sync Start 0xe9-0x0d */
+       spca506_WriteI2c(gspca_dev, 0xf0, 0x07);
+                                       /* Horizontal Sync Stop  0x0d-0xf0 */
+
+       spca506_WriteI2c(gspca_dev, 0x98, 0x08);        /* Sync Control */
+/*             Defaults value                  */
+       spca506_WriteI2c(gspca_dev, 0x03, 0x09);        /* Luminance Control */
+       spca506_WriteI2c(gspca_dev, 0x80, 0x0a);
+                                               /* Luminance Brightness */
+       spca506_WriteI2c(gspca_dev, 0x47, 0x0b);        /* Luminance Contrast */
+       spca506_WriteI2c(gspca_dev, 0x48, 0x0c);
+                                               /* Chrominance Saturation */
+       spca506_WriteI2c(gspca_dev, 0x00, 0x0d);
+                                               /* Chrominance Hue Control */
+       spca506_WriteI2c(gspca_dev, 0x2a, 0x0f);
+                                               /* Chrominance Gain Control */
+       /**************************************/
+       spca506_WriteI2c(gspca_dev, 0x00, 0x10);
+                                               /* Format/Delay Control */
+       spca506_WriteI2c(gspca_dev, 0x0c, 0x11);        /* Output Control 1 */
+       spca506_WriteI2c(gspca_dev, 0xb8, 0x12);        /* Output Control 2 */
+       spca506_WriteI2c(gspca_dev, 0x01, 0x13);        /* Output Control 3 */
+       spca506_WriteI2c(gspca_dev, 0x00, 0x14);        /* reserved */
+       spca506_WriteI2c(gspca_dev, 0x00, 0x15);        /* VGATE START */
+       spca506_WriteI2c(gspca_dev, 0x00, 0x16);        /* VGATE STOP */
+       spca506_WriteI2c(gspca_dev, 0x00, 0x17);    /* VGATE Control (MSB) */
+       spca506_WriteI2c(gspca_dev, 0x00, 0x18);
+       spca506_WriteI2c(gspca_dev, 0x00, 0x19);
+       spca506_WriteI2c(gspca_dev, 0x00, 0x1a);
+       spca506_WriteI2c(gspca_dev, 0x00, 0x1b);
+       spca506_WriteI2c(gspca_dev, 0x00, 0x1c);
+       spca506_WriteI2c(gspca_dev, 0x00, 0x1d);
+       spca506_WriteI2c(gspca_dev, 0x00, 0x1e);
+       spca506_WriteI2c(gspca_dev, 0xa1, 0x1f);
+       spca506_WriteI2c(gspca_dev, 0x02, 0x40);
+       spca506_WriteI2c(gspca_dev, 0xff, 0x41);
+       spca506_WriteI2c(gspca_dev, 0xff, 0x42);
+       spca506_WriteI2c(gspca_dev, 0xff, 0x43);
+       spca506_WriteI2c(gspca_dev, 0xff, 0x44);
+       spca506_WriteI2c(gspca_dev, 0xff, 0x45);
+       spca506_WriteI2c(gspca_dev, 0xff, 0x46);
+       spca506_WriteI2c(gspca_dev, 0xff, 0x47);
+       spca506_WriteI2c(gspca_dev, 0xff, 0x48);
+       spca506_WriteI2c(gspca_dev, 0xff, 0x49);
+       spca506_WriteI2c(gspca_dev, 0xff, 0x4a);
+       spca506_WriteI2c(gspca_dev, 0xff, 0x4b);
+       spca506_WriteI2c(gspca_dev, 0xff, 0x4c);
+       spca506_WriteI2c(gspca_dev, 0xff, 0x4d);
+       spca506_WriteI2c(gspca_dev, 0xff, 0x4e);
+       spca506_WriteI2c(gspca_dev, 0xff, 0x4f);
+       spca506_WriteI2c(gspca_dev, 0xff, 0x50);
+       spca506_WriteI2c(gspca_dev, 0xff, 0x51);
+       spca506_WriteI2c(gspca_dev, 0xff, 0x52);
+       spca506_WriteI2c(gspca_dev, 0xff, 0x53);
+       spca506_WriteI2c(gspca_dev, 0xff, 0x54);
+       spca506_WriteI2c(gspca_dev, 0xff, 0x55);
+       spca506_WriteI2c(gspca_dev, 0xff, 0x56);
+       spca506_WriteI2c(gspca_dev, 0xff, 0x57);
+       spca506_WriteI2c(gspca_dev, 0x00, 0x58);
+       spca506_WriteI2c(gspca_dev, 0x54, 0x59);
+       spca506_WriteI2c(gspca_dev, 0x07, 0x5a);
+       spca506_WriteI2c(gspca_dev, 0x83, 0x5b);
+       spca506_WriteI2c(gspca_dev, 0x00, 0x5c);
+       spca506_WriteI2c(gspca_dev, 0x00, 0x5d);
+       spca506_WriteI2c(gspca_dev, 0x00, 0x5e);
+       spca506_WriteI2c(gspca_dev, 0x00, 0x5f);
+       spca506_WriteI2c(gspca_dev, 0x00, 0x60);
+       spca506_WriteI2c(gspca_dev, 0x05, 0x61);
+       spca506_WriteI2c(gspca_dev, 0x9f, 0x62);
+       /**************************************/
+       reg_w(dev, 0x05, 0x00, 0x0003);
+       reg_w(dev, 0x05, 0x00, 0x0004);
+       reg_w(dev, 0x03, 0x10, 0x0001);
+       reg_w(dev, 0x03, 0x78, 0x0000);
+       switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].mode) {
+       case 0:
+               spca506_Setsize(gspca_dev, 0, 0x10, 0x10);
+               break;
+       case 1:
+               spca506_Setsize(gspca_dev, 1, 0x1a, 0x1a);
+               break;
+       case 2:
+               spca506_Setsize(gspca_dev, 2, 0x1c, 0x1c);
+               break;
+       case 4:
+               spca506_Setsize(gspca_dev, 4, 0x34, 0x34);
+               break;
+       default:
+/*     case 5: */
+               spca506_Setsize(gspca_dev, 5, 0x40, 0x40);
+               break;
+       }
+
+       /* compress setting and size */
+       /* set i2c luma */
+       reg_w(dev, 0x02, 0x01, 0x0000);
+       reg_w(dev, 0x03, 0x12, 0x000);
+       reg_r(dev, 0x04, 0x0001, Data, 2);
+       PDEBUG(D_STREAM, "webcam started");
+       spca506_GetNormeInput(gspca_dev, &norme, &channel);
+       spca506_SetNormeInput(gspca_dev, norme, channel);
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+       struct usb_device *dev = gspca_dev->dev;
+
+       reg_w(dev, 0x02, 0x00, 0x0000);
+       reg_w(dev, 0x03, 0x00, 0x0004);
+       reg_w(dev, 0x03, 0x00, 0x0003);
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+/* convert YYUV per line to YUYV (YUV 4:2:2) */
+static void yyuv_decode(unsigned char *out,
+                       unsigned char *in,
+                       int width,
+                       int height)
+{
+       unsigned char *Ui, *Vi, *yi, *yi1;
+       unsigned char *out1;
+       int i, j;
+
+       yi = in;
+       for (i = height / 2; --i >= 0; ) {
+               out1 = out + width * 2;         /* next line */
+               yi1 = yi + width;
+               Ui = yi1 + width;
+               Vi = Ui + width / 2;
+               for (j = width / 2; --j >= 0; ) {
+                       *out++ = 128 + *yi++;
+                       *out++ = 128 + *Ui;
+                       *out++ = 128 + *yi++;
+                       *out++ = 128 + *Vi;
+
+                       *out1++ = 128 + *yi1++;
+                       *out1++ = 128 + *Ui++;
+                       *out1++ = 128 + *yi1++;
+                       *out1++ = 128 + *Vi++;
+               }
+               yi += width * 2;
+               out = out1;
+       }
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+                       struct gspca_frame *frame,      /* target */
+                       unsigned char *data,            /* isoc packet */
+                       int len)                        /* iso packet length */
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       switch (data[0]) {
+       case 0:                         /* start of frame */
+               if (gspca_dev->last_packet_type == FIRST_PACKET) {
+                       yyuv_decode(sd->tmpbuf2, sd->tmpbuf,
+                                       gspca_dev->width,
+                                       gspca_dev->height);
+                       frame = gspca_frame_add(gspca_dev,
+                                               LAST_PACKET,
+                                               frame,
+                                               sd->tmpbuf2,
+                                               gspca_dev->width
+                                                       * gspca_dev->height
+                                                       * 2);
+               }
+               gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+                               data, 0);
+               data += SPCA50X_OFFSET_DATA;
+               len -= SPCA50X_OFFSET_DATA;
+               if (len > 0)
+                       memcpy(sd->tmpbuf, data, len);
+               else
+                       len = 0;
+               sd->buflen = len;
+               return;
+       case 0xff:                      /* drop */
+/*             gspca_dev->last_packet_type = DISCARD_PACKET; */
+               return;
+       }
+       data += 1;
+       len -= 1;
+       memcpy(&sd->tmpbuf[sd->buflen], data, len);
+       sd->buflen += len;
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       spca506_Initi2c(gspca_dev);
+       spca506_WriteI2c(gspca_dev, sd->brightness, SAA7113_bright);
+       spca506_WriteI2c(gspca_dev, 0x01, 0x09);
+}
+
+static void getbrightness(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->brightness = spca506_ReadI2c(gspca_dev, SAA7113_bright);
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       spca506_Initi2c(gspca_dev);
+       spca506_WriteI2c(gspca_dev, sd->contrast, SAA7113_contrast);
+       spca506_WriteI2c(gspca_dev, 0x01, 0x09);
+}
+
+static void getcontrast(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->contrast = spca506_ReadI2c(gspca_dev, SAA7113_contrast);
+}
+
+static void setcolors(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       spca506_Initi2c(gspca_dev);
+       spca506_WriteI2c(gspca_dev, sd->colors, SAA7113_saturation);
+       spca506_WriteI2c(gspca_dev, 0x01, 0x09);
+}
+
+static void getcolors(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->colors = spca506_ReadI2c(gspca_dev, SAA7113_saturation);
+}
+
+static void sethue(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       spca506_Initi2c(gspca_dev);
+       spca506_WriteI2c(gspca_dev, sd->hue, SAA7113_hue);
+       spca506_WriteI2c(gspca_dev, 0x01, 0x09);
+}
+
+static void gethue(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->hue = spca506_ReadI2c(gspca_dev, SAA7113_hue);
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->brightness = val;
+       if (gspca_dev->streaming)
+               setbrightness(gspca_dev);
+       return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       getbrightness(gspca_dev);
+       *val = sd->brightness;
+       return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->contrast = val;
+       if (gspca_dev->streaming)
+               setcontrast(gspca_dev);
+       return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       getcontrast(gspca_dev);
+       *val = sd->contrast;
+       return 0;
+}
+
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->colors = val;
+       if (gspca_dev->streaming)
+               setcolors(gspca_dev);
+       return 0;
+}
+
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       getcolors(gspca_dev);
+       *val = sd->colors;
+       return 0;
+}
+
+static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->hue = val;
+       if (gspca_dev->streaming)
+               sethue(gspca_dev);
+       return 0;
+}
+
+static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       gethue(gspca_dev);
+       *val = sd->hue;
+       return 0;
+}
+
+/* sub-driver description */
+static struct sd_desc sd_desc = {
+       .name = MODULE_NAME,
+       .ctrls = sd_ctrls,
+       .nctrls = ARRAY_SIZE(sd_ctrls),
+       .config = sd_config,
+       .open = sd_open,
+       .start = sd_start,
+       .stopN = sd_stopN,
+       .stop0 = sd_stop0,
+       .close = sd_close,
+       .pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static __devinitdata struct usb_device_id device_table[] = {
+       {USB_DEVICE(0x06e1, 0xa190), DVNM("ADS Instant VCD")},
+/*     {USB_DEVICE(0x0733, 0x0430), DVNM("UsbGrabber PV321c")}, */
+       {USB_DEVICE(0x0734, 0x043b), DVNM("3DeMon USB Capture aka")},
+       {USB_DEVICE(0x99fa, 0x8988), DVNM("Grandtec V.cap")},
+       {}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+                       const struct usb_device_id *id)
+{
+       return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+                               THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+       .name = MODULE_NAME,
+       .id_table = device_table,
+       .probe = sd_probe,
+       .disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+       if (usb_register(&sd_driver) < 0)
+               return -1;
+       PDEBUG(D_PROBE, "v%s registered", version);
+       return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+       usb_deregister(&sd_driver);
+       PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/spca508.c b/drivers/media/video/gspca/spca508.c
new file mode 100644 (file)
index 0000000..566adf4
--- /dev/null
@@ -0,0 +1,1774 @@
+/*
+ * SPCA508 chip based cameras subdriver
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define MODULE_NAME "spca508"
+
+#include "gspca.h"
+
+#define DRIVER_VERSION_NUMBER  KERNEL_VERSION(2, 1, 0)
+static const char version[] = "2.1.0";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("GSPCA/SPCA508 USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+       struct gspca_dev gspca_dev;             /* !! must be the first item */
+
+       int buflen;
+       unsigned char tmpbuf[352 * 288 * 3 / 2]; /* YUVY per line */
+       unsigned char tmpbuf2[352 * 288 * 2];   /* YUYV */
+
+       unsigned char brightness;
+
+       char subtype;
+#define CreativeVista 0
+#define HamaUSBSightcam 1
+#define HamaUSBSightcam2 2
+#define IntelEasyPCCamera 3
+#define MicroInnovationIC200 4
+#define ViewQuestVQ110 5
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+#define SD_BRIGHTNESS 0
+       {
+           {
+               .id      = V4L2_CID_BRIGHTNESS,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Brightness",
+               .minimum = 0,
+               .maximum = 0xff,
+               .step    = 1,
+               .default_value = 0x80,
+           },
+           .set = sd_setbrightness,
+           .get = sd_getbrightness,
+       },
+};
+
+static struct cam_mode sif_mode[] = {
+       {V4L2_PIX_FMT_YUYV, 160, 120, 3},
+       {V4L2_PIX_FMT_YUYV, 176, 144, 2},
+       {V4L2_PIX_FMT_YUYV, 320, 240, 1},
+       {V4L2_PIX_FMT_YUYV, 352, 288, 0},
+};
+
+/* Frame packet header offsets for the spca508 */
+#define SPCA508_OFFSET_TYPE 1
+#define SPCA508_OFFSET_COMPRESS 2
+#define SPCA508_OFFSET_FRAMSEQ 8
+#define SPCA508_OFFSET_WIN1LUM 11
+#define SPCA508_OFFSET_DATA 37
+
+#define SPCA508_SNAPBIT 0x20
+#define SPCA508_SNAPCTRL 0x40
+/*************** I2c ****************/
+#define SPCA508_INDEX_I2C_BASE 0x8800
+
+/*
+ * Initialization data: this is the first set-up data written to the
+ * device (before the open data).
+ */
+static __u16 spca508_init_data[][3] =
+#define IGN(x)                 /* nothing */
+{
+       /*  line   URB      value, index */
+       /* 44274  1804 */ {0x0000, 0x870b},
+
+       /* 44299  1805 */ {0x0020, 0x8112},
+       /* Video drop enable, ISO streaming disable */
+       /* 44324  1806 */ {0x0003, 0x8111},
+       /* Reset compression & memory */
+       /* 44349  1807 */ {0x0000, 0x8110},
+       /* Disable all outputs */
+       /* 44372  1808 */ /* READ {0x0000, 0x8114} -> 0000: 00  */
+       /* 44398  1809 */ {0x0000, 0x8114},
+       /* SW GPIO data */
+       /* 44423  1810 */ {0x0008, 0x8110},
+       /* Enable charge pump output */
+       /* 44527  1811 */ {0x0002, 0x8116},
+       /* 200 kHz pump clock */
+       /* 44555  1812 */
+               /* UNKNOWN DIRECTION (URB_FUNCTION_SELECT_INTERFACE:) */
+       /* 44590  1813 */ {0x0003, 0x8111},
+       /* Reset compression & memory */
+       /* 44615  1814 */ {0x0000, 0x8111},
+       /* Normal mode (not reset) */
+       /* 44640  1815 */ {0x0098, 0x8110},
+       /* Enable charge pump output, sync.serial,external 2x clock */
+       /* 44665  1816 */ {0x000d, 0x8114},
+       /* SW GPIO data */
+       /* 44690  1817 */ {0x0002, 0x8116},
+       /* 200 kHz pump clock */
+       /* 44715  1818 */ {0x0020, 0x8112},
+       /* Video drop enable, ISO streaming disable */
+/* --------------------------------------- */
+       /* 44740  1819 */ {0x000f, 0x8402},
+       /* memory bank */
+       /* 44765  1820 */ {0x0000, 0x8403},
+       /* ... address */
+/* --------------------------------------- */
+/* 0x88__ is Synchronous Serial Interface. */
+/* TBD: This table could be expressed more compactly */
+/* using spca508_write_i2c_vector(). */
+/* TBD: Should see if the values in spca50x_i2c_data */
+/* would work with the VQ110 instead of the values */
+/* below. */
+       /* 44790  1821 */ {0x00c0, 0x8804},
+       /* SSI slave addr */
+       /* 44815  1822 */ {0x0008, 0x8802},
+       /* 375 Khz SSI clock */
+       /* 44838  1823 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 44862  1824 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+       /* 44888  1825 */ {0x0008, 0x8802},
+       /* 375 Khz SSI clock */
+       /* 44913  1826 */ {0x0012, 0x8801},
+       /* SSI reg addr */
+       /* 44938  1827 */ {0x0080, 0x8800},
+       /* SSI data to write */
+       /* 44961  1828 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 44985  1829 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 45009  1830 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+       /* 45035  1831 */ {0x0008, 0x8802},
+       /* 375 Khz SSI clock */
+       /* 45060  1832 */ {0x0012, 0x8801},
+       /* SSI reg addr */
+       /* 45085  1833 */ {0x0000, 0x8800},
+       /* SSI data to write */
+       /* 45108  1834 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 45132  1835 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 45156  1836 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+       /* 45182  1837 */ {0x0008, 0x8802},
+       /* 375 Khz SSI clock */
+       /* 45207  1838 */ {0x0011, 0x8801},
+       /* SSI reg addr */
+       /* 45232  1839 */ {0x0040, 0x8800},
+       /* SSI data to write */
+       /* 45255  1840 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 45279  1841 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 45303  1842 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+       /* 45329  1843 */ {0x0008, 0x8802},
+       /* 45354  1844 */ {0x0013, 0x8801},
+       /* 45379  1845 */ {0x0000, 0x8800},
+       /* 45402  1846 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 45426  1847 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 45450  1848 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+       /* 45476  1849 */ {0x0008, 0x8802},
+       /* 45501  1850 */ {0x0014, 0x8801},
+       /* 45526  1851 */ {0x0000, 0x8800},
+       /* 45549  1852 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 45573  1853 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 45597  1854 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+       /* 45623  1855 */ {0x0008, 0x8802},
+       /* 45648  1856 */ {0x0015, 0x8801},
+       /* 45673  1857 */ {0x0001, 0x8800},
+       /* 45696  1858 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 45720  1859 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 45744  1860 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+       /* 45770  1861 */ {0x0008, 0x8802},
+       /* 45795  1862 */ {0x0016, 0x8801},
+       /* 45820  1863 */ {0x0003, 0x8800},
+       /* 45843  1864 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 45867  1865 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 45891  1866 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+       /* 45917  1867 */ {0x0008, 0x8802},
+       /* 45942  1868 */ {0x0017, 0x8801},
+       /* 45967  1869 */ {0x0036, 0x8800},
+       /* 45990  1870 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 46014  1871 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 46038  1872 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+       /* 46064  1873 */ {0x0008, 0x8802},
+       /* 46089  1874 */ {0x0018, 0x8801},
+       /* 46114  1875 */ {0x00ec, 0x8800},
+       /* 46137  1876 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 46161  1877 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 46185  1878 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+       /* 46211  1879 */ {0x0008, 0x8802},
+       /* 46236  1880 */ {0x001a, 0x8801},
+       /* 46261  1881 */ {0x0094, 0x8800},
+       /* 46284  1882 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 46308  1883 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 46332  1884 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+       /* 46358  1885 */ {0x0008, 0x8802},
+       /* 46383  1886 */ {0x001b, 0x8801},
+       /* 46408  1887 */ {0x0000, 0x8800},
+       /* 46431  1888 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 46455  1889 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 46479  1890 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+       /* 46505  1891 */ {0x0008, 0x8802},
+       /* 46530  1892 */ {0x0027, 0x8801},
+       /* 46555  1893 */ {0x00a2, 0x8800},
+       /* 46578  1894 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 46602  1895 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 46626  1896 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+       /* 46652  1897 */ {0x0008, 0x8802},
+       /* 46677  1898 */ {0x0028, 0x8801},
+       /* 46702  1899 */ {0x0040, 0x8800},
+       /* 46725  1900 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 46749  1901 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 46773  1902 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+       /* 46799  1903 */ {0x0008, 0x8802},
+       /* 46824  1904 */ {0x002a, 0x8801},
+       /* 46849  1905 */ {0x0084, 0x8800},
+       /* 46872  1906 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 46896  1907 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+       /* 46920  1908 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+       /* 46946  1909 */ {0x0008, 0x8802},
+       /* 46971  1910 */ {0x002b, 0x8801},
+       /* 46996  1911 */ {0x00a8, 0x8800},
+       /* 47019  1912 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 47043  1913 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 47067  1914 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+       /* 47093  1915 */ {0x0008, 0x8802},
+       /* 47118  1916 */ {0x002c, 0x8801},
+       /* 47143  1917 */ {0x00fe, 0x8800},
+       /* 47166  1918 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 47190  1919 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 47214  1920 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+       /* 47240  1921 */ {0x0008, 0x8802},
+       /* 47265  1922 */ {0x002d, 0x8801},
+       /* 47290  1923 */ {0x0003, 0x8800},
+       /* 47313  1924 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 47337  1925 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 47361  1926 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+       /* 47387  1927 */ {0x0008, 0x8802},
+       /* 47412  1928 */ {0x0038, 0x8801},
+       /* 47437  1929 */ {0x0083, 0x8800},
+       /* 47460  1930 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 47484  1931 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 47508  1932 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+       /* 47534  1933 */ {0x0008, 0x8802},
+       /* 47559  1934 */ {0x0033, 0x8801},
+       /* 47584  1935 */ {0x0081, 0x8800},
+       /* 47607  1936 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 47631  1937 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 47655  1938 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+       /* 47681  1939 */ {0x0008, 0x8802},
+       /* 47706  1940 */ {0x0034, 0x8801},
+       /* 47731  1941 */ {0x004a, 0x8800},
+       /* 47754  1942 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 47778  1943 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 47802  1944 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+       /* 47828  1945 */ {0x0008, 0x8802},
+       /* 47853  1946 */ {0x0039, 0x8801},
+       /* 47878  1947 */ {0x0000, 0x8800},
+       /* 47901  1948 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 47925  1949 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 47949  1950 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+       /* 47975  1951 */ {0x0008, 0x8802},
+       /* 48000  1952 */ {0x0010, 0x8801},
+       /* 48025  1953 */ {0x00a8, 0x8800},
+       /* 48048  1954 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 48072  1955 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 48096  1956 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+       /* 48122  1957 */ {0x0008, 0x8802},
+       /* 48147  1958 */ {0x0006, 0x8801},
+       /* 48172  1959 */ {0x0058, 0x8800},
+       /* 48195  1960 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 48219  1961 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+       /* 48243  1962 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+       /* 48269  1963 */ {0x0008, 0x8802},
+       /* 48294  1964 */ {0x0000, 0x8801},
+       /* 48319  1965 */ {0x0004, 0x8800},
+       /* 48342  1966 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 48366  1967 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 48390  1968 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+       /* 48416  1969 */ {0x0008, 0x8802},
+       /* 48441  1970 */ {0x0040, 0x8801},
+       /* 48466  1971 */ {0x0080, 0x8800},
+       /* 48489  1972 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 48513  1973 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 48537  1974 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+       /* 48563  1975 */ {0x0008, 0x8802},
+       /* 48588  1976 */ {0x0041, 0x8801},
+       /* 48613  1977 */ {0x000c, 0x8800},
+       /* 48636  1978 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 48660  1979 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 48684  1980 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+       /* 48710  1981 */ {0x0008, 0x8802},
+       /* 48735  1982 */ {0x0042, 0x8801},
+       /* 48760  1983 */ {0x000c, 0x8800},
+       /* 48783  1984 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 48807  1985 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 48831  1986 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+       /* 48857  1987 */ {0x0008, 0x8802},
+       /* 48882  1988 */ {0x0043, 0x8801},
+       /* 48907  1989 */ {0x0028, 0x8800},
+       /* 48930  1990 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 48954  1991 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 48978  1992 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+       /* 49004  1993 */ {0x0008, 0x8802},
+       /* 49029  1994 */ {0x0044, 0x8801},
+       /* 49054  1995 */ {0x0080, 0x8800},
+       /* 49077  1996 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 49101  1997 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 49125  1998 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+       /* 49151  1999 */ {0x0008, 0x8802},
+       /* 49176  2000 */ {0x0045, 0x8801},
+       /* 49201  2001 */ {0x0020, 0x8800},
+       /* 49224  2002 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 49248  2003 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 49272  2004 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+       /* 49298  2005 */ {0x0008, 0x8802},
+       /* 49323  2006 */ {0x0046, 0x8801},
+       /* 49348  2007 */ {0x0020, 0x8800},
+       /* 49371  2008 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 49395  2009 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 49419  2010 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+       /* 49445  2011 */ {0x0008, 0x8802},
+       /* 49470  2012 */ {0x0047, 0x8801},
+       /* 49495  2013 */ {0x0080, 0x8800},
+       /* 49518  2014 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 49542  2015 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 49566  2016 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+       /* 49592  2017 */ {0x0008, 0x8802},
+       /* 49617  2018 */ {0x0048, 0x8801},
+       /* 49642  2019 */ {0x004c, 0x8800},
+       /* 49665  2020 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 49689  2021 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 49713  2022 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+       /* 49739  2023 */ {0x0008, 0x8802},
+       /* 49764  2024 */ {0x0049, 0x8801},
+       /* 49789  2025 */ {0x0084, 0x8800},
+       /* 49812  2026 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 49836  2027 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 49860  2028 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+       /* 49886  2029 */ {0x0008, 0x8802},
+       /* 49911  2030 */ {0x004a, 0x8801},
+       /* 49936  2031 */ {0x0084, 0x8800},
+       /* 49959  2032 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 49983  2033 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 50007  2034 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+       /* 50033  2035 */ {0x0008, 0x8802},
+       /* 50058  2036 */ {0x004b, 0x8801},
+       /* 50083  2037 */ {0x0084, 0x8800},
+       /* 50106  2038 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* --------------------------------------- */
+       /* 50132  2039 */ {0x0012, 0x8700},
+       /* Clock speed 48Mhz/(2+2)/2= 6 Mhz */
+       /* 50157  2040 */ {0x0000, 0x8701},
+       /* CKx1 clock delay adj */
+       /* 50182  2041 */ {0x0000, 0x8701},
+       /* CKx1 clock delay adj */
+       /* 50207  2042 */ {0x0001, 0x870c},
+       /* CKOx2 output */
+       /* --------------------------------------- */
+       /* 50232  2043 */ {0x0080, 0x8600},
+       /* Line memory read counter (L) */
+       /* 50257  2044 */ {0x0001, 0x8606},
+       /* reserved */
+       /* 50282  2045 */ {0x0064, 0x8607},
+       /* Line memory read counter (H) 0x6480=25,728 */
+       /* 50307  2046 */ {0x002a, 0x8601},
+       /* CDSP sharp interpolation mode,
+        *                      line sel for color sep, edge enhance enab */
+       /* 50332  2047 */ {0x0000, 0x8602},
+       /* optical black level for user settng = 0 */
+       /* 50357  2048 */ {0x0080, 0x8600},
+       /* Line memory read counter (L) */
+       /* 50382  2049 */ {0x000a, 0x8603},
+       /* optical black level calc mode: auto; optical black offset = 10 */
+       /* 50407  2050 */ {0x00df, 0x865b},
+       /* Horiz offset for valid pixels (L)=0xdf */
+       /* 50432  2051 */ {0x0012, 0x865c},
+       /* Vert offset for valid lines (L)=0x12 */
+
+/* The following two lines seem to be the "wrong" resolution. */
+/* But perhaps these indicate the actual size of the sensor */
+/* rather than the size of the current video mode. */
+       /* 50457  2052 */ {0x0058, 0x865d},
+       /* Horiz valid pixels (*4) (L) = 352 */
+       /* 50482  2053 */ {0x0048, 0x865e},
+       /* Vert valid lines (*4) (L) = 288 */
+
+       /* 50507  2054 */ {0x0015, 0x8608},
+       /* A11 Coef ... */
+       /* 50532  2055 */ {0x0030, 0x8609},
+       /* 50557  2056 */ {0x00fb, 0x860a},
+       /* 50582  2057 */ {0x003e, 0x860b},
+       /* 50607  2058 */ {0x00ce, 0x860c},
+       /* 50632  2059 */ {0x00f4, 0x860d},
+       /* 50657  2060 */ {0x00eb, 0x860e},
+       /* 50682  2061 */ {0x00dc, 0x860f},
+       /* 50707  2062 */ {0x0039, 0x8610},
+       /* 50732  2063 */ {0x0001, 0x8611},
+       /* R offset for white balance ... */
+       /* 50757  2064 */ {0x0000, 0x8612},
+       /* 50782  2065 */ {0x0001, 0x8613},
+       /* 50807  2066 */ {0x0000, 0x8614},
+       /* 50832  2067 */ {0x005b, 0x8651},
+       /* R gain for white balance ... */
+       /* 50857  2068 */ {0x0040, 0x8652},
+       /* 50882  2069 */ {0x0060, 0x8653},
+       /* 50907  2070 */ {0x0040, 0x8654},
+       /* 50932  2071 */ {0x0000, 0x8655},
+       /* 50957  2072 */ {0x0001, 0x863f},
+       /* Fixed gamma correction enable, USB control,
+        *                       lum filter disable, lum noise clip disable */
+       /* 50982  2073 */ {0x00a1, 0x8656},
+       /* Window1 size 256x256, Windows2 size 64x64,
+        *               gamma look-up disable, new edge enhancement enable */
+       /* 51007  2074 */ {0x0018, 0x8657},
+       /* Edge gain high thresh */
+       /* 51032  2075 */ {0x0020, 0x8658},
+       /* Edge gain low thresh */
+       /* 51057  2076 */ {0x000a, 0x8659},
+       /* Edge bandwidth high threshold */
+       /* 51082  2077 */ {0x0005, 0x865a},
+       /* Edge bandwidth low threshold */
+       /* -------------------------------- */
+       /* 51107  2078 */ {0x0030, 0x8112},
+       /* Video drop enable, ISO streaming enable */
+       /* 51130  2079 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 51154  2080 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+       /* 51180  2081 */ {0xa908, 0x8802},
+       /* 51205  2082 */ {0x0034, 0x8801},
+       /* SSI reg addr */
+       /* 51230  2083 */ {0x00ca, 0x8800},
+       /* SSI data to write */
+       /* 51253  2084 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 51277  2085 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 51301  2086 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+       /* 51327  2087 */ {0x1f08, 0x8802},
+       /* 51352  2088 */ {0x0006, 0x8801},
+       /* 51377  2089 */ {0x0080, 0x8800},
+       /* 51400  2090 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+
+/* ----- Read back coefs we wrote earlier. */
+       /* 51424  2091 */ /* READ { 0, 0x0000, 0x8608 } -> 0000: 15  */
+       /* 51448  2092 */ /* READ { 0, 0x0000, 0x8609 } -> 0000: 30  */
+       /* 51472  2093 */ /* READ { 0, 0x0000, 0x860a } -> 0000: fb  */
+       /* 51496  2094 */ /* READ { 0, 0x0000, 0x860b } -> 0000: 3e  */
+       /* 51520  2095 */ /* READ { 0, 0x0000, 0x860c } -> 0000: ce  */
+       /* 51544  2096 */ /* READ { 0, 0x0000, 0x860d } -> 0000: f4  */
+       /* 51568  2097 */ /* READ { 0, 0x0000, 0x860e } -> 0000: eb  */
+       /* 51592  2098 */ /* READ { 0, 0x0000, 0x860f } -> 0000: dc  */
+       /* 51616  2099 */ /* READ { 0, 0x0000, 0x8610 } -> 0000: 39  */
+       /* 51640  2100 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 51664  2101 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+       /* 51690  2102 */ {0xb008, 0x8802},
+       /* 51715  2103 */ {0x0006, 0x8801},
+       /* 51740  2104 */ {0x007d, 0x8800},
+       /* 51763  2105 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+
+
+       /* This chunk is seemingly redundant with */
+       /* earlier commands (A11 Coef...), but if I disable it, */
+       /* the image appears too dark.  Maybe there was some kind of */
+       /* reset since the earlier commands, so this is necessary again. */
+       /* 51789  2106 */ {0x0015, 0x8608},
+       /* 51814  2107 */ {0x0030, 0x8609},
+       /* 51839  2108 */ {0xfffb, 0x860a},
+       /* 51864  2109 */ {0x003e, 0x860b},
+       /* 51889  2110 */ {0xffce, 0x860c},
+       /* 51914  2111 */ {0xfff4, 0x860d},
+       /* 51939  2112 */ {0xffeb, 0x860e},
+       /* 51964  2113 */ {0xffdc, 0x860f},
+       /* 51989  2114 */ {0x0039, 0x8610},
+       /* 52014  2115 */ {0x0018, 0x8657},
+
+       /* 52039  2116 */ {0x0000, 0x8508},
+       /* Disable compression. */
+       /* Previous line was:
+        * 52039  2116 *  { 0, 0x0021, 0x8508 },  * Enable compression. */
+       /* 52064  2117 */ {0x0032, 0x850b},
+       /* compression stuff */
+       /* 52089  2118 */ {0x0003, 0x8509},
+       /* compression stuff */
+       /* 52114  2119 */ {0x0011, 0x850a},
+       /* compression stuff */
+       /* 52139  2120 */ {0x0021, 0x850d},
+       /* compression stuff */
+       /* 52164  2121 */ {0x0010, 0x850c},
+       /* compression stuff */
+       /* 52189  2122 */ {0x0003, 0x8500},
+       /* *** Video mode: 160x120 */
+       /* 52214  2123 */ {0x0001, 0x8501},
+       /* Hardware-dominated snap control */
+       /* 52239  2124 */ {0x0061, 0x8656},
+       /* Window1 size 128x128, Windows2 size 128x128,
+        *              gamma look-up disable, new edge enhancement enable */
+       /* 52264  2125 */ {0x0018, 0x8617},
+       /* Window1 start X (*2) */
+       /* 52289  2126 */ {0x0008, 0x8618},
+       /* Window1 start Y (*2) */
+       /* 52314  2127 */ {0x0061, 0x8656},
+       /* Window1 size 128x128, Windows2 size 128x128,
+        *              gamma look-up disable, new edge enhancement enable */
+       /* 52339  2128 */ {0x0058, 0x8619},
+       /* Window2 start X (*2) */
+       /* 52364  2129 */ {0x0008, 0x861a},
+       /* Window2 start Y (*2) */
+       /* 52389  2130 */ {0x00ff, 0x8615},
+       /* High lum thresh for white balance */
+       /* 52414  2131 */ {0x0000, 0x8616},
+       /* Low lum thresh for white balance */
+       /* 52439  2132 */ {0x0012, 0x8700},
+       /* Clock speed 48Mhz/(2+2)/2= 6 Mhz */
+       /* 52464  2133 */ {0x0012, 0x8700},
+       /* Clock speed 48Mhz/(2+2)/2= 6 Mhz */
+       /* 52487  2134 */ /* READ { 0, 0x0000, 0x8656 } -> 0000: 61  */
+       /* 52513  2135 */ {0x0028, 0x8802},
+       /* 375 Khz SSI clock, SSI r/w sync with VSYNC */
+       /* 52536  2136 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 52560  2137 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 28  */
+       /* 52586  2138 */ {0x1f28, 0x8802},
+       /* 375 Khz SSI clock, SSI r/w sync with VSYNC */
+       /* 52611  2139 */ {0x0010, 0x8801},
+       /* SSI reg addr */
+       /* 52636  2140 */ {0x003e, 0x8800},
+       /* SSI data to write */
+       /* 52659  2141 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 52685  2142 */ {0x0028, 0x8802},
+       /* 52708  2143 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 52732  2144 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 28  */
+       /* 52758  2145 */ {0x1f28, 0x8802},
+       /* 52783  2146 */ {0x0000, 0x8801},
+       /* 52808  2147 */ {0x001f, 0x8800},
+       /* 52831  2148 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 52857  2149 */ {0x0001, 0x8602},
+       /* optical black level for user settning = 1 */
+
+       /* Original: */
+       /* 52882  2150 */ {0x0023, 0x8700},
+       /* Clock speed 48Mhz/(3+2)/4= 2.4 Mhz */
+       /* 52907  2151 */ {0x000f, 0x8602},
+       /* optical black level for user settning = 15 */
+
+       /* 52932  2152 */ {0x0028, 0x8802},
+       /* 52955  2153 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 52979  2154 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 28  */
+       /* 53005  2155 */ {0x1f28, 0x8802},
+       /* 53030  2156 */ {0x0010, 0x8801},
+       /* 53055  2157 */ {0x007b, 0x8800},
+       /* 53078  2158 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* 53104  2159 */ {0x002f, 0x8651},
+       /* R gain for white balance ... */
+       /* 53129  2160 */ {0x0080, 0x8653},
+       /* 53152  2161 */ /* READ { 0, 0x0000, 0x8655 } -> 0000: 00  */
+       /* 53178  2162 */ {0x0000, 0x8655},
+
+       /* 53203  2163 */ {0x0030, 0x8112},
+       /* Video drop enable, ISO streaming enable */
+       /* 53228  2164 */ {0x0020, 0x8112},
+       /* Video drop enable, ISO streaming disable */
+       /* 53252  2165 */
+            /* UNKNOWN DIRECTION (URB_FUNCTION_SELECT_INTERFACE: (ALT=0) ) */
+       {0, 0}
+};
+
+
+/*
+ * Initialization data for Intel EasyPC Camera CS110
+ */
+static __u16 spca508cs110_init_data[][3] = {
+       {0x0000, 0x870b}, /* Reset CTL3 */
+       {0x0003, 0x8111}, /* Soft Reset compression, memory, TG & CDSP */
+       {0x0000, 0x8111}, /* Normal operation on reset */
+       {0x0090, 0x8110},
+                /* External Clock 2x & Synchronous Serial Interface Output */
+       {0x0020, 0x8112}, /* Video Drop packet enable */
+       {0x0000, 0x8114}, /* Software GPIO output data */
+       {0x0001, 0x8114},
+       {0x0001, 0x8114},
+       {0x0001, 0x8114},
+       {0x0003, 0x8114},
+
+       /* Initial sequence Synchronous Serial Interface */
+       {0x000f, 0x8402}, /* Memory bank Address */
+       {0x0000, 0x8403}, /* Memory bank Address */
+       {0x00ba, 0x8804}, /* SSI Slave address */
+       {0x0010, 0x8802}, /* 93.75kHz SSI Clock Two DataByte */
+       {0x0010, 0x8802}, /* 93.75kHz SSI Clock two DataByte */
+
+       {0x0001, 0x8801},
+       {0x000a, 0x8805},/* a - NWG: Dunno what this is about */
+       {0x0000, 0x8800},
+       {0x0010, 0x8802},
+
+       {0x0002, 0x8801},
+       {0x0000, 0x8805},
+       {0x0000, 0x8800},
+       {0x0010, 0x8802},
+
+       {0x0003, 0x8801},
+       {0x0027, 0x8805},
+       {0x0001, 0x8800},
+       {0x0010, 0x8802},
+
+       {0x0004, 0x8801},
+       {0x0065, 0x8805},
+       {0x0001, 0x8800},
+       {0x0010, 0x8802},
+
+       {0x0005, 0x8801},
+       {0x0003, 0x8805},
+       {0x0000, 0x8800},
+       {0x0010, 0x8802},
+
+       {0x0006, 0x8801},
+       {0x001c, 0x8805},
+       {0x0000, 0x8800},
+       {0x0010, 0x8802},
+
+       {0x0007, 0x8801},
+       {0x002a, 0x8805},
+       {0x0000, 0x8800},
+       {0x0010, 0x8802},
+
+       {0x0002, 0x8704}, /* External input CKIx1 */
+       {0x0001, 0x8606}, /* 1 Line memory Read Counter (H) Result: (d)410 */
+       {0x009a, 0x8600}, /* Line memory Read Counter (L) */
+       {0x0001, 0x865b}, /* 1 Horizontal Offset for Valid Pixel(L) */
+       {0x0003, 0x865c}, /* 3 Vertical Offset for Valid Lines(L) */
+       {0x0058, 0x865d}, /* 58 Horizontal Valid Pixel Window(L) */
+
+       {0x0006, 0x8660}, /* Nibble data + input order */
+
+       {0x000a, 0x8602}, /* Optical black level set to 0x0a */
+/* 1945 */ {0x0000, 0x8603}, /* Optical black level Offset */
+
+/* 1962 *  {0, 0x0000, 0x8611},  * 0 R  Offset for white Balance */
+/* 1963 *  {0, 0x0000, 0x8612},  * 1 Gr Offset for white Balance */
+/* 1964 *  {0, 0x0000, 0x8613},  * 1f B  Offset for white Balance */
+/* 1965 *  {0, 0x0000, 0x8614},  * f0 Gb Offset for white Balance */
+
+       {0x0040, 0x8651}, /* 2b BLUE gain for white balance  good at all 60 */
+       {0x0030, 0x8652}, /* 41 Gr Gain for white Balance (L) */
+       {0x0035, 0x8653}, /* 26 RED gain for white balance */
+       {0x0035, 0x8654}, /* 40Gb Gain for white Balance (L) */
+       {0x0041, 0x863f},
+             /* Fixed Gamma correction enabled (makes colours look better) */
+
+/* 2422 */ {0x0000, 0x8655},
+       /* High bits for white balance*****brightness control*** */
+       {}
+};
+
+static __u16 spca508_sightcam_init_data[][3] = {
+/* This line seems to setup the frame/canvas */
+       /*368  */ {0x000f, 0x8402},
+
+/* Theese 6 lines are needed to startup the webcam */
+       /*398  */ {0x0090, 0x8110},
+       /*399  */ {0x0001, 0x8114},
+       /*400  */ {0x0001, 0x8114},
+       /*401  */ {0x0001, 0x8114},
+       /*402  */ {0x0003, 0x8114},
+       /*403  */ {0x0080, 0x8804},
+
+/* This part seems to make the pictures darker? (autobrightness?) */
+       /*436  */ {0x0001, 0x8801},
+       /*437  */ {0x0004, 0x8800},
+       /*439  */ {0x0003, 0x8801},
+       /*440  */ {0x00e0, 0x8800},
+       /*442  */ {0x0004, 0x8801},
+       /*443  */ {0x00b4, 0x8800},
+       /*445  */ {0x0005, 0x8801},
+       /*446  */ {0x0000, 0x8800},
+
+       /*448  */ {0x0006, 0x8801},
+       /*449  */ {0x00e0, 0x8800},
+       /*451  */ {0x0007, 0x8801},
+       /*452  */ {0x000c, 0x8800},
+
+/* This section is just needed, it probably
+ * does something like the previous section,
+ * but the cam won't start if it's not included.
+ */
+       /*484  */ {0x0014, 0x8801},
+       /*485  */ {0x0008, 0x8800},
+       /*487  */ {0x0015, 0x8801},
+       /*488  */ {0x0067, 0x8800},
+       /*490  */ {0x0016, 0x8801},
+       /*491  */ {0x0000, 0x8800},
+       /*493  */ {0x0017, 0x8801},
+       /*494  */ {0x0020, 0x8800},
+       /*496  */ {0x0018, 0x8801},
+       /*497  */ {0x0044, 0x8800},
+
+/* Makes the picture darker - and the
+ * cam won't start if not included
+ */
+       /*505  */ {0x001e, 0x8801},
+       /*506  */ {0x00ea, 0x8800},
+       /*508  */ {0x001f, 0x8801},
+       /*509  */ {0x0001, 0x8800},
+       /*511  */ {0x0003, 0x8801},
+       /*512  */ {0x00e0, 0x8800},
+
+/* seems to place the colors ontop of each other #1 */
+       /*517  */ {0x0006, 0x8704},
+       /*518  */ {0x0001, 0x870c},
+       /*519  */ {0x0016, 0x8600},
+       /*520  */ {0x0002, 0x8606},
+
+/* if not included the pictures becomes _very_ dark */
+       /*521  */ {0x0064, 0x8607},
+       /*522  */ {0x003a, 0x8601},
+       /*523  */ {0x0000, 0x8602},
+
+/* seems to place the colors ontop of each other #2 */
+       /*524  */ {0x0016, 0x8600},
+       /*525  */ {0x0018, 0x8617},
+       /*526  */ {0x0008, 0x8618},
+       /*527  */ {0x00a1, 0x8656},
+
+/* webcam won't start if not included */
+       /*528  */ {0x0007, 0x865b},
+       /*529  */ {0x0001, 0x865c},
+       /*530  */ {0x0058, 0x865d},
+       /*531  */ {0x0048, 0x865e},
+
+/* adjusts the colors */
+       /*541  */ {0x0049, 0x8651},
+       /*542  */ {0x0040, 0x8652},
+       /*543  */ {0x004c, 0x8653},
+       /*544  */ {0x0040, 0x8654},
+
+       {0, 0}
+};
+
+static __u16 spca508_sightcam2_init_data[][3] = {
+/* 35 */ {0x0020, 0x8112},
+
+/* 36 */ {0x000f, 0x8402},
+/* 37 */ {0x0000, 0x8403},
+
+/* 38 */ {0x0008, 0x8201},
+/* 39 */ {0x0008, 0x8200},
+/* 40 */ {0x0001, 0x8200},
+/* 43 */ {0x0009, 0x8201},
+/* 44 */ {0x0008, 0x8200},
+/* 45 */ {0x0001, 0x8200},
+/* 48 */ {0x000a, 0x8201},
+/* 49 */ {0x0008, 0x8200},
+/* 50 */ {0x0001, 0x8200},
+/* 53 */ {0x000b, 0x8201},
+/* 54 */ {0x0008, 0x8200},
+/* 55 */ {0x0001, 0x8200},
+/* 58 */ {0x000c, 0x8201},
+/* 59 */ {0x0008, 0x8200},
+/* 60 */ {0x0001, 0x8200},
+/* 63 */ {0x000d, 0x8201},
+/* 64 */ {0x0008, 0x8200},
+/* 65 */ {0x0001, 0x8200},
+/* 68 */ {0x000e, 0x8201},
+/* 69 */ {0x0008, 0x8200},
+/* 70 */ {0x0001, 0x8200},
+/* 73 */ {0x0007, 0x8201},
+/* 74 */ {0x0008, 0x8200},
+/* 75 */ {0x0001, 0x8200},
+/* 78 */ {0x000f, 0x8201},
+/* 79 */ {0x0008, 0x8200},
+/* 80 */ {0x0001, 0x8200},
+
+/* 84 */ {0x0018, 0x8660},
+/* 85 */ {0x0010, 0x8201},
+
+/* 86 */ {0x0008, 0x8200},
+/* 87 */ {0x0001, 0x8200},
+/* 90 */ {0x0011, 0x8201},
+/* 91 */ {0x0008, 0x8200},
+/* 92 */ {0x0001, 0x8200},
+
+/* 95 */ {0x0000, 0x86b0},
+/* 96 */ {0x0034, 0x86b1},
+/* 97 */ {0x0000, 0x86b2},
+/* 98 */ {0x0049, 0x86b3},
+/* 99 */ {0x0000, 0x86b4},
+/* 100 */ {0x0000, 0x86b4},
+
+/* 101 */ {0x0012, 0x8201},
+/* 102 */ {0x0008, 0x8200},
+/* 103 */ {0x0001, 0x8200},
+/* 106 */ {0x0013, 0x8201},
+/* 107 */ {0x0008, 0x8200},
+/* 108 */ {0x0001, 0x8200},
+
+/* 111 */ {0x0001, 0x86b0},
+/* 112 */ {0x00aa, 0x86b1},
+/* 113 */ {0x0000, 0x86b2},
+/* 114 */ {0x00e4, 0x86b3},
+/* 115 */ {0x0000, 0x86b4},
+/* 116 */ {0x0000, 0x86b4},
+
+/* 118 */ {0x0018, 0x8660},
+
+/* 119 */ {0x0090, 0x8110},
+/* 120 */ {0x0001, 0x8114},
+/* 121 */ {0x0001, 0x8114},
+/* 122 */ {0x0001, 0x8114},
+/* 123 */ {0x0003, 0x8114},
+
+/* 124 */ {0x0080, 0x8804},
+/* 157 */ {0x0003, 0x8801},
+/* 158 */ {0x0012, 0x8800},
+/* 160 */ {0x0004, 0x8801},
+/* 161 */ {0x0005, 0x8800},
+/* 163 */ {0x0005, 0x8801},
+/* 164 */ {0x0000, 0x8800},
+/* 166 */ {0x0006, 0x8801},
+/* 167 */ {0x0000, 0x8800},
+/* 169 */ {0x0007, 0x8801},
+/* 170 */ {0x0000, 0x8800},
+/* 172 */ {0x0008, 0x8801},
+/* 173 */ {0x0005, 0x8800},
+/* 175 */ {0x000a, 0x8700},
+/* 176 */ {0x000e, 0x8801},
+/* 177 */ {0x0004, 0x8800},
+/* 179 */ {0x0005, 0x8801},
+/* 180 */ {0x0047, 0x8800},
+/* 182 */ {0x0006, 0x8801},
+/* 183 */ {0x0000, 0x8800},
+/* 185 */ {0x0007, 0x8801},
+/* 186 */ {0x00c0, 0x8800},
+/* 188 */ {0x0008, 0x8801},
+/* 189 */ {0x0003, 0x8800},
+/* 191 */ {0x0013, 0x8801},
+/* 192 */ {0x0001, 0x8800},
+/* 194 */ {0x0009, 0x8801},
+/* 195 */ {0x0000, 0x8800},
+/* 197 */ {0x000a, 0x8801},
+/* 198 */ {0x0000, 0x8800},
+/* 200 */ {0x000b, 0x8801},
+/* 201 */ {0x0000, 0x8800},
+/* 203 */ {0x000c, 0x8801},
+/* 204 */ {0x0000, 0x8800},
+/* 206 */ {0x000e, 0x8801},
+/* 207 */ {0x0004, 0x8800},
+/* 209 */ {0x000f, 0x8801},
+/* 210 */ {0x0000, 0x8800},
+/* 212 */ {0x0010, 0x8801},
+/* 213 */ {0x0006, 0x8800},
+/* 215 */ {0x0011, 0x8801},
+/* 216 */ {0x0006, 0x8800},
+/* 218 */ {0x0012, 0x8801},
+/* 219 */ {0x0000, 0x8800},
+/* 221 */ {0x0013, 0x8801},
+/* 222 */ {0x0001, 0x8800},
+
+/* 224 */ {0x000a, 0x8700},
+/* 225 */ {0x0000, 0x8702},
+/* 226 */ {0x0000, 0x8703},
+/* 227 */ {0x00c2, 0x8704},
+/* 228 */ {0x0001, 0x870c},
+
+/* 229 */ {0x0044, 0x8600},
+/* 230 */ {0x0002, 0x8606},
+/* 231 */ {0x0064, 0x8607},
+/* 232 */ {0x003a, 0x8601},
+/* 233 */ {0x0008, 0x8602},
+/* 234 */ {0x0044, 0x8600},
+/* 235 */ {0x0018, 0x8617},
+/* 236 */ {0x0008, 0x8618},
+/* 237 */ {0x00a1, 0x8656},
+/* 238 */ {0x0004, 0x865b},
+/* 239 */ {0x0002, 0x865c},
+/* 240 */ {0x0058, 0x865d},
+/* 241 */ {0x0048, 0x865e},
+/* 242 */ {0x0012, 0x8608},
+/* 243 */ {0x002c, 0x8609},
+/* 244 */ {0x0002, 0x860a},
+/* 245 */ {0x002c, 0x860b},
+/* 246 */ {0x00db, 0x860c},
+/* 247 */ {0x00f9, 0x860d},
+/* 248 */ {0x00f1, 0x860e},
+/* 249 */ {0x00e3, 0x860f},
+/* 250 */ {0x002c, 0x8610},
+/* 251 */ {0x006c, 0x8651},
+/* 252 */ {0x0041, 0x8652},
+/* 253 */ {0x0059, 0x8653},
+/* 254 */ {0x0040, 0x8654},
+/* 255 */ {0x00fa, 0x8611},
+/* 256 */ {0x00ff, 0x8612},
+/* 257 */ {0x00f8, 0x8613},
+/* 258 */ {0x0000, 0x8614},
+/* 259 */ {0x0001, 0x863f},
+/* 260 */ {0x0000, 0x8640},
+/* 261 */ {0x0026, 0x8641},
+/* 262 */ {0x0045, 0x8642},
+/* 263 */ {0x0060, 0x8643},
+/* 264 */ {0x0075, 0x8644},
+/* 265 */ {0x0088, 0x8645},
+/* 266 */ {0x009b, 0x8646},
+/* 267 */ {0x00b0, 0x8647},
+/* 268 */ {0x00c5, 0x8648},
+/* 269 */ {0x00d2, 0x8649},
+/* 270 */ {0x00dc, 0x864a},
+/* 271 */ {0x00e5, 0x864b},
+/* 272 */ {0x00eb, 0x864c},
+/* 273 */ {0x00f0, 0x864d},
+/* 274 */ {0x00f6, 0x864e},
+/* 275 */ {0x00fa, 0x864f},
+/* 276 */ {0x00ff, 0x8650},
+/* 277 */ {0x0060, 0x8657},
+/* 278 */ {0x0010, 0x8658},
+/* 279 */ {0x0018, 0x8659},
+/* 280 */ {0x0005, 0x865a},
+/* 281 */ {0x0018, 0x8660},
+/* 282 */ {0x0003, 0x8509},
+/* 283 */ {0x0011, 0x850a},
+/* 284 */ {0x0032, 0x850b},
+/* 285 */ {0x0010, 0x850c},
+/* 286 */ {0x0021, 0x850d},
+/* 287 */ {0x0001, 0x8500},
+/* 288 */ {0x0000, 0x8508},
+/* 289 */ {0x0012, 0x8608},
+/* 290 */ {0x002c, 0x8609},
+/* 291 */ {0x0002, 0x860a},
+/* 292 */ {0x0039, 0x860b},
+/* 293 */ {0x00d0, 0x860c},
+/* 294 */ {0x00f7, 0x860d},
+/* 295 */ {0x00ed, 0x860e},
+/* 296 */ {0x00db, 0x860f},
+/* 297 */ {0x0039, 0x8610},
+/* 298 */ {0x0012, 0x8657},
+/* 299 */ {0x000c, 0x8619},
+/* 300 */ {0x0004, 0x861a},
+/* 301 */ {0x00a1, 0x8656},
+/* 302 */ {0x00c8, 0x8615},
+/* 303 */ {0x0032, 0x8616},
+
+/* 306 */ {0x0030, 0x8112},
+/* 313 */ {0x0020, 0x8112},
+/* 314 */ {0x0020, 0x8112},
+/* 315 */ {0x000f, 0x8402},
+/* 316 */ {0x0000, 0x8403},
+
+/* 317 */ {0x0090, 0x8110},
+/* 318 */ {0x0001, 0x8114},
+/* 319 */ {0x0001, 0x8114},
+/* 320 */ {0x0001, 0x8114},
+/* 321 */ {0x0003, 0x8114},
+/* 322 */ {0x0080, 0x8804},
+
+/* 355 */ {0x0003, 0x8801},
+/* 356 */ {0x0012, 0x8800},
+/* 358 */ {0x0004, 0x8801},
+/* 359 */ {0x0005, 0x8800},
+/* 361 */ {0x0005, 0x8801},
+/* 362 */ {0x0047, 0x8800},
+/* 364 */ {0x0006, 0x8801},
+/* 365 */ {0x0000, 0x8800},
+/* 367 */ {0x0007, 0x8801},
+/* 368 */ {0x00c0, 0x8800},
+/* 370 */ {0x0008, 0x8801},
+/* 371 */ {0x0003, 0x8800},
+/* 373 */ {0x000a, 0x8700},
+/* 374 */ {0x000e, 0x8801},
+/* 375 */ {0x0004, 0x8800},
+/* 377 */ {0x0005, 0x8801},
+/* 378 */ {0x0047, 0x8800},
+/* 380 */ {0x0006, 0x8801},
+/* 381 */ {0x0000, 0x8800},
+/* 383 */ {0x0007, 0x8801},
+/* 384 */ {0x00c0, 0x8800},
+/* 386 */ {0x0008, 0x8801},
+/* 387 */ {0x0003, 0x8800},
+/* 389 */ {0x0013, 0x8801},
+/* 390 */ {0x0001, 0x8800},
+/* 392 */ {0x0009, 0x8801},
+/* 393 */ {0x0000, 0x8800},
+/* 395 */ {0x000a, 0x8801},
+/* 396 */ {0x0000, 0x8800},
+/* 398 */ {0x000b, 0x8801},
+/* 399 */ {0x0000, 0x8800},
+/* 401 */ {0x000c, 0x8801},
+/* 402 */ {0x0000, 0x8800},
+/* 404 */ {0x000e, 0x8801},
+/* 405 */ {0x0004, 0x8800},
+/* 407 */ {0x000f, 0x8801},
+/* 408 */ {0x0000, 0x8800},
+/* 410 */ {0x0010, 0x8801},
+/* 411 */ {0x0006, 0x8800},
+/* 413 */ {0x0011, 0x8801},
+/* 414 */ {0x0006, 0x8800},
+/* 416 */ {0x0012, 0x8801},
+/* 417 */ {0x0000, 0x8800},
+/* 419 */ {0x0013, 0x8801},
+/* 420 */ {0x0001, 0x8800},
+/* 422 */ {0x000a, 0x8700},
+/* 423 */ {0x0000, 0x8702},
+/* 424 */ {0x0000, 0x8703},
+/* 425 */ {0x00c2, 0x8704},
+/* 426 */ {0x0001, 0x870c},
+/* 427 */ {0x0044, 0x8600},
+/* 428 */ {0x0002, 0x8606},
+/* 429 */ {0x0064, 0x8607},
+/* 430 */ {0x003a, 0x8601},
+/* 431 */ {0x0008, 0x8602},
+/* 432 */ {0x0044, 0x8600},
+/* 433 */ {0x0018, 0x8617},
+/* 434 */ {0x0008, 0x8618},
+/* 435 */ {0x00a1, 0x8656},
+/* 436 */ {0x0004, 0x865b},
+/* 437 */ {0x0002, 0x865c},
+/* 438 */ {0x0058, 0x865d},
+/* 439 */ {0x0048, 0x865e},
+/* 440 */ {0x0012, 0x8608},
+/* 441 */ {0x002c, 0x8609},
+/* 442 */ {0x0002, 0x860a},
+/* 443 */ {0x002c, 0x860b},
+/* 444 */ {0x00db, 0x860c},
+/* 445 */ {0x00f9, 0x860d},
+/* 446 */ {0x00f1, 0x860e},
+/* 447 */ {0x00e3, 0x860f},
+/* 448 */ {0x002c, 0x8610},
+/* 449 */ {0x006c, 0x8651},
+/* 450 */ {0x0041, 0x8652},
+/* 451 */ {0x0059, 0x8653},
+/* 452 */ {0x0040, 0x8654},
+/* 453 */ {0x00fa, 0x8611},
+/* 454 */ {0x00ff, 0x8612},
+/* 455 */ {0x00f8, 0x8613},
+/* 456 */ {0x0000, 0x8614},
+/* 457 */ {0x0001, 0x863f},
+/* 458 */ {0x0000, 0x8640},
+/* 459 */ {0x0026, 0x8641},
+/* 460 */ {0x0045, 0x8642},
+/* 461 */ {0x0060, 0x8643},
+/* 462 */ {0x0075, 0x8644},
+/* 463 */ {0x0088, 0x8645},
+/* 464 */ {0x009b, 0x8646},
+/* 465 */ {0x00b0, 0x8647},
+/* 466 */ {0x00c5, 0x8648},
+/* 467 */ {0x00d2, 0x8649},
+/* 468 */ {0x00dc, 0x864a},
+/* 469 */ {0x00e5, 0x864b},
+/* 470 */ {0x00eb, 0x864c},
+/* 471 */ {0x00f0, 0x864d},
+/* 472 */ {0x00f6, 0x864e},
+/* 473 */ {0x00fa, 0x864f},
+/* 474 */ {0x00ff, 0x8650},
+/* 475 */ {0x0060, 0x8657},
+/* 476 */ {0x0010, 0x8658},
+/* 477 */ {0x0018, 0x8659},
+/* 478 */ {0x0005, 0x865a},
+/* 479 */ {0x0018, 0x8660},
+/* 480 */ {0x0003, 0x8509},
+/* 481 */ {0x0011, 0x850a},
+/* 482 */ {0x0032, 0x850b},
+/* 483 */ {0x0010, 0x850c},
+/* 484 */ {0x0021, 0x850d},
+/* 485 */ {0x0001, 0x8500},
+/* 486 */ {0x0000, 0x8508},
+
+/* 487 */ {0x0012, 0x8608},
+/* 488 */ {0x002c, 0x8609},
+/* 489 */ {0x0002, 0x860a},
+/* 490 */ {0x0039, 0x860b},
+/* 491 */ {0x00d0, 0x860c},
+/* 492 */ {0x00f7, 0x860d},
+/* 493 */ {0x00ed, 0x860e},
+/* 494 */ {0x00db, 0x860f},
+/* 495 */ {0x0039, 0x8610},
+/* 496 */ {0x0012, 0x8657},
+/* 497 */ {0x0064, 0x8619},
+
+/* This line starts it all, it is not needed here */
+/* since it has been build into the driver */
+/* jfm: don't start now */
+/* 590  *  {0x0030, 0x8112}, */
+       {}
+};
+
+/*
+ * Initialization data for Creative Webcam Vista
+ */
+static __u16 spca508_vista_init_data[][3] = {
+       {0x0008, 0x8200},       /* Clear register */
+       {0x0000, 0x870b},       /* Reset CTL3 */
+       {0x0020, 0x8112},       /* Video Drop packet enable */
+       {0x0003, 0x8111},  /* Soft Reset compression, memory, TG & CDSP */
+       {0x0000, 0x8110},       /* Disable everything */
+       {0x0000, 0x8114},       /* Software GPIO output data */
+       {0x0000, 0x8114},
+
+       {0x0003, 0x8111},
+       {0x0000, 0x8111},
+       {0x0090, 0x8110},  /* Enable: SSI output, External 2X clock output */
+       {0x0020, 0x8112},
+       {0x0000, 0x8114},
+       {0x0001, 0x8114},
+       {0x0001, 0x8114},
+       {0x0001, 0x8114},
+       {0x0003, 0x8114},
+
+       {0x000f, 0x8402},       /* Memory bank Address */
+       {0x0000, 0x8403},       /* Memory bank Address */
+       {0x00ba, 0x8804},       /* SSI Slave address */
+       {0x0010, 0x8802},       /* 93.75kHz SSI Clock Two DataByte */
+
+       /* READ { 0, 0x0001, 0x8803 } ->
+               0000: 00  */
+       /* READ { 0, 0x0001, 0x8802 } ->
+               0000: 10  */
+       {0x0010, 0x8802},       /* Will write 2 bytes (DATA1+DATA2) */
+       {0x0020, 0x8801},       /* Register address for SSI read/write */
+       {0x0044, 0x8805},       /* DATA2 */
+       {0x0004, 0x8800},       /* DATA1 -> write triggered */
+       /* READ { 0, 0x0001, 0x8803 } ->
+               0000: 00  */
+
+       /* READ { 0, 0x0001, 0x8803 } ->
+               0000: 00  */
+       /* READ { 0, 0x0001, 0x8802 } ->
+               0000: 10  */
+       {0x0010, 0x8802},
+       {0x0009, 0x8801},
+       {0x0042, 0x8805},
+       {0x0001, 0x8800},
+       /* READ { 0, 0x0001, 0x8803 } ->
+               0000: 00  */
+
+       /* READ { 0, 0x0001, 0x8803 } ->
+               0000: 00  */
+       /* READ { 0, 0x0001, 0x8802 } ->
+               0000: 10  */
+       {0x0010, 0x8802},
+       {0x003c, 0x8801},
+       {0x0001, 0x8805},
+       {0x0000, 0x8800},
+       /* READ { 0, 0x0001, 0x8803 } ->
+               0000: 00  */
+
+       /* READ { 0, 0x0001, 0x8803 } ->
+               0000: 00  */
+       /* READ { 0, 0x0001, 0x8802 } ->
+               0000: 10  */
+       {0x0010, 0x8802},
+       {0x0001, 0x8801},
+       {0x000a, 0x8805},
+       {0x0000, 0x8800},
+       /* READ { 0, 0x0001, 0x8803 } ->
+               0000: 00  */
+
+       /* READ { 0, 0x0001, 0x8803 } ->
+               0000: 00  */
+       /* READ { 0, 0x0001, 0x8802 } ->
+               0000: 10  */
+       {0x0010, 0x8802},
+       {0x0002, 0x8801},
+       {0x0000, 0x8805},
+       {0x0000, 0x8800},
+       /* READ { 0, 0x0001, 0x8803 } ->
+               0000: 00  */
+
+       /* READ { 0, 0x0001, 0x8803 } ->
+               0000: 00  */
+       /* READ { 0, 0x0001, 0x8802 } ->
+               0000: 10  */
+       {0x0010, 0x8802},
+       {0x0003, 0x8801},
+       {0x0027, 0x8805},
+       {0x0001, 0x8800},
+       /* READ { 0, 0x0001, 0x8803 } ->
+               0000: 00  */
+
+       /* READ { 0, 0x0001, 0x8803 } ->
+               0000: 00  */
+       /* READ { 0, 0x0001, 0x8802 } ->
+               0000: 10  */
+       {0x0010, 0x8802},
+       {0x0004, 0x8801},
+       {0x0065, 0x8805},
+       {0x0001, 0x8800},
+       /* READ { 0, 0x0001, 0x8803 } ->
+               0000: 00  */
+
+       /* READ { 0, 0x0001, 0x8803 } ->
+               0000: 00  */
+       /* READ { 0, 0x0001, 0x8802 } ->
+               0000: 10  */
+       {0x0010, 0x8802},
+       {0x0005, 0x8801},
+       {0x0003, 0x8805},
+       {0x0000, 0x8800},
+       /* READ { 0, 0x0001, 0x8803 } ->
+               0000: 00  */
+
+       /* READ { 0, 0x0001, 0x8803 } ->
+               0000: 00  */
+       /* READ { 0, 0x0001, 0x8802 } ->
+               0000: 10  */
+       {0x0010, 0x8802},
+       {0x0006, 0x8801},
+       {0x001c, 0x8805},
+       {0x0000, 0x8800},
+       /* READ { 0, 0x0001, 0x8803 } ->
+               0000: 00  */
+
+       /* READ { 0, 0x0001, 0x8803 } ->
+               0000: 00  */
+       /* READ { 0, 0x0001, 0x8802 } ->
+               0000: 10  */
+       {0x0010, 0x8802},
+       {0x0007, 0x8801},
+       {0x002a, 0x8805},
+       {0x0000, 0x8800},
+       /* READ { 0, 0x0001, 0x8803 } ->
+               0000: 00  */
+
+       /* READ { 0, 0x0001, 0x8803 } ->
+               0000: 00  */
+       /* READ { 0, 0x0001, 0x8802 } ->
+               0000: 10  */
+       {0x0010, 0x8802},
+       {0x000e, 0x8801},
+       {0x0000, 0x8805},
+       {0x0000, 0x8800},
+       /* READ { 0, 0x0001, 0x8803 } ->
+               0000: 00  */
+
+       /* READ { 0, 0x0001, 0x8803 } ->
+               0000: 00  */
+       /* READ { 0, 0x0001, 0x8802 } ->
+               0000: 10  */
+       {0x0010, 0x8802},
+       {0x0028, 0x8801},
+       {0x002e, 0x8805},
+       {0x0000, 0x8800},
+       /* READ { 0, 0x0001, 0x8803 } ->
+               0000: 00  */
+
+       /* READ { 0, 0x0001, 0x8803 } ->
+               0000: 00  */
+       /* READ { 0, 0x0001, 0x8802 } ->
+               0000: 10  */
+       {0x0010, 0x8802},
+       {0x0039, 0x8801},
+       {0x0013, 0x8805},
+       {0x0000, 0x8800},
+       /* READ { 0, 0x0001, 0x8803 } ->
+               0000: 00  */
+
+       /* READ { 0, 0x0001, 0x8803 } ->
+               0000: 00  */
+       /* READ { 0, 0x0001, 0x8802 } ->
+               0000: 10  */
+       {0x0010, 0x8802},
+       {0x003b, 0x8801},
+       {0x000c, 0x8805},
+       {0x0000, 0x8800},
+       /* READ { 0, 0x0001, 0x8803 } ->
+               0000: 00  */
+
+       /* READ { 0, 0x0001, 0x8803 } ->
+               0000: 00  */
+       /* READ { 0, 0x0001, 0x8802 } ->
+               0000: 10  */
+       {0x0010, 0x8802},
+       {0x0035, 0x8801},
+       {0x0028, 0x8805},
+       {0x0000, 0x8800},
+       /* READ { 0, 0x0001, 0x8803 } ->
+               0000: 00  */
+
+       /* READ { 0, 0x0001, 0x8803 } ->
+               0000: 00  */
+       /* READ { 0, 0x0001, 0x8802 } ->
+               0000: 10  */
+       {0x0010, 0x8802},
+       {0x0009, 0x8801},
+       {0x0042, 0x8805},
+       {0x0001, 0x8800},
+       /* READ { 0, 0x0001, 0x8803 } ->
+               0000: 00  */
+
+       {0x0050, 0x8703},
+       {0x0002, 0x8704},       /* External input CKIx1 */
+       {0x0001, 0x870C},       /* Select CKOx2 output */
+       {0x009A, 0x8600},       /* Line memory Read Counter (L) */
+       {0x0001, 0x8606},  /* 1 Line memory Read Counter (H) Result: (d)410 */
+       {0x0023, 0x8601},
+       {0x0010, 0x8602},
+       {0x000A, 0x8603},
+       {0x009A, 0x8600},
+       {0x0001, 0x865B},       /* 1 Horizontal Offset for Valid Pixel(L) */
+       {0x0003, 0x865C},       /* Vertical offset for valid lines (L) */
+       {0x0058, 0x865D},       /* Horizontal valid pixels window (L) */
+       {0x0048, 0x865E},       /* Vertical valid lines window (L) */
+       {0x0000, 0x865F},
+
+       {0x0006, 0x8660},
+                   /* Enable nibble data input, select nibble input order */
+
+       {0x0013, 0x8608},       /* A11 Coeficients for color correction */
+       {0x0028, 0x8609},
+                   /* Note: these values are confirmed at the end of array */
+       {0x0005, 0x860A},       /* ... */
+       {0x0025, 0x860B},
+       {0x00E1, 0x860C},
+       {0x00FA, 0x860D},
+       {0x00F4, 0x860E},
+       {0x00E8, 0x860F},
+       {0x0025, 0x8610},       /* A33 Coef. */
+       {0x00FC, 0x8611},       /* White balance offset: R */
+       {0x0001, 0x8612},       /* White balance offset: Gr */
+       {0x00FE, 0x8613},       /* White balance offset: B */
+       {0x0000, 0x8614},       /* White balance offset: Gb */
+
+       {0x0064, 0x8651},       /* R gain for white balance (L) */
+       {0x0040, 0x8652},       /* Gr gain for white balance (L) */
+       {0x0066, 0x8653},       /* B gain for white balance (L) */
+       {0x0040, 0x8654},       /* Gb gain for white balance (L) */
+       {0x0001, 0x863F},       /* Enable fixed gamma correction */
+
+       {0x00A1, 0x8656},       /* Size - Window1: 256x256, Window2: 128x128 */
+       /* UV division: UV no change, Enable New edge enhancement */
+       {0x0018, 0x8657},       /* Edge gain high threshold */
+       {0x0020, 0x8658},       /* Edge gain low threshold */
+       {0x000A, 0x8659},       /* Edge bandwidth high threshold */
+       {0x0005, 0x865A},       /* Edge bandwidth low threshold */
+       {0x0064, 0x8607},       /* UV filter enable */
+
+       {0x0016, 0x8660},
+       {0x0000, 0x86B0},       /* Bad pixels compensation address */
+       {0x00DC, 0x86B1},       /* X coord for bad pixels compensation (L) */
+       {0x0000, 0x86B2},
+       {0x0009, 0x86B3},       /* Y coord for bad pixels compensation (L) */
+       {0x0000, 0x86B4},
+
+       {0x0001, 0x86B0},
+       {0x00F5, 0x86B1},
+       {0x0000, 0x86B2},
+       {0x00C6, 0x86B3},
+       {0x0000, 0x86B4},
+
+       {0x0002, 0x86B0},
+       {0x001C, 0x86B1},
+       {0x0001, 0x86B2},
+       {0x00D7, 0x86B3},
+       {0x0000, 0x86B4},
+
+       {0x0003, 0x86B0},
+       {0x001C, 0x86B1},
+       {0x0001, 0x86B2},
+       {0x00D8, 0x86B3},
+       {0x0000, 0x86B4},
+
+       {0x0004, 0x86B0},
+       {0x001D, 0x86B1},
+       {0x0001, 0x86B2},
+       {0x00D8, 0x86B3},
+       {0x0000, 0x86B4},
+       {0x001E, 0x8660},
+
+       /* READ { 0, 0x0000, 0x8608 } ->
+               0000: 13  */
+       /* READ { 0, 0x0000, 0x8609 } ->
+               0000: 28  */
+       /* READ { 0, 0x0000, 0x8610 } ->
+               0000: 05  */
+       /* READ { 0, 0x0000, 0x8611 } ->
+               0000: 25  */
+       /* READ { 0, 0x0000, 0x8612 } ->
+               0000: e1  */
+       /* READ { 0, 0x0000, 0x8613 } ->
+               0000: fa  */
+       /* READ { 0, 0x0000, 0x8614 } ->
+               0000: f4  */
+       /* READ { 0, 0x0000, 0x8615 } ->
+               0000: e8  */
+       /* READ { 0, 0x0000, 0x8616 } ->
+               0000: 25  */
+       {}
+};
+
+static int reg_write(struct usb_device *dev,
+                       __u16 index, __u16 value)
+{
+       int ret;
+
+       ret = usb_control_msg(dev,
+                       usb_sndctrlpipe(dev, 0),
+                       0,              /* request */
+                       USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       value, index, NULL, 0, 500);
+       PDEBUG(D_USBO, "reg write i:0x%04x = 0x%02x",
+               index, value);
+       if (ret < 0)
+               PDEBUG(D_ERR|D_USBO, "reg write: error %d", ret);
+       return ret;
+}
+
+/* read 1 byte */
+/* returns: negative is error, pos or zero is data */
+static int reg_read(struct usb_device *dev,
+                       __u16 index)    /* wIndex */
+{
+       int ret;
+       __u8 data;
+
+       ret = usb_control_msg(dev,
+                       usb_rcvctrlpipe(dev, 0),
+                       0,                      /* register */
+                       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       (__u16) 0,              /* value */
+                       index,
+                       &data, 1,
+                       500);                   /* timeout */
+       PDEBUG(D_USBI, "reg read i:%04x --> %02x", index, data);
+       if (ret < 0) {
+               PDEBUG(D_ERR|D_USBI, "reg_read err %d", ret);
+               return ret;
+       }
+       return data;
+}
+
+static int write_vector(struct gspca_dev *gspca_dev,
+                               __u16 data[][3])
+{
+       struct usb_device *dev = gspca_dev->dev;
+       int ret, i = 0;
+
+       while (data[i][1] != 0) {
+               ret = reg_write(dev, data[i][1], data[i][0]);
+               if (ret < 0)
+                       return ret;
+               i++;
+       }
+       return 0;
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+                       const struct usb_device_id *id)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct usb_device *dev = gspca_dev->dev;
+       struct cam *cam;
+       __u16 vendor;
+       __u16 product;
+       int data1, data2;
+
+       vendor = id->idVendor;
+       product = id->idProduct;
+       switch (vendor) {
+       case 0x041e:            /* Creative cameras */
+/*             switch (product) { */
+/*             case 0x4018: */
+                       sd->subtype = CreativeVista;
+/*                     break; */
+/*             } */
+               break;
+       case 0x0461:            /* MicroInnovation */
+/*             switch (product) { */
+/*             case 0x0815: */
+                       sd->subtype = MicroInnovationIC200;
+/*                     break; */
+/*             } */
+               break;
+       case 0x0733:    /* Rebadged ViewQuest (Intel) and ViewQuest cameras */
+/*             switch (product) { */
+/*             case 0x110: */
+                       sd->subtype = ViewQuestVQ110;
+/*                     break; */
+/*             } */
+               break;
+       case 0x0af9:            /* Hama cameras */
+               switch (product) {
+               case 0x0010:
+                       sd->subtype = HamaUSBSightcam;
+                       break;
+               case 0x0011:
+                       sd->subtype = HamaUSBSightcam2;
+                       break;
+               }
+               break;
+       case 0x8086:            /* Intel */
+/*             switch (product) { */
+/*             case 0x0110: */
+                       sd->subtype = IntelEasyPCCamera;
+/*                     break; */
+/*             } */
+               break;
+       }
+
+       /* Read from global register the USB product and vendor IDs, just to */
+       /* prove that we can communicate with the device.  This works, which */
+       /* confirms at we are communicating properly and that the device */
+       /* is a 508. */
+       data1 = reg_read(dev, 0x8104);
+       data2 = reg_read(dev, 0x8105);
+       PDEBUG(D_PROBE,
+               "Read from GLOBAL: USB Vendor ID 0x%02x%02x", data2, data1);
+
+       data1 = reg_read(dev, 0x8106);
+       data2 = reg_read(dev, 0x8107);
+       PDEBUG(D_PROBE,
+               "Read from GLOBAL: USB Product ID 0x%02x%02x", data2, data1);
+
+       data1 = reg_read(dev, 0x8621);
+       PDEBUG(D_PROBE,
+               "Read from GLOBAL: Window 1 average luminance %d", data1);
+
+       cam = &gspca_dev->cam;
+       cam->dev_name = (char *) id->driver_info;
+       cam->epaddr = 0x01;
+       cam->cam_mode = sif_mode;
+       cam->nmodes = sizeof sif_mode / sizeof sif_mode[0];
+       sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
+
+       switch (sd->subtype) {
+       case ViewQuestVQ110:
+               if (write_vector(gspca_dev, spca508_init_data))
+                       return -1;
+               break;
+       default:
+/*     case MicroInnovationIC200: */
+/*     case IntelEasyPCCamera: */
+               if (write_vector(gspca_dev, spca508cs110_init_data))
+                       return -1;
+               break;
+       case HamaUSBSightcam:
+               if (write_vector(gspca_dev, spca508_sightcam_init_data))
+                       return -1;
+               break;
+       case HamaUSBSightcam2:
+               if (write_vector(gspca_dev, spca508_sightcam2_init_data))
+                       return -1;
+               break;
+       case CreativeVista:
+               if (write_vector(gspca_dev, spca508_vista_init_data))
+                       return -1;
+               break;
+       }
+       return 0;                       /* success */
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+/*     write_vector(gspca_dev, spca508_open_data); */
+       return 0;
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+       int mode;
+
+       mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].mode;
+       reg_write(gspca_dev->dev, 0x8500, mode);
+       switch (mode) {
+       case 0:
+       case 1:
+               reg_write(gspca_dev->dev, 0x8700, 0x28);        /* clock */
+               break;
+       default:
+/*     case 2: */
+/*     case 3: */
+               reg_write(gspca_dev->dev, 0x8700, 0x23);        /* clock */
+               break;
+       }
+       reg_write(gspca_dev->dev, 0x8112, 0x10 | 0x20);
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+       /* Video ISO disable, Video Drop Packet enable: */
+       reg_write(gspca_dev->dev, 0x8112, 0x20);
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+/* this function is called at close time */
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+/* convert YUVY per line to YUYV (YUV 4:2:2) */
+static void yuvy_decode(unsigned char *out,
+                       unsigned char *in,
+                       int width,
+                       int height)
+{
+       unsigned char *Ui, *Vi, *yi, *yi1;
+       unsigned char *out1;
+       int i, j;
+
+       yi = in;
+       for (i = height / 2; --i >= 0; ) {
+               out1 = out + width * 2;         /* next line */
+               Ui = yi + width;
+               Vi = Ui + width / 2;
+               yi1 = Vi + width / 2;
+               for (j = width / 2; --j >= 0; ) {
+                       *out++ = 128 + *yi++;
+                       *out++ = 128 + *Ui;
+                       *out++ = 128 + *yi++;
+                       *out++ = 128 + *Vi;
+
+                       *out1++ = 128 + *yi1++;
+                       *out1++ = 128 + *Ui++;
+                       *out1++ = 128 + *yi1++;
+                       *out1++ = 128 + *Vi++;
+               }
+               yi += width * 2;
+               out = out1;
+       }
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+                       struct gspca_frame *frame,      /* target */
+                       unsigned char *data,            /* isoc packet */
+                       int len)                        /* iso packet length */
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       switch (data[0]) {
+       case 0:                         /* start of frame */
+               if (gspca_dev->last_packet_type == FIRST_PACKET) {
+                       yuvy_decode(sd->tmpbuf2, sd->tmpbuf,
+                                       gspca_dev->width,
+                                       gspca_dev->height);
+                       frame = gspca_frame_add(gspca_dev,
+                                               LAST_PACKET,
+                                               frame,
+                                               sd->tmpbuf2,
+                                               gspca_dev->width
+                                                       * gspca_dev->height
+                                                       * 2);
+               }
+               gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+                               data, 0);
+               data += SPCA508_OFFSET_DATA;
+               len -= SPCA508_OFFSET_DATA;
+               if (len > 0)
+                       memcpy(sd->tmpbuf, data, len);
+               else
+                       len = 0;
+               sd->buflen = len;
+               return;
+       case 0xff:                      /* drop */
+/*             gspca_dev->last_packet_type = DISCARD_PACKET; */
+               return;
+       }
+       data += 1;
+       len -= 1;
+       memcpy(&sd->tmpbuf[sd->buflen], data, len);
+       sd->buflen += len;
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       __u8 brightness = sd->brightness;
+
+/* MX seem contrast */
+       reg_write(gspca_dev->dev, 0x8651, brightness);
+       reg_write(gspca_dev->dev, 0x8652, brightness);
+       reg_write(gspca_dev->dev, 0x8653, brightness);
+       reg_write(gspca_dev->dev, 0x8654, brightness);
+}
+
+static void getbrightness(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->brightness = reg_read(gspca_dev->dev, 0x8651);
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->brightness = val;
+       if (gspca_dev->streaming)
+               setbrightness(gspca_dev);
+       return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       getbrightness(gspca_dev);
+       *val = sd->brightness;
+       return 0;
+}
+
+/* sub-driver description */
+static struct sd_desc sd_desc = {
+       .name = MODULE_NAME,
+       .ctrls = sd_ctrls,
+       .nctrls = ARRAY_SIZE(sd_ctrls),
+       .config = sd_config,
+       .open = sd_open,
+       .start = sd_start,
+       .stopN = sd_stopN,
+       .stop0 = sd_stop0,
+       .close = sd_close,
+       .pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static __devinitdata struct usb_device_id device_table[] = {
+       {USB_DEVICE(0x041e, 0x4018), DVNM("Creative Webcam Vista (PD1100)")},
+       {USB_DEVICE(0x0461, 0x0815), DVNM("Micro Innovation IC200")},
+       {USB_DEVICE(0x0733, 0x0110), DVNM("ViewQuest VQ110")},
+       {USB_DEVICE(0x0af9, 0x0010), DVNM("Hama USB Sightcam 100")},
+       {USB_DEVICE(0x0af9, 0x0011), DVNM("Hama USB Sightcam 100")},
+       {USB_DEVICE(0x8086, 0x0110), DVNM("Intel Easy PC Camera")},
+       {}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+                       const struct usb_device_id *id)
+{
+       return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+                               THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+       .name = MODULE_NAME,
+       .id_table = device_table,
+       .probe = sd_probe,
+       .disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+       if (usb_register(&sd_driver) < 0)
+               return -1;
+       PDEBUG(D_PROBE, "v%s registered", version);
+       return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+       usb_deregister(&sd_driver);
+       PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/spca561.c b/drivers/media/video/gspca/spca561.c
new file mode 100644 (file)
index 0000000..a94e627
--- /dev/null
@@ -0,0 +1,1025 @@
+/*
+ * Sunplus spca561 subdriver
+ *
+ * Copyright (C) 2004 Michel Xhaard mxhaard@magic.fr
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define MODULE_NAME "spca561"
+
+#include "gspca.h"
+
+#define DRIVER_VERSION_NUMBER  KERNEL_VERSION(2, 1, 0)
+static const char version[] = "2.1.0";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("GSPCA/SPCA561 USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+       struct gspca_dev gspca_dev;     /* !! must be the first item */
+
+       unsigned short contrast;
+       __u8 brightness;
+       __u8 autogain;
+
+       __u8 chip_revision;
+       signed char ag_cnt;
+#define AG_CNT_START 13
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+#define SD_BRIGHTNESS 0
+       {
+        {
+         .id = V4L2_CID_BRIGHTNESS,
+         .type = V4L2_CTRL_TYPE_INTEGER,
+         .name = "Brightness",
+         .minimum = 0,
+         .maximum = 63,
+         .step = 1,
+         .default_value = 32,
+         },
+        .set = sd_setbrightness,
+        .get = sd_getbrightness,
+        },
+#define SD_CONTRAST 1
+       {
+        {
+         .id = V4L2_CID_CONTRAST,
+         .type = V4L2_CTRL_TYPE_INTEGER,
+         .name = "Contrast",
+         .minimum = 0,
+         .maximum = 0x3fff,
+         .step = 1,
+         .default_value = 0x2000,
+         },
+        .set = sd_setcontrast,
+        .get = sd_getcontrast,
+        },
+#define SD_AUTOGAIN 2
+       {
+        {
+         .id = V4L2_CID_AUTOGAIN,
+         .type = V4L2_CTRL_TYPE_BOOLEAN,
+         .name = "Auto Gain",
+         .minimum = 0,
+         .maximum = 1,
+         .step = 1,
+         .default_value = 1,
+         },
+        .set = sd_setautogain,
+        .get = sd_getautogain,
+        },
+};
+
+static struct cam_mode sif_mode[] = {
+       {V4L2_PIX_FMT_SPCA561, 160, 120, 3},
+       {V4L2_PIX_FMT_SPCA561, 176, 144, 2},
+       {V4L2_PIX_FMT_SPCA561, 320, 240, 1},
+       {V4L2_PIX_FMT_SPCA561, 352, 288, 0},
+};
+
+/*
+ * Initialization data
+ * I'm not very sure how to split initialization from open data
+ * chunks. For now, we'll consider everything as initialization
+ */
+/* Frame packet header offsets for the spca561 */
+#define SPCA561_OFFSET_SNAP 1
+#define SPCA561_OFFSET_TYPE 2
+#define SPCA561_OFFSET_COMPRESS 3
+#define SPCA561_OFFSET_FRAMSEQ   4
+#define SPCA561_OFFSET_GPIO 5
+#define SPCA561_OFFSET_USBBUFF 6
+#define SPCA561_OFFSET_WIN2GRAVE 7
+#define SPCA561_OFFSET_WIN2RAVE 8
+#define SPCA561_OFFSET_WIN2BAVE 9
+#define SPCA561_OFFSET_WIN2GBAVE 10
+#define SPCA561_OFFSET_WIN1GRAVE 11
+#define SPCA561_OFFSET_WIN1RAVE 12
+#define SPCA561_OFFSET_WIN1BAVE 13
+#define SPCA561_OFFSET_WIN1GBAVE 14
+#define SPCA561_OFFSET_FREQ 15
+#define SPCA561_OFFSET_VSYNC 16
+#define SPCA561_OFFSET_DATA 1
+#define SPCA561_INDEX_I2C_BASE 0x8800
+#define SPCA561_SNAPBIT 0x20
+#define SPCA561_SNAPCTRL 0x40
+enum {
+       Rev072A = 0,
+       Rev012A,
+};
+
+static void reg_w_val(struct usb_device *dev, __u16 index, __u16 value)
+{
+       int ret;
+
+       ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+                             0,                /* request */
+                             USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                             value, index, NULL, 0, 500);
+       PDEBUG(D_USBO, "reg write: 0x%02x:0x%02x", index, value);
+       if (ret < 0)
+               PDEBUG(D_ERR, "reg write: error %d", ret);
+}
+
+static void write_vector(struct gspca_dev *gspca_dev, __u16 data[][2])
+{
+       struct usb_device *dev = gspca_dev->dev;
+       int i;
+
+       i = 0;
+       while (data[i][1] != 0) {
+               reg_w_val(dev, data[i][1], data[i][0]);
+               i++;
+       }
+}
+
+static void reg_r(struct usb_device *dev,
+                 __u16 index, __u8 *buffer, __u16 length)
+{
+       usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+                       0,                      /* request */
+                       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       0,                      /* value */
+                       index, buffer, length, 500);
+}
+
+static void reg_w_buf(struct usb_device *dev,
+                     __u16 index, __u8 *buffer, __u16 length)
+{
+       usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+                       0,                      /* request */
+                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       0,                      /* value */
+                       index, buffer, length, 500);
+}
+
+static void i2c_init(struct gspca_dev *gspca_dev, __u8 mode)
+{
+       reg_w_val(gspca_dev->dev, 0x92, 0x8804);
+       reg_w_val(gspca_dev->dev, mode, 0x8802);
+}
+
+static void i2c_write(struct gspca_dev *gspca_dev, __u16 valeur, __u16 reg)
+{
+       int retry = 60;
+       __u8 DataLow;
+       __u8 DataHight;
+       __u8 Data;
+
+       DataLow = valeur;
+       DataHight = valeur >> 8;
+       reg_w_val(gspca_dev->dev, reg, 0x8801);
+       reg_w_val(gspca_dev->dev, DataLow, 0x8805);
+       reg_w_val(gspca_dev->dev, DataHight, 0x8800);
+       while (retry--) {
+               reg_r(gspca_dev->dev, 0x8803, &Data, 1);
+               if (!Data)
+                       break;
+       }
+}
+
+static int i2c_read(struct gspca_dev *gspca_dev, __u16 reg, __u8 mode)
+{
+       int retry = 60;
+       __u8 value;
+       __u8 vallsb;
+       __u8 Data;
+
+       reg_w_val(gspca_dev->dev, 0x92, 0x8804);
+       reg_w_val(gspca_dev->dev, reg, 0x8801);
+       reg_w_val(gspca_dev->dev, (mode | 0x01), 0x8802);
+       while (retry--) {
+               reg_r(gspca_dev->dev, 0x8803, &Data, 1);
+               if (!Data)
+                       break;
+       }
+       if (retry == 0)
+               return -1;
+       reg_r(gspca_dev->dev, 0x8800, &value, 1);
+       reg_r(gspca_dev->dev, 0x8805, &vallsb, 1);
+       return ((int) value << 8) | vallsb;
+}
+
+static __u16 spca561_init_data[][2] = {
+       {0x0000, 0x8114},       /* Software GPIO output data */
+       {0x0001, 0x8114},       /* Software GPIO output data */
+       {0x0000, 0x8112},       /* Some kind of reset */
+       {0x0003, 0x8701},       /* PCLK clock delay adjustment */
+       {0x0001, 0x8703},       /* HSYNC from cmos inverted */
+       {0x0011, 0x8118},       /* Enable and conf sensor */
+       {0x0001, 0x8118},       /* Conf sensor */
+       {0x0092, 0x8804},       /* I know nothing about these */
+       {0x0010, 0x8802},       /* 0x88xx registers, so I won't */
+       /***************/
+       {0x000d, 0x8805},       /* sensor default setting */
+       {0x0001, 0x8801},       /* 1 <- 0x0d */
+       {0x0000, 0x8800},
+       {0x0018, 0x8805},
+       {0x0002, 0x8801},       /* 2 <- 0x18 */
+       {0x0000, 0x8800},
+       {0x0065, 0x8805},
+       {0x0004, 0x8801},       /* 4 <- 0x01 0x65 */
+       {0x0001, 0x8800},
+       {0x0021, 0x8805},
+       {0x0005, 0x8801},       /* 5 <- 0x21 */
+       {0x0000, 0x8800},
+       {0x00aa, 0x8805},
+       {0x0007, 0x8801},       /* 7 <- 0xaa */
+       {0x0000, 0x8800},
+       {0x0004, 0x8805},
+       {0x0020, 0x8801},       /* 0x20 <- 0x15 0x04 */
+       {0x0015, 0x8800},
+       {0x0002, 0x8805},
+       {0x0039, 0x8801},       /* 0x39 <- 0x02 */
+       {0x0000, 0x8800},
+       {0x0010, 0x8805},
+       {0x0035, 0x8801},       /* 0x35 <- 0x10 */
+       {0x0000, 0x8800},
+       {0x0049, 0x8805},
+       {0x0009, 0x8801},       /* 0x09 <- 0x10 0x49 */
+       {0x0010, 0x8800},
+       {0x000b, 0x8805},
+       {0x0028, 0x8801},       /* 0x28 <- 0x0b */
+       {0x0000, 0x8800},
+       {0x000f, 0x8805},
+       {0x003b, 0x8801},       /* 0x3b <- 0x0f */
+       {0x0000, 0x8800},
+       {0x0000, 0x8805},
+       {0x003c, 0x8801},       /* 0x3c <- 0x00 */
+       {0x0000, 0x8800},
+       /***************/
+       {0x0018, 0x8601},       /* Pixel/line selection for color separation */
+       {0x0000, 0x8602},       /* Optical black level for user setting */
+       {0x0060, 0x8604},       /* Optical black horizontal offset */
+       {0x0002, 0x8605},       /* Optical black vertical offset */
+       {0x0000, 0x8603},       /* Non-automatic optical black level */
+       {0x0002, 0x865b},       /* Horizontal offset for valid pixels */
+       {0x0000, 0x865f},       /* Vertical valid pixels window (x2) */
+       {0x00b0, 0x865d},       /* Horizontal valid pixels window (x2) */
+       {0x0090, 0x865e},       /* Vertical valid lines window (x2) */
+       {0x00e0, 0x8406},       /* Memory buffer threshold */
+       {0x0000, 0x8660},       /* Compensation memory stuff */
+       {0x0002, 0x8201},       /* Output address for r/w serial EEPROM */
+       {0x0008, 0x8200},       /* Clear valid bit for serial EEPROM */
+       {0x0001, 0x8200},       /* OprMode to be executed by hardware */
+       {0x0007, 0x8201},       /* Output address for r/w serial EEPROM */
+       {0x0008, 0x8200},       /* Clear valid bit for serial EEPROM */
+       {0x0001, 0x8200},       /* OprMode to be executed by hardware */
+       {0x0010, 0x8660},       /* Compensation memory stuff */
+       {0x0018, 0x8660},       /* Compensation memory stuff */
+
+       {0x0004, 0x8611},       /* R offset for white balance */
+       {0x0004, 0x8612},       /* Gr offset for white balance */
+       {0x0007, 0x8613},       /* B offset for white balance */
+       {0x0000, 0x8614},       /* Gb offset for white balance */
+       {0x008c, 0x8651},       /* R gain for white balance */
+       {0x008c, 0x8652},       /* Gr gain for white balance */
+       {0x00b5, 0x8653},       /* B gain for white balance */
+       {0x008c, 0x8654},       /* Gb gain for white balance */
+       {0x0002, 0x8502},       /* Maximum average bit rate stuff */
+
+       {0x0011, 0x8802},
+       {0x0087, 0x8700},       /* Set master clock (96Mhz????) */
+       {0x0081, 0x8702},       /* Master clock output enable */
+
+       {0x0000, 0x8500},       /* Set image type (352x288 no compression) */
+       /* Originally was 0x0010 (352x288 compression) */
+
+       {0x0002, 0x865b},       /* Horizontal offset for valid pixels */
+       {0x0003, 0x865c},       /* Vertical offset for valid lines */
+       /***************//* sensor active */
+       {0x0003, 0x8801},       /* 0x03 <- 0x01 0x21 //289 */
+       {0x0021, 0x8805},
+       {0x0001, 0x8800},
+       {0x0004, 0x8801},       /* 0x04 <- 0x01 0x65 //357 */
+       {0x0065, 0x8805},
+       {0x0001, 0x8800},
+       {0x0005, 0x8801},       /* 0x05 <- 0x2f */
+       {0x002f, 0x8805},
+       {0x0000, 0x8800},
+       {0x0006, 0x8801},       /* 0x06 <- 0 */
+       {0x0000, 0x8805},
+       {0x0000, 0x8800},
+       {0x000a, 0x8801},       /* 0x0a <- 2 */
+       {0x0002, 0x8805},
+       {0x0000, 0x8800},
+       {0x0009, 0x8801},       /* 0x09 <- 0x1061 */
+       {0x0061, 0x8805},
+       {0x0010, 0x8800},
+       {0x0035, 0x8801},       /* 0x35 <-0x14 */
+       {0x0014, 0x8805},
+       {0x0000, 0x8800},
+       {0x0030, 0x8112},       /* ISO and drop packet enable */
+       {0x0000, 0x8112},       /* Some kind of reset ???? */
+       {0x0009, 0x8118},       /* Enable sensor and set standby */
+       {0x0000, 0x8114},       /* Software GPIO output data */
+       {0x0000, 0x8114},       /* Software GPIO output data */
+       {0x0001, 0x8114},       /* Software GPIO output data */
+       {0x0000, 0x8112},       /* Some kind of reset ??? */
+       {0x0003, 0x8701},
+       {0x0001, 0x8703},
+       {0x0011, 0x8118},
+       {0x0001, 0x8118},
+       /***************/
+       {0x0092, 0x8804},
+       {0x0010, 0x8802},
+       {0x000d, 0x8805},
+       {0x0001, 0x8801},
+       {0x0000, 0x8800},
+       {0x0018, 0x8805},
+       {0x0002, 0x8801},
+       {0x0000, 0x8800},
+       {0x0065, 0x8805},
+       {0x0004, 0x8801},
+       {0x0001, 0x8800},
+       {0x0021, 0x8805},
+       {0x0005, 0x8801},
+       {0x0000, 0x8800},
+       {0x00aa, 0x8805},
+       {0x0007, 0x8801},       /* mode 0xaa */
+       {0x0000, 0x8800},
+       {0x0004, 0x8805},
+       {0x0020, 0x8801},
+       {0x0015, 0x8800},       /* mode 0x0415 */
+       {0x0002, 0x8805},
+       {0x0039, 0x8801},
+       {0x0000, 0x8800},
+       {0x0010, 0x8805},
+       {0x0035, 0x8801},
+       {0x0000, 0x8800},
+       {0x0049, 0x8805},
+       {0x0009, 0x8801},
+       {0x0010, 0x8800},
+       {0x000b, 0x8805},
+       {0x0028, 0x8801},
+       {0x0000, 0x8800},
+       {0x000f, 0x8805},
+       {0x003b, 0x8801},
+       {0x0000, 0x8800},
+       {0x0000, 0x8805},
+       {0x003c, 0x8801},
+       {0x0000, 0x8800},
+       {0x0002, 0x8502},
+       {0x0039, 0x8801},
+       {0x0000, 0x8805},
+       {0x0000, 0x8800},
+
+       {0x0087, 0x8700},       /* overwrite by start */
+       {0x0081, 0x8702},
+       {0x0000, 0x8500},
+/*     {0x0010, 0x8500},  -- Previous line was this */
+       {0x0002, 0x865b},
+       {0x0003, 0x865c},
+       /***************/
+       {0x0003, 0x8801},       /* 0x121-> 289 */
+       {0x0021, 0x8805},
+       {0x0001, 0x8800},
+       {0x0004, 0x8801},       /* 0x165 -> 357 */
+       {0x0065, 0x8805},
+       {0x0001, 0x8800},
+       {0x0005, 0x8801},       /* 0x2f //blanking control colonne */
+       {0x002f, 0x8805},
+       {0x0000, 0x8800},
+       {0x0006, 0x8801},       /* 0x00 //blanking mode row */
+       {0x0000, 0x8805},
+       {0x0000, 0x8800},
+       {0x000a, 0x8801},       /* 0x01 //0x02 */
+       {0x0001, 0x8805},
+       {0x0000, 0x8800},
+       {0x0009, 0x8801},       /* 0x1061 - setexposure times && pixel clock
+                                * 0001 0 | 000 0110 0001 */
+       {0x0061, 0x8805},       /* 61 31 */
+       {0x0008, 0x8800},       /* 08 */
+       {0x0035, 0x8801},       /* 0x14 - set gain general */
+       {0x001f, 0x8805},       /* 0x14 */
+       {0x0000, 0x8800},
+       {0x0030, 0x8112},
+       {}
+};
+
+static void sensor_reset(struct gspca_dev *gspca_dev)
+{
+       reg_w_val(gspca_dev->dev, 0x8631, 0xc8);
+       reg_w_val(gspca_dev->dev, 0x8634, 0xc8);
+       reg_w_val(gspca_dev->dev, 0x8112, 0x00);
+       reg_w_val(gspca_dev->dev, 0x8114, 0x00);
+       reg_w_val(gspca_dev->dev, 0x8118, 0x21);
+       i2c_init(gspca_dev, 0x14);
+       i2c_write(gspca_dev, 1, 0x0d);
+       i2c_write(gspca_dev, 0, 0x0d);
+}
+
+/******************** QC Express etch2 stuff ********************/
+static __u16 Pb100_1map8300[][2] = {
+       /* reg, value */
+       {0x8320, 0x3304},
+
+       {0x8303, 0x0125},       /* image area */
+       {0x8304, 0x0169},
+       {0x8328, 0x000b},
+       {0x833c, 0x0001},
+
+       {0x832f, 0x0419},
+       {0x8307, 0x00aa},
+       {0x8301, 0x0003},
+       {0x8302, 0x000e},
+       {}
+};
+static __u16 Pb100_2map8300[][2] = {
+       /* reg, value */
+       {0x8339, 0x0000},
+       {0x8307, 0x00aa},
+       {}
+};
+
+static __u16 spca561_161rev12A_data1[][2] = {
+       {0x21, 0x8118},
+       {0x01, 0x8114},
+       {0x00, 0x8112},
+       {0x92, 0x8804},
+       {0x04, 0x8802},         /* windows uses 08 */
+       {}
+};
+static __u16 spca561_161rev12A_data2[][2] = {
+       {0x21, 0x8118},
+       {0x10, 0x8500},
+       {0x07, 0x8601},
+       {0x07, 0x8602},
+       {0x04, 0x8501},
+       {0x21, 0x8118},
+
+       {0x07, 0x8201},         /* windows uses 02 */
+       {0x08, 0x8200},
+       {0x01, 0x8200},
+
+       {0x00, 0x8114},
+       {0x01, 0x8114},         /* windows uses 00 */
+
+       {0x90, 0x8604},
+       {0x00, 0x8605},
+       {0xb0, 0x8603},
+
+       /* sensor gains */
+       {0x00, 0x8610},         /* *red */
+       {0x00, 0x8611},         /* 3f   *green */
+       {0x00, 0x8612},         /* green *blue */
+       {0x00, 0x8613},         /* blue *green */
+       {0x35, 0x8614},         /* green *red */
+       {0x35, 0x8615},         /* 40   *green */
+       {0x35, 0x8616},         /* 7a   *blue */
+       {0x35, 0x8617},         /* 40   *green */
+
+       {0x0c, 0x8620},         /* 0c */
+       {0xc8, 0x8631},         /* c8 */
+       {0xc8, 0x8634},         /* c8 */
+       {0x23, 0x8635},         /* 23 */
+       {0x1f, 0x8636},         /* 1f */
+       {0xdd, 0x8637},         /* dd */
+       {0xe1, 0x8638},         /* e1 */
+       {0x1d, 0x8639},         /* 1d */
+       {0x21, 0x863a},         /* 21 */
+       {0xe3, 0x863b},         /* e3 */
+       {0xdf, 0x863c},         /* df */
+       {0xf0, 0x8505},
+       {0x32, 0x850a},
+       {}
+};
+
+static void sensor_mapwrite(struct gspca_dev *gspca_dev,
+                           __u16 sensormap[][2])
+{
+       int i = 0;
+       __u8 usbval[2];
+
+       while (sensormap[i][0]) {
+               usbval[0] = sensormap[i][1];
+               usbval[1] = sensormap[i][1] >> 8;
+               reg_w_buf(gspca_dev->dev, sensormap[i][0], usbval, 2);
+               i++;
+       }
+}
+static void init_161rev12A(struct gspca_dev *gspca_dev)
+{
+       sensor_reset(gspca_dev);
+       write_vector(gspca_dev, spca561_161rev12A_data1);
+       sensor_mapwrite(gspca_dev, Pb100_1map8300);
+       write_vector(gspca_dev, spca561_161rev12A_data2);
+       sensor_mapwrite(gspca_dev, Pb100_2map8300);
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+                    const struct usb_device_id *id)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct usb_device *dev = gspca_dev->dev;
+       struct cam *cam;
+       __u16 vendor, product;
+       __u8 data1, data2;
+
+       /* Read frm global register the USB product and vendor IDs, just to
+        * prove that we can communicate with the device.  This works, which
+        * confirms at we are communicating properly and that the device
+        * is a 561. */
+       reg_r(dev, 0x8104, &data1, 1);
+       reg_r(dev, 0x8105, &data2, 1);
+       vendor = (data2 << 8) | data1;
+       reg_r(dev, 0x8106, &data1, 1);
+       reg_r(dev, 0x8107, &data2, 1);
+       product = (data2 << 8) | data1;
+       if (vendor != id->idVendor || product != id->idProduct) {
+               PDEBUG(D_PROBE, "Bad vendor / product from device");
+               return -EINVAL;
+       }
+       switch (product) {
+       case 0x0928:
+       case 0x0929:
+       case 0x092a:
+       case 0x092b:
+       case 0x092c:
+       case 0x092d:
+       case 0x092e:
+       case 0x092f:
+       case 0x403b:
+               sd->chip_revision = Rev012A;
+               break;
+       default:
+/*     case 0x0561:
+       case 0x0815:                    * ?? in spca508.c
+       case 0x401a:
+       case 0x7004:
+       case 0x7e50:
+       case 0xa001:
+       case 0xcdee: */
+               sd->chip_revision = Rev072A;
+               break;
+       }
+       cam = &gspca_dev->cam;
+       cam->dev_name = (char *) id->driver_info;
+       cam->epaddr = 0x01;
+       gspca_dev->nbalt = 7 + 1;       /* choose alternate 7 first */
+       cam->cam_mode = sif_mode;
+       cam->nmodes = sizeof sif_mode / sizeof sif_mode[0];
+       sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
+       sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
+       sd->autogain = sd_ctrls[SD_AUTOGAIN].qctrl.default_value;
+       return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       switch (sd->chip_revision) {
+       case Rev072A:
+               PDEBUG(D_STREAM, "Chip revision id: 072a");
+               write_vector(gspca_dev, spca561_init_data);
+               break;
+       default:
+/*     case Rev012A: */
+               PDEBUG(D_STREAM, "Chip revision id: 012a");
+               init_161rev12A(gspca_dev);
+               break;
+       }
+       return 0;
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct usb_device *dev = gspca_dev->dev;
+       __u8 lowb;
+       int expotimes;
+
+       switch (sd->chip_revision) {
+       case Rev072A:
+               lowb = sd->contrast >> 8;
+               reg_w_val(dev, lowb, 0x8651);
+               reg_w_val(dev, lowb, 0x8652);
+               reg_w_val(dev, lowb, 0x8653);
+               reg_w_val(dev, lowb, 0x8654);
+               break;
+       case Rev012A: {
+               __u8 Reg8391[] =
+                       { 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00 };
+
+               /* Write camera sensor settings */
+               expotimes = (sd->contrast >> 5) & 0x07ff;
+               Reg8391[0] = expotimes & 0xff;  /* exposure */
+               Reg8391[1] = 0x18 | (expotimes >> 8);
+               Reg8391[2] = sd->brightness;    /* gain */
+               reg_w_buf(dev, 0x8391, Reg8391, 8);
+               reg_w_buf(dev, 0x8390, Reg8391, 8);
+               break;
+           }
+       }
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct usb_device *dev = gspca_dev->dev;
+       int Clck;
+       __u8 Reg8307[] = { 0xaa, 0x00 };
+       int mode;
+
+       mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].mode;
+       switch (sd->chip_revision) {
+       case Rev072A:
+               switch (mode) {
+               default:
+/*             case 0:
+               case 1: */
+                       Clck = 0x25;
+                       break;
+               case 2:
+                       Clck = 0x22;
+                       break;
+               case 3:
+                       Clck = 0x21;
+                       break;
+               }
+               reg_w_val(dev, 0x8500, mode);   /* mode */
+               reg_w_val(dev, 0x8700, Clck);   /* 0x27 clock */
+               reg_w_val(dev, 0x8112, 0x10 | 0x20);
+               break;
+       default:
+/*     case Rev012A: */
+               switch (mode) {
+               case 0:
+               case 1:
+                       Clck = 0x8a;
+                       break;
+               case 2:
+                       Clck = 0x85;
+                       break;
+               default:
+                       Clck = 0x83;
+                       break;
+               }
+               if (mode <= 1) {
+                       /* Use compression on 320x240 and above */
+                       reg_w_val(dev, 0x8500, 0x10 | mode);
+               } else {
+                       /* I couldn't get the compression to work below 320x240
+                        * Fortunately at these resolutions the bandwidth
+                        * is sufficient to push raw frames at ~20fps */
+                       reg_w_val(dev, 0x8500, mode);
+               }               /* -- qq@kuku.eu.org */
+               reg_w_buf(dev, 0x8307, Reg8307, 2);
+               reg_w_val(dev, 0x8700, Clck);   /* 0x8f 0x85 0x27 clock */
+               reg_w_val(dev, 0x8112, 0x1e | 0x20);
+               reg_w_val(dev, 0x850b, 0x03);
+               setcontrast(gspca_dev);
+               break;
+       }
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+       reg_w_val(gspca_dev->dev, 0x8112, 0x20);
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+/* this function is called at close time */
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+       reg_w_val(gspca_dev->dev, 0x8114, 0);
+}
+
+static void setautogain(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int expotimes = 0;
+       int pixelclk = 0;
+       int gainG = 0;
+       __u8 R, Gr, Gb, B;
+       int y;
+       __u8 luma_mean = 110;
+       __u8 luma_delta = 20;
+       __u8 spring = 4;
+
+       switch (sd->chip_revision) {
+       case Rev072A:
+               reg_r(gspca_dev->dev, 0x8621, &Gr, 1);
+               reg_r(gspca_dev->dev, 0x8622, &R, 1);
+               reg_r(gspca_dev->dev, 0x8623, &B, 1);
+               reg_r(gspca_dev->dev, 0x8624, &Gb, 1);
+               y = (77 * R + 75 * (Gr + Gb) + 29 * B) >> 8;
+               /* u= (128*B-(43*(Gr+Gb+R))) >> 8; */
+               /* v= (128*R-(53*(Gr+Gb))-21*B) >> 8; */
+               /* PDEBUG(D_CONF,"reading Y %d U %d V %d ",y,u,v); */
+
+               if (y < luma_mean - luma_delta ||
+                   y > luma_mean + luma_delta) {
+                       expotimes = i2c_read(gspca_dev, 0x09, 0x10);
+                       pixelclk = 0x0800;
+                       expotimes = expotimes & 0x07ff;
+                       /* PDEBUG(D_PACK,
+                               "Exposition Times 0x%03X Clock 0x%04X ",
+                               expotimes,pixelclk); */
+                       gainG = i2c_read(gspca_dev, 0x35, 0x10);
+                       /* PDEBUG(D_PACK,
+                               "reading Gain register %d", gainG); */
+
+                       expotimes += (luma_mean - y) >> spring;
+                       gainG += (luma_mean - y) / 50;
+                       /* PDEBUG(D_PACK,
+                               "compute expotimes %d gain %d",
+                               expotimes,gainG); */
+
+                       if (gainG > 0x3f)
+                               gainG = 0x3f;
+                       else if (gainG < 4)
+                               gainG = 3;
+                       i2c_write(gspca_dev, gainG, 0x35);
+
+                       if (expotimes >= 0x0256)
+                               expotimes = 0x0256;
+                       else if (expotimes < 4)
+                               expotimes = 3;
+                       i2c_write(gspca_dev, expotimes | pixelclk, 0x09);
+               }
+               break;
+       case Rev012A:
+               /* sensor registers is access and memory mapped to 0x8300 */
+               /* readind all 0x83xx block the sensor */
+               /*
+                * The data from the header seem wrong where is the luma
+                * and chroma mean value
+                * at the moment set exposure in contrast set
+                */
+               break;
+       }
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+                       struct gspca_frame *frame, /* target */
+                       __u8 *data,             /* isoc packet */
+                       int len)                /* iso packet length */
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       switch (data[0]) {
+       case 0:         /* start of frame */
+               frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+                                       data, 0);
+               if (sd->ag_cnt >= 0) {
+                       if (--sd->ag_cnt < 0) {
+                               sd->ag_cnt = AG_CNT_START;
+                               setautogain(gspca_dev);
+                       }
+               }
+               data += SPCA561_OFFSET_DATA;
+               len -= SPCA561_OFFSET_DATA;
+               if (data[1] & 0x10) {
+                       /* compressed bayer */
+                       gspca_frame_add(gspca_dev, FIRST_PACKET,
+                                       frame, data, len);
+               } else {
+                       /*fixme: which format?*/
+                       data += 20;
+                       len -= 20;
+                       gspca_frame_add(gspca_dev, FIRST_PACKET,
+                                               frame, data, len);
+               }
+               return;
+       case 0xff:              /* drop */
+/*             gspca_dev->last_packet_type = DISCARD_PACKET; */
+               return;
+       }
+       data++;
+       len--;
+       gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       __u8 value;
+
+       switch (sd->chip_revision) {
+       case Rev072A:
+               value = sd->brightness;
+               reg_w_val(gspca_dev->dev, value, 0x8611);
+               reg_w_val(gspca_dev->dev, value, 0x8612);
+               reg_w_val(gspca_dev->dev, value, 0x8613);
+               reg_w_val(gspca_dev->dev, value, 0x8614);
+               break;
+       default:
+/*     case Rev012A: */
+               setcontrast(gspca_dev);
+               break;
+       }
+}
+
+static void getbrightness(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       __u8 value;
+       __u16 tot;
+
+       switch (sd->chip_revision) {
+       case Rev072A:
+               tot = 0;
+               reg_r(gspca_dev->dev, 0x8611, &value, 1);
+               tot += value;
+               reg_r(gspca_dev->dev, 0x8612, &value, 1);
+               tot += value;
+               reg_r(gspca_dev->dev, 0x8613, &value, 1);
+               tot += value;
+               reg_r(gspca_dev->dev, 0x8614, &value, 1);
+               tot += value;
+               sd->brightness = tot >> 2;
+               break;
+       default:
+/*     case Rev012A: */
+               /* no way to read sensor settings */
+               break;
+       }
+}
+
+static void getcontrast(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       __u8 value;
+       __u16 tot;
+
+       switch (sd->chip_revision) {
+       case Rev072A:
+               tot = 0;
+               reg_r(gspca_dev->dev, 0x8651, &value, 1);
+               tot += value;
+               reg_r(gspca_dev->dev, 0x8652, &value, 1);
+               tot += value;
+               reg_r(gspca_dev->dev, 0x8653, &value, 1);
+               tot += value;
+               reg_r(gspca_dev->dev, 0x8654, &value, 1);
+               tot += value;
+               sd->contrast = tot << 6;
+               break;
+       default:
+/*     case Rev012A: */
+               /* no way to read sensor settings */
+               break;
+       }
+       PDEBUG(D_CONF, "get contrast %d", sd->contrast);
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->brightness = val;
+       if (gspca_dev->streaming)
+               setbrightness(gspca_dev);
+       return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       getbrightness(gspca_dev);
+       *val = sd->brightness;
+       return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->contrast = val;
+       if (gspca_dev->streaming)
+               setcontrast(gspca_dev);
+       return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       getcontrast(gspca_dev);
+       *val = sd->contrast;
+       return 0;
+}
+
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->autogain = val;
+       if (val)
+               sd->ag_cnt = AG_CNT_START;
+       else
+               sd->ag_cnt = -1;
+       return 0;
+}
+
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->autogain;
+       return 0;
+}
+
+/* sub-driver description */
+static struct sd_desc sd_desc = {
+       .name = MODULE_NAME,
+       .ctrls = sd_ctrls,
+       .nctrls = ARRAY_SIZE(sd_ctrls),
+       .config = sd_config,
+       .open = sd_open,
+       .start = sd_start,
+       .stopN = sd_stopN,
+       .stop0 = sd_stop0,
+       .close = sd_close,
+       .pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static __devinitdata struct usb_device_id device_table[] = {
+       {USB_DEVICE(0x041e, 0x401a), DVNM("Creative Webcam Vista (PD1100)")},
+       {USB_DEVICE(0x041e, 0x403b),  DVNM("Creative Webcam Vista (VF0010)")},
+       {USB_DEVICE(0x0458, 0x7004), DVNM("Genius VideoCAM Express V2")},
+       {USB_DEVICE(0x046d, 0x0928), DVNM("Logitech QC Express Etch2")},
+       {USB_DEVICE(0x046d, 0x0929), DVNM("Labtec Webcam Elch2")},
+       {USB_DEVICE(0x046d, 0x092a), DVNM("Logitech QC for Notebook")},
+       {USB_DEVICE(0x046d, 0x092b), DVNM("Labtec Webcam Plus")},
+       {USB_DEVICE(0x046d, 0x092c), DVNM("Logitech QC chat Elch2")},
+       {USB_DEVICE(0x046d, 0x092d), DVNM("Logitech QC Elch2")},
+       {USB_DEVICE(0x046d, 0x092e), DVNM("Logitech QC Elch2")},
+       {USB_DEVICE(0x046d, 0x092f), DVNM("Logitech QC Elch2")},
+       {USB_DEVICE(0x04fc, 0x0561), DVNM("Flexcam 100")},
+       {USB_DEVICE(0x060b, 0xa001), DVNM("Maxell Compact Pc PM3")},
+       {USB_DEVICE(0x10fd, 0x7e50), DVNM("FlyCam Usb 100")},
+       {USB_DEVICE(0xabcd, 0xcdee), DVNM("Petcam")},
+       {}
+};
+
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+                   const struct usb_device_id *id)
+{
+       return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+                              THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+       .name = MODULE_NAME,
+       .id_table = device_table,
+       .probe = sd_probe,
+       .disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+       if (usb_register(&sd_driver) < 0)
+               return -1;
+       PDEBUG(D_PROBE, "v%s registered", version);
+       return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+       usb_deregister(&sd_driver);
+       PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
index d8c203e99cd38e7269d151e4a02f3638cc79ff2b..6832fe0f3403f009ed2a7afe443a0041e01ed3e4 100644 (file)
@@ -23,8 +23,8 @@
 #include "gspca.h"
 #include "jpeg.h"
 
-#define DRIVER_VERSION_NUMBER  KERNEL_VERSION(0, 2, 7)
-static const char version[] = "0.2.7";
+#define DRIVER_VERSION_NUMBER  KERNEL_VERSION(2, 1, 0)
+static const char version[] = "2.1.0";
 
 MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>");
 MODULE_DESCRIPTION("Syntek DV4000 (STK014) USB Camera Driver");
@@ -37,10 +37,10 @@ struct sd {
        unsigned char brightness;
        unsigned char contrast;
        unsigned char colors;
+       unsigned char lightfreq;
 };
 
 /* global parameters */
-static int lightfreq = 50;
 static int sd_quant = 7;               /* <= 4 KO - 7: good (enough!) */
 
 /* V4L2 controls supported by the driver */
@@ -50,6 +50,8 @@ static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
 static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
 
 static struct ctrl sd_ctrls[] = {
 #define SD_BRIGHTNESS 0
@@ -94,6 +96,20 @@ static struct ctrl sd_ctrls[] = {
            .set = sd_setcolors,
            .get = sd_getcolors,
        },
+#define SD_FREQ 3
+       {
+           {
+               .id      = V4L2_CID_POWER_LINE_FREQUENCY,
+               .type    = V4L2_CTRL_TYPE_MENU,
+               .name    = "Light frequency filter",
+               .minimum = 1,
+               .maximum = 2,   /* 0: 0, 1: 50Hz, 2:60Hz */
+               .step    = 1,
+               .default_value = 1,
+           },
+           .set = sd_setfreq,
+           .get = sd_getfreq,
+       },
 };
 
 static struct cam_mode vga_mode[] = {
@@ -102,11 +118,11 @@ static struct cam_mode vga_mode[] = {
 };
 
 /* -- read a register -- */
-static int reg_read(struct gspca_dev *gspca_dev,
+static int reg_r(struct gspca_dev *gspca_dev,
                        __u16 index, __u8 *buf)
 {
-       int ret;
        struct usb_device *dev = gspca_dev->dev;
+       int ret;
 
        ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
                        0x00,
@@ -116,12 +132,12 @@ static int reg_read(struct gspca_dev *gspca_dev,
                        buf, 1,
                        500);
        if (ret < 0)
-               PDEBUG(D_ERR, "reg_read err %d", ret);
+               PDEBUG(D_ERR, "reg_r err %d", ret);
        return ret;
 }
 
 /* -- write a register -- */
-static int reg_write(struct gspca_dev *gspca_dev,
+static int reg_w(struct gspca_dev *gspca_dev,
                        __u16 index, __u16 value)
 {
        struct usb_device *dev = gspca_dev->dev;
@@ -136,7 +152,7 @@ static int reg_write(struct gspca_dev *gspca_dev,
                        0,
                        500);
        if (ret < 0)
-               PDEBUG(D_ERR, "reg_write err %d", ret);
+               PDEBUG(D_ERR, "reg_w err %d", ret);
        return ret;
 }
 
@@ -149,15 +165,15 @@ static int rcv_val(struct gspca_dev *gspca_dev,
        int alen, ret;
        unsigned char bulk_buf[4];
 
-       reg_write(gspca_dev, 0x634, (ads >> 16) & 0xff);
-       reg_write(gspca_dev, 0x635, (ads >> 8) & 0xff);
-       reg_write(gspca_dev, 0x636, ads & 0xff);
-       reg_write(gspca_dev, 0x637, 0);
-       reg_write(gspca_dev, 0x638, len & 0xff);
-       reg_write(gspca_dev, 0x639, len >> 8);
-       reg_write(gspca_dev, 0x63a, 0);
-       reg_write(gspca_dev, 0x63b, 0);
-       reg_write(gspca_dev, 0x630, 5);
+       reg_w(gspca_dev, 0x634, (ads >> 16) & 0xff);
+       reg_w(gspca_dev, 0x635, (ads >> 8) & 0xff);
+       reg_w(gspca_dev, 0x636, ads & 0xff);
+       reg_w(gspca_dev, 0x637, 0);
+       reg_w(gspca_dev, 0x638, len & 0xff);
+       reg_w(gspca_dev, 0x639, len >> 8);
+       reg_w(gspca_dev, 0x63a, 0);
+       reg_w(gspca_dev, 0x63b, 0);
+       reg_w(gspca_dev, 0x630, 5);
        if (len > sizeof bulk_buf)
                return -1;
        ret = usb_bulk_msg(dev,
@@ -180,26 +196,26 @@ static int snd_val(struct gspca_dev *gspca_dev,
        unsigned char bulk_buf[4];
 
        if (ads == 0x003f08) {
-               ret = reg_read(gspca_dev, 0x0704, &value);
+               ret = reg_r(gspca_dev, 0x0704, &value);
                if (ret < 0)
                        goto ko;
-               ret = reg_read(gspca_dev, 0x0705, &seq);
+               ret = reg_r(gspca_dev, 0x0705, &seq);
                if (ret < 0)
                        goto ko;
-               ret = reg_read(gspca_dev, 0x0650, &value);
+               ret = reg_r(gspca_dev, 0x0650, &value);
                if (ret < 0)
                        goto ko;
-               reg_write(gspca_dev, 0x654, seq);
+               reg_w(gspca_dev, 0x654, seq);
        } else
-               reg_write(gspca_dev, 0x654, (ads >> 16) & 0xff);
-       reg_write(gspca_dev, 0x655, (ads >> 8) & 0xff);
-       reg_write(gspca_dev, 0x656, ads & 0xff);
-       reg_write(gspca_dev, 0x657, 0);
-       reg_write(gspca_dev, 0x658, 0x04);      /* size */
-       reg_write(gspca_dev, 0x659, 0);
-       reg_write(gspca_dev, 0x65a, 0);
-       reg_write(gspca_dev, 0x65b, 0);
-       reg_write(gspca_dev, 0x650, 5);
+               reg_w(gspca_dev, 0x654, (ads >> 16) & 0xff);
+       reg_w(gspca_dev, 0x655, (ads >> 8) & 0xff);
+       reg_w(gspca_dev, 0x656, ads & 0xff);
+       reg_w(gspca_dev, 0x657, 0);
+       reg_w(gspca_dev, 0x658, 0x04);  /* size */
+       reg_w(gspca_dev, 0x659, 0);
+       reg_w(gspca_dev, 0x65a, 0);
+       reg_w(gspca_dev, 0x65b, 0);
+       reg_w(gspca_dev, 0x650, 5);
        bulk_buf[0] = (val >> 24) & 0xff;
        bulk_buf[1] = (val >> 16) & 0xff;
        bulk_buf[2] = (val >> 8) & 0xff;
@@ -215,7 +231,7 @@ static int snd_val(struct gspca_dev *gspca_dev,
        if (ads == 0x003f08) {
                seq += 4;
                seq &= 0x3f;
-               reg_write(gspca_dev, 0x705, seq);
+               reg_w(gspca_dev, 0x705, seq);
        }
        return ret;
 ko:
@@ -235,7 +251,6 @@ static void setbrightness(struct gspca_dev *gspca_dev)
        struct sd *sd = (struct sd *) gspca_dev;
        int parval;
 
-       PDEBUG(D_CONF, "brightness: %d", sd->brightness);
        parval = 0x06000000             /* whiteness */
                + (sd->brightness << 16);
        set_par(gspca_dev, parval);
@@ -246,7 +261,6 @@ static void setcontrast(struct gspca_dev *gspca_dev)
        struct sd *sd = (struct sd *) gspca_dev;
        int parval;
 
-       PDEBUG(D_CONF, "contrast: %d", sd->contrast);
        parval = 0x07000000             /* contrast */
                + (sd->contrast << 16);
        set_par(gspca_dev, parval);
@@ -257,13 +271,20 @@ static void setcolors(struct gspca_dev *gspca_dev)
        struct sd *sd = (struct sd *) gspca_dev;
        int parval;
 
-       PDEBUG(D_CONF, "saturation: %d",
-               sd->colors);
        parval = 0x08000000             /* saturation */
                + (sd->colors << 16);
        set_par(gspca_dev, parval);
 }
 
+static void setfreq(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       set_par(gspca_dev, sd->lightfreq == 1
+                       ? 0x33640000            /* 50 Hz */
+                       : 0x33780000);          /* 60 Hz */
+}
+
 /* this function is called at probe time */
 static int sd_config(struct gspca_dev *gspca_dev,
                        const struct usb_device_id *id)
@@ -278,6 +299,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
        sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
        sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
        sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value;
+       sd->lightfreq = sd_ctrls[SD_FREQ].qctrl.default_value;
        return 0;
 }
 
@@ -289,7 +311,7 @@ static int sd_open(struct gspca_dev *gspca_dev)
 
        /* check if the device responds */
        usb_set_interface(gspca_dev->dev, gspca_dev->iface, 1);
-       ret = reg_read(gspca_dev, 0x0740, &value);
+       ret = reg_r(gspca_dev, 0x0740, &value);
        if (ret < 0)
                return ret;
        if (value != 0xff) {
@@ -320,21 +342,24 @@ static void sd_start(struct gspca_dev *gspca_dev)
        ret = usb_set_interface(gspca_dev->dev,
                                        gspca_dev->iface,
                                        gspca_dev->alt);
-       if (ret < 0)
+       if (ret < 0) {
+               PDEBUG(D_ERR|D_STREAM, "set intf %d %d failed",
+                       gspca_dev->iface, gspca_dev->alt);
                goto out;
-       ret = reg_read(gspca_dev, 0x0630, &dum);
+       }
+       ret = reg_r(gspca_dev, 0x0630, &dum);
        if (ret < 0)
                goto out;
        rcv_val(gspca_dev, 0x000020, 4);        /* << (value ff ff ff ff) */
-       ret = reg_read(gspca_dev, 0x0650, &dum);
+       ret = reg_r(gspca_dev, 0x0650, &dum);
        if (ret < 0)
                goto out;
        snd_val(gspca_dev, 0x000020, 0xffffffff);
-       reg_write(gspca_dev, 0x0620, 0);
-       reg_write(gspca_dev, 0x0630, 0);
-       reg_write(gspca_dev, 0x0640, 0);
-       reg_write(gspca_dev, 0x0650, 0);
-       reg_write(gspca_dev, 0x0660, 0);
+       reg_w(gspca_dev, 0x0620, 0);
+       reg_w(gspca_dev, 0x0630, 0);
+       reg_w(gspca_dev, 0x0640, 0);
+       reg_w(gspca_dev, 0x0650, 0);
+       reg_w(gspca_dev, 0x0660, 0);
        setbrightness(gspca_dev);               /* whiteness */
        setcontrast(gspca_dev);                 /* contrast */
        setcolors(gspca_dev);                   /* saturation */
@@ -342,9 +367,7 @@ static void sd_start(struct gspca_dev *gspca_dev)
        set_par(gspca_dev, 0x0a800000);         /* Green ? */
        set_par(gspca_dev, 0x0b800000);         /* Blue ? */
        set_par(gspca_dev, 0x0d030000);         /* Gamma ? */
-       set_par(gspca_dev, lightfreq == 60
-                       ? 0x33780000            /* 60 Hz */
-                       : 0x33640000);          /* 50 Hz */
+       setfreq(gspca_dev);                     /* light frequency */
 
        /* start the video flow */
        set_par(gspca_dev, 0x01000000);
@@ -363,15 +386,15 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
        set_par(gspca_dev, 0x02000000);
        set_par(gspca_dev, 0x02000000);
        usb_set_interface(dev, gspca_dev->iface, 1);
-       reg_read(gspca_dev, 0x0630, &value);
+       reg_r(gspca_dev, 0x0630, &value);
        rcv_val(gspca_dev, 0x000020, 4);        /* << (value ff ff ff ff) */
-       reg_read(gspca_dev, 0x0650, &value);
+       reg_r(gspca_dev, 0x0650, &value);
        snd_val(gspca_dev, 0x000020, 0xffffffff);
-       reg_write(gspca_dev, 0x0620, 0);
-       reg_write(gspca_dev, 0x0630, 0);
-       reg_write(gspca_dev, 0x0640, 0);
-       reg_write(gspca_dev, 0x0650, 0);
-       reg_write(gspca_dev, 0x0660, 0);
+       reg_w(gspca_dev, 0x0620, 0);
+       reg_w(gspca_dev, 0x0630, 0);
+       reg_w(gspca_dev, 0x0640, 0);
+       reg_w(gspca_dev, 0x0650, 0);
+       reg_w(gspca_dev, 0x0660, 0);
        PDEBUG(D_STREAM, "camera stopped");
 }
 
@@ -470,6 +493,42 @@ static int sd_getcolors(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->lightfreq = val;
+       if (gspca_dev->streaming)
+               setfreq(gspca_dev);
+       return 0;
+}
+
+static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->lightfreq;
+       return 0;
+}
+
+static int sd_querymenu(struct gspca_dev *gspca_dev,
+                       struct v4l2_querymenu *menu)
+{
+       switch (menu->id) {
+       case V4L2_CID_POWER_LINE_FREQUENCY:
+               switch (menu->index) {
+               case 1:         /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
+                       strcpy(menu->name, "50 Hz");
+                       return 0;
+               case 2:         /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
+                       strcpy(menu->name, "60 Hz");
+                       return 0;
+               }
+               break;
+       }
+       return -EINVAL;
+}
+
 /* sub-driver description */
 static struct sd_desc sd_desc = {
        .name = MODULE_NAME,
@@ -482,6 +541,7 @@ static struct sd_desc sd_desc = {
        .stop0 = sd_stop0,
        .close = sd_close,
        .pkt_scan = sd_pkt_scan,
+       .querymenu = sd_querymenu,
 };
 
 /* -- module initialisation -- */
@@ -524,7 +584,5 @@ static void __exit sd_mod_exit(void)
 module_init(sd_mod_init);
 module_exit(sd_mod_exit);
 
-module_param(lightfreq, int, 0644);
-MODULE_PARM_DESC(lightfreq, "Light frequency 50 or 60 Hz");
 module_param_named(quant, sd_quant, int, 0644);
 MODULE_PARM_DESC(quant, "Quantization index (0..8)");
diff --git a/drivers/media/video/gspca/sunplus.c b/drivers/media/video/gspca/sunplus.c
new file mode 100644 (file)
index 0000000..52d1b32
--- /dev/null
@@ -0,0 +1,1638 @@
+/*
+ *             Sunplus spca504(abc) spca533 spca536 library
+ *             Copyright (C) 2005 Michel Xhaard mxhaard@magic.fr
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define MODULE_NAME "sunplus"
+
+#include "gspca.h"
+#include "jpeg.h"
+
+#define DRIVER_VERSION_NUMBER  KERNEL_VERSION(2, 1, 0)
+static const char version[] = "2.1.0";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("GSPCA/SPCA5xx USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+       struct gspca_dev gspca_dev;     /* !! must be the first item */
+
+       unsigned char packet[ISO_MAX_SIZE + 128];
+                               /* !! no more than 128 ff in an ISO packet */
+
+       unsigned char brightness;
+       unsigned char contrast;
+       unsigned char colors;
+       unsigned char autogain;
+
+       char qindex;
+       char bridge;
+#define BRIDGE_SPCA504 0
+#define BRIDGE_SPCA504B 1
+#define BRIDGE_SPCA504C 2
+#define BRIDGE_SPCA533 3
+#define BRIDGE_SPCA536 4
+       char subtype;
+#define AiptekMiniPenCam13 1
+#define LogitechClickSmart420 2
+#define LogitechClickSmart820 3
+#define MegapixV4 4
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+#define SD_BRIGHTNESS 0
+       {
+           {
+               .id      = V4L2_CID_BRIGHTNESS,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Brightness",
+               .minimum = 0,
+               .maximum = 0xff,
+               .step    = 1,
+               .default_value = 0,
+           },
+           .set = sd_setbrightness,
+           .get = sd_getbrightness,
+       },
+#define SD_CONTRAST 1
+       {
+           {
+               .id      = V4L2_CID_CONTRAST,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Contrast",
+               .minimum = 0,
+               .maximum = 0xff,
+               .step    = 1,
+               .default_value = 0x20,
+           },
+           .set = sd_setcontrast,
+           .get = sd_getcontrast,
+       },
+#define SD_COLOR 2
+       {
+           {
+               .id      = V4L2_CID_SATURATION,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Color",
+               .minimum = 0,
+               .maximum = 0xff,
+               .step    = 1,
+               .default_value = 0x1a,
+           },
+           .set = sd_setcolors,
+           .get = sd_getcolors,
+       },
+#define SD_AUTOGAIN 3
+       {
+           {
+               .id      = V4L2_CID_AUTOGAIN,
+               .type    = V4L2_CTRL_TYPE_BOOLEAN,
+               .name    = "Auto Gain",
+               .minimum = 0,
+               .maximum = 1,
+               .step    = 1,
+               .default_value = 1,
+           },
+           .set = sd_setautogain,
+           .get = sd_getautogain,
+       },
+};
+
+static struct cam_mode vga_mode[] = {
+       {V4L2_PIX_FMT_JPEG, 320, 240, 2},
+       {V4L2_PIX_FMT_JPEG, 640, 480, 1},
+};
+
+static struct cam_mode custom_mode[] = {
+       {V4L2_PIX_FMT_JPEG, 320, 240, 2},
+       {V4L2_PIX_FMT_JPEG, 464, 480, 1},
+};
+
+static struct cam_mode vga_mode2[] = {
+       {V4L2_PIX_FMT_JPEG, 176, 144, 4},
+       {V4L2_PIX_FMT_JPEG, 320, 240, 3},
+       {V4L2_PIX_FMT_JPEG, 352, 288, 2},
+       {V4L2_PIX_FMT_JPEG, 640, 480, 1},
+};
+
+#define SPCA50X_OFFSET_DATA 10
+#define SPCA504_PCCAM600_OFFSET_SNAPSHOT 3
+#define SPCA504_PCCAM600_OFFSET_COMPRESS 4
+#define SPCA504_PCCAM600_OFFSET_MODE    5
+#define SPCA504_PCCAM600_OFFSET_DATA    14
+ /* Frame packet header offsets for the spca533 */
+#define SPCA533_OFFSET_DATA      16
+#define SPCA533_OFFSET_FRAMSEQ 15
+/* Frame packet header offsets for the spca536 */
+#define SPCA536_OFFSET_DATA      4
+#define SPCA536_OFFSET_FRAMSEQ  1
+
+/* Initialisation data for the Creative PC-CAM 600 */
+static __u16 spca504_pccam600_init_data[][3] = {
+/*     {0xa0, 0x0000, 0x0503},  * capture mode */
+       {0x00, 0x0000, 0x2000},
+       {0x00, 0x0013, 0x2301},
+       {0x00, 0x0003, 0x2000},
+       {0x00, 0x0001, 0x21ac},
+       {0x00, 0x0001, 0x21a6},
+       {0x00, 0x0000, 0x21a7}, /* brightness */
+       {0x00, 0x0020, 0x21a8}, /* contrast */
+       {0x00, 0x0001, 0x21ac}, /* sat/hue */
+       {0x00, 0x0000, 0x21ad}, /* hue */
+       {0x00, 0x001a, 0x21ae}, /* saturation */
+       {0x00, 0x0002, 0x21a3}, /* gamma */
+       {0x30, 0x0154, 0x0008},
+       {0x30, 0x0004, 0x0006},
+       {0x30, 0x0258, 0x0009},
+       {0x30, 0x0004, 0x0000},
+       {0x30, 0x0093, 0x0004},
+       {0x30, 0x0066, 0x0005},
+       {0x00, 0x0000, 0x2000},
+       {0x00, 0x0013, 0x2301},
+       {0x00, 0x0003, 0x2000},
+       {0x00, 0x0013, 0x2301},
+       {0x00, 0x0003, 0x2000},
+       {}
+};
+
+/* Creative PC-CAM 600 specific open data, sent before using the
+ * generic initialisation data from spca504_open_data.
+ */
+static __u16 spca504_pccam600_open_data[][3] = {
+       {0x00, 0x0001, 0x2501},
+       {0x20, 0x0500, 0x0001}, /* snapshot mode */
+       {0x00, 0x0003, 0x2880},
+       {0x00, 0x0001, 0x2881},
+       {}
+};
+
+/* Initialisation data for the logitech clicksmart 420 */
+static __u16 spca504A_clicksmart420_init_data[][3] = {
+/*     {0xa0, 0x0000, 0x0503},  * capture mode */
+       {0x00, 0x0000, 0x2000},
+       {0x00, 0x0013, 0x2301},
+       {0x00, 0x0003, 0x2000},
+       {0x00, 0x0001, 0x21ac},
+       {0x00, 0x0001, 0x21a6},
+       {0x00, 0x0000, 0x21a7}, /* brightness */
+       {0x00, 0x0020, 0x21a8}, /* contrast */
+       {0x00, 0x0001, 0x21ac}, /* sat/hue */
+       {0x00, 0x0000, 0x21ad}, /* hue */
+       {0x00, 0x001a, 0x21ae}, /* saturation */
+       {0x00, 0x0002, 0x21a3}, /* gamma */
+       {0x30, 0x0004, 0x000a},
+       {0xb0, 0x0001, 0x0000},
+
+
+       {0x0a1, 0x0080, 0x0001},
+       {0x30, 0x0049, 0x0000},
+       {0x30, 0x0060, 0x0005},
+       {0x0c, 0x0004, 0x0000},
+       {0x00, 0x0000, 0x0000},
+       {0x00, 0x0000, 0x2000},
+       {0x00, 0x0013, 0x2301},
+       {0x00, 0x0003, 0x2000},
+       {0x00, 0x0000, 0x2000},
+
+       {}
+};
+
+/* clicksmart 420 open data ? */
+static __u16 spca504A_clicksmart420_open_data[][3] = {
+       {0x00, 0x0001, 0x2501},
+       {0x20, 0x0502, 0x0000},
+       {0x06, 0x0000, 0x0000},
+       {0x00, 0x0004, 0x2880},
+       {0x00, 0x0001, 0x2881},
+/* look like setting a qTable */
+       {0x00, 0x0006, 0x2800},
+       {0x00, 0x0004, 0x2801},
+       {0x00, 0x0004, 0x2802},
+       {0x00, 0x0006, 0x2803},
+       {0x00, 0x000a, 0x2804},
+       {0x00, 0x0010, 0x2805},
+       {0x00, 0x0014, 0x2806},
+       {0x00, 0x0018, 0x2807},
+       {0x00, 0x0005, 0x2808},
+       {0x00, 0x0005, 0x2809},
+       {0x00, 0x0006, 0x280a},
+       {0x00, 0x0008, 0x280b},
+       {0x00, 0x000a, 0x280c},
+       {0x00, 0x0017, 0x280d},
+       {0x00, 0x0018, 0x280e},
+       {0x00, 0x0016, 0x280f},
+
+       {0x00, 0x0006, 0x2810},
+       {0x00, 0x0005, 0x2811},
+       {0x00, 0x0006, 0x2812},
+       {0x00, 0x000a, 0x2813},
+       {0x00, 0x0010, 0x2814},
+       {0x00, 0x0017, 0x2815},
+       {0x00, 0x001c, 0x2816},
+       {0x00, 0x0016, 0x2817},
+       {0x00, 0x0006, 0x2818},
+       {0x00, 0x0007, 0x2819},
+       {0x00, 0x0009, 0x281a},
+       {0x00, 0x000c, 0x281b},
+       {0x00, 0x0014, 0x281c},
+       {0x00, 0x0023, 0x281d},
+       {0x00, 0x0020, 0x281e},
+       {0x00, 0x0019, 0x281f},
+
+       {0x00, 0x0007, 0x2820},
+       {0x00, 0x0009, 0x2821},
+       {0x00, 0x000f, 0x2822},
+       {0x00, 0x0016, 0x2823},
+       {0x00, 0x001b, 0x2824},
+       {0x00, 0x002c, 0x2825},
+       {0x00, 0x0029, 0x2826},
+       {0x00, 0x001f, 0x2827},
+       {0x00, 0x000a, 0x2828},
+       {0x00, 0x000e, 0x2829},
+       {0x00, 0x0016, 0x282a},
+       {0x00, 0x001a, 0x282b},
+       {0x00, 0x0020, 0x282c},
+       {0x00, 0x002a, 0x282d},
+       {0x00, 0x002d, 0x282e},
+       {0x00, 0x0025, 0x282f},
+
+       {0x00, 0x0014, 0x2830},
+       {0x00, 0x001a, 0x2831},
+       {0x00, 0x001f, 0x2832},
+       {0x00, 0x0023, 0x2833},
+       {0x00, 0x0029, 0x2834},
+       {0x00, 0x0030, 0x2835},
+       {0x00, 0x0030, 0x2836},
+       {0x00, 0x0028, 0x2837},
+       {0x00, 0x001d, 0x2838},
+       {0x00, 0x0025, 0x2839},
+       {0x00, 0x0026, 0x283a},
+       {0x00, 0x0027, 0x283b},
+       {0x00, 0x002d, 0x283c},
+       {0x00, 0x0028, 0x283d},
+       {0x00, 0x0029, 0x283e},
+       {0x00, 0x0028, 0x283f},
+
+       {0x00, 0x0007, 0x2840},
+       {0x00, 0x0007, 0x2841},
+       {0x00, 0x000a, 0x2842},
+       {0x00, 0x0013, 0x2843},
+       {0x00, 0x0028, 0x2844},
+       {0x00, 0x0028, 0x2845},
+       {0x00, 0x0028, 0x2846},
+       {0x00, 0x0028, 0x2847},
+       {0x00, 0x0007, 0x2848},
+       {0x00, 0x0008, 0x2849},
+       {0x00, 0x000a, 0x284a},
+       {0x00, 0x001a, 0x284b},
+       {0x00, 0x0028, 0x284c},
+       {0x00, 0x0028, 0x284d},
+       {0x00, 0x0028, 0x284e},
+       {0x00, 0x0028, 0x284f},
+
+       {0x00, 0x000a, 0x2850},
+       {0x00, 0x000a, 0x2851},
+       {0x00, 0x0016, 0x2852},
+       {0x00, 0x0028, 0x2853},
+       {0x00, 0x0028, 0x2854},
+       {0x00, 0x0028, 0x2855},
+       {0x00, 0x0028, 0x2856},
+       {0x00, 0x0028, 0x2857},
+       {0x00, 0x0013, 0x2858},
+       {0x00, 0x001a, 0x2859},
+       {0x00, 0x0028, 0x285a},
+       {0x00, 0x0028, 0x285b},
+       {0x00, 0x0028, 0x285c},
+       {0x00, 0x0028, 0x285d},
+       {0x00, 0x0028, 0x285e},
+       {0x00, 0x0028, 0x285f},
+
+       {0x00, 0x0028, 0x2860},
+       {0x00, 0x0028, 0x2861},
+       {0x00, 0x0028, 0x2862},
+       {0x00, 0x0028, 0x2863},
+       {0x00, 0x0028, 0x2864},
+       {0x00, 0x0028, 0x2865},
+       {0x00, 0x0028, 0x2866},
+       {0x00, 0x0028, 0x2867},
+       {0x00, 0x0028, 0x2868},
+       {0x00, 0x0028, 0x2869},
+       {0x00, 0x0028, 0x286a},
+       {0x00, 0x0028, 0x286b},
+       {0x00, 0x0028, 0x286c},
+       {0x00, 0x0028, 0x286d},
+       {0x00, 0x0028, 0x286e},
+       {0x00, 0x0028, 0x286f},
+
+       {0x00, 0x0028, 0x2870},
+       {0x00, 0x0028, 0x2871},
+       {0x00, 0x0028, 0x2872},
+       {0x00, 0x0028, 0x2873},
+       {0x00, 0x0028, 0x2874},
+       {0x00, 0x0028, 0x2875},
+       {0x00, 0x0028, 0x2876},
+       {0x00, 0x0028, 0x2877},
+       {0x00, 0x0028, 0x2878},
+       {0x00, 0x0028, 0x2879},
+       {0x00, 0x0028, 0x287a},
+       {0x00, 0x0028, 0x287b},
+       {0x00, 0x0028, 0x287c},
+       {0x00, 0x0028, 0x287d},
+       {0x00, 0x0028, 0x287e},
+       {0x00, 0x0028, 0x287f},
+
+       {0xa0, 0x0000, 0x0503},
+       {}
+};
+
+static unsigned char qtable_creative_pccam[2][64] = {
+       {                               /* Q-table Y-components */
+        0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
+        0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
+        0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11,
+        0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13,
+        0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17,
+        0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c,
+        0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e,
+        0x16, 0x1c, 0x1d, 0x1d, 0x22, 0x1e, 0x1f, 0x1e},
+       {                               /* Q-table C-components */
+        0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e,
+        0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e,
+        0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+        0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+        0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+        0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+        0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+        0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
+};
+
+/* FIXME: This Q-table is identical to the Creative PC-CAM one,
+ *             except for one byte. Possibly a typo?
+ *             NWG: 18/05/2003.
+ */
+static unsigned char qtable_spca504_default[2][64] = {
+       {                               /* Q-table Y-components */
+        0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
+        0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
+        0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11,
+        0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13,
+        0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17,
+        0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c,
+        0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e,
+        0x16, 0x1c, 0x1d, 0x1d, 0x1d /* 0x22 */ , 0x1e, 0x1f, 0x1e,
+        },
+       {                               /* Q-table C-components */
+        0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e,
+        0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e,
+        0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+        0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+        0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+        0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+        0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+        0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
+};
+
+static void spca5xxRegRead(struct usb_device *dev,
+                          __u16 req,
+                          __u16 index,
+                          __u8 *buffer, __u16 length)
+{
+       usb_control_msg(dev,
+                       usb_rcvctrlpipe(dev, 0),
+                       req,
+                       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       0,              /* value */
+                       index, buffer, length,
+                       500);
+}
+
+static void spca5xxRegWrite(struct usb_device *dev,
+                           __u16 req,
+                           __u16 value,
+                           __u16 index,
+                           __u8 *buffer, __u16 length)
+{
+       usb_control_msg(dev,
+                       usb_sndctrlpipe(dev, 0),
+                       req,
+                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       value, index, buffer, length,
+                       500);
+}
+
+static int reg_write(struct usb_device *dev,
+                    __u16 req, __u16 index, __u16 value)
+{
+       int ret;
+
+       ret = usb_control_msg(dev,
+                       usb_sndctrlpipe(dev, 0),
+                       req,
+                       USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       value, index, NULL, 0, 500);
+       PDEBUG(D_PACK, "reg write: 0x%02x,0x%02x:0x%02x, 0x%x",
+               reg, index, value, ret);
+       if (ret < 0)
+               PDEBUG(D_ERR, "reg write: error %d", ret);
+       return ret;
+}
+
+static int reg_read_info(struct usb_device *dev,
+                       __u16 value)    /* wValue */
+{
+       int ret;
+       __u8 data;
+
+       ret = usb_control_msg(dev,
+                       usb_rcvctrlpipe(dev, 0),
+                       0x20,                   /* request */
+                       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       value,
+                       0,                      /* index */
+                       &data, 1,
+                       500);                   /* timeout */
+       if (ret < 0) {
+               PDEBUG(D_ERR, "reg_read_info err %d", ret);
+               return 0;
+       }
+       return data;
+}
+
+/* returns: negative is error, pos or zero is data */
+static int reg_read(struct usb_device *dev,
+                       __u16 req,      /* bRequest */
+                       __u16 index,    /* wIndex */
+                       __u16 length)   /* wLength (1 or 2 only) */
+{
+       int ret;
+       __u8 buf[2];
+
+       buf[1] = 0;
+       ret = usb_control_msg(dev,
+                       usb_rcvctrlpipe(dev, 0),
+                       req,
+                       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       0,              /* value */
+                       index,
+                       buf, length,
+                       500);
+       if (ret < 0) {
+               PDEBUG(D_ERR, "reg_read err %d", ret);
+               return -1;
+       }
+       return (buf[1] << 8) + buf[0];
+}
+
+static int write_vector(struct gspca_dev *gspca_dev,
+                               __u16 data[][3])
+{
+       struct usb_device *dev = gspca_dev->dev;
+       int ret, i = 0;
+
+       while (data[i][0] != 0 || data[i][1] != 0 || data[i][2] != 0) {
+               ret = reg_write(dev, data[i][0], data[i][2], data[i][1]);
+               if (ret < 0) {
+                       PDEBUG(D_ERR,
+                               "Register write failed for 0x%x,0x%x,0x%x",
+                               data[i][0], data[i][1], data[i][2]);
+                       return ret;
+               }
+               i++;
+       }
+       return 0;
+}
+
+static int spca50x_setup_qtable(struct gspca_dev *gspca_dev,
+                               unsigned int request,
+                               unsigned int ybase,
+                               unsigned int cbase,
+                               unsigned char qtable[2][64])
+{
+       struct usb_device *dev = gspca_dev->dev;
+       int i, err;
+
+       /* loop over y components */
+       for (i = 0; i < 64; i++) {
+               err = reg_write(dev, request, ybase + i, qtable[0][i]);
+               if (err < 0)
+                       return err;
+       }
+
+       /* loop over c components */
+       for (i = 0; i < 64; i++) {
+               err = reg_write(dev, request, cbase + i, qtable[1][i]);
+               if (err < 0)
+                       return err;
+       }
+       return 0;
+}
+
+static void spca504_acknowledged_command(struct gspca_dev *gspca_dev,
+                            __u16 req, __u16 idx, __u16 val)
+{
+       struct usb_device *dev = gspca_dev->dev;
+       __u8 notdone;
+
+       reg_write(dev, req, idx, val);
+       notdone = reg_read(dev, 0x01, 0x0001, 1);
+       reg_write(dev, req, idx, val);
+
+       PDEBUG(D_FRAM, "before wait 0x%x", notdone);
+
+       msleep(200);
+       notdone = reg_read(dev, 0x01, 0x0001, 1);
+       PDEBUG(D_FRAM, "after wait 0x%x", notdone);
+}
+
+static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev,
+                       __u16 req,
+                       __u16 idx, __u16 val, __u8 stat, __u8 count)
+{
+       struct usb_device *dev = gspca_dev->dev;
+       __u8 status;
+       __u8 endcode;
+
+       reg_write(dev, req, idx, val);
+       status = reg_read(dev, 0x01, 0x0001, 1);
+       endcode = stat;
+       PDEBUG(D_FRAM, "Status 0x%x Need 0x%x", status, stat);
+       if (!count)
+               return;
+       count = 200;
+       while (--count > 0) {
+               msleep(10);
+               /* gsmart mini2 write a each wait setting 1 ms is enought */
+/*             reg_write(dev, req, idx, val); */
+               status = reg_read(dev, 0x01, 0x0001, 1);
+               if (status == endcode) {
+                       PDEBUG(D_FRAM, "status 0x%x after wait 0x%x",
+                               status, 200 - count);
+                               break;
+               }
+       }
+}
+
+static int spca504B_PollingDataReady(struct usb_device *dev)
+{
+       __u8 DataReady;
+       int count = 10;
+
+       while (--count > 0) {
+               spca5xxRegRead(dev, 0x21, 0, &DataReady, 1);
+               if ((DataReady & 0x01) == 0)
+                       break;
+               msleep(10);
+       }
+       return DataReady;
+}
+
+static void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev)
+{
+       struct usb_device *dev = gspca_dev->dev;
+       __u8 DataReady;
+       int count = 50;
+
+       while (--count > 0) {
+               spca5xxRegRead(dev, 0x21, 1, &DataReady, 1);
+
+               if (DataReady) {
+                       DataReady = 0;
+                       spca5xxRegWrite(dev, 0x21, 0, 1, &DataReady, 1);
+                       spca5xxRegRead(dev, 0x21, 1, &DataReady, 1);
+                       spca504B_PollingDataReady(dev);
+                       break;
+               }
+               msleep(10);
+       }
+}
+
+static void spca50x_GetFirmware(struct gspca_dev *gspca_dev)
+{
+       struct usb_device *dev = gspca_dev->dev;
+       __u8 FW[5];
+       __u8 ProductInfo[64];
+
+       spca5xxRegRead(dev, 0x20, 0, FW, 5);
+       PDEBUG(D_STREAM, "FirmWare : %d %d %d %d %d ",
+               FW[0], FW[1], FW[2], FW[3], FW[4]);
+       spca5xxRegRead(dev, 0x23, 0, ProductInfo, 64);
+       spca5xxRegRead(dev, 0x23, 1, ProductInfo, 64);
+}
+
+static void spca504B_SetSizeType(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct usb_device *dev = gspca_dev->dev;
+       __u8 Size;
+       __u8 Type;
+       int rc;
+
+       Size = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].mode;
+       Type = 0;
+       switch (sd->bridge) {
+       case BRIDGE_SPCA533:
+               spca5xxRegWrite(dev, 0x31, 0, 0, NULL, 0);
+               spca504B_WaitCmdStatus(gspca_dev);
+               rc = spca504B_PollingDataReady(dev);
+               spca50x_GetFirmware(gspca_dev);
+               Type = 2;
+               spca5xxRegWrite(dev, 0x24, 0, 8, &Type, 1);
+               spca5xxRegRead(dev, 0x24, 8, &Type, 1);
+
+               spca5xxRegWrite(dev, 0x25, 0, 4, &Size, 1);
+               spca5xxRegRead(dev, 0x25, 4, &Size, 1);
+               rc = spca504B_PollingDataReady(dev);
+
+               /* Init the cam width height with some values get on init ? */
+               spca5xxRegWrite(dev, 0x31, 0, 4, NULL, 0);
+               spca504B_WaitCmdStatus(gspca_dev);
+               rc = spca504B_PollingDataReady(dev);
+               break;
+       default:
+/* case BRIDGE_SPCA504B: */
+/* case BRIDGE_SPCA536: */
+               Type = 6;
+               spca5xxRegWrite(dev, 0x25, 0, 4, &Size, 1);
+               spca5xxRegRead(dev, 0x25, 4, &Size, 1);
+               spca5xxRegWrite(dev, 0x27, 0, 0, &Type, 1);
+               spca5xxRegRead(dev, 0x27, 0, &Type, 1);
+               rc = spca504B_PollingDataReady(dev);
+               break;
+       case BRIDGE_SPCA504:
+               Size += 3;
+               if (sd->subtype == AiptekMiniPenCam13) {
+                       /* spca504a aiptek */
+                       spca504A_acknowledged_command(gspca_dev,
+                                               0x08, Size, 0,
+                                               0x80 | (Size & 0x0f), 1);
+                       spca504A_acknowledged_command(gspca_dev,
+                                                       1, 3, 0, 0x9f, 0);
+               } else {
+                       spca504_acknowledged_command(gspca_dev, 0x08, Size, 0);
+               }
+               break;
+       case BRIDGE_SPCA504C:
+               /* capture mode */
+               reg_write(dev, 0xa0, (0x0500 | (Size & 0x0f)), 0x0);
+               reg_write(dev, 0x20, 0x01, 0x0500 | (Size & 0x0f));
+               break;
+       }
+}
+
+static void spca504_wait_status(struct gspca_dev *gspca_dev)
+{
+       struct usb_device *dev = gspca_dev->dev;
+       int cnt;
+
+       cnt = 256;
+       while (--cnt > 0) {
+               /* With this we get the status, when return 0 it's all ok */
+               if (reg_read(dev, 0x06, 0x00, 1) == 0)
+                       return;
+               msleep(10);
+       }
+}
+
+static void spca504B_setQtable(struct gspca_dev *gspca_dev)
+{
+       struct usb_device *dev = gspca_dev->dev;
+       __u8 Data = 3;
+
+       spca5xxRegWrite(dev, 0x26, 0, 0, &Data, 1);
+       spca5xxRegRead(dev, 0x26, 0, &Data, 1);
+       spca504B_PollingDataReady(dev);
+}
+
+static void sp5xx_initContBrigHueRegisters(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct usb_device *dev = gspca_dev->dev;
+       int pollreg = 1;
+
+       switch (sd->bridge) {
+       case BRIDGE_SPCA504:
+       case BRIDGE_SPCA504C:
+               pollreg = 0;
+               /* fall thru */
+       default:
+/*     case BRIDGE_SPCA533: */
+/*     case BRIDGE_SPCA504B: */
+               spca5xxRegWrite(dev, 0, 0, 0x21a7, NULL, 0);    /* brightness */
+               spca5xxRegWrite(dev, 0, 0x20, 0x21a8, NULL, 0); /* contrast */
+               spca5xxRegWrite(dev, 0, 0, 0x21ad, NULL, 0);    /* hue */
+               spca5xxRegWrite(dev, 0, 1, 0x21ac, NULL, 0);    /* sat/hue */
+               spca5xxRegWrite(dev, 0, 0x20, 0x21ae, NULL, 0); /* saturation */
+               spca5xxRegWrite(dev, 0, 0, 0x21a3, NULL, 0);    /* gamma */
+               break;
+       case BRIDGE_SPCA536:
+               spca5xxRegWrite(dev, 0, 0, 0x20f0, NULL, 0);
+               spca5xxRegWrite(dev, 0, 0x21, 0x20f1, NULL, 0);
+               spca5xxRegWrite(dev, 0, 0x40, 0x20f5, NULL, 0);
+               spca5xxRegWrite(dev, 0, 1, 0x20f4, NULL, 0);
+               spca5xxRegWrite(dev, 0, 0x40, 0x20f6, NULL, 0);
+               spca5xxRegWrite(dev, 0, 0, 0x2089, NULL, 0);
+               break;
+       }
+       if (pollreg)
+               spca504B_PollingDataReady(dev);
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+                       const struct usb_device_id *id)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct usb_device *dev = gspca_dev->dev;
+       struct cam *cam;
+       __u16 vendor;
+       __u16 product;
+       __u8 fw;
+
+       vendor = id->idVendor;
+       product = id->idProduct;
+       switch (vendor) {
+       case 0x041e:            /* Creative cameras */
+/*             switch (product) { */
+/*             case 0x400b: */
+/*             case 0x4012: */
+/*             case 0x4013: */
+/*                     sd->bridge = BRIDGE_SPCA504C; */
+/*                     break; */
+/*             } */
+               break;
+       case 0x0458:            /* Genius KYE cameras */
+/*             switch (product) { */
+/*             case 0x7006: */
+                       sd->bridge = BRIDGE_SPCA504B;
+/*                     break; */
+/*             } */
+               break;
+       case 0x046d:            /* Logitech Labtec */
+               switch (product) {
+               case 0x0905:
+                       sd->subtype = LogitechClickSmart820;
+                       sd->bridge = BRIDGE_SPCA533;
+                       break;
+               case 0x0960:
+                       sd->subtype = LogitechClickSmart420;
+                       sd->bridge = BRIDGE_SPCA504C;
+                       break;
+               }
+               break;
+       case 0x0471:                            /* Philips */
+/*             switch (product) { */
+/*             case 0x0322: */
+                       sd->bridge = BRIDGE_SPCA504B;
+/*                     break; */
+/*             } */
+               break;
+       case 0x04a5:            /* Benq */
+               switch (product) {
+               case 0x3003:
+                       sd->bridge = BRIDGE_SPCA504B;
+                       break;
+               case 0x3008:
+               case 0x300a:
+                       sd->bridge = BRIDGE_SPCA533;
+                       break;
+               }
+               break;
+       case 0x04f1:            /* JVC */
+/*             switch (product) { */
+/*             case 0x1001: */
+                       sd->bridge = BRIDGE_SPCA504B;
+/*                     break; */
+/*             } */
+               break;
+       case 0x04fc:            /* SunPlus */
+               switch (product) {
+               case 0x500c:
+                       sd->bridge = BRIDGE_SPCA504B;
+                       break;
+               case 0x504a:
+/* try to get the firmware as some cam answer 2.0.1.2.2
+ * and should be a spca504b then overwrite that setting */
+                       spca5xxRegRead(dev, 0x20, 0, &fw, 1);
+                       if (fw == 1) {
+                               sd->subtype = AiptekMiniPenCam13;
+                               sd->bridge = BRIDGE_SPCA504;
+                       } else if (fw == 2) {
+                               sd->bridge = BRIDGE_SPCA504B;
+                       } else
+                               return -ENODEV;
+                       break;
+               case 0x504b:
+                       sd->bridge = BRIDGE_SPCA504B;
+                       break;
+               case 0x5330:
+                       sd->bridge = BRIDGE_SPCA533;
+                       break;
+               case 0x5360:
+                       sd->bridge = BRIDGE_SPCA536;
+                       break;
+               case 0xffff:
+                       sd->bridge = BRIDGE_SPCA504B;
+                       break;
+               }
+               break;
+       case 0x052b:            /* ?? Megapix */
+/*             switch (product) { */
+/*             case 0x1513: */
+                       sd->subtype = MegapixV4;
+                       sd->bridge = BRIDGE_SPCA533;
+/*                     break; */
+/*             } */
+               break;
+       case 0x0546:            /* Polaroid */
+               switch (product) {
+               case 0x3155:
+                       sd->bridge = BRIDGE_SPCA533;
+                       break;
+               case 0x3191:
+               case 0x3273:
+                       sd->bridge = BRIDGE_SPCA504B;
+                       break;
+               }
+               break;
+       case 0x055f:            /* Mustek cameras */
+               switch (product) {
+               case 0xc211:
+                       sd->bridge = BRIDGE_SPCA536;
+                       break;
+               case 0xc230:
+               case 0xc232:
+                       sd->bridge = BRIDGE_SPCA533;
+                       break;
+               case 0xc360:
+                       sd->bridge = BRIDGE_SPCA536;
+                       break;
+               case 0xc420:
+                       sd->bridge = BRIDGE_SPCA504;
+                       break;
+               case 0xc430:
+               case 0xc440:
+                       sd->bridge = BRIDGE_SPCA533;
+                       break;
+               case 0xc520:
+                       sd->bridge = BRIDGE_SPCA504;
+                       break;
+               case 0xc530:
+               case 0xc540:
+               case 0xc630:
+               case 0xc650:
+                       sd->bridge = BRIDGE_SPCA533;
+                       break;
+               }
+               break;
+       case 0x05da:            /* Digital Dream cameras */
+/*             switch (product) { */
+/*             case 0x1018: */
+                       sd->bridge = BRIDGE_SPCA504B;
+/*                     break; */
+/*             } */
+               break;
+       case 0x06d6:            /* Trust */
+/*             switch (product) { */
+/*             case 0x0031: */
+                       sd->bridge = BRIDGE_SPCA533;    /* SPCA533A */
+/*                     break; */
+/*             } */
+               break;
+       case 0x0733:    /* Rebadged ViewQuest (Intel) and ViewQuest cameras */
+               switch (product) {
+               case 0x1311:
+               case 0x1314:
+               case 0x2211:
+               case 0x2221:
+                       sd->bridge = BRIDGE_SPCA533;
+                       break;
+               case 0x3261:
+               case 0x3281:
+                       sd->bridge = BRIDGE_SPCA536;
+                       break;
+               }
+               break;
+       case 0x08ca:            /* Aiptek */
+               switch (product) {
+               case 0x0104:
+               case 0x0106:
+                       sd->bridge = BRIDGE_SPCA533;
+                       break;
+               case 0x2008:
+                       sd->bridge = BRIDGE_SPCA504B;
+                       break;
+               case 0x2010:
+                       sd->bridge = BRIDGE_SPCA533;
+                       break;
+               case 0x2016:
+               case 0x2018:
+                       sd->bridge = BRIDGE_SPCA504B;
+                       break;
+               case 0x2020:
+               case 0x2022:
+                       sd->bridge = BRIDGE_SPCA533;
+                       break;
+               case 0x2024:
+                       sd->bridge = BRIDGE_SPCA536;
+                       break;
+               case 0x2028:
+                       sd->bridge = BRIDGE_SPCA533;
+                       break;
+               case 0x2040:
+               case 0x2042:
+               case 0x2060:
+                       sd->bridge = BRIDGE_SPCA536;
+                       break;
+               }
+               break;
+       case 0x0d64:            /* SunPlus */
+/*             switch (product) { */
+/*             case 0x0303: */
+                       sd->bridge = BRIDGE_SPCA536;
+/*                     break; */
+/*             } */
+               break;
+       }
+
+       cam = &gspca_dev->cam;
+       cam->dev_name = (char *) id->driver_info;
+       cam->epaddr = 0x01;
+
+       switch (sd->bridge) {
+       default:
+/*     case BRIDGE_SPCA504B: */
+/*     case BRIDGE_SPCA504: */
+/*     case BRIDGE_SPCA536: */
+               cam->cam_mode = vga_mode;
+               cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+               break;
+       case BRIDGE_SPCA533:
+               cam->cam_mode = custom_mode;
+               cam->nmodes = sizeof custom_mode / sizeof custom_mode[0];
+               break;
+       case BRIDGE_SPCA504C:
+               cam->cam_mode = vga_mode2;
+               cam->nmodes = sizeof vga_mode2 / sizeof vga_mode2[0];
+               break;
+       }
+       sd->qindex = 5;                 /* set the quantization table */
+       sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
+       sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
+       sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value;
+       return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct usb_device *dev = gspca_dev->dev;
+       int rc;
+       __u8 Data;
+       __u8 i;
+       __u8 info[6];
+       int err_code;
+
+       switch (sd->bridge) {
+       case BRIDGE_SPCA504B:
+               spca5xxRegWrite(dev, 0x1d, 0, 0, NULL, 0);
+               spca5xxRegWrite(dev, 0, 1, 0x2306, NULL, 0);
+               spca5xxRegWrite(dev, 0, 0, 0x0d04, NULL, 0);
+               spca5xxRegWrite(dev, 0, 0, 0x2000, NULL, 0);
+               spca5xxRegWrite(dev, 0, 0x13, 0x2301, NULL, 0);
+               spca5xxRegWrite(dev, 0, 0, 0x2306, NULL, 0);
+               /* fall thru */
+       case BRIDGE_SPCA533:
+               rc = spca504B_PollingDataReady(dev);
+               spca50x_GetFirmware(gspca_dev);
+               break;
+       case BRIDGE_SPCA536:
+               spca50x_GetFirmware(gspca_dev);
+               spca5xxRegRead(dev, 0x00, 0x5002, &Data, 1);
+               Data = 0;
+               spca5xxRegWrite(dev, 0x24, 0, 0, &Data, 1);
+               spca5xxRegRead(dev, 0x24, 0, &Data, 1);
+               rc = spca504B_PollingDataReady(dev);
+               spca5xxRegWrite(dev, 0x34, 0, 0, NULL, 0);
+               spca504B_WaitCmdStatus(gspca_dev);
+               break;
+       case BRIDGE_SPCA504C:   /* pccam600 */
+               PDEBUG(D_STREAM, "Opening SPCA504 (PC-CAM 600)");
+               reg_write(dev, 0xe0, 0x0000, 0x0000);
+               reg_write(dev, 0xe0, 0x0000, 0x0001);   /* reset */
+               spca504_wait_status(gspca_dev);
+               if (sd->subtype == LogitechClickSmart420)
+                       write_vector(gspca_dev,
+                                       spca504A_clicksmart420_open_data);
+               else
+                       write_vector(gspca_dev, spca504_pccam600_open_data);
+               err_code = spca50x_setup_qtable(gspca_dev,
+                                               0x00, 0x2800,
+                                               0x2840, qtable_creative_pccam);
+               if (err_code < 0) {
+                       PDEBUG(D_ERR|D_STREAM, "spca50x_setup_qtable failed");
+                       return err_code;
+               }
+               break;
+       default:
+/*     case BRIDGE_SPCA504: */
+               PDEBUG(D_STREAM, "Opening SPCA504");
+               if (sd->subtype == AiptekMiniPenCam13) {
+                       /*****************************/
+                       for (i = 0; i < 6; i++)
+                               info[i] = reg_read_info(dev, i);
+                       PDEBUG(D_STREAM,
+                               "Read info: %d %d %d %d %d %d."
+                               " Should be 1,0,2,2,0,0",
+                               info[0], info[1], info[2],
+                               info[3], info[4], info[5]);
+                       /* spca504a aiptek */
+                       /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
+                       spca504A_acknowledged_command(gspca_dev, 0x24,
+                                                       8, 3, 0x9e, 1);
+                       /* Twice sequencial need status 0xff->0x9e->0x9d */
+                       spca504A_acknowledged_command(gspca_dev, 0x24,
+                                                       8, 3, 0x9e, 0);
+
+                       spca504A_acknowledged_command(gspca_dev, 0x24,
+                                                       0, 0, 0x9d, 1);
+                       /******************************/
+                       /* spca504a aiptek */
+                       spca504A_acknowledged_command(gspca_dev, 0x08,
+                                                       6, 0, 0x86, 1);
+/*                     reg_write (dev, 0, 0x2000, 0); */
+/*                     reg_write (dev, 0, 0x2883, 1); */
+/*                     spca504A_acknowledged_command (gspca_dev, 0x08,
+                                                       6, 0, 0x86, 1); */
+/*                     spca504A_acknowledged_command (gspca_dev, 0x24,
+                                                       0, 0, 0x9D, 1); */
+                       reg_write(dev, 0x0, 0x270c, 0x5); /* L92 sno1t.txt */
+                       reg_write(dev, 0x0, 0x2310, 0x5);
+                       spca504A_acknowledged_command(gspca_dev, 0x01,
+                                                       0x0f, 0, 0xff, 0);
+               }
+               /* setup qtable */
+               reg_write(dev, 0, 0x2000, 0);
+               reg_write(dev, 0, 0x2883, 1);
+               err_code = spca50x_setup_qtable(gspca_dev,
+                                               0x00, 0x2800,
+                                               0x2840,
+                                               qtable_spca504_default);
+               if (err_code < 0) {
+                       PDEBUG(D_ERR, "spca50x_setup_qtable failed");
+                       return err_code;
+               }
+               break;
+       }
+       return 0;
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct usb_device *dev = gspca_dev->dev;
+       int rc;
+       int enable;
+       __u8 i;
+       __u8 info[6];
+
+       if (sd->bridge == BRIDGE_SPCA504B)
+               spca504B_setQtable(gspca_dev);
+       spca504B_SetSizeType(gspca_dev);
+       switch (sd->bridge) {
+       default:
+/*     case BRIDGE_SPCA504B: */
+/*     case BRIDGE_SPCA533: */
+/*     case BRIDGE_SPCA536: */
+               if (sd->subtype == MegapixV4 ||
+                   sd->subtype == LogitechClickSmart820) {
+                       spca5xxRegWrite(dev, 0xf0, 0, 0, NULL, 0);
+                       spca504B_WaitCmdStatus(gspca_dev);
+                       spca5xxRegRead(dev, 0xf0, 4, NULL, 0);
+                       spca504B_WaitCmdStatus(gspca_dev);
+               } else {
+                       spca5xxRegWrite(dev, 0x31, 0, 4, NULL, 0);
+                       spca504B_WaitCmdStatus(gspca_dev);
+                       rc = spca504B_PollingDataReady(dev);
+               }
+               break;
+       case BRIDGE_SPCA504:
+               if (sd->subtype == AiptekMiniPenCam13) {
+                       for (i = 0; i < 6; i++)
+                               info[i] = reg_read_info(dev, i);
+                       PDEBUG(D_STREAM,
+                               "Read info: %d %d %d %d %d %d."
+                               " Should be 1,0,2,2,0,0",
+                               info[0], info[1], info[2],
+                               info[3], info[4], info[5]);
+                       /* spca504a aiptek */
+                       /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
+                       spca504A_acknowledged_command(gspca_dev, 0x24,
+                                                       8, 3, 0x9e, 1);
+                       /* Twice sequencial need status 0xff->0x9e->0x9d */
+                       spca504A_acknowledged_command(gspca_dev, 0x24,
+                                                       8, 3, 0x9e, 0);
+                       spca504A_acknowledged_command(gspca_dev, 0x24,
+                                                       0, 0, 0x9d, 1);
+               } else {
+                       spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
+                       for (i = 0; i < 6; i++)
+                               info[i] = reg_read_info(dev, i);
+                       PDEBUG(D_STREAM,
+                               "Read info: %d %d %d %d %d %d."
+                               " Should be 1,0,2,2,0,0",
+                               info[0], info[1], info[2],
+                               info[3], info[4], info[5]);
+                       spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
+                       spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
+               }
+               spca504B_SetSizeType(gspca_dev);
+               reg_write(dev, 0x0, 0x270c, 0x5);       /* L92 sno1t.txt */
+               reg_write(dev, 0x0, 0x2310, 0x5);
+               break;
+       case BRIDGE_SPCA504C:
+               if (sd->subtype == LogitechClickSmart420) {
+                       write_vector(gspca_dev,
+                                       spca504A_clicksmart420_init_data);
+               } else {
+                       write_vector(gspca_dev, spca504_pccam600_init_data);
+               }
+               enable = (sd->autogain ? 0x4 : 0x1);
+               reg_write(dev, 0x0c, 0x0000, enable);   /* auto exposure */
+               reg_write(dev, 0xb0, 0x0000, enable);   /* auto whiteness */
+
+               /* set default exposure compensation and whiteness balance */
+               reg_write(dev, 0x30, 0x0001, 800);      /* ~ 20 fps */
+               reg_write(dev, 0x30, 0x0002, 1600);
+               spca504B_SetSizeType(gspca_dev);
+               break;
+       }
+       sp5xx_initContBrigHueRegisters(gspca_dev);
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct usb_device *dev = gspca_dev->dev;
+
+       switch (sd->bridge) {
+       default:
+/*     case BRIDGE_SPCA533: */
+/*     case BRIDGE_SPCA536: */
+/*     case BRIDGE_SPCA504B: */
+               spca5xxRegWrite(dev, 0x31, 0, 0, NULL, 0);
+               spca504B_WaitCmdStatus(gspca_dev);
+               spca504B_PollingDataReady(dev);
+               break;
+       case BRIDGE_SPCA504:
+       case BRIDGE_SPCA504C:
+               reg_write(dev, 0x00, 0x2000, 0x0000);
+
+               if (sd->subtype == AiptekMiniPenCam13) {
+                       /* spca504a aiptek */
+/*                     spca504A_acknowledged_command(gspca_dev, 0x08,
+                                                        6, 0, 0x86, 1); */
+                       spca504A_acknowledged_command(gspca_dev, 0x24,
+                                                       0x00, 0x00, 0x9d, 1);
+                       spca504A_acknowledged_command(gspca_dev, 0x01,
+                                                       0x0f, 0x00, 0xff, 1);
+               } else {
+                       spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
+                       reg_write(dev, 0x01, 0x000f, 0x0);
+               }
+               break;
+       }
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+                       struct gspca_frame *frame,      /* target */
+                       unsigned char *data,            /* isoc packet */
+                       int len)                        /* iso packet length */
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int i, sof = 0;
+       unsigned char *s, *d;
+       static unsigned char ffd9[] = {0xff, 0xd9};
+
+/* frames are jpeg 4.1.1 without 0xff escape */
+       switch (sd->bridge) {
+       case BRIDGE_SPCA533:
+               if (data[0] == 0xff) {
+                       if (data[1] != 0x01) {  /* drop packet */
+/*                             gspca_dev->last_packet_type = DISCARD_PACKET; */
+                               return;
+                       }
+                       sof = 1;
+                       data += SPCA533_OFFSET_DATA;
+                       len -= SPCA533_OFFSET_DATA;
+               } else {
+                       data += 1;
+                       len -= 1;
+               }
+               break;
+       case BRIDGE_SPCA536:
+               if (data[0] == 0xff) {
+                       sof = 1;
+                       data += SPCA536_OFFSET_DATA;
+                       len -= SPCA536_OFFSET_DATA;
+               } else {
+                       data += 2;
+                       len -= 2;
+               }
+               break;
+       default:
+/*     case BRIDGE_SPCA504: */
+/*     case BRIDGE_SPCA504B: */
+               switch (data[0]) {
+               case 0xfe:                      /* start of frame */
+                       sof = 1;
+                       data += SPCA50X_OFFSET_DATA;
+                       len -= SPCA50X_OFFSET_DATA;
+                       break;
+               case 0xff:                      /* drop packet */
+/*                     gspca_dev->last_packet_type = DISCARD_PACKET; */
+                       return;
+               default:
+                       data += 1;
+                       len -= 1;
+                       break;
+               }
+               break;
+       case BRIDGE_SPCA504C:
+               switch (data[0]) {
+               case 0xfe:                      /* start of frame */
+                       sof = 1;
+                       data += SPCA504_PCCAM600_OFFSET_DATA;
+                       len -= SPCA504_PCCAM600_OFFSET_DATA;
+                       break;
+               case 0xff:                      /* drop packet */
+/*                     gspca_dev->last_packet_type = DISCARD_PACKET; */
+                       return;
+               default:
+                       data += 1;
+                       len -= 1;
+                       break;
+               }
+               break;
+       }
+       if (sof) {              /* start of frame */
+               frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+                                       ffd9, 2);
+
+               /* put the JPEG header in the new frame */
+               jpeg_put_header(gspca_dev, frame,
+                               ((struct sd *) gspca_dev)->qindex,
+                               0x22);
+       }
+
+       /* add 0x00 after 0xff */
+       for (i = len; --i >= 0; )
+               if (data[i] == 0xff)
+                       break;
+       if (i < 0) {                    /* no 0xff */
+               gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+               return;
+       }
+       s = data;
+       d = sd->packet;
+       for (i = 0; i < len; i++) {
+               *d++ = *s++;
+               if (s[-1] == 0xff)
+                       *d++ = 0x00;
+       }
+       gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+                       sd->packet, d - sd->packet);
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct usb_device *dev = gspca_dev->dev;
+
+       switch (sd->bridge) {
+       default:
+/*     case BRIDGE_SPCA533: */
+/*     case BRIDGE_SPCA504B: */
+/*     case BRIDGE_SPCA504: */
+/*     case BRIDGE_SPCA504C: */
+               reg_write(dev, 0x0, 0x21a7, sd->brightness);
+               break;
+       case BRIDGE_SPCA536:
+               reg_write(dev, 0x0, 0x20f0, sd->brightness);
+               break;
+       }
+}
+
+static void getbrightness(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct usb_device *dev = gspca_dev->dev;
+       __u16 brightness = 0;
+
+       switch (sd->bridge) {
+       default:
+/*     case BRIDGE_SPCA533: */
+/*     case BRIDGE_SPCA504B: */
+/*     case BRIDGE_SPCA504: */
+/*     case BRIDGE_SPCA504C: */
+               brightness = reg_read(dev, 0x0, 0x21a7, 2);
+               break;
+       case BRIDGE_SPCA536:
+               brightness = reg_read(dev, 0x0, 0x20f0, 2);
+               break;
+       }
+       sd->brightness = ((brightness & 0xff) - 128) % 255;
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct usb_device *dev = gspca_dev->dev;
+
+       switch (sd->bridge) {
+       default:
+/*     case BRIDGE_SPCA533: */
+/*     case BRIDGE_SPCA504B: */
+/*     case BRIDGE_SPCA504: */
+/*     case BRIDGE_SPCA504C: */
+               reg_write(dev, 0x0, 0x21a8, sd->contrast);
+               break;
+       case BRIDGE_SPCA536:
+               reg_write(dev, 0x0, 0x20f1, sd->contrast);
+               break;
+       }
+}
+
+static void getcontrast(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct usb_device *dev = gspca_dev->dev;
+
+       switch (sd->bridge) {
+       default:
+/*     case BRIDGE_SPCA533: */
+/*     case BRIDGE_SPCA504B: */
+/*     case BRIDGE_SPCA504: */
+/*     case BRIDGE_SPCA504C: */
+               sd->contrast = reg_read(dev, 0x0, 0x21a8, 2);
+               break;
+       case BRIDGE_SPCA536:
+               sd->contrast = reg_read(dev, 0x0, 0x20f1, 2);
+               break;
+       }
+}
+
+static void setcolors(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct usb_device *dev = gspca_dev->dev;
+
+       switch (sd->bridge) {
+       default:
+/*     case BRIDGE_SPCA533: */
+/*     case BRIDGE_SPCA504B: */
+/*     case BRIDGE_SPCA504: */
+/*     case BRIDGE_SPCA504C: */
+               reg_write(dev, 0x0, 0x21ae, sd->colors);
+               break;
+       case BRIDGE_SPCA536:
+               reg_write(dev, 0x0, 0x20f6, sd->colors);
+               break;
+       }
+}
+
+static void getcolors(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct usb_device *dev = gspca_dev->dev;
+
+       switch (sd->bridge) {
+       default:
+/*     case BRIDGE_SPCA533: */
+/*     case BRIDGE_SPCA504B: */
+/*     case BRIDGE_SPCA504: */
+/*     case BRIDGE_SPCA504C: */
+               sd->colors = reg_read(dev, 0x0, 0x21ae, 2) >> 1;
+               break;
+       case BRIDGE_SPCA536:
+               sd->colors = reg_read(dev, 0x0, 0x20f6, 2) >> 1;
+               break;
+       }
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->brightness = val;
+       if (gspca_dev->streaming)
+               setbrightness(gspca_dev);
+       return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       getbrightness(gspca_dev);
+       *val = sd->brightness;
+       return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->contrast = val;
+       if (gspca_dev->streaming)
+               setcontrast(gspca_dev);
+       return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       getcontrast(gspca_dev);
+       *val = sd->contrast;
+       return 0;
+}
+
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->colors = val;
+       if (gspca_dev->streaming)
+               setcolors(gspca_dev);
+       return 0;
+}
+
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       getcolors(gspca_dev);
+       *val = sd->colors;
+       return 0;
+}
+
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->autogain = val;
+       return 0;
+}
+
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->autogain;
+       return 0;
+}
+
+/* sub-driver description */
+static struct sd_desc sd_desc = {
+       .name = MODULE_NAME,
+       .ctrls = sd_ctrls,
+       .nctrls = ARRAY_SIZE(sd_ctrls),
+       .config = sd_config,
+       .open = sd_open,
+       .start = sd_start,
+       .stopN = sd_stopN,
+       .stop0 = sd_stop0,
+       .close = sd_close,
+       .pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static __devinitdata struct usb_device_id device_table[] = {
+       {USB_DEVICE(0x041e, 0x400b), DVNM("Creative PC-CAM 600")},
+       {USB_DEVICE(0x041e, 0x4012), DVNM("PC-Cam350")},
+       {USB_DEVICE(0x041e, 0x4013), DVNM("Creative Pccam750")},
+       {USB_DEVICE(0x0458, 0x7006), DVNM("Genius Dsc 1.3 Smart")},
+       {USB_DEVICE(0x046d, 0x0905), DVNM("Logitech ClickSmart 820")},
+       {USB_DEVICE(0x046d, 0x0960), DVNM("Logitech ClickSmart 420")},
+       {USB_DEVICE(0x0471, 0x0322), DVNM("Philips DMVC1300K")},
+       {USB_DEVICE(0x04a5, 0x3003), DVNM("Benq DC 1300")},
+       {USB_DEVICE(0x04a5, 0x3008), DVNM("Benq DC 1500")},
+       {USB_DEVICE(0x04a5, 0x300a), DVNM("Benq DC3410")},
+       {USB_DEVICE(0x04f1, 0x1001), DVNM("JVC GC A50")},
+       {USB_DEVICE(0x04fc, 0x500c), DVNM("Sunplus CA500C")},
+       {USB_DEVICE(0x04fc, 0x504a), DVNM("Aiptek Mini PenCam 1.3")},
+       {USB_DEVICE(0x04fc, 0x504b), DVNM("Maxell MaxPocket LE 1.3")},
+       {USB_DEVICE(0x04fc, 0x5330), DVNM("Digitrex 2110")},
+       {USB_DEVICE(0x04fc, 0x5360), DVNM("Sunplus Generic")},
+       {USB_DEVICE(0x04fc, 0xffff), DVNM("Pure DigitalDakota")},
+       {USB_DEVICE(0x052b, 0x1513), DVNM("Megapix V4")},
+       {USB_DEVICE(0x0546, 0x3155), DVNM("Polaroid PDC3070")},
+       {USB_DEVICE(0x0546, 0x3191), DVNM("Polaroid Ion 80")},
+       {USB_DEVICE(0x0546, 0x3273), DVNM("Polaroid PDC2030")},
+       {USB_DEVICE(0x055f, 0xc211), DVNM("Kowa Bs888e Microcamera")},
+       {USB_DEVICE(0x055f, 0xc230), DVNM("Mustek Digicam 330K")},
+       {USB_DEVICE(0x055f, 0xc232), DVNM("Mustek MDC3500")},
+       {USB_DEVICE(0x055f, 0xc360), DVNM("Mustek DV4000 Mpeg4 ")},
+       {USB_DEVICE(0x055f, 0xc420), DVNM("Mustek gSmart Mini 2")},
+       {USB_DEVICE(0x055f, 0xc430), DVNM("Mustek Gsmart LCD 2")},
+       {USB_DEVICE(0x055f, 0xc440), DVNM("Mustek DV 3000")},
+       {USB_DEVICE(0x055f, 0xc520), DVNM("Mustek gSmart Mini 3")},
+       {USB_DEVICE(0x055f, 0xc530), DVNM("Mustek Gsmart LCD 3")},
+       {USB_DEVICE(0x055f, 0xc540), DVNM("Gsmart D30")},
+       {USB_DEVICE(0x055f, 0xc630), DVNM("Mustek MDC4000")},
+       {USB_DEVICE(0x055f, 0xc650), DVNM("Mustek MDC5500Z")},
+       {USB_DEVICE(0x05da, 0x1018), DVNM("Digital Dream Enigma 1.3")},
+       {USB_DEVICE(0x06d6, 0x0031), DVNM("Trust 610 LCD PowerC@m Zoom")},
+       {USB_DEVICE(0x0733, 0x1311), DVNM("Digital Dream Epsilon 1.3")},
+       {USB_DEVICE(0x0733, 0x1314), DVNM("Mercury 2.1MEG Deluxe Classic Cam")},
+       {USB_DEVICE(0x0733, 0x2211), DVNM("Jenoptik jdc 21 LCD")},
+       {USB_DEVICE(0x0733, 0x2221), DVNM("Mercury Digital Pro 3.1p")},
+       {USB_DEVICE(0x0733, 0x3261), DVNM("Concord 3045 spca536a")},
+       {USB_DEVICE(0x0733, 0x3281), DVNM("Cyberpix S550V")},
+       {USB_DEVICE(0x08ca, 0x0104), DVNM("Aiptek PocketDVII 1.3")},
+       {USB_DEVICE(0x08ca, 0x0106), DVNM("Aiptek Pocket DV3100+")},
+       {USB_DEVICE(0x08ca, 0x2008), DVNM("Aiptek Mini PenCam 2 M")},
+       {USB_DEVICE(0x08ca, 0x2010), DVNM("Aiptek PocketCam 3M")},
+       {USB_DEVICE(0x08ca, 0x2016), DVNM("Aiptek PocketCam 2 Mega")},
+       {USB_DEVICE(0x08ca, 0x2018), DVNM("Aiptek Pencam SD 2M")},
+       {USB_DEVICE(0x08ca, 0x2020), DVNM("Aiptek Slim 3000F")},
+       {USB_DEVICE(0x08ca, 0x2022), DVNM("Aiptek Slim 3200")},
+       {USB_DEVICE(0x08ca, 0x2024), DVNM("Aiptek DV3500 Mpeg4 ")},
+       {USB_DEVICE(0x08ca, 0x2028), DVNM("Aiptek PocketCam4M")},
+       {USB_DEVICE(0x08ca, 0x2040), DVNM("Aiptek PocketDV4100M")},
+       {USB_DEVICE(0x08ca, 0x2042), DVNM("Aiptek PocketDV5100")},
+       {USB_DEVICE(0x08ca, 0x2060), DVNM("Aiptek PocketDV5300")},
+       {USB_DEVICE(0x0d64, 0x0303), DVNM("Sunplus FashionCam DXG")},
+       {}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+                       const struct usb_device_id *id)
+{
+       return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+                               THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+       .name = MODULE_NAME,
+       .id_table = device_table,
+       .probe = sd_probe,
+       .disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+       if (usb_register(&sd_driver) < 0)
+               return -1;
+       PDEBUG(D_PROBE, "v%s registered", version);
+       return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+       usb_deregister(&sd_driver);
+       PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/t613.c b/drivers/media/video/gspca/t613.c
new file mode 100644 (file)
index 0000000..c22b301
--- /dev/null
@@ -0,0 +1,1013 @@
+/*
+ *Notes: * t613  + tas5130A
+ *     * Focus to light do not balance well as in win.
+ *       Quality in win is not good, but its kinda better.
+ *      * Fix some "extraneous bytes", most of apps will show the image anyway
+ *      * Gamma table, is there, but its really doing something?
+ *      * 7~8 Fps, its ok, max on win its 10.
+ *                     Costantino Leandro
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define MODULE_NAME "t613"
+#include "gspca.h"
+#define DRIVER_VERSION_NUMBER  KERNEL_VERSION(2, 1, 0)
+static const char version[] = "2.1.0";
+
+struct control_menu_info {
+       int value;
+       char name[32];
+};
+
+#define MAX_GAMMA 0x10         /* 0 to 15 */
+
+/* From LUVCVIEW */
+#define V4L2_CID_EFFECTS (V4L2_CID_PRIVATE_BASE + 3)
+
+MODULE_AUTHOR("Leandro Costantino <le_costantino@pixartargentina.com.ar>");
+MODULE_DESCRIPTION("GSPCA/T613 (JPEG Compliance) USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+struct sd {
+       struct gspca_dev gspca_dev;     /* !! must be the first item */
+
+       unsigned char brightness;
+       unsigned char contrast;
+       unsigned char colors;
+       unsigned char autogain;
+       unsigned char gamma;
+       unsigned char sharpness;
+       unsigned char freq;
+       unsigned char whitebalance;
+       unsigned char mirror;
+       unsigned char effect;
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setlowlight(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getlowlight(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setflip(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getflip(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_seteffect(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_geteffect(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_querymenu(struct gspca_dev *gspca_dev,
+                       struct v4l2_querymenu *menu);
+
+static struct ctrl sd_ctrls[] = {
+#define SD_BRIGHTNESS 0
+       {
+        {
+         .id = V4L2_CID_BRIGHTNESS,
+         .type = V4L2_CTRL_TYPE_INTEGER,
+         .name = "Brightness",
+         .minimum = 0,
+         .maximum = 0x0f,
+         .step = 1,
+         .default_value = 0x09,
+         },
+        .set = sd_setbrightness,
+        .get = sd_getbrightness,
+        },
+#define SD_CONTRAST 1
+       {
+        {
+         .id = V4L2_CID_CONTRAST,
+         .type = V4L2_CTRL_TYPE_INTEGER,
+         .name = "Contrast",
+         .minimum = 0,
+         .maximum = 0x0d,
+         .step = 1,
+         .default_value = 0x07,
+         },
+        .set = sd_setcontrast,
+        .get = sd_getcontrast,
+        },
+#define SD_COLOR 2
+       {
+        {
+         .id = V4L2_CID_SATURATION,
+         .type = V4L2_CTRL_TYPE_INTEGER,
+         .name = "Color",
+         .minimum = 0,
+         .maximum = 0x0f,
+         .step = 1,
+         .default_value = 0x05,
+         },
+        .set = sd_setcolors,
+        .get = sd_getcolors,
+        },
+#define SD_GAMMA 3
+       {
+        {
+         .id = V4L2_CID_GAMMA, /* (gamma on win) */
+         .type = V4L2_CTRL_TYPE_INTEGER,
+         .name = "Gamma (Untested)",
+         .minimum = 0,
+         .maximum = MAX_GAMMA,
+         .step = 1,
+         .default_value = 0x09,
+         },
+        .set = sd_setgamma,
+        .get = sd_getgamma,
+        },
+#define SD_AUTOGAIN 4
+       {
+        {
+         .id = V4L2_CID_GAIN,  /* here, i activate only the lowlight,
+                                * some apps dont bring up the
+                                * backligth_compensation control) */
+         .type = V4L2_CTRL_TYPE_INTEGER,
+         .name = "Low Light",
+         .minimum = 0,
+         .maximum = 1,
+         .step = 1,
+         .default_value = 0x01,
+         },
+        .set = sd_setlowlight,
+        .get = sd_getlowlight,
+        },
+#define SD_MIRROR 5
+       {
+        {
+         .id = V4L2_CID_HFLIP,
+         .type = V4L2_CTRL_TYPE_BOOLEAN,
+         .name = "Mirror Image",
+         .minimum = 0,
+         .maximum = 1,
+         .step = 1,
+         .default_value = 0,
+         },
+        .set = sd_setflip,
+        .get = sd_getflip
+       },
+#define SD_LIGHTFREQ 6
+       {
+        {
+         .id = V4L2_CID_POWER_LINE_FREQUENCY,
+         .type = V4L2_CTRL_TYPE_MENU,
+         .name = "Light Frequency Filter",
+         .minimum = 1,         /* 1 -> 0x50, 2->0x60 */
+         .maximum = 2,
+         .step = 1,
+         .default_value = 1,
+         },
+        .set = sd_setfreq,
+        .get = sd_getfreq},
+
+#define SD_WHITE_BALANCE 7
+       {
+        {
+         .id = V4L2_CID_WHITE_BALANCE_TEMPERATURE,
+         .type = V4L2_CTRL_TYPE_INTEGER,
+         .name = "White Balance",
+         .minimum = 0,
+         .maximum = 1,
+         .step = 1,
+         .default_value = 1,
+         },
+        .set = sd_setwhitebalance,
+        .get = sd_getwhitebalance
+       },
+#define SD_SHARPNESS 8         /* (aka definition on win) */
+       {
+        {
+         .id = V4L2_CID_SHARPNESS,
+         .type = V4L2_CTRL_TYPE_INTEGER,
+         .name = "Sharpness",
+         .minimum = 0,
+         .maximum = MAX_GAMMA, /* 0 to 16 */
+         .step = 1,
+         .default_value = 0x06,
+         },
+        .set = sd_setsharpness,
+        .get = sd_getsharpness,
+        },
+#define SD_EFFECTS 9
+       {
+        {
+         .id = V4L2_CID_EFFECTS,
+         .type = V4L2_CTRL_TYPE_MENU,
+         .name = "Webcam Effects",
+         .minimum = 0,
+         .maximum = 4,
+         .step = 1,
+         .default_value = 0,
+         },
+        .set = sd_seteffect,
+        .get = sd_geteffect
+       },
+};
+
+static struct control_menu_info effects_control[] = {
+       {0, "Normal"},
+       {1, "Emboss"},          /* disabled */
+       {2, "Monochrome"},
+       {3, "Sepia"},
+       {4, "Sketch"},
+       {5, "Sun Effect"},      /* disabled */
+       {6, "Negative"},
+};
+
+#define NUM_EFFECTS_CONTROL \
+                       (sizeof(effects_control)/sizeof(effects_control[0]))
+
+static struct cam_mode vga_mode_t16[] = {
+       {V4L2_PIX_FMT_JPEG, 160, 120, 4},
+       {V4L2_PIX_FMT_JPEG, 176, 144, 3},
+       {V4L2_PIX_FMT_JPEG, 320, 240, 2},
+       {V4L2_PIX_FMT_JPEG, 352, 288, 1},
+       {V4L2_PIX_FMT_JPEG, 640, 480, 0},
+};
+
+#define T16_OFFSET_DATA 631
+#define MAX_EFFECTS 7
+/* easily done by soft, this table could be removed,
+ * i keep it here just in case */
+unsigned char effects_table[MAX_EFFECTS][6] = {
+       {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x00},   /* Normal */
+       {0xa8, 0xc8, 0xc6, 0x52, 0xc0, 0x04},   /* Repujar */
+       {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x20},   /* Monochrome */
+       {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x80},   /* Sepia */
+       {0xa8, 0xc8, 0xc6, 0x52, 0xc0, 0x02},   /* Croquis */
+       {0xa8, 0xc8, 0xc6, 0xd2, 0xc0, 0x10},   /* Sun Effect */
+       {0xa8, 0xc8, 0xc6, 0xd2, 0xc0, 0x40},   /* Negative */
+};
+
+unsigned char gamma_table[MAX_GAMMA][34] = {
+       {0x90, 0x00, 0x91, 0x3e, 0x92, 0x69, 0x93, 0x85,
+        0x94, 0x95, 0x95, 0xa1, 0x96, 0xae, 0x97, 0xb9,
+        0x98, 0xc2, 0x99, 0xcb, 0x9a, 0xd4, 0x9b, 0xdb,
+        0x9c, 0xe3, 0x9d, 0xea, 0x9e, 0xf1, 0x9f, 0xf8,
+        0xa0, 0xff},
+       {0x90, 0x00, 0x91, 0x33, 0x92, 0x5A, 0x93, 0x75,
+        0x94, 0x85, 0x95, 0x93, 0x96, 0xA1, 0x97, 0xAD,
+        0x98, 0xB7, 0x99, 0xC2, 0x9A, 0xCB, 0x9B, 0xD4,
+        0x9C, 0xDE, 0x9D, 0xE7, 0x9E, 0xF0, 0x9F, 0xF7,
+        0xa0, 0xff},
+       {0x90, 0x00, 0x91, 0x2F, 0x92, 0x51, 0x93, 0x6B,
+        0x94, 0x7C, 0x95, 0x8A, 0x96, 0x99, 0x97, 0xA6,
+        0x98, 0xB1, 0x99, 0xBC, 0x9A, 0xC6, 0x9B, 0xD0,
+        0x9C, 0xDB, 0x9D, 0xE4, 0x9E, 0xED, 0x9F, 0xF6,
+        0xa0, 0xff},
+       {0x90, 0x00, 0x91, 0x29, 0x92, 0x48, 0x93, 0x60,
+        0x94, 0x72, 0x95, 0x81, 0x96, 0x90, 0x97, 0x9E,
+        0x98, 0xAA, 0x99, 0xB5, 0x9A, 0xBF, 0x9B, 0xCB,
+        0x9C, 0xD6, 0x9D, 0xE1, 0x9E, 0xEB, 0x9F, 0xF5,
+        0xa0, 0xff},
+       {0x90, 0x00, 0x91, 0x23, 0x92, 0x3F, 0x93, 0x55,
+        0x94, 0x68, 0x95, 0x77, 0x96, 0x86, 0x97, 0x95,
+        0x98, 0xA2, 0x99, 0xAD, 0x9A, 0xB9, 0x9B, 0xC6,
+        0x9C, 0xD2, 0x9D, 0xDE, 0x9E, 0xE9, 0x9F, 0xF4,
+        0xa0, 0xff},
+       {0x90, 0x00, 0x91, 0x1B, 0x92, 0x33, 0x93, 0x48,
+        0x94, 0x59, 0x95, 0x69, 0x96, 0x79, 0x97, 0x87,
+        0x98, 0x96, 0x99, 0xA3, 0x9A, 0xB1, 0x9B, 0xBE,
+        0x9C, 0xCC, 0x9D, 0xDA, 0x9E, 0xE7, 0x9F, 0xF3,
+        0xa0, 0xff},
+       {0x90, 0x00, 0x91, 0x02, 0x92, 0x10, 0x93, 0x20,
+        0x94, 0x32, 0x95, 0x40, 0x96, 0x57, 0x97, 0x67,
+        0x98, 0x77, 0x99, 0x88, 0x9a, 0x99, 0x9b, 0xaa,
+        0x9c, 0xbb, 0x9d, 0xcc, 0x9e, 0xdd, 0x9f, 0xee,
+        0xa0, 0xff},
+       {0x90, 0x00, 0x91, 0x02, 0x92, 0x14, 0x93, 0x26,
+        0x94, 0x38, 0x95, 0x4A, 0x96, 0x60, 0x97, 0x70,
+        0x98, 0x80, 0x99, 0x90, 0x9A, 0xA0, 0x9B, 0xB0,
+        0x9C, 0xC0, 0x9D, 0xD0, 0x9E, 0xE0, 0x9F, 0xF0,
+        0xa0, 0xff},
+       {0x90, 0x00, 0x91, 0x10, 0x92, 0x22, 0x93, 0x35,
+        0x94, 0x47, 0x95, 0x5A, 0x96, 0x69, 0x97, 0x79,
+        0x98, 0x88, 0x99, 0x97, 0x9A, 0xA7, 0x9B, 0xB6,
+        0x9C, 0xC4, 0x9D, 0xD3, 0x9E, 0xE0, 0x9F, 0xF0,
+        0xa0, 0xff},
+       {0x90, 0x00, 0x91, 0x10, 0x92, 0x26, 0x93, 0x40,
+        0x94, 0x54, 0x95, 0x65, 0x96, 0x75, 0x97, 0x84,
+        0x98, 0x93, 0x99, 0xa1, 0x9a, 0xb0, 0x9b, 0xbd,
+        0x9c, 0xca, 0x9d, 0xd6, 0x9e, 0xe0, 0x9f, 0xf0,
+        0xa0, 0xff},
+       {0x90, 0x00, 0x91, 0x18, 0x92, 0x2B, 0x93, 0x44,
+        0x94, 0x60, 0x95, 0x70, 0x96, 0x80, 0x97, 0x8E,
+        0x98, 0x9C, 0x99, 0xAA, 0x9A, 0xB7, 0x9B, 0xC4,
+        0x9C, 0xD0, 0x9D, 0xD8, 0x9E, 0xE2, 0x9F, 0xF0,
+        0xa0, 0xff},
+       {0x90, 0x00, 0x91, 0x1A, 0x92, 0x34, 0x93, 0x52,
+        0x94, 0x66, 0x95, 0x7E, 0x96, 0x8D, 0x97, 0x9B,
+        0x98, 0xA8, 0x99, 0xB4, 0x9A, 0xC0, 0x9B, 0xCB,
+        0x9C, 0xD6, 0x9D, 0xE1, 0x9E, 0xEB, 0x9F, 0xF5,
+        0xa0, 0xff},
+       {0x90, 0x00, 0x91, 0x3F, 0x92, 0x5A, 0x93, 0x6E,
+        0x94, 0x7F, 0x95, 0x8E, 0x96, 0x9C, 0x97, 0xA8,
+        0x98, 0xB4, 0x99, 0xBF, 0x9A, 0xC9, 0x9B, 0xD3,
+        0x9C, 0xDC, 0x9D, 0xE5, 0x9E, 0xEE, 0x9F, 0xF6,
+        0xA0, 0xFF},
+       {0x90, 0x00, 0x91, 0x54, 0x92, 0x6F, 0x93, 0x83,
+        0x94, 0x93, 0x95, 0xA0, 0x96, 0xAD, 0x97, 0xB7,
+        0x98, 0xC2, 0x99, 0xCB, 0x9A, 0xD4, 0x9B, 0xDC,
+        0x9C, 0xE4, 0x9D, 0xEB, 0x9E, 0xF2, 0x9F, 0xF9,
+        0xa0, 0xff},
+       {0x90, 0x00, 0x91, 0x6E, 0x92, 0x88, 0x93, 0x9A,
+        0x94, 0xA8, 0x95, 0xB3, 0x96, 0xBD, 0x97, 0xC6,
+        0x98, 0xCF, 0x99, 0xD6, 0x9A, 0xDD, 0x9B, 0xE3,
+        0x9C, 0xE9, 0x9D, 0xEF, 0x9E, 0xF4, 0x9F, 0xFA,
+        0xa0, 0xff},
+       {0x90, 0x00, 0x91, 0x93, 0x92, 0xA8, 0x93, 0xB7,
+        0x94, 0xC1, 0x95, 0xCA, 0x96, 0xD2, 0x97, 0xD8,
+        0x98, 0xDE, 0x99, 0xE3, 0x9A, 0xE8, 0x9B, 0xED,
+        0x9C, 0xF1, 0x9D, 0xF5, 0x9E, 0xF8, 0x9F, 0xFC,
+        0xA0, 0xFF}
+};
+
+static __u8 tas5130a_sensor_init[][8] = {
+       {0x62, 0x08, 0x63, 0x70, 0x64, 0x1d, 0x60, 0x09},
+       {0x62, 0x20, 0x63, 0x01, 0x64, 0x02, 0x60, 0x09},
+       {0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09},
+       {0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09},
+       {},
+};
+
+static void t16RegRead(struct usb_device *dev,
+                      __u16 index, __u8 *buffer, __u16 length)
+{
+       usb_control_msg(dev,
+                       usb_rcvctrlpipe(dev, 0),
+                       0,              /* request */
+                       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       0,              /* value */
+                       index, buffer, length, 500);
+}
+
+static void t16RegWrite(struct usb_device *dev,
+                       __u16 value,
+                       __u16 index, __u8 *buffer, __u16 length)
+{
+       usb_control_msg(dev,
+                       usb_sndctrlpipe(dev, 0),
+                       0,              /* request */
+                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       value, index, buffer, length, 500);
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+                    const struct usb_device_id *id)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct cam *cam;
+
+       cam = &gspca_dev->cam;
+       cam->dev_name = (char *) id->driver_info;
+       cam->epaddr = 0x01;
+
+       cam->cam_mode = vga_mode_t16;
+       cam->nmodes = ARRAY_SIZE(vga_mode_t16);
+
+       sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
+       sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
+       sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value;
+       sd->gamma = sd_ctrls[SD_GAMMA].qctrl.default_value;
+       sd->mirror = sd_ctrls[SD_MIRROR].qctrl.default_value;
+       sd->freq = sd_ctrls[SD_LIGHTFREQ].qctrl.default_value;
+       sd->whitebalance = sd_ctrls[SD_WHITE_BALANCE].qctrl.default_value;
+       sd->sharpness = sd_ctrls[SD_SHARPNESS].qctrl.default_value;
+       sd->effect = sd_ctrls[SD_EFFECTS].qctrl.default_value;
+       return 0;
+}
+
+static int init_default_parameters(struct gspca_dev *gspca_dev)
+{
+       struct usb_device *dev = gspca_dev->dev;
+
+       /* some of this registers are not really neded, because
+        * they are overriden by setbrigthness, setcontrast, etc,
+        * but wont hurt anyway, and can help someone with similar webcam
+        * to see the initial parameters.*/
+       int i = 0;
+       __u8 test_byte;
+
+       static unsigned char read_indexs[] =
+               { 0x06, 0x07, 0x0a, 0x0b, 0x66, 0x80, 0x81, 0x8e, 0x8f, 0xa5,
+                 0xa6, 0xa8, 0xbb, 0xbc, 0xc6, 0x00, 0x00 };
+       static unsigned char n1[6] =
+                       {0x08, 0x03, 0x09, 0x03, 0x12, 0x04};
+       static unsigned char n2[2] =
+                       {0x08, 0x00};
+       static unsigned char nset[6] =
+               { 0x61, 0x68, 0x62, 0xff, 0x60, 0x07 };
+       static unsigned char n3[6] =
+                       {0x61, 0x68, 0x65, 0x0a, 0x60, 0x04};
+       static unsigned char n4[0x46] =
+               {0x09, 0x01, 0x12, 0x04, 0x66, 0x8a, 0x80, 0x3c,
+                0x81, 0x22, 0x84, 0x50, 0x8a, 0x78, 0x8b, 0x68,
+                0x8c, 0x88, 0x8e, 0x33, 0x8f, 0x24, 0xaa, 0xb1,
+                0xa2, 0x60, 0xa5, 0x30, 0xa6, 0x3a, 0xa8, 0xe8,
+                0xae, 0x05, 0xb1, 0x00, 0xbb, 0x04, 0xbc, 0x48,
+                0xbe, 0x36, 0xc6, 0x88, 0xe9, 0x00, 0xc5, 0xc0,
+                0x65, 0x0a, 0xbb, 0x86, 0xaf, 0x58, 0xb0, 0x68,
+                0x87, 0x40, 0x89, 0x2b, 0x8d, 0xff, 0x83, 0x40,
+                0xac, 0x84, 0xad, 0x86, 0xaf, 0x46};
+       static unsigned char nset4[18] = {
+               0xe0, 0x60, 0xe1, 0xa8, 0xe2, 0xe0, 0xe3, 0x60, 0xe4, 0xa8,
+               0xe5, 0xe0, 0xe6, 0x60, 0xe7, 0xa8,
+               0xe8, 0xe0
+       };
+       /* ojo puede ser 0xe6 en vez de 0xe9 */
+       static unsigned char nset2[20] = {
+               0xd0, 0xbb, 0xd1, 0x28, 0xd2, 0x10, 0xd3, 0x10, 0xd4, 0xbb,
+               0xd5, 0x28, 0xd6, 0x1e, 0xd7, 0x27,
+               0xd8, 0xc8, 0xd9, 0xfc
+       };
+       static unsigned char missing[8] =
+               { 0x87, 0x20, 0x88, 0x20, 0x89, 0x20, 0x80, 0x38 };
+       static unsigned char nset3[18] = {
+               0xc7, 0x60, 0xc8, 0xa8, 0xc9, 0xe0, 0xca, 0x60, 0xcb, 0xa8,
+               0xcc, 0xe0, 0xcd, 0x60, 0xce, 0xa8,
+               0xcf, 0xe0
+       };
+       static unsigned char nset5[4] =
+               { 0x8f, 0x24, 0xc3, 0x00 };     /* bright */
+       static unsigned char nset6[34] = {
+               0x90, 0x00, 0x91, 0x1c, 0x92, 0x30, 0x93, 0x43, 0x94, 0x54,
+               0x95, 0x65, 0x96, 0x75, 0x97, 0x84,
+               0x98, 0x93, 0x99, 0xa1, 0x9a, 0xb0, 0x9b, 0xbd, 0x9c, 0xca,
+               0x9d, 0xd8, 0x9e, 0xe5, 0x9f, 0xf2,
+               0xa0, 0xff
+       };                      /* Gamma */
+       static unsigned char nset7[4] =
+                       { 0x66, 0xca, 0xa8, 0xf8 };     /* 50/60 Hz */
+       static unsigned char nset9[4] =
+                       { 0x0b, 0x04, 0x0a, 0x78 };
+       static unsigned char nset8[6] =
+                       { 0xa8, 0xf0, 0xc6, 0x88, 0xc0, 0x00 };
+       static unsigned char nset10[6] =
+                       { 0x0c, 0x03, 0xab, 0x10, 0x81, 0x20 };
+
+       t16RegWrite(dev, 0x01, 0x0000, n1, 0x06);
+       t16RegWrite(dev, 0x01, 0x0000, nset, 0x06);
+       t16RegRead(dev, 0x0063, &test_byte, 1);
+       t16RegWrite(dev, 0x01, 0x0000, n2, 0x02);
+
+       while (read_indexs[i] != 0x00) {
+               t16RegRead(dev, read_indexs[i], &test_byte, 1);
+               PDEBUG(D_CONF, "Reg 0x%x => 0x%x", read_indexs[i],
+                      test_byte);
+               i++;
+       }
+
+       t16RegWrite(dev, 0x01, 0x0000, n3, 0x06);
+       t16RegWrite(dev, 0x01, 0x0000, n4, 0x46);
+       t16RegRead(dev, 0x0080, &test_byte, 1);
+       t16RegWrite(dev, 0x00, 0x2c80, 0x00, 0x0);
+       t16RegWrite(dev, 0x01, 0x0000, nset2, 0x14);
+       t16RegWrite(dev, 0x01, 0x0000, nset3, 0x12);
+       t16RegWrite(dev, 0x01, 0x0000, nset4, 0x12);
+       t16RegWrite(dev, 0x00, 0x3880, 0x00, 0x0);
+       t16RegWrite(dev, 0x00, 0x3880, 0x00, 0x0);
+       t16RegWrite(dev, 0x00, 0x338e, 0x00, 0x0);
+       t16RegWrite(dev, 0x01, 00, nset5, 0x04);
+       t16RegWrite(dev, 0x00, 0x00a9, 0x00, 0x0);
+       t16RegWrite(dev, 0x01, 00, nset6, 0x22);
+       t16RegWrite(dev, 0x00, 0x86bb, 0x00, 0x0);
+       t16RegWrite(dev, 0x00, 0x4aa6, 0x00, 0x0);
+
+       t16RegWrite(dev, 0x01, 00, missing, 0x08);
+
+       t16RegWrite(dev, 0x00, 0x2087, 0x00, 0x0);
+       t16RegWrite(dev, 0x00, 0x2088, 0x00, 0x0);
+       t16RegWrite(dev, 0x00, 0x2089, 0x00, 0x0);
+
+       t16RegWrite(dev, 0x01, 00, nset7, 0x4);
+       t16RegWrite(dev, 0x01, 00, nset10, 0x06);
+       t16RegWrite(dev, 0x01, 00, nset8, 0x06);
+       t16RegWrite(dev, 0x01, 00, nset9, 0x04);
+
+       t16RegWrite(dev, 0x00, 0x2880, 0x00, 0x0);
+       t16RegWrite(dev, 0x01, 0x0000, nset2, 0x14);
+       t16RegWrite(dev, 0x01, 0x0000, nset3, 0x12);
+       t16RegWrite(dev, 0x01, 0x0000, nset4, 0x12);
+
+       return 0;
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct usb_device *dev = gspca_dev->dev;
+       unsigned int brightness;
+       unsigned char set6[4] = { 0x8f, 0x26, 0xc3, 0x80 };
+       brightness = sd->brightness;
+
+       if (brightness < 7) {
+               set6[3] = 0x70 - (brightness * 0xa);
+       } else {
+               set6[1] = 0x24;
+               set6[3] = 0x00 + ((brightness - 7) * 0xa);
+       }
+
+       t16RegWrite(dev, 0x01, 0x0000, set6, 4);
+}
+
+static void setflip(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct usb_device *dev = gspca_dev->dev;
+
+       unsigned char flipcmd[8] =
+           { 0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09 };
+
+       if (sd->mirror == 1)
+               flipcmd[3] = 0x01;
+
+       t16RegWrite(dev, 0x01, 0x0000, flipcmd, 8);
+}
+
+static void seteffect(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct usb_device *dev = gspca_dev->dev;
+
+       t16RegWrite(dev, 0x01, 0x0000, effects_table[sd->effect], 0x06);
+       if (sd->effect == 1 || sd->effect == 5) {
+               PDEBUG(D_CONF,
+                      "This effect have been disabled for webcam \"safety\"");
+               return;
+       }
+
+       if (sd->effect == 1 || sd->effect == 4)
+               t16RegWrite(dev, 0x00, 0x4aa6, 0x00, 0x00);
+       else
+               t16RegWrite(dev, 0x00, 0xfaa6, 0x00, 0x00);
+}
+
+static void setwhitebalance(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct usb_device *dev = gspca_dev->dev;
+
+       unsigned char white_balance[8] =
+           { 0x87, 0x20, 0x88, 0x20, 0x89, 0x20, 0x80, 0x38 };
+
+       if (sd->whitebalance == 1)
+               white_balance[7] = 0x3c;
+
+       t16RegWrite(dev, 0x01, 0x0000, white_balance, 8);
+}
+
+static void setlightfreq(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct usb_device *dev = gspca_dev->dev;
+       __u8 freq[4] = { 0x66, 0x40, 0xa8, 0xe8 };
+
+       if (sd->freq == 2)      /* 60hz */
+               freq[1] = 0x00;
+
+       t16RegWrite(dev, 0x1, 0x0000, freq, 0x4);
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct usb_device *dev = gspca_dev->dev;
+       unsigned int contrast = sd->contrast;
+       __u16 reg_to_write = 0x00;
+
+       if (contrast < 7)
+               reg_to_write = 0x8ea9 - (0x200 * contrast);
+       else
+               reg_to_write = (0x00a9 + ((contrast - 7) * 0x200));
+
+       t16RegWrite(dev, 0x00, reg_to_write, 0x00, 0);
+
+}
+
+static void setcolors(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct usb_device *dev = gspca_dev->dev;
+       __u16 reg_to_write = 0x00;
+
+       reg_to_write = 0xc0bb + sd->colors * 0x100;
+       t16RegWrite(dev, 0x00, reg_to_write, 0x00, 0);
+}
+
+static void setgamma(struct gspca_dev *gspca_dev)
+{
+}
+
+static void setsharpness(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct usb_device *dev = gspca_dev->dev;
+       __u16 reg_to_write = 0x00;
+
+       reg_to_write = 0x0aa6 + 0x1000 * sd->sharpness;
+
+       t16RegWrite(dev, 0x00, reg_to_write, 0x00, 0x00);
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->brightness = val;
+       if (gspca_dev->streaming)
+               setbrightness(gspca_dev);
+       return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       *val = sd->brightness;
+       return *val;
+}
+
+static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->whitebalance = val;
+       if (gspca_dev->streaming)
+               setwhitebalance(gspca_dev);
+       return 0;
+}
+
+static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->whitebalance;
+       return *val;
+}
+
+
+static int sd_setflip(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->mirror = val;
+       if (gspca_dev->streaming)
+               setflip(gspca_dev);
+       return 0;
+}
+
+static int sd_getflip(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->mirror;
+       return *val;
+}
+
+static int sd_seteffect(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->effect = val;
+       if (gspca_dev->streaming)
+               seteffect(gspca_dev);
+       return 0;
+}
+
+static int sd_geteffect(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->effect;
+       return *val;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->contrast = val;
+       if (gspca_dev->streaming)
+               setcontrast(gspca_dev);
+       return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->contrast;
+       return *val;
+}
+
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->colors = val;
+       if (gspca_dev->streaming)
+               setcolors(gspca_dev);
+       return 0;
+}
+
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->colors;
+       return 0;
+}
+
+static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->gamma = val;
+       if (gspca_dev->streaming)
+               setgamma(gspca_dev);
+       return 0;
+}
+
+static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       *val = sd->gamma;
+       return 0;
+}
+
+static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->freq = val;
+       if (gspca_dev->streaming)
+               setlightfreq(gspca_dev);
+       return 0;
+}
+
+static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->freq;
+       return 0;
+}
+
+static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->sharpness = val;
+       if (gspca_dev->streaming)
+               setsharpness(gspca_dev);
+       return 0;
+}
+
+static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->sharpness;
+       return 0;
+}
+
+/* Low Light set  here......*/
+static int sd_setlowlight(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct usb_device *dev = gspca_dev->dev;
+
+       sd->autogain = val;
+       if (val != 0)
+               t16RegWrite(dev, 0x00, 0xf48e, 0x00, 0);
+       else
+               t16RegWrite(dev, 0x00, 0xb48e, 0x00, 0);
+       return 0;
+}
+
+static int sd_getlowlight(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->autogain;
+       return 0;
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+       struct usb_device *dev = gspca_dev->dev;
+       int mode;
+       __u8 test_byte;
+
+       static __u8 t1[] = { 0x66, 0x00, 0xa8, 0xe8 };
+       __u8 t2[] = { 0x07, 0x00, 0x0d, 0x60, 0x0e, 0x80 };
+       static __u8 t3[] =
+               { 0xb3, 0x07, 0xb4, 0x00, 0xb5, 0x88, 0xb6, 0x02, 0xb7, 0x06,
+                 0xb8, 0x00, 0xb9, 0xe7, 0xba, 0x01 };
+       static __u8 t4[] = { 0x0b, 0x04, 0x0a, 0x40 };
+
+       mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode]. mode;
+       switch (mode) {
+       case 1:         /* 352x288 */
+               t2[1] = 0x40;
+               break;
+       case 2:         /* 320x240 */
+               t2[1] = 0x10;
+               break;
+       case 3:         /* 176x144 */
+               t2[1] = 0x50;
+               break;
+       case 4:         /* 160x120 */
+               t2[1] = 0x20;
+               break;
+       default:        /* 640x480 (0x00) */
+               break;
+       }
+
+       t16RegWrite(dev, 0x01, 0x0000, tas5130a_sensor_init[0], 0x8);
+       t16RegWrite(dev, 0x01, 0x0000, tas5130a_sensor_init[1], 0x8);
+       t16RegWrite(dev, 0x01, 0x0000, tas5130a_sensor_init[2], 0x8);
+       t16RegWrite(dev, 0x01, 0x0000, tas5130a_sensor_init[3], 0x8);
+       t16RegWrite(dev, 0x00, 0x3c80, 0x00, 0x00);
+               /* just in case and to keep sync with logs  (for mine) */
+       t16RegWrite(dev, 0x01, 0x0000, tas5130a_sensor_init[3], 0x8);
+       t16RegWrite(dev, 0x00, 0x3c80, 0x00, 0x00);
+               /* just in case and to keep sync with logs  (for mine) */
+       t16RegWrite(dev, 0x01, 0x0000, t1, 4);
+       t16RegWrite(dev, 0x01, 0x0000, t2, 6);
+       t16RegRead(dev, 0x0012, &test_byte, 0x1);
+       t16RegWrite(dev, 0x01, 0x0000, t3, 0x10);
+       t16RegWrite(dev, 0x00, 0x0013, 0x00, 0x00);
+       t16RegWrite(dev, 0x01, 0x0000, t4, 0x4);
+       /* restart on each start, just in case, sometimes regs goes wrong
+        * when using controls from app */
+       setbrightness(gspca_dev);
+       setcontrast(gspca_dev);
+       setcolors(gspca_dev);
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+                       struct gspca_frame *frame,      /* target */
+                       unsigned char *data,            /* isoc packet */
+                       int len)                        /* iso packet length */
+{
+       int sof = 0;
+       static unsigned char ffd9[] = { 0xff, 0xd9 };
+
+       if (data[0] == 0x5a) {
+               /* Control Packet, after this came the header again,
+                * but extra bytes came in the packet before this,
+                * sometimes an EOF arrives, sometimes not... */
+               return;
+       }
+
+       if (data[len - 1] == 0xff && data[len] == 0xd9) {
+               /* Just in case, i have seen packets with the marker,
+                * other's do not include it... */
+               data += 2;
+               len -= 4;
+       } else if (data[2] == 0xff && data[3] == 0xd8) {
+               sof = 1;
+               data += 2;
+               len -= 2;
+       } else {
+               data += 2;
+               len -= 2;
+       }
+
+       if (sof) {
+               /* extra bytes....., could be processed too but would be
+                * a waste of time, right now leave the application and
+                * libjpeg do it for ourserlves.. */
+               frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+                                       ffd9, 2);
+               gspca_frame_add(gspca_dev, FIRST_PACKET, frame, data, len);
+               return;
+       }
+
+       gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+}
+
+static int sd_querymenu(struct gspca_dev *gspca_dev,
+                       struct v4l2_querymenu *menu)
+{
+       memset(menu->name, 0, sizeof menu->name);
+
+       switch (menu->id) {
+       case V4L2_CID_POWER_LINE_FREQUENCY:
+               switch (menu->index) {
+               case 1:         /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
+                       strcpy(menu->name, "50 Hz");
+                       return 0;
+               case 2:         /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
+                       strcpy(menu->name, "60 Hz");
+                       return 0;
+               }
+               break;
+       case V4L2_CID_EFFECTS:
+               if (menu->index < 0 || menu->index >= NUM_EFFECTS_CONTROL)
+                       return -EINVAL;
+               strncpy((char *) menu->name,
+                       effects_control[menu->index].name, 32);
+               break;
+       }
+       return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+       init_default_parameters(gspca_dev);
+       return 0;
+}
+
+/* sub-driver description */
+static struct sd_desc sd_desc = {
+       .name = MODULE_NAME,
+       .ctrls = sd_ctrls,
+       .nctrls = ARRAY_SIZE(sd_ctrls),
+       .config = sd_config,
+       .open = sd_open,
+       .start = sd_start,
+       .stopN = sd_stopN,
+       .stop0 = sd_stop0,
+       .close = sd_close,
+       .pkt_scan = sd_pkt_scan,
+       .querymenu = sd_querymenu,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static __devinitdata struct usb_device_id device_table[] = {
+       {USB_DEVICE(0x17a1, 0x0128), DVNM("XPX Webcam")},
+       {}
+};
+
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+                   const struct usb_device_id *id)
+{
+       return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+                              THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+       .name = MODULE_NAME,
+       .id_table = device_table,
+       .probe = sd_probe,
+       .disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+       if (usb_register(&sd_driver) < 0)
+               return -1;
+       PDEBUG(D_PROBE, "v%s registered", version);
+       return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+       usb_deregister(&sd_driver);
+       PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/tv8532.c b/drivers/media/video/gspca/tv8532.c
new file mode 100644 (file)
index 0000000..6218441
--- /dev/null
@@ -0,0 +1,709 @@
+/*
+ * Quickcam cameras initialization data
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#define MODULE_NAME "tv8532"
+
+#include "gspca.h"
+
+#define DRIVER_VERSION_NUMBER  KERNEL_VERSION(2, 1, 0)
+static const char version[] = "2.1.0";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("TV8532 USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+       struct gspca_dev gspca_dev;     /* !! must be the first item */
+
+       int buflen;                     /* current length of tmpbuf */
+       __u8 tmpbuf[352 * 288 + 10 * 288];      /* no protection... */
+       __u8 tmpbuf2[352 * 288];                /* no protection... */
+
+       unsigned short brightness;
+       unsigned short contrast;
+
+       char packet;
+       char synchro;
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+#define SD_BRIGHTNESS 0
+       {
+        {
+         .id = V4L2_CID_BRIGHTNESS,
+         .type = V4L2_CTRL_TYPE_INTEGER,
+         .name = "Brightness",
+         .minimum = 1,
+         .maximum = 0x2ff,
+         .step = 1,
+         .default_value = 0x18f,
+         },
+        .set = sd_setbrightness,
+        .get = sd_getbrightness,
+        },
+#define SD_CONTRAST 1
+       {
+        {
+         .id = V4L2_CID_CONTRAST,
+         .type = V4L2_CTRL_TYPE_INTEGER,
+         .name = "Contrast",
+         .minimum = 0,
+         .maximum = 0xffff,
+         .step = 1,
+         .default_value = 0x7fff,
+         },
+        .set = sd_setcontrast,
+        .get = sd_getcontrast,
+        },
+};
+
+static struct cam_mode sif_mode[] = {
+       {V4L2_PIX_FMT_SBGGR8, 176, 144, 1},
+       {V4L2_PIX_FMT_SBGGR8, 352, 288, 0},
+};
+
+/*
+ * Initialization data: this is the first set-up data written to the
+ * device (before the open data).
+ */
+#define TESTCLK 0x10           /* reg 0x2c -> 0x12 //10 */
+#define TESTCOMP 0x90          /* reg 0x28 -> 0x80 */
+#define TESTLINE 0x81          /* reg 0x29 -> 0x81 */
+#define QCIFLINE 0x41          /* reg 0x29 -> 0x81 */
+#define TESTPTL 0x14           /* reg 0x2D -> 0x14 */
+#define TESTPTH 0x01           /* reg 0x2E -> 0x01 */
+#define TESTPTBL 0x12          /* reg 0x2F -> 0x0a */
+#define TESTPTBH 0x01          /* reg 0x30 -> 0x01 */
+#define ADWIDTHL 0xe8          /* reg 0x0c -> 0xe8 */
+#define ADWIDTHH 0x03          /* reg 0x0d -> 0x03 */
+#define ADHEIGHL 0x90          /* reg 0x0e -> 0x91 //93 */
+#define ADHEIGHH 0x01          /* reg 0x0f -> 0x01 */
+#define EXPOL 0x8f             /* reg 0x1c -> 0x8f */
+#define EXPOH 0x01             /* reg 0x1d -> 0x01 */
+#define ADCBEGINL 0x44         /* reg 0x10 -> 0x46 //47 */
+#define ADCBEGINH 0x00         /* reg 0x11 -> 0x00 */
+#define ADRBEGINL 0x0a         /* reg 0x14 -> 0x0b //0x0c */
+#define ADRBEGINH 0x00         /* reg 0x15 -> 0x00 */
+#define TV8532_CMD_UPDATE 0x84
+
+#define TV8532_EEprom_Add 0x03
+#define TV8532_EEprom_DataL 0x04
+#define TV8532_EEprom_DataM 0x05
+#define TV8532_EEprom_DataH 0x06
+#define TV8532_EEprom_TableLength 0x07
+#define TV8532_EEprom_Write 0x08
+#define TV8532_PART_CTRL 0x00
+#define TV8532_CTRL 0x01
+#define TV8532_CMD_EEprom_Open 0x30
+#define TV8532_CMD_EEprom_Close 0x29
+#define TV8532_UDP_UPDATE 0x31
+#define TV8532_GPIO 0x39
+#define TV8532_GPIO_OE 0x3B
+#define TV8532_REQ_RegWrite 0x02
+#define TV8532_REQ_RegRead 0x03
+
+#define TV8532_ADWIDTH_L 0x0C
+#define TV8532_ADWIDTH_H 0x0D
+#define TV8532_ADHEIGHT_L 0x0E
+#define TV8532_ADHEIGHT_H 0x0F
+#define TV8532_EXPOSURE 0x1C
+#define TV8532_QUANT_COMP 0x28
+#define TV8532_MODE_PACKET 0x29
+#define TV8532_SETCLK 0x2C
+#define TV8532_POINT_L 0x2D
+#define TV8532_POINT_H 0x2E
+#define TV8532_POINTB_L 0x2F
+#define TV8532_POINTB_H 0x30
+#define TV8532_BUDGET_L 0x2A
+#define TV8532_BUDGET_H 0x2B
+#define TV8532_VID_L 0x34
+#define TV8532_VID_H 0x35
+#define TV8532_PID_L 0x36
+#define TV8532_PID_H 0x37
+#define TV8532_DeviceID 0x83
+#define TV8532_AD_SLOPE 0x91
+#define TV8532_AD_BITCTRL 0x94
+#define TV8532_AD_COLBEGIN_L 0x10
+#define TV8532_AD_COLBEGIN_H 0x11
+#define TV8532_AD_ROWBEGIN_L 0x14
+#define TV8532_AD_ROWBEGIN_H 0x15
+
+static __u32 tv_8532_eeprom_data[] = {
+/*     add             dataL      dataM        dataH */
+       0x00010001, 0x01018011, 0x02050014, 0x0305001c,
+       0x040d001e, 0x0505001f, 0x06050519, 0x0705011b,
+       0x0805091e, 0x090d892e, 0x0a05892f, 0x0b050dd9,
+       0x0c0509f1, 0
+};
+
+static void reg_r(struct usb_device *dev,
+                 __u16 index, __u8 *buffer)
+{
+       usb_control_msg(dev,
+                       usb_rcvctrlpipe(dev, 0),
+                       TV8532_REQ_RegRead,
+                       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       0,      /* value */
+                       index, buffer, sizeof(__u8),
+                       500);
+}
+
+static void reg_w(struct usb_device *dev,
+                 __u16 index, __u8 *buffer, __u16 length)
+{
+       usb_control_msg(dev,
+                       usb_sndctrlpipe(dev, 0),
+                       TV8532_REQ_RegWrite,
+                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       0,      /* value */
+                       index, buffer, length, 500);
+}
+
+static void tv_8532WriteEEprom(struct gspca_dev *gspca_dev)
+{
+       int i = 0;
+       __u8 reg, data0, data1, data2, datacmd;
+       struct usb_device *dev = gspca_dev->dev;
+
+       datacmd = 0xb0;;
+       reg_w(dev, TV8532_GPIO, &datacmd, 1);
+       datacmd = TV8532_CMD_EEprom_Open;
+       reg_w(dev, TV8532_CTRL, &datacmd,
+                       1);
+/*     msleep(1); */
+       while (tv_8532_eeprom_data[i]) {
+               reg = (tv_8532_eeprom_data[i] & 0xff000000) >> 24;
+               reg_w(dev, TV8532_EEprom_Add, &reg, 1);
+               /* msleep(1); */
+               data0 = (tv_8532_eeprom_data[i] & 0x000000ff);
+               reg_w(dev, TV8532_EEprom_DataL, &data0, 1);
+               /* msleep(1); */
+               data1 = (tv_8532_eeprom_data[i] & 0x0000FF00) >> 8;
+               reg_w(dev, TV8532_EEprom_DataM, &data1, 1);
+               /* msleep(1); */
+               data2 = (tv_8532_eeprom_data[i] & 0x00FF0000) >> 16;
+               reg_w(dev, TV8532_EEprom_DataH, &data2, 1);
+               /* msleep(1); */
+               datacmd = 0;
+               reg_w(dev, TV8532_EEprom_Write, &datacmd, 1);
+               /* msleep(10); */
+               i++;
+       }
+       datacmd = i;
+       reg_w(dev, TV8532_EEprom_TableLength, &datacmd, 1);
+/*     msleep(1); */
+       datacmd = TV8532_CMD_EEprom_Close;
+       reg_w(dev, TV8532_CTRL, &datacmd, 1);
+       msleep(10);
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+                    const struct usb_device_id *id)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct cam *cam;
+
+       tv_8532WriteEEprom(gspca_dev);
+
+       cam = &gspca_dev->cam;
+       cam->dev_name = (char *) id->driver_info;
+       cam->epaddr = 1;
+       cam->cam_mode = sif_mode;
+       cam->nmodes = sizeof sif_mode / sizeof sif_mode[0];
+
+       sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
+       sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
+       return 0;
+}
+
+static void tv_8532ReadRegisters(struct gspca_dev *gspca_dev)
+{
+       struct usb_device *dev = gspca_dev->dev;
+       __u8 data = 0;
+/*     __u16 vid, pid; */
+
+       reg_r(dev, 0x0001, &data);
+       PDEBUG(D_USBI, "register 0x01-> %x", data);
+       reg_r(dev, 0x0002, &data);
+       PDEBUG(D_USBI, "register 0x02-> %x", data);
+       reg_r(dev, TV8532_ADWIDTH_L, &data);
+       reg_r(dev, TV8532_ADWIDTH_H, &data);
+       reg_r(dev, TV8532_QUANT_COMP, &data);
+       reg_r(dev, TV8532_MODE_PACKET, &data);
+       reg_r(dev, TV8532_SETCLK, &data);
+       reg_r(dev, TV8532_POINT_L, &data);
+       reg_r(dev, TV8532_POINT_H, &data);
+       reg_r(dev, TV8532_POINTB_L, &data);
+       reg_r(dev, TV8532_POINTB_H, &data);
+       reg_r(dev, TV8532_BUDGET_L, &data);
+       reg_r(dev, TV8532_BUDGET_H, &data);
+       reg_r(dev, TV8532_VID_L, &data);
+       reg_r(dev, TV8532_VID_H, &data);
+       reg_r(dev, TV8532_PID_L, &data);
+       reg_r(dev, TV8532_PID_H, &data);
+       reg_r(dev, TV8532_DeviceID, &data);
+       reg_r(dev, TV8532_AD_COLBEGIN_L, &data);
+       reg_r(dev, TV8532_AD_COLBEGIN_H, &data);
+       reg_r(dev, TV8532_AD_ROWBEGIN_L, &data);
+       reg_r(dev, TV8532_AD_ROWBEGIN_H, &data);
+}
+
+static void tv_8532_setReg(struct gspca_dev *gspca_dev)
+{
+       struct usb_device *dev = gspca_dev->dev;
+       __u8 data = 0;
+       __u8 value[2] = { 0, 0 };
+
+       data = ADCBEGINL;
+       reg_w(dev, TV8532_AD_COLBEGIN_L, &data, 1);     /* 0x10 */
+       data = ADCBEGINH;       /* also digital gain */
+       reg_w(dev, TV8532_AD_COLBEGIN_H, &data, 1);
+       data = TV8532_CMD_UPDATE;
+       reg_w(dev, TV8532_PART_CTRL, &data, 1); /* 0x00<-0x84 */
+
+       data = 0x0a;
+       reg_w(dev, TV8532_GPIO_OE, &data, 1);
+       /******************************************************/
+       data = ADHEIGHL;
+       reg_w(dev, TV8532_ADHEIGHT_L, &data, 1);        /* 0e */
+       data = ADHEIGHH;
+       reg_w(dev, TV8532_ADHEIGHT_H, &data, 1);        /* 0f */
+       value[0] = EXPOL;
+       value[1] = EXPOH;       /* 350d 0x014c; */
+       reg_w(dev, TV8532_EXPOSURE, value, 2);  /* 1c */
+       data = ADCBEGINL;
+       reg_w(dev, TV8532_AD_COLBEGIN_L, &data, 1);     /* 0x10 */
+       data = ADCBEGINH;       /* also digital gain */
+       reg_w(dev, TV8532_AD_COLBEGIN_H, &data, 1);
+       data = ADRBEGINL;
+       reg_w(dev, TV8532_AD_ROWBEGIN_L, &data, 1);     /* 0x14 */
+
+       data = 0x00;
+       reg_w(dev, TV8532_AD_SLOPE, &data, 1);  /* 0x91 */
+       data = 0x02;
+       reg_w(dev, TV8532_AD_BITCTRL, &data, 1);        /* 0x94 */
+
+
+       data = TV8532_CMD_EEprom_Close;
+       reg_w(dev, TV8532_CTRL, &data, 1);      /* 0x01 */
+
+       data = 0x00;
+       reg_w(dev, TV8532_AD_SLOPE, &data, 1);  /* 0x91 */
+       data = TV8532_CMD_UPDATE;
+       reg_w(dev, TV8532_PART_CTRL, &data, 1); /* 0x00<-0x84 */
+}
+
+static void tv_8532_PollReg(struct gspca_dev *gspca_dev)
+{
+       struct usb_device *dev = gspca_dev->dev;
+       __u8 data = 0;
+       int i;
+
+       /* strange polling from tgc */
+       for (i = 0; i < 10; i++) {
+               data = TESTCLK; /* 0x48; //0x08; */
+               reg_w(dev, TV8532_SETCLK, &data, 1);    /* 0x2c */
+               data = TV8532_CMD_UPDATE;
+               reg_w(dev, TV8532_PART_CTRL, &data, 1);
+               data = 0x01;
+               reg_w(dev, TV8532_UDP_UPDATE, &data, 1);        /* 0x31 */
+       }
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+       struct usb_device *dev = gspca_dev->dev;
+       __u8 data = 0;
+       __u8 dataStart = 0;
+       __u8 value[2] = { 0, 0 };
+
+       data = 0x32;
+       reg_w(dev, TV8532_AD_SLOPE, &data, 1);
+       data = 0;
+       reg_w(dev, TV8532_AD_BITCTRL, &data, 1);
+       tv_8532ReadRegisters(gspca_dev);
+       data = 0x0b;
+       reg_w(dev, TV8532_GPIO_OE, &data, 1);
+       value[0] = ADHEIGHL;
+       value[1] = ADHEIGHH;    /* 401d 0x0169; */
+       reg_w(dev, TV8532_ADHEIGHT_L, value, 2);        /* 0e */
+       value[0] = EXPOL;
+       value[1] = EXPOH;       /* 350d 0x014c; */
+       reg_w(dev, TV8532_EXPOSURE, value, 2);  /* 1c */
+       data = ADWIDTHL;        /* 0x20; */
+       reg_w(dev, TV8532_ADWIDTH_L, &data, 1); /* 0x0c */
+       data = ADWIDTHH;
+       reg_w(dev, TV8532_ADWIDTH_H, &data, 1); /* 0x0d */
+
+       /*******************************************************************/
+       data = TESTCOMP;        /* 0x72 compressed mode */
+       reg_w(dev, TV8532_QUANT_COMP, &data, 1);        /* 0x28 */
+       data = TESTLINE;        /* 0x84; // CIF | 4 packet */
+       reg_w(dev, TV8532_MODE_PACKET, &data, 1);       /* 0x29 */
+
+       /************************************************/
+       data = TESTCLK;         /* 0x48; //0x08; */
+       reg_w(dev, TV8532_SETCLK, &data, 1);    /* 0x2c */
+       data = TESTPTL;         /* 0x38; */
+       reg_w(dev, TV8532_POINT_L, &data, 1);   /* 0x2d */
+       data = TESTPTH;         /* 0x04; */
+       reg_w(dev, TV8532_POINT_H, &data, 1);   /* 0x2e */
+       dataStart = TESTPTBL;   /* 0x04; */
+       reg_w(dev, TV8532_POINTB_L, &dataStart, 1);     /* 0x2f */
+       data = TESTPTBH;        /* 0x04; */
+       reg_w(dev, TV8532_POINTB_H, &data, 1);  /* 0x30 */
+       data = TV8532_CMD_UPDATE;
+       reg_w(dev, TV8532_PART_CTRL, &data, 1); /* 0x00<-0x84 */
+       /*************************************************/
+       data = 0x01;
+       reg_w(dev, TV8532_UDP_UPDATE, &data, 1);        /* 0x31 */
+       msleep(200);
+       data = 0x00;
+       reg_w(dev, TV8532_UDP_UPDATE, &data, 1);        /* 0x31 */
+       /*************************************************/
+       tv_8532_setReg(gspca_dev);
+       /*************************************************/
+       data = 0x0b;
+       reg_w(dev, TV8532_GPIO_OE, &data,
+                       1);
+       /*************************************************/
+       tv_8532_setReg(gspca_dev);
+       /*************************************************/
+       tv_8532_PollReg(gspca_dev);
+       return 0;
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       __u8 value[2];
+       __u8 data;
+       int brightness = sd->brightness;
+
+       value[1] = (brightness >> 8) & 0xff;
+       value[0] = (brightness) & 0xff;
+       reg_w(gspca_dev->dev, TV8532_EXPOSURE, value, 2);       /* 1c */
+       data = TV8532_CMD_UPDATE;
+       reg_w(gspca_dev->dev, TV8532_PART_CTRL, &data, 1);
+}
+
+/* -- start the camera -- */
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+       struct usb_device *dev = gspca_dev->dev;
+       __u8 data = 0;
+       __u8 dataStart = 0;
+       __u8 value[2];
+
+       data = 0x32;
+       reg_w(dev, TV8532_AD_SLOPE, &data, 1);
+       data = 0;
+       reg_w(dev, TV8532_AD_BITCTRL, &data, 1);
+       tv_8532ReadRegisters(gspca_dev);
+       data = 0x0b;
+       reg_w(dev, TV8532_GPIO_OE, &data, 1);
+       value[0] = ADHEIGHL;
+       value[1] = ADHEIGHH;    /* 401d 0x0169; */
+       reg_w(dev, TV8532_ADHEIGHT_L, value, 2);        /* 0e */
+/*     value[0] = EXPOL; value[1] =EXPOH;               * 350d 0x014c; */
+/*     reg_w(dev,TV8532_REQ_RegWrite,0,TV8532_EXPOSURE,value,2);  * 1c */
+       setbrightness(gspca_dev);
+
+       data = ADWIDTHL;        /* 0x20; */
+       reg_w(dev, TV8532_ADWIDTH_L, &data, 1); /* 0x0c */
+       data = ADWIDTHH;
+       reg_w(dev, TV8532_ADWIDTH_H, &data, 1); /* 0x0d */
+
+       /************************************************/
+       data = TESTCOMP;        /* 0x72 compressed mode */
+       reg_w(dev, TV8532_QUANT_COMP, &data, 1);        /* 0x28 */
+       if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].mode) {
+               /* 176x144 */
+               data = QCIFLINE;        /* 0x84; // CIF | 4 packet */
+               reg_w(dev, TV8532_MODE_PACKET, &data, 1);       /* 0x29 */
+       } else {
+               /* 352x288 */
+               data = TESTLINE;        /* 0x84; // CIF | 4 packet */
+               reg_w(dev, TV8532_MODE_PACKET, &data, 1);       /* 0x29 */
+       }
+       /************************************************/
+       data = TESTCLK;         /* 0x48; //0x08; */
+       reg_w(dev, TV8532_SETCLK, &data, 1);    /* 0x2c */
+       data = TESTPTL;         /* 0x38; */
+       reg_w(dev, TV8532_POINT_L, &data, 1);   /* 0x2d */
+       data = TESTPTH;         /* 0x04; */
+       reg_w(dev, TV8532_POINT_H, &data, 1);   /* 0x2e */
+       dataStart = TESTPTBL;   /* 0x04; */
+       reg_w(dev, TV8532_POINTB_L, &dataStart, 1);     /* 0x2f */
+       data = TESTPTBH;        /* 0x04; */
+       reg_w(dev, TV8532_POINTB_H, &data, 1);  /* 0x30 */
+       data = TV8532_CMD_UPDATE;
+       reg_w(dev, TV8532_PART_CTRL, &data, 1); /* 0x00<-0x84 */
+       /************************************************/
+       data = 0x01;
+       reg_w(dev, TV8532_UDP_UPDATE, &data, 1);        /* 0x31 */
+       msleep(200);
+       data = 0x00;
+       reg_w(dev, TV8532_UDP_UPDATE, &data, 1);        /* 0x31 */
+       /************************************************/
+       tv_8532_setReg(gspca_dev);
+       /************************************************/
+       data = 0x0b;
+       reg_w(dev, TV8532_GPIO_OE, &data, 1);
+       /************************************************/
+       tv_8532_setReg(gspca_dev);
+       /************************************************/
+       tv_8532_PollReg(gspca_dev);
+       data = 0x00;
+       reg_w(dev, TV8532_UDP_UPDATE, &data, 1);        /* 0x31 */
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+       struct usb_device *dev = gspca_dev->dev;
+       __u8 data;
+
+       data = 0x0b;
+       reg_w(dev, TV8532_GPIO_OE, &data, 1);
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+static void tv8532_preprocess(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+/* we should received a whole frame with header and EOL marker
+ * in gspca_dev->tmpbuf and return a GBRG pattern in gspca_dev->tmpbuf2
+ * sequence 2bytes header the Alternate pixels bayer GB 4 bytes
+ * Alternate pixels bayer RG 4 bytes EOL */
+       int width = gspca_dev->width;
+       int height = gspca_dev->height;
+       unsigned char *dst = sd->tmpbuf2;
+       unsigned char *data = sd->tmpbuf;
+       int i;
+
+       /* precompute where is the good bayer line */
+       if (((data[3] + data[width + 7]) >> 1)
+           + (data[4] >> 2)
+           + (data[width + 6] >> 1) >= ((data[2] + data[width + 6]) >> 1)
+           + (data[3] >> 2)
+           + (data[width + 5] >> 1))
+               data += 3;
+       else
+               data += 2;
+       for (i = 0; i < height / 2; i++) {
+               memcpy(dst, data, width);
+               data += width + 3;
+               dst += width;
+               memcpy(dst, data, width);
+               data += width + 7;
+               dst += width;
+       }
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+                       struct gspca_frame *frame,      /* target */
+                       __u8 *data,                     /* isoc packet */
+                       int len)                        /* iso packet length */
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       if (data[0] != 0x80) {
+               sd->packet++;
+               if (sd->buflen + len > sizeof sd->tmpbuf) {
+                       if (gspca_dev->last_packet_type != DISCARD_PACKET) {
+                               PDEBUG(D_PACK, "buffer overflow");
+                               gspca_dev->last_packet_type = DISCARD_PACKET;
+                       }
+                       return;
+               }
+               memcpy(&sd->tmpbuf[sd->buflen], data, len);
+               sd->buflen += len;
+               return;
+       }
+
+       /* here we detect 0x80 */
+       /* counter is limited so we need few header for a frame :) */
+
+       /* header 0x80 0x80 0x80 0x80 0x80 */
+       /* packet  00   63  127  145  00   */
+       /* sof     0     1   1    0    0   */
+
+       /* update sequence */
+       if (sd->packet == 63 || sd->packet == 127)
+               sd->synchro = 1;
+
+       /* is there a frame start ? */
+       if (sd->packet >= (gspca_dev->height >> 1) - 1) {
+               PDEBUG(D_PACK, "SOF > %d packet %d", sd->synchro,
+                      sd->packet);
+               if (!sd->synchro) {     /* start of frame */
+                       if (gspca_dev->last_packet_type == FIRST_PACKET) {
+                               tv8532_preprocess(gspca_dev);
+                               frame = gspca_frame_add(gspca_dev,
+                                                       LAST_PACKET,
+                                                       frame, sd->tmpbuf2,
+                                                       gspca_dev->width *
+                                                           gspca_dev->width);
+                       }
+                       gspca_frame_add(gspca_dev, FIRST_PACKET,
+                                       frame, data, 0);
+                       memcpy(sd->tmpbuf, data, len);
+                       sd->buflen = len;
+                       sd->packet = 0;
+                       return;
+               }
+               if (gspca_dev->last_packet_type != DISCARD_PACKET) {
+                       PDEBUG(D_PACK,
+                              "Warning wrong TV8532 frame detection %d",
+                              sd->packet);
+                       gspca_dev->last_packet_type = DISCARD_PACKET;
+               }
+               return;
+       }
+
+       if (!sd->synchro) {
+               /* Drop packet frame corrupt */
+               PDEBUG(D_PACK, "DROP SOF %d packet %d",
+                      sd->synchro, sd->packet);
+               sd->packet = 0;
+               gspca_dev->last_packet_type = DISCARD_PACKET;
+               return;
+       }
+       sd->synchro = 1;
+       sd->packet++;
+       memcpy(&sd->tmpbuf[sd->buflen], data, len);
+       sd->buflen += len;
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->brightness = val;
+       if (gspca_dev->streaming)
+               setbrightness(gspca_dev);
+       return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->brightness;
+       return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->contrast = val;
+       if (gspca_dev->streaming)
+               setcontrast(gspca_dev);
+       return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->contrast;
+       return 0;
+}
+
+/* sub-driver description */
+static struct sd_desc sd_desc = {
+       .name = MODULE_NAME,
+       .ctrls = sd_ctrls,
+       .nctrls = ARRAY_SIZE(sd_ctrls),
+       .config = sd_config,
+       .open = sd_open,
+       .start = sd_start,
+       .stopN = sd_stopN,
+       .stop0 = sd_stop0,
+       .close = sd_close,
+       .pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static __devinitdata struct usb_device_id device_table[] = {
+       {USB_DEVICE(0x046d, 0x0920), DVNM("QC Express")},
+       {USB_DEVICE(0x046d, 0x0921), DVNM("Labtec Webcam")},
+       {USB_DEVICE(0x0545, 0x808b), DVNM("Veo Stingray")},
+       {USB_DEVICE(0x0545, 0x8333), DVNM("Veo Stingray")},
+       {USB_DEVICE(0x0923, 0x010f), DVNM("ICM532 cams")},
+       {}
+};
+
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+                   const struct usb_device_id *id)
+{
+       return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+                              THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+       .name = MODULE_NAME,
+       .id_table = device_table,
+       .probe = sd_probe,
+       .disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+       if (usb_register(&sd_driver) < 0)
+               return -1;
+       PDEBUG(D_PROBE, "v%s registered", version);
+       return 0;
+}
+
+static void __exit sd_mod_exit(void)
+{
+       usb_deregister(&sd_driver);
+       PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/vc032x.c b/drivers/media/video/gspca/vc032x.c
new file mode 100644 (file)
index 0000000..8b5f6d1
--- /dev/null
@@ -0,0 +1,1816 @@
+/*
+ *             Z-star vc0321 library
+ *             Copyright (C) 2006 Koninski Artur takeshi87@o2.pl
+ *             Copyright (C) 2006 Michel Xhaard
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define MODULE_NAME "vc032x"
+
+#include "gspca.h"
+
+#define DRIVER_VERSION_NUMBER  KERNEL_VERSION(2, 1, 0)
+static const char version[] = "2.1.0";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("GSPCA/VC032X USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+       struct gspca_dev gspca_dev;     /* !! must be the first item */
+
+       unsigned char autogain;
+       unsigned char lightfreq;
+
+       char qindex;
+       char bridge;
+#define BRIDGE_VC0321 0
+#define BRIDGE_VC0323 1
+       char sensor;
+#define SENSOR_HV7131R 0
+#define SENSOR_MI1320 1
+#define SENSOR_MI1310_SOC 2
+#define SENSOR_OV7660 3
+#define SENSOR_OV7670 4
+#define SENSOR_PO3130NC 5
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+#define SD_AUTOGAIN 0
+       {
+           {
+               .id      = V4L2_CID_AUTOGAIN,
+               .type    = V4L2_CTRL_TYPE_BOOLEAN,
+               .name    = "Auto Gain",
+               .minimum = 0,
+               .maximum = 1,
+               .step    = 1,
+               .default_value = 1,
+           },
+           .set = sd_setautogain,
+           .get = sd_getautogain,
+       },
+#define SD_FREQ 1
+       {
+           {
+               .id      = V4L2_CID_POWER_LINE_FREQUENCY,
+               .type    = V4L2_CTRL_TYPE_MENU,
+               .name    = "Light frequency filter",
+               .minimum = 0,
+               .maximum = 2,   /* 0: 0, 1: 50Hz, 2:60Hz */
+               .step    = 1,
+               .default_value = 1,
+           },
+           .set = sd_setfreq,
+           .get = sd_getfreq,
+       },
+};
+
+static struct cam_mode vc0321_mode[] = {
+       {V4L2_PIX_FMT_YUYV, 320, 240, 1},
+       {V4L2_PIX_FMT_YUYV, 640, 480, 0},
+};
+static struct cam_mode vc0323_mode[] = {
+       {V4L2_PIX_FMT_JPEG, 320, 240, 1},
+       {V4L2_PIX_FMT_JPEG, 640, 480, 0},
+};
+
+static __u8 mi1310_socinitVGA_JPG[][4] = {
+       {0xb0, 0x03, 0x19, 0xcc},
+       {0xb0, 0x04, 0x02, 0xcc},
+       {0xb3, 0x00, 0x64, 0xcc},
+       {0xb3, 0x00, 0x65, 0xcc},
+       {0xb3, 0x05, 0x00, 0xcc},
+       {0xb3, 0x06, 0x00, 0xcc},
+       {0xb3, 0x08, 0x01, 0xcc},
+       {0xb3, 0x09, 0x0c, 0xcc},
+       {0xb3, 0x34, 0x02, 0xcc},
+       {0xb3, 0x35, 0xdd, 0xcc},
+       {0xb3, 0x02, 0x00, 0xcc},
+       {0xb3, 0x03, 0x0a, 0xcc},
+       {0xb3, 0x04, 0x05, 0xcc},
+       {0xb3, 0x20, 0x00, 0xcc},
+       {0xb3, 0x21, 0x00, 0xcc},
+       {0xb3, 0x22, 0x03, 0xcc},
+       {0xb3, 0x23, 0xc0, 0xcc},
+       {0xb3, 0x14, 0x00, 0xcc},
+       {0xb3, 0x15, 0x00, 0xcc},
+       {0xb3, 0x16, 0x04, 0xcc},
+       {0xb3, 0x17, 0xff, 0xcc},
+       {0xb3, 0x00, 0x65, 0xcc},
+       {0xb8, 0x00, 0x00, 0xcc},
+       {0xbc, 0x00, 0xd0, 0xcc},
+       {0xbc, 0x01, 0x01, 0xcc},
+       {0xf0, 0x00, 0x02, 0xbb},
+       {0xc8, 0x9f, 0x0b, 0xbb},
+       {0x5b, 0x00, 0x01, 0xbb},
+       {0x2f, 0xde, 0x20, 0xbb},
+       {0xf0, 0x00, 0x00, 0xbb},
+       {0x20, 0x03, 0x02, 0xbb},
+       {0xf0, 0x00, 0x01, 0xbb},
+       {0x05, 0x00, 0x07, 0xbb},
+       {0x34, 0x00, 0x00, 0xbb},
+       {0x35, 0xff, 0x00, 0xbb},
+       {0xdc, 0x07, 0x02, 0xbb},
+       {0xdd, 0x3c, 0x18, 0xbb},
+       {0xde, 0x92, 0x6d, 0xbb},
+       {0xdf, 0xcd, 0xb1, 0xbb},
+       {0xe0, 0xff, 0xe7, 0xbb},
+       {0x06, 0xf0, 0x0d, 0xbb},
+       {0x06, 0x70, 0x0e, 0xbb},
+       {0x4c, 0x00, 0x01, 0xbb},
+       {0x4d, 0x00, 0x01, 0xbb},
+       {0xf0, 0x00, 0x02, 0xbb},
+       {0x2e, 0x0c, 0x55, 0xbb},
+       {0x21, 0xb6, 0x6e, 0xbb},
+       {0x36, 0x30, 0x10, 0xbb},
+       {0x37, 0x00, 0xc1, 0xbb},
+       {0xf0, 0x00, 0x00, 0xbb},
+       {0x07, 0x00, 0x84, 0xbb},
+       {0x08, 0x02, 0x4a, 0xbb},
+       {0x05, 0x01, 0x10, 0xbb},
+       {0x06, 0x00, 0x39, 0xbb},
+       {0xf0, 0x00, 0x02, 0xbb},
+       {0x58, 0x02, 0x67, 0xbb},
+       {0x57, 0x02, 0x00, 0xbb},
+       {0x5a, 0x02, 0x67, 0xbb},
+       {0x59, 0x02, 0x00, 0xbb},
+       {0x5c, 0x12, 0x0d, 0xbb},
+       {0x5d, 0x16, 0x11, 0xbb},
+       {0x39, 0x06, 0x18, 0xbb},
+       {0x3a, 0x06, 0x18, 0xbb},
+       {0x3b, 0x06, 0x18, 0xbb},
+       {0x3c, 0x06, 0x18, 0xbb},
+       {0x64, 0x7b, 0x5b, 0xbb},
+       {0xf0, 0x00, 0x02, 0xbb},
+       {0x36, 0x30, 0x10, 0xbb},
+       {0x37, 0x00, 0xc0, 0xbb},
+       {0xbc, 0x0e, 0x00, 0xcc},
+       {0xbc, 0x0f, 0x05, 0xcc},
+       {0xbc, 0x10, 0xc0, 0xcc},
+       {0xbc, 0x11, 0x03, 0xcc},
+       {0xb6, 0x00, 0x00, 0xcc},
+       {0xb6, 0x03, 0x02, 0xcc},
+       {0xb6, 0x02, 0x80, 0xcc},
+       {0xb6, 0x05, 0x01, 0xcc},
+       {0xb6, 0x04, 0xe0, 0xcc},
+       {0xb6, 0x12, 0xf8, 0xcc},
+       {0xb6, 0x13, 0x25, 0xcc},
+       {0xb6, 0x18, 0x02, 0xcc},
+       {0xb6, 0x17, 0x58, 0xcc},
+       {0xb6, 0x16, 0x00, 0xcc},
+       {0xb6, 0x22, 0x12, 0xcc},
+       {0xb6, 0x23, 0x0b, 0xcc},
+       {0xbf, 0xc0, 0x39, 0xcc},
+       {0xbf, 0xc1, 0x04, 0xcc},
+       {0xbf, 0xcc, 0x00, 0xcc},
+       {0xbc, 0x02, 0x18, 0xcc},
+       {0xbc, 0x03, 0x50, 0xcc},
+       {0xbc, 0x04, 0x18, 0xcc},
+       {0xbc, 0x05, 0x00, 0xcc},
+       {0xbc, 0x06, 0x00, 0xcc},
+       {0xbc, 0x08, 0x30, 0xcc},
+       {0xbc, 0x09, 0x40, 0xcc},
+       {0xbc, 0x0a, 0x10, 0xcc},
+       {0xbc, 0x0b, 0x00, 0xcc},
+       {0xbc, 0x0c, 0x00, 0xcc},
+       {0xb3, 0x5c, 0x01, 0xcc},
+       {0xf0, 0x00, 0x01, 0xbb},
+       {0x80, 0x00, 0x03, 0xbb},
+       {0x81, 0xc7, 0x14, 0xbb},
+       {0x82, 0xeb, 0xe8, 0xbb},
+       {0x83, 0xfe, 0xf4, 0xbb},
+       {0x84, 0xcd, 0x10, 0xbb},
+       {0x85, 0xf3, 0xee, 0xbb},
+       {0x86, 0xff, 0xf1, 0xbb},
+       {0x87, 0xcd, 0x10, 0xbb},
+       {0x88, 0xf3, 0xee, 0xbb},
+       {0x89, 0x01, 0xf1, 0xbb},
+       {0x8a, 0xe5, 0x17, 0xbb},
+       {0x8b, 0xe8, 0xe2, 0xbb},
+       {0x8c, 0xf7, 0xed, 0xbb},
+       {0x8d, 0x00, 0xff, 0xbb},
+       {0x8e, 0xec, 0x10, 0xbb},
+       {0x8f, 0xf0, 0xed, 0xbb},
+       {0x90, 0xf9, 0xf2, 0xbb},
+       {0x91, 0x00, 0x00, 0xbb},
+       {0x92, 0xe9, 0x0d, 0xbb},
+       {0x93, 0xf4, 0xf2, 0xbb},
+       {0x94, 0xfb, 0xf5, 0xbb},
+       {0x95, 0x00, 0xff, 0xbb},
+       {0xb6, 0x0f, 0x08, 0xbb},
+       {0xb7, 0x3d, 0x16, 0xbb},
+       {0xb8, 0x0c, 0x04, 0xbb},
+       {0xb9, 0x1c, 0x07, 0xbb},
+       {0xba, 0x0a, 0x03, 0xbb},
+       {0xbb, 0x1b, 0x09, 0xbb},
+       {0xbc, 0x17, 0x0d, 0xbb},
+       {0xbd, 0x23, 0x1d, 0xbb},
+       {0xbe, 0x00, 0x28, 0xbb},
+       {0xbf, 0x11, 0x09, 0xbb},
+       {0xc0, 0x16, 0x15, 0xbb},
+       {0xc1, 0x00, 0x1b, 0xbb},
+       {0xc2, 0x0e, 0x07, 0xbb},
+       {0xc3, 0x14, 0x10, 0xbb},
+       {0xc4, 0x00, 0x17, 0xbb},
+       {0x06, 0x74, 0x8e, 0xbb},
+       {0xf0, 0x00, 0x01, 0xbb},
+       {0x06, 0xf4, 0x8e, 0xbb},
+       {0x00, 0x00, 0x50, 0xdd},
+       {0x06, 0x74, 0x8e, 0xbb},
+       {0xf0, 0x00, 0x02, 0xbb},
+       {0x24, 0x50, 0x20, 0xbb},
+       {0xf0, 0x00, 0x02, 0xbb},
+       {0x34, 0x0c, 0x50, 0xbb},
+       {0xb3, 0x01, 0x41, 0xcc},
+       {0xf0, 0x00, 0x00, 0xbb},
+       {0x03, 0x03, 0xc0, 0xbb},
+       {},
+};
+static __u8 mi1310_socinitQVGA_JPG[][4] = {
+       {0xb0, 0x03, 0x19, 0xcc},       {0xb0, 0x04, 0x02, 0xcc},
+       {0xb3, 0x00, 0x64, 0xcc},       {0xb3, 0x00, 0x65, 0xcc},
+       {0xb3, 0x05, 0x00, 0xcc},       {0xb3, 0x06, 0x00, 0xcc},
+       {0xb3, 0x08, 0x01, 0xcc},       {0xb3, 0x09, 0x0c, 0xcc},
+       {0xb3, 0x34, 0x02, 0xcc},       {0xb3, 0x35, 0xdd, 0xcc},
+       {0xb3, 0x02, 0x00, 0xcc},       {0xb3, 0x03, 0x0a, 0xcc},
+       {0xb3, 0x04, 0x05, 0xcc},       {0xb3, 0x20, 0x00, 0xcc},
+       {0xb3, 0x21, 0x00, 0xcc},       {0xb3, 0x22, 0x03, 0xcc},
+       {0xb3, 0x23, 0xc0, 0xcc},       {0xb3, 0x14, 0x00, 0xcc},
+       {0xb3, 0x15, 0x00, 0xcc},       {0xb3, 0x16, 0x04, 0xcc},
+       {0xb3, 0x17, 0xff, 0xcc},       {0xb3, 0x00, 0x65, 0xcc},
+       {0xb8, 0x00, 0x00, 0xcc},       {0xbc, 0x00, 0xf0, 0xcc},
+       {0xbc, 0x01, 0x01, 0xcc},       {0xf0, 0x00, 0x02, 0xbb},
+       {0xc8, 0x9f, 0x0b, 0xbb},       {0x5b, 0x00, 0x01, 0xbb},
+       {0x2f, 0xde, 0x20, 0xbb},       {0xf0, 0x00, 0x00, 0xbb},
+       {0x20, 0x03, 0x02, 0xbb},       {0xf0, 0x00, 0x01, 0xbb},
+       {0x05, 0x00, 0x07, 0xbb},       {0x34, 0x00, 0x00, 0xbb},
+       {0x35, 0xff, 0x00, 0xbb},       {0xdc, 0x07, 0x02, 0xbb},
+       {0xdd, 0x3c, 0x18, 0xbb},       {0xde, 0x92, 0x6d, 0xbb},
+       {0xdf, 0xcd, 0xb1, 0xbb},       {0xe0, 0xff, 0xe7, 0xbb},
+       {0x06, 0xf0, 0x0d, 0xbb},       {0x06, 0x70, 0x0e, 0xbb},
+       {0x4c, 0x00, 0x01, 0xbb},       {0x4d, 0x00, 0x01, 0xbb},
+       {0xf0, 0x00, 0x02, 0xbb},       {0x2e, 0x0c, 0x55, 0xbb},
+       {0x21, 0xb6, 0x6e, 0xbb},       {0x36, 0x30, 0x10, 0xbb},
+       {0x37, 0x00, 0xc1, 0xbb},       {0xf0, 0x00, 0x00, 0xbb},
+       {0x07, 0x00, 0x84, 0xbb},       {0x08, 0x02, 0x4a, 0xbb},
+       {0x05, 0x01, 0x10, 0xbb},       {0x06, 0x00, 0x39, 0xbb},
+       {0xf0, 0x00, 0x02, 0xbb},       {0x58, 0x02, 0x67, 0xbb},
+       {0x57, 0x02, 0x00, 0xbb},       {0x5a, 0x02, 0x67, 0xbb},
+       {0x59, 0x02, 0x00, 0xbb},       {0x5c, 0x12, 0x0d, 0xbb},
+       {0x5d, 0x16, 0x11, 0xbb},       {0x39, 0x06, 0x18, 0xbb},
+       {0x3a, 0x06, 0x18, 0xbb},       {0x3b, 0x06, 0x18, 0xbb},
+       {0x3c, 0x06, 0x18, 0xbb},       {0x64, 0x7b, 0x5b, 0xbb},
+       {0xf0, 0x00, 0x02, 0xbb},       {0x36, 0x30, 0x10, 0xbb},
+       {0x37, 0x00, 0xc0, 0xbb},       {0xbc, 0x0e, 0x00, 0xcc},
+       {0xbc, 0x0f, 0x05, 0xcc},       {0xbc, 0x10, 0xc0, 0xcc},
+       {0xbc, 0x11, 0x03, 0xcc},       {0xb6, 0x00, 0x00, 0xcc},
+       {0xb6, 0x03, 0x01, 0xcc},       {0xb6, 0x02, 0x40, 0xcc},
+       {0xb6, 0x05, 0x00, 0xcc},       {0xb6, 0x04, 0xf0, 0xcc},
+       {0xb6, 0x12, 0xf8, 0xcc},       {0xb6, 0x13, 0x25, 0xcc},
+       {0xb6, 0x18, 0x00, 0xcc},       {0xb6, 0x17, 0x96, 0xcc},
+       {0xb6, 0x16, 0x00, 0xcc},       {0xb6, 0x22, 0x12, 0xcc},
+       {0xb6, 0x23, 0x0b, 0xcc},       {0xbf, 0xc0, 0x39, 0xcc},
+       {0xbf, 0xc1, 0x04, 0xcc},       {0xbf, 0xcc, 0x00, 0xcc},
+       {0xb3, 0x5c, 0x01, 0xcc},       {0xf0, 0x00, 0x01, 0xbb},
+       {0x80, 0x00, 0x03, 0xbb},       {0x81, 0xc7, 0x14, 0xbb},
+       {0x82, 0xeb, 0xe8, 0xbb},       {0x83, 0xfe, 0xf4, 0xbb},
+       {0x84, 0xcd, 0x10, 0xbb},       {0x85, 0xf3, 0xee, 0xbb},
+       {0x86, 0xff, 0xf1, 0xbb},       {0x87, 0xcd, 0x10, 0xbb},
+       {0x88, 0xf3, 0xee, 0xbb},       {0x89, 0x01, 0xf1, 0xbb},
+       {0x8a, 0xe5, 0x17, 0xbb},       {0x8b, 0xe8, 0xe2, 0xbb},
+       {0x8c, 0xf7, 0xed, 0xbb},       {0x8d, 0x00, 0xff, 0xbb},
+       {0x8e, 0xec, 0x10, 0xbb},       {0x8f, 0xf0, 0xed, 0xbb},
+       {0x90, 0xf9, 0xf2, 0xbb},       {0x91, 0x00, 0x00, 0xbb},
+       {0x92, 0xe9, 0x0d, 0xbb},       {0x93, 0xf4, 0xf2, 0xbb},
+       {0x94, 0xfb, 0xf5, 0xbb},       {0x95, 0x00, 0xff, 0xbb},
+       {0xb6, 0x0f, 0x08, 0xbb},       {0xb7, 0x3d, 0x16, 0xbb},
+       {0xb8, 0x0c, 0x04, 0xbb},       {0xb9, 0x1c, 0x07, 0xbb},
+       {0xba, 0x0a, 0x03, 0xbb},       {0xbb, 0x1b, 0x09, 0xbb},
+       {0xbc, 0x17, 0x0d, 0xbb},       {0xbd, 0x23, 0x1d, 0xbb},
+       {0xbe, 0x00, 0x28, 0xbb},       {0xbf, 0x11, 0x09, 0xbb},
+       {0xc0, 0x16, 0x15, 0xbb},       {0xc1, 0x00, 0x1b, 0xbb},
+       {0xc2, 0x0e, 0x07, 0xbb},       {0xc3, 0x14, 0x10, 0xbb},
+       {0xc4, 0x00, 0x17, 0xbb},       {0x06, 0x74, 0x8e, 0xbb},
+       {0xf0, 0x00, 0x01, 0xbb},       {0x06, 0xf4, 0x8e, 0xbb},
+       {0x00, 0x00, 0x50, 0xdd},       {0x06, 0x74, 0x8e, 0xbb},
+       {0xf0, 0x00, 0x02, 0xbb},       {0x24, 0x50, 0x20, 0xbb},
+       {0xf0, 0x00, 0x02, 0xbb},       {0x34, 0x0c, 0x50, 0xbb},
+       {0xb3, 0x01, 0x41, 0xcc},       {0xf0, 0x00, 0x00, 0xbb},
+       {0x03, 0x03, 0xc0, 0xbb},
+       {},
+};
+
+static __u8 mi1320_gamma[17] = {
+       0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
+       0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff
+};
+static __u8 mi1320_matrix[9] = {
+       0x54, 0xda, 0x06, 0xf1, 0x50, 0xf4, 0xf7, 0xea, 0x52
+};
+static __u8 mi1320_initVGA_data[][4] = {
+       {0xb3, 0x01, 0x01, 0xcc},       {0x00, 0x00, 0x33, 0xdd},
+       {0xb0, 0x03, 0x19, 0xcc},       {0x00, 0x00, 0x33, 0xdd},
+       {0xb0, 0x04, 0x02, 0xcc},       {0x00, 0x00, 0x33, 0xdd},
+       {0xb3, 0x00, 0x64, 0xcc},       {0xb3, 0x00, 0x65, 0xcc},
+       {0xb0, 0x16, 0x03, 0xcc},       {0xb3, 0x05, 0x00, 0xcc},
+       {0xb3, 0x06, 0x00, 0xcc},       {0xb3, 0x08, 0x01, 0xcc},
+       {0xb3, 0x09, 0x0c, 0xcc},       {0xb3, 0x34, 0x02, 0xcc},
+       {0xb3, 0x35, 0xc8, 0xcc},       {0xb3, 0x02, 0x00, 0xcc},
+       {0xb3, 0x03, 0x0a, 0xcc},       {0xb3, 0x04, 0x05, 0xcc},
+       {0xb3, 0x20, 0x00, 0xcc},       {0xb3, 0x21, 0x00, 0xcc},
+       {0xb3, 0x22, 0x03, 0xcc},       {0xb3, 0x23, 0xc0, 0xcc},
+       {0xb3, 0x14, 0x00, 0xcc},       {0xb3, 0x15, 0x00, 0xcc},
+       {0xb3, 0x16, 0x04, 0xcc},       {0xb3, 0x17, 0xff, 0xcc},
+       {0xb3, 0x00, 0x67, 0xcc},       {0xbc, 0x00, 0xd0, 0xcc},
+       {0xbc, 0x01, 0x01, 0xcc},       {0xf0, 0x00, 0x00, 0xbb},
+       {0x0d, 0x00, 0x09, 0xbb},       {0x00, 0x01, 0x00, 0xdd},
+       {0x0d, 0x00, 0x08, 0xbb},       {0xf0, 0x00, 0x01, 0xbb},
+       {0xa1, 0x05, 0x00, 0xbb},       {0xa4, 0x03, 0xc0, 0xbb},
+       {0xf0, 0x00, 0x02, 0xbb},       {0x00, 0x00, 0x10, 0xdd},
+       {0xc8, 0x9f, 0x0b, 0xbb},       {0x00, 0x00, 0x10, 0xdd},
+       {0xf0, 0x00, 0x00, 0xbb},       {0x00, 0x00, 0x10, 0xdd},
+       {0x20, 0x01, 0x00, 0xbb},       {0x00, 0x00, 0x10, 0xdd},
+       {0xf0, 0x00, 0x01, 0xbb},       {0x9d, 0x3c, 0xa0, 0xbb},
+       {0x47, 0x30, 0x30, 0xbb},       {0xf0, 0x00, 0x00, 0xbb},
+       {0x0a, 0x80, 0x11, 0xbb},       {0x35, 0x00, 0x22, 0xbb},
+       {0xf0, 0x00, 0x02, 0xbb},       {0x9d, 0xc5, 0x05, 0xbb},
+       {0xdc, 0x0f, 0xfc, 0xbb},       {0xf0, 0x00, 0x01, 0xbb},
+       {0x06, 0x74, 0x0e, 0xbb},       {0x80, 0x00, 0x06, 0xbb},
+       {0x81, 0x04, 0x00, 0xbb},       {0x82, 0x01, 0x02, 0xbb},
+       {0x83, 0x03, 0x02, 0xbb},       {0x84, 0x05, 0x00, 0xbb},
+       {0x85, 0x01, 0x00, 0xbb},       {0x86, 0x03, 0x02, 0xbb},
+       {0x87, 0x05, 0x00, 0xbb},       {0x88, 0x01, 0x00, 0xbb},
+       {0x89, 0x02, 0x02, 0xbb},       {0x8a, 0xfd, 0x04, 0xbb},
+       {0x8b, 0xfc, 0xfd, 0xbb},       {0x8c, 0xff, 0xfd, 0xbb},
+       {0x8d, 0x00, 0x00, 0xbb},       {0x8e, 0xfe, 0x05, 0xbb},
+       {0x8f, 0xfc, 0xfd, 0xbb},       {0x90, 0xfe, 0xfd, 0xbb},
+       {0x91, 0x00, 0x00, 0xbb},       {0x92, 0xfe, 0x03, 0xbb},
+       {0x93, 0xfd, 0xfe, 0xbb},       {0x94, 0xff, 0xfd, 0xbb},
+       {0x95, 0x00, 0x00, 0xbb},       {0xb6, 0x07, 0x05, 0xbb},
+       {0xb7, 0x13, 0x06, 0xbb},       {0xb8, 0x08, 0x06, 0xbb},
+       {0xb9, 0x14, 0x08, 0xbb},       {0xba, 0x06, 0x05, 0xbb},
+       {0xbb, 0x13, 0x06, 0xbb},       {0xbc, 0x03, 0x01, 0xbb},
+       {0xbd, 0x03, 0x04, 0xbb},       {0xbe, 0x00, 0x02, 0xbb},
+       {0xbf, 0x03, 0x01, 0xbb},       {0xc0, 0x02, 0x04, 0xbb},
+       {0xc1, 0x00, 0x04, 0xbb},       {0xc2, 0x02, 0x01, 0xbb},
+       {0xc3, 0x01, 0x03, 0xbb},       {0xc4, 0x00, 0x04, 0xbb},
+       {0xf0, 0x00, 0x00, 0xbb},       {0x05, 0x01, 0x13, 0xbb},
+       {0x06, 0x00, 0x11, 0xbb},       {0x07, 0x00, 0x85, 0xbb},
+       {0x08, 0x00, 0x27, 0xbb},       {0x20, 0x01, 0x03, 0xbb},
+       {0x21, 0x80, 0x00, 0xbb},       {0x22, 0x0d, 0x0f, 0xbb},
+       {0x24, 0x80, 0x00, 0xbb},       {0x59, 0x00, 0xff, 0xbb},
+       {0xf0, 0x00, 0x02, 0xbb},       {0x39, 0x03, 0x0d, 0xbb},
+       {0x3a, 0x06, 0x1b, 0xbb},       {0x3b, 0x00, 0x95, 0xbb},
+       {0x3c, 0x04, 0xdb, 0xbb},       {0x57, 0x02, 0x00, 0xbb},
+       {0x58, 0x02, 0x66, 0xbb},       {0x59, 0x00, 0xff, 0xbb},
+       {0x5a, 0x01, 0x33, 0xbb},       {0x5c, 0x12, 0x0d, 0xbb},
+       {0x5d, 0x16, 0x11, 0xbb},       {0x64, 0x5e, 0x1c, 0xbb},
+       {0xf0, 0x00, 0x02, 0xbb},       {0x2f, 0xd1, 0x00, 0xbb},
+       {0x5b, 0x00, 0x01, 0xbb},       {0xf0, 0x00, 0x02, 0xbb},
+       {0x36, 0x68, 0x10, 0xbb},       {0x00, 0x00, 0x30, 0xdd},
+       {0x37, 0x82, 0x00, 0xbb},       {0xbc, 0x0e, 0x00, 0xcc},
+       {0xbc, 0x0f, 0x05, 0xcc},       {0xbc, 0x10, 0xc0, 0xcc},
+       {0xbc, 0x11, 0x03, 0xcc},       {0xb6, 0x00, 0x00, 0xcc},
+       {0xb6, 0x03, 0x05, 0xcc},       {0xb6, 0x02, 0x00, 0xcc},
+       {0xb6, 0x05, 0x04, 0xcc},       {0xb6, 0x04, 0x00, 0xcc},
+       {0xb6, 0x12, 0xf8, 0xcc},       {0xb6, 0x13, 0x29, 0xcc},
+       {0xb6, 0x18, 0x0a, 0xcc},       {0xb6, 0x17, 0x00, 0xcc},
+       {0xb6, 0x16, 0x00, 0xcc},       {0xb6, 0x22, 0x12, 0xcc},
+       {0xb6, 0x23, 0x0b, 0xcc},       {0xbf, 0xc0, 0x26, 0xcc},
+       {0xbf, 0xc1, 0x02, 0xcc},       {0xbf, 0xcc, 0x04, 0xcc},
+       {0xbc, 0x02, 0x18, 0xcc},       {0xbc, 0x03, 0x50, 0xcc},
+       {0xbc, 0x04, 0x18, 0xcc},       {0xbc, 0x05, 0x00, 0xcc},
+       {0xbc, 0x06, 0x00, 0xcc},       {0xbc, 0x08, 0x30, 0xcc},
+       {0xbc, 0x09, 0x40, 0xcc},       {0xbc, 0x0a, 0x10, 0xcc},
+       {0xbc, 0x0b, 0x00, 0xcc},       {0xbc, 0x0c, 0x00, 0xcc},
+       {0xb3, 0x5c, 0x01, 0xcc},       {0xb3, 0x01, 0x41, 0xcc},
+       {}
+};
+static __u8 mi1320_initQVGA_data[][4] = {
+       {0xb3, 0x01, 0x01, 0xcc},       {0x00, 0x00, 0x33, 0xdd},
+       {0xb0, 0x03, 0x19, 0xcc},       {0x00, 0x00, 0x33, 0xdd},
+       {0xb0, 0x04, 0x02, 0xcc},       {0x00, 0x00, 0x33, 0xdd},
+       {0xb3, 0x00, 0x64, 0xcc},       {0xb3, 0x00, 0x65, 0xcc},
+       {0xb0, 0x16, 0x03, 0xcc},       {0xb3, 0x05, 0x01, 0xcc},
+       {0xb3, 0x06, 0x01, 0xcc},       {0xb3, 0x08, 0x01, 0xcc},
+       {0xb3, 0x09, 0x0c, 0xcc},       {0xb3, 0x34, 0x02, 0xcc},
+       {0xb3, 0x35, 0xc8, 0xcc},       {0xb3, 0x02, 0x00, 0xcc},
+       {0xb3, 0x03, 0x0a, 0xcc},       {0xb3, 0x04, 0x05, 0xcc},
+       {0xb3, 0x20, 0x00, 0xcc},       {0xb3, 0x21, 0x00, 0xcc},
+       {0xb3, 0x22, 0x01, 0xcc},       {0xb3, 0x23, 0xe0, 0xcc},
+       {0xb3, 0x14, 0x00, 0xcc},       {0xb3, 0x15, 0x00, 0xcc},
+       {0xb3, 0x16, 0x02, 0xcc},       {0xb3, 0x17, 0x7f, 0xcc},
+       {0xb3, 0x00, 0x65, 0xcc},       {0xb8, 0x00, 0x00, 0xcc},
+       {0xbc, 0x00, 0xd0, 0xcc},       {0xbc, 0x01, 0x01, 0xcc},
+       {0xf0, 0x00, 0x00, 0xbb},       {0x0d, 0x00, 0x09, 0xbb},
+       {0x00, 0x01, 0x00, 0xdd},       {0x0d, 0x00, 0x08, 0xbb},
+       {0xf0, 0x00, 0x00, 0xbb},       {0x02, 0x00, 0x64, 0xbb},
+       {0x05, 0x01, 0x78, 0xbb},       {0x06, 0x00, 0x11, 0xbb},
+       {0x07, 0x01, 0x42, 0xbb},       {0x08, 0x00, 0x11, 0xbb},
+       {0x20, 0x01, 0x00, 0xbb},       {0x21, 0x80, 0x00, 0xbb},
+       {0x22, 0x0d, 0x0f, 0xbb},       {0x24, 0x80, 0x00, 0xbb},
+       {0x59, 0x00, 0xff, 0xbb},       {0xf0, 0x00, 0x01, 0xbb},
+       {0x9d, 0x3c, 0xa0, 0xbb},       {0x47, 0x30, 0x30, 0xbb},
+       {0xf0, 0x00, 0x00, 0xbb},       {0x0a, 0x80, 0x11, 0xbb},
+       {0x35, 0x00, 0x22, 0xbb},       {0xf0, 0x00, 0x02, 0xbb},
+       {0x9d, 0xc5, 0x05, 0xbb},       {0xdc, 0x0f, 0xfc, 0xbb},
+       {0xf0, 0x00, 0x01, 0xbb},       {0x06, 0x74, 0x0e, 0xbb},
+       {0x80, 0x00, 0x06, 0xbb},       {0x81, 0x04, 0x00, 0xbb},
+       {0x82, 0x01, 0x02, 0xbb},       {0x83, 0x03, 0x02, 0xbb},
+       {0x84, 0x05, 0x00, 0xbb},       {0x85, 0x01, 0x00, 0xbb},
+       {0x86, 0x03, 0x02, 0xbb},       {0x87, 0x05, 0x00, 0xbb},
+       {0x88, 0x01, 0x00, 0xbb},       {0x89, 0x02, 0x02, 0xbb},
+       {0x8a, 0xfd, 0x04, 0xbb},       {0x8b, 0xfc, 0xfd, 0xbb},
+       {0x8c, 0xff, 0xfd, 0xbb},       {0x8d, 0x00, 0x00, 0xbb},
+       {0x8e, 0xfe, 0x05, 0xbb},       {0x8f, 0xfc, 0xfd, 0xbb},
+       {0x90, 0xfe, 0xfd, 0xbb},       {0x91, 0x00, 0x00, 0xbb},
+       {0x92, 0xfe, 0x03, 0xbb},       {0x93, 0xfd, 0xfe, 0xbb},
+       {0x94, 0xff, 0xfd, 0xbb},       {0x95, 0x00, 0x00, 0xbb},
+       {0xb6, 0x07, 0x05, 0xbb},       {0xb7, 0x13, 0x06, 0xbb},
+       {0xb8, 0x08, 0x06, 0xbb},       {0xb9, 0x14, 0x08, 0xbb},
+       {0xba, 0x06, 0x05, 0xbb},       {0xbb, 0x13, 0x06, 0xbb},
+       {0xbc, 0x03, 0x01, 0xbb},       {0xbd, 0x03, 0x04, 0xbb},
+       {0xbe, 0x00, 0x02, 0xbb},       {0xbf, 0x03, 0x01, 0xbb},
+       {0xc0, 0x02, 0x04, 0xbb},       {0xc1, 0x00, 0x04, 0xbb},
+       {0xc2, 0x02, 0x01, 0xbb},       {0xc3, 0x01, 0x03, 0xbb},
+       {0xc4, 0x00, 0x04, 0xbb},       {0xf0, 0x00, 0x02, 0xbb},
+       {0xc8, 0x00, 0x00, 0xbb},       {0x2e, 0x00, 0x00, 0xbb},
+       {0x2e, 0x0c, 0x5b, 0xbb},       {0x2f, 0xd1, 0x00, 0xbb},
+       {0x39, 0x03, 0xca, 0xbb},       {0x3a, 0x06, 0x80, 0xbb},
+       {0x3b, 0x01, 0x52, 0xbb},       {0x3c, 0x05, 0x40, 0xbb},
+       {0x57, 0x01, 0x9c, 0xbb},       {0x58, 0x01, 0xee, 0xbb},
+       {0x59, 0x00, 0xf0, 0xbb},       {0x5a, 0x01, 0x20, 0xbb},
+       {0x5c, 0x1d, 0x17, 0xbb},       {0x5d, 0x22, 0x1c, 0xbb},
+       {0x64, 0x1e, 0x1c, 0xbb},       {0x5b, 0x00, 0x01, 0xbb},
+       {0xf0, 0x00, 0x02, 0xbb},       {0x36, 0x68, 0x10, 0xbb},
+       {0x00, 0x00, 0x30, 0xdd},       {0x37, 0x81, 0x00, 0xbb},
+       {0xbc, 0x02, 0x18, 0xcc},       {0xbc, 0x03, 0x50, 0xcc},
+       {0xbc, 0x04, 0x18, 0xcc},       {0xbc, 0x05, 0x00, 0xcc},
+       {0xbc, 0x06, 0x00, 0xcc},       {0xbc, 0x08, 0x30, 0xcc},
+       {0xbc, 0x09, 0x40, 0xcc},       {0xbc, 0x0a, 0x10, 0xcc},
+       {0xbc, 0x0b, 0x00, 0xcc},       {0xbc, 0x0c, 0x00, 0xcc},
+       {0xbf, 0xc0, 0x26, 0xcc},       {0xbf, 0xc1, 0x02, 0xcc},
+       {0xbf, 0xcc, 0x04, 0xcc},       {0xb3, 0x5c, 0x01, 0xcc},
+       {0xb3, 0x01, 0x41, 0xcc},
+       {}
+};
+
+static __u8 po3130_gamma[17] = {
+       0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
+       0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff
+};
+static __u8 po3130_matrix[9] = {
+       0x5f, 0xec, 0xf5, 0xf1, 0x5a, 0xf5, 0xf1, 0xec, 0x63
+};
+
+static __u8 po3130_initVGA_data[][4] = {
+       {0xb0, 0x4d, 0x00, 0xcc},       {0xb3, 0x01, 0x01, 0xcc},
+       {0x00, 0x00, 0x50, 0xdd},       {0xb0, 0x03, 0x01, 0xcc},
+       {0xb3, 0x00, 0x04, 0xcc},       {0xb3, 0x00, 0x24, 0xcc},
+       {0xb3, 0x00, 0x25, 0xcc},       {0xb3, 0x08, 0x01, 0xcc},
+       {0xb3, 0x09, 0x0c, 0xcc},       {0xb3, 0x05, 0x00, 0xcc},
+       {0xb3, 0x06, 0x01, 0xcc},       {0xb3, 0x03, 0x1a, 0xcc},
+       {0xb3, 0x04, 0x15, 0xcc},       {0xb3, 0x20, 0x00, 0xcc},
+       {0xb3, 0x21, 0x00, 0xcc},       {0xb3, 0x22, 0x01, 0xcc},
+       {0xb3, 0x23, 0xe8, 0xcc},       {0xb8, 0x08, 0xe8, 0xcc},
+       {0xb3, 0x14, 0x00, 0xcc},       {0xb3, 0x15, 0x00, 0xcc},
+       {0xb3, 0x16, 0x02, 0xcc},       {0xb3, 0x17, 0x7f, 0xcc},
+       {0xb3, 0x34, 0x01, 0xcc},       {0xb3, 0x35, 0xf6, 0xcc},
+       {0xb3, 0x00, 0x27, 0xcc},       {0xbc, 0x00, 0x71, 0xcc},
+       {0xb8, 0x00, 0x21, 0xcc},       {0xb8, 0x27, 0x20, 0xcc},
+       {0xb8, 0x01, 0x79, 0xcc},       {0xb8, 0x81, 0x09, 0xcc},
+       {0xb8, 0x2c, 0x50, 0xcc},       {0xb8, 0x2d, 0xf8, 0xcc},
+       {0xb8, 0x2e, 0xf8, 0xcc},       {0xb8, 0x2f, 0xf8, 0xcc},
+       {0xb8, 0x30, 0x50, 0xcc},       {0xb8, 0x31, 0xf8, 0xcc},
+       {0xb8, 0x32, 0xf8, 0xcc},       {0xb8, 0x33, 0xf8, 0xcc},
+       {0xb8, 0x34, 0x50, 0xcc},       {0xb8, 0x35, 0x00, 0xcc},
+       {0xb8, 0x36, 0x00, 0xcc},       {0xb8, 0x37, 0x00, 0xcc},
+       {0x00, 0x1e, 0xc6, 0xaa},       {0x00, 0x20, 0x44, 0xaa},
+       {0x00, 0xad, 0x02, 0xaa},       {0x00, 0xae, 0x2c, 0xaa},
+       {0x00, 0x12, 0x08, 0xaa},       {0x00, 0x17, 0x41, 0xaa},
+       {0x00, 0x19, 0x41, 0xaa},       {0x00, 0x1e, 0x06, 0xaa},
+       {0x00, 0x21, 0x00, 0xaa},       {0x00, 0x36, 0xc0, 0xaa},
+       {0x00, 0x37, 0xc8, 0xaa},       {0x00, 0x3b, 0x36, 0xaa},
+       {0x00, 0x4b, 0xfe, 0xaa},       {0x00, 0x51, 0x1c, 0xaa},
+       {0x00, 0x52, 0x01, 0xaa},       {0x00, 0x55, 0x0a, 0xaa},
+       {0x00, 0x59, 0x02, 0xaa},       {0x00, 0x5a, 0x04, 0xaa},
+       {0x00, 0x5c, 0x10, 0xaa},       {0x00, 0x5d, 0x10, 0xaa},
+       {0x00, 0x5e, 0x10, 0xaa},       {0x00, 0x5f, 0x10, 0xaa},
+       {0x00, 0x61, 0x00, 0xaa},       {0x00, 0x62, 0x18, 0xaa},
+       {0x00, 0x63, 0x30, 0xaa},       {0x00, 0x70, 0x68, 0xaa},
+       {0x00, 0x80, 0x71, 0xaa},       {0x00, 0x81, 0x08, 0xaa},
+       {0x00, 0x82, 0x00, 0xaa},       {0x00, 0x83, 0x55, 0xaa},
+       {0x00, 0x84, 0x06, 0xaa},       {0x00, 0x85, 0x06, 0xaa},
+       {0x00, 0x86, 0x13, 0xaa},       {0x00, 0x87, 0x18, 0xaa},
+       {0x00, 0xaa, 0x3f, 0xaa},       {0x00, 0xab, 0x44, 0xaa},
+       {0x00, 0xb0, 0x68, 0xaa},       {0x00, 0xb5, 0x10, 0xaa},
+       {0x00, 0xb8, 0x20, 0xaa},       {0x00, 0xb9, 0xa0, 0xaa},
+       {0x00, 0xbc, 0x04, 0xaa},       {0x00, 0x8b, 0x40, 0xaa},
+       {0x00, 0x8c, 0x91, 0xaa},       {0x00, 0x8d, 0x8f, 0xaa},
+       {0x00, 0x8e, 0x91, 0xaa},       {0x00, 0x8f, 0x43, 0xaa},
+       {0x00, 0x90, 0x92, 0xaa},       {0x00, 0x91, 0x89, 0xaa},
+       {0x00, 0x92, 0x9d, 0xaa},       {0x00, 0x93, 0x46, 0xaa},
+       {0x00, 0xd6, 0x22, 0xaa},       {0x00, 0x73, 0x00, 0xaa},
+       {0x00, 0x74, 0x10, 0xaa},       {0x00, 0x75, 0x20, 0xaa},
+       {0x00, 0x76, 0x2b, 0xaa},       {0x00, 0x77, 0x36, 0xaa},
+       {0x00, 0x78, 0x49, 0xaa},       {0x00, 0x79, 0x5a, 0xaa},
+       {0x00, 0x7a, 0x7f, 0xaa},       {0x00, 0x7b, 0x9b, 0xaa},
+       {0x00, 0x7c, 0xba, 0xaa},       {0x00, 0x7d, 0xd4, 0xaa},
+       {0x00, 0x7e, 0xea, 0xaa},       {0x00, 0xd6, 0x62, 0xaa},
+       {0x00, 0x73, 0x00, 0xaa},       {0x00, 0x74, 0x10, 0xaa},
+       {0x00, 0x75, 0x20, 0xaa},       {0x00, 0x76, 0x2b, 0xaa},
+       {0x00, 0x77, 0x36, 0xaa},       {0x00, 0x78, 0x49, 0xaa},
+       {0x00, 0x79, 0x5a, 0xaa},       {0x00, 0x7a, 0x7f, 0xaa},
+       {0x00, 0x7b, 0x9b, 0xaa},       {0x00, 0x7c, 0xba, 0xaa},
+       {0x00, 0x7d, 0xd4, 0xaa},       {0x00, 0x7e, 0xea, 0xaa},
+       {0x00, 0xd6, 0xa2, 0xaa},       {0x00, 0x73, 0x00, 0xaa},
+       {0x00, 0x74, 0x10, 0xaa},       {0x00, 0x75, 0x20, 0xaa},
+       {0x00, 0x76, 0x2b, 0xaa},       {0x00, 0x77, 0x36, 0xaa},
+       {0x00, 0x78, 0x49, 0xaa},       {0x00, 0x79, 0x5a, 0xaa},
+       {0x00, 0x7a, 0x7f, 0xaa},       {0x00, 0x7b, 0x9b, 0xaa},
+       {0x00, 0x7c, 0xba, 0xaa},       {0x00, 0x7d, 0xd4, 0xaa},
+       {0x00, 0x7e, 0xea, 0xaa},
+       {0x00, 0x4c, 0x07, 0xaa},
+       {0x00, 0x4b, 0xe0, 0xaa},       {0x00, 0x4e, 0x77, 0xaa},
+       {0x00, 0x59, 0x02, 0xaa},       {0x00, 0x4d, 0x0a, 0xaa},
+/*     {0x00, 0xd1, 0x00, 0xaa},       {0x00, 0x20, 0xc4, 0xaa},
+       {0xb8, 0x8e, 0x00, 0xcc},       {0xb8, 0x8f, 0xff, 0xcc}, */
+       {0x00, 0xd1, 0x3c, 0xaa},       {0x00, 0x20, 0xc4, 0xaa},
+       {0xb8, 0x8e, 0x00, 0xcc},       {0xb8, 0x8f, 0xff, 0xcc},
+       {0xb8, 0xfe, 0x00, 0xcc},       {0xb8, 0xff, 0x28, 0xcc},
+       {0xb9, 0x00, 0x28, 0xcc},       {0xb9, 0x01, 0x28, 0xcc},
+       {0xb9, 0x02, 0x28, 0xcc},       {0xb9, 0x03, 0x00, 0xcc},
+       {0xb9, 0x04, 0x00, 0xcc},       {0xb9, 0x05, 0x3c, 0xcc},
+       {0xb9, 0x06, 0x3c, 0xcc},       {0xb9, 0x07, 0x3c, 0xcc},
+       {0xb9, 0x08, 0x3c, 0xcc},       {0x00, 0x05, 0x00, 0xaa},
+       {0xb3, 0x5c, 0x00, 0xcc},       {0xb3, 0x01, 0x41, 0xcc},
+       {}
+};
+static __u8 po3130_rundata[][4] = {
+       {0x00, 0x47, 0x45, 0xaa},       {0x00, 0x48, 0x9b, 0xaa},
+       {0x00, 0x49, 0x3a, 0xaa},       {0x00, 0x4a, 0x01, 0xaa},
+       {0x00, 0x44, 0x40, 0xaa},
+/*     {0x00, 0xd5, 0x7c, 0xaa}, */
+       {0x00, 0xad, 0x04, 0xaa},       {0x00, 0xae, 0x00, 0xaa},
+       {0x00, 0xb0, 0x78, 0xaa},       {0x00, 0x98, 0x02, 0xaa},
+       {0x00, 0x94, 0x25, 0xaa},       {0x00, 0x95, 0x25, 0xaa},
+       {0x00, 0x59, 0x68, 0xaa},       {0x00, 0x44, 0x20, 0xaa},
+       {0x00, 0x17, 0x50, 0xaa},       {0x00, 0x19, 0x50, 0xaa},
+       {0x00, 0xd1, 0x3c, 0xaa},       {0x00, 0xd1, 0x3c, 0xaa},
+       {0x00, 0x1e, 0x06, 0xaa},       {0x00, 0x1e, 0x06, 0xaa},
+       {}
+};
+
+static __u8 po3130_initQVGA_data[][4] = {
+       {0xb0, 0x4d, 0x00, 0xcc},       {0xb3, 0x01, 0x01, 0xcc},
+       {0x00, 0x00, 0x50, 0xdd},       {0xb0, 0x03, 0x09, 0xcc},
+       {0xb3, 0x00, 0x04, 0xcc},       {0xb3, 0x00, 0x24, 0xcc},
+       {0xb3, 0x00, 0x25, 0xcc},       {0xb3, 0x08, 0x01, 0xcc},
+       {0xb3, 0x09, 0x0c, 0xcc},       {0xb3, 0x05, 0x00, 0xcc},
+       {0xb3, 0x06, 0x01, 0xcc},       {0xb3, 0x03, 0x1a, 0xcc},
+       {0xb3, 0x04, 0x15, 0xcc},       {0xb3, 0x20, 0x00, 0xcc},
+       {0xb3, 0x21, 0x00, 0xcc},       {0xb3, 0x22, 0x01, 0xcc},
+       {0xb3, 0x23, 0xe0, 0xcc},       {0xb8, 0x08, 0xe0, 0xcc},
+       {0xb3, 0x14, 0x00, 0xcc},       {0xb3, 0x15, 0x00, 0xcc},
+       {0xb3, 0x16, 0x02, 0xcc},       {0xb3, 0x17, 0x7f, 0xcc},
+       {0xb3, 0x34, 0x01, 0xcc},       {0xb3, 0x35, 0xf6, 0xcc},
+       {0xb3, 0x00, 0x27, 0xcc},       {0xbc, 0x00, 0xd1, 0xcc},
+       {0xb8, 0x00, 0x21, 0xcc},       {0xb8, 0x27, 0x20, 0xcc},
+       {0xb8, 0x01, 0x79, 0xcc},       {0xb8, 0x81, 0x09, 0xcc},
+       {0xb8, 0x2c, 0x50, 0xcc},       {0xb8, 0x2d, 0xf8, 0xcc},
+       {0xb8, 0x2e, 0xf8, 0xcc},       {0xb8, 0x2f, 0xf8, 0xcc},
+       {0xb8, 0x30, 0x50, 0xcc},       {0xb8, 0x31, 0xf8, 0xcc},
+       {0xb8, 0x32, 0xf8, 0xcc},       {0xb8, 0x33, 0xf8, 0xcc},
+       {0xb8, 0x34, 0x50, 0xcc},       {0xb8, 0x35, 0x00, 0xcc},
+       {0xb8, 0x36, 0x00, 0xcc},       {0xb8, 0x37, 0x00, 0xcc},
+       {0x00, 0x1e, 0xc6, 0xaa},       {0x00, 0x20, 0x44, 0xaa},
+       {0x00, 0xad, 0x02, 0xaa},       {0x00, 0xae, 0x2c, 0xaa},
+       {0x00, 0x12, 0x08, 0xaa},       {0x00, 0x17, 0x41, 0xaa},
+       {0x00, 0x19, 0x41, 0xaa},       {0x00, 0x1e, 0x06, 0xaa},
+       {0x00, 0x21, 0x00, 0xaa},       {0x00, 0x36, 0xc0, 0xaa},
+       {0x00, 0x37, 0xc8, 0xaa},       {0x00, 0x3b, 0x36, 0xaa},
+       {0x00, 0x4b, 0xfe, 0xaa},       {0x00, 0x51, 0x1c, 0xaa},
+       {0x00, 0x52, 0x01, 0xaa},       {0x00, 0x55, 0x0a, 0xaa},
+       {0x00, 0x59, 0x6f, 0xaa},       {0x00, 0x5a, 0x04, 0xaa},
+       {0x00, 0x5c, 0x10, 0xaa},       {0x00, 0x5d, 0x10, 0xaa},
+       {0x00, 0x5e, 0x10, 0xaa},       {0x00, 0x5f, 0x10, 0xaa},
+       {0x00, 0x61, 0x00, 0xaa},       {0x00, 0x62, 0x18, 0xaa},
+       {0x00, 0x63, 0x30, 0xaa},       {0x00, 0x70, 0x68, 0xaa},
+       {0x00, 0x80, 0x71, 0xaa},       {0x00, 0x81, 0x08, 0xaa},
+       {0x00, 0x82, 0x00, 0xaa},       {0x00, 0x83, 0x55, 0xaa},
+       {0x00, 0x84, 0x06, 0xaa},       {0x00, 0x85, 0x06, 0xaa},
+       {0x00, 0x86, 0x13, 0xaa},       {0x00, 0x87, 0x18, 0xaa},
+       {0x00, 0xaa, 0x3f, 0xaa},       {0x00, 0xab, 0x44, 0xaa},
+       {0x00, 0xb0, 0x68, 0xaa},       {0x00, 0xb5, 0x10, 0xaa},
+       {0x00, 0xb8, 0x20, 0xaa},       {0x00, 0xb9, 0xa0, 0xaa},
+       {0x00, 0xbc, 0x04, 0xaa},       {0x00, 0x8b, 0x40, 0xaa},
+       {0x00, 0x8c, 0x91, 0xaa},       {0x00, 0x8d, 0x8f, 0xaa},
+       {0x00, 0x8e, 0x91, 0xaa},       {0x00, 0x8f, 0x43, 0xaa},
+       {0x00, 0x90, 0x92, 0xaa},       {0x00, 0x91, 0x89, 0xaa},
+       {0x00, 0x92, 0x9d, 0xaa},       {0x00, 0x93, 0x46, 0xaa},
+       {0x00, 0xd6, 0x22, 0xaa},       {0x00, 0x73, 0x00, 0xaa},
+       {0x00, 0x74, 0x10, 0xaa},       {0x00, 0x75, 0x20, 0xaa},
+       {0x00, 0x76, 0x2b, 0xaa},       {0x00, 0x77, 0x36, 0xaa},
+       {0x00, 0x78, 0x49, 0xaa},       {0x00, 0x79, 0x5a, 0xaa},
+       {0x00, 0x7a, 0x7f, 0xaa},       {0x00, 0x7b, 0x9b, 0xaa},
+       {0x00, 0x7c, 0xba, 0xaa},       {0x00, 0x7d, 0xd4, 0xaa},
+       {0x00, 0x7e, 0xea, 0xaa},       {0x00, 0xd6, 0x62, 0xaa},
+       {0x00, 0x73, 0x00, 0xaa},       {0x00, 0x74, 0x10, 0xaa},
+       {0x00, 0x75, 0x20, 0xaa},       {0x00, 0x76, 0x2b, 0xaa},
+       {0x00, 0x77, 0x36, 0xaa},       {0x00, 0x78, 0x49, 0xaa},
+       {0x00, 0x79, 0x5a, 0xaa},       {0x00, 0x7a, 0x7f, 0xaa},
+       {0x00, 0x7b, 0x9b, 0xaa},       {0x00, 0x7c, 0xba, 0xaa},
+       {0x00, 0x7d, 0xd4, 0xaa},       {0x00, 0x7e, 0xea, 0xaa},
+       {0x00, 0xd6, 0xa2, 0xaa},       {0x00, 0x73, 0x00, 0xaa},
+       {0x00, 0x74, 0x10, 0xaa},       {0x00, 0x75, 0x20, 0xaa},
+       {0x00, 0x76, 0x2b, 0xaa},       {0x00, 0x77, 0x36, 0xaa},
+       {0x00, 0x78, 0x49, 0xaa},       {0x00, 0x79, 0x5a, 0xaa},
+       {0x00, 0x7a, 0x7f, 0xaa},       {0x00, 0x7b, 0x9b, 0xaa},
+       {0x00, 0x7c, 0xba, 0xaa},       {0x00, 0x7d, 0xd4, 0xaa},
+       {0x00, 0x7e, 0xea, 0xaa},       {0x00, 0x4c, 0x07, 0xaa},
+       {0x00, 0x4b, 0xe0, 0xaa},       {0x00, 0x4e, 0x77, 0xaa},
+       {0x00, 0x59, 0x66, 0xaa},       {0x00, 0x4d, 0x0a, 0xaa},
+       {0x00, 0xd1, 0x00, 0xaa},       {0x00, 0x20, 0xc4, 0xaa},
+       {0xb8, 0x8e, 0x00, 0xcc},       {0xb8, 0x8f, 0xff, 0xcc},
+       {0xb8, 0xfe, 0x00, 0xcc},       {0xb8, 0xff, 0x28, 0xcc},
+       {0xb9, 0x00, 0x28, 0xcc},       {0xb9, 0x01, 0x28, 0xcc},
+       {0xb9, 0x02, 0x28, 0xcc},       {0xb9, 0x03, 0x00, 0xcc},
+       {0xb9, 0x04, 0x00, 0xcc},       {0xb9, 0x05, 0x3c, 0xcc},
+       {0xb9, 0x06, 0x3c, 0xcc},       {0xb9, 0x07, 0x3c, 0xcc},
+       {0xb9, 0x08, 0x3c, 0xcc},       {0xbc, 0x02, 0x18, 0xcc},
+       {0xbc, 0x03, 0x50, 0xcc},       {0xbc, 0x04, 0x18, 0xcc},
+       {0xbc, 0x05, 0x00, 0xcc},       {0xbc, 0x06, 0x00, 0xcc},
+       {0xbc, 0x08, 0x30, 0xcc},       {0xbc, 0x09, 0x40, 0xcc},
+       {0xbc, 0x0a, 0x10, 0xcc},       {0xbc, 0x0b, 0x00, 0xcc},
+       {0xbc, 0x0c, 0x00, 0xcc},       {0x00, 0x05, 0x00, 0xaa},
+       {0xb3, 0x5c, 0x00, 0xcc},       {0xb3, 0x01, 0x41, 0xcc},
+       {}
+};
+
+static __u8 hv7131r_gamma[17] = {
+/*     0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
+ *     0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff */
+       0x04, 0x1a, 0x36, 0x55, 0x6f, 0x87, 0x9d, 0xb0, 0xc1,
+       0xcf, 0xda, 0xe4, 0xec, 0xf3, 0xf8, 0xfd, 0xff
+};
+static __u8 hv7131r_matrix[9] = {
+       0x5f, 0xec, 0xf5, 0xf1, 0x5a, 0xf5, 0xf1, 0xec, 0x63
+};
+static __u8 hv7131r_initVGA_data[][4] = {
+       {0xb0, 0x4d, 0x00, 0xcc},       {0xb3, 0x01, 0x01, 0xcc},
+       {0x00, 0x00, 0x50, 0xdd},       {0xb0, 0x03, 0x01, 0xcc},
+       {0xb3, 0x00, 0x24, 0xcc},
+       {0xb3, 0x00, 0x25, 0xcc},       {0xb3, 0x08, 0x01, 0xcc},
+       {0xb3, 0x09, 0x0c, 0xcc},       {0xb3, 0x05, 0x00, 0xcc},
+       {0xb3, 0x06, 0x01, 0xcc},
+       {0xb3, 0x01, 0x45, 0xcc},       {0xb3, 0x03, 0x0b, 0xcc},
+       {0xb3, 0x04, 0x05, 0xcc},       {0xb3, 0x20, 0x00, 0xcc},
+       {0xb3, 0x21, 0x00, 0xcc},
+       {0xb3, 0x22, 0x01, 0xcc},       {0xb3, 0x23, 0xe0, 0xcc},
+       {0xb3, 0x14, 0x00, 0xcc},       {0xb3, 0x15, 0x00, 0xcc},
+       {0xb3, 0x16, 0x02, 0xcc},
+       {0xb3, 0x17, 0x7f, 0xcc},       {0xb3, 0x34, 0x01, 0xcc},
+       {0xb3, 0x35, 0x91, 0xcc},       {0xb3, 0x00, 0x27, 0xcc},
+       {0xbc, 0x00, 0x73, 0xcc},
+       {0xb8, 0x00, 0x23, 0xcc},       {0x00, 0x01, 0x0c, 0xaa},
+       {0x00, 0x14, 0x01, 0xaa},       {0x00, 0x15, 0xe6, 0xaa},
+       {0x00, 0x16, 0x02, 0xaa},
+       {0x00, 0x17, 0x86, 0xaa},       {0x00, 0x23, 0x00, 0xaa},
+       {0x00, 0x25, 0x09, 0xaa},       {0x00, 0x26, 0x27, 0xaa},
+       {0x00, 0x27, 0xc0, 0xaa},
+       {0xb8, 0x2c, 0x60, 0xcc},       {0xb8, 0x2d, 0xf8, 0xcc},
+       {0xb8, 0x2e, 0xf8, 0xcc},       {0xb8, 0x2f, 0xf8, 0xcc},
+       {0xb8, 0x30, 0x50, 0xcc},
+       {0xb8, 0x31, 0xf8, 0xcc},       {0xb8, 0x32, 0xf8, 0xcc},
+       {0xb8, 0x33, 0xf8, 0xcc},       {0xb8, 0x34, 0x65, 0xcc},
+       {0xb8, 0x35, 0x00, 0xcc},
+       {0xb8, 0x36, 0x00, 0xcc},       {0xb8, 0x37, 0x00, 0xcc},
+       {0xb8, 0x27, 0x20, 0xcc},       {0xb8, 0x01, 0x7d, 0xcc},
+       {0xb8, 0x81, 0x09, 0xcc},
+       {0xb3, 0x01, 0x41, 0xcc},       {0xb8, 0xfe, 0x00, 0xcc},
+       {0xb8, 0xff, 0x28, 0xcc},       {0xb9, 0x00, 0x28, 0xcc},
+       {0xb9, 0x01, 0x28, 0xcc},
+       {0xb9, 0x02, 0x28, 0xcc},       {0xb9, 0x03, 0x00, 0xcc},
+       {0xb9, 0x04, 0x00, 0xcc},       {0xb9, 0x05, 0x3c, 0xcc},
+       {0xb9, 0x06, 0x3c, 0xcc},
+       {0xb9, 0x07, 0x3c, 0xcc},       {0xb9, 0x08, 0x3c, 0xcc},
+       {0xb8, 0x8e, 0x00, 0xcc},       {0xb8, 0x8f, 0xff, 0xcc},
+       {0x00, 0x30, 0x18, 0xaa},
+       {}
+};
+
+static __u8 hv7131r_initQVGA_data[][4] = {
+       {0xb0, 0x4d, 0x00, 0xcc},       {0xb3, 0x01, 0x01, 0xcc},
+       {0x00, 0x00, 0x50, 0xdd},       {0xb0, 0x03, 0x01, 0xcc},
+       {0xb3, 0x00, 0x24, 0xcc},
+       {0xb3, 0x00, 0x25, 0xcc},       {0xb3, 0x08, 0x01, 0xcc},
+       {0xb3, 0x09, 0x0c, 0xcc},       {0xb3, 0x05, 0x00, 0xcc},
+       {0xb3, 0x06, 0x01, 0xcc},
+       {0xb3, 0x03, 0x0b, 0xcc},       {0xb3, 0x04, 0x05, 0xcc},
+       {0xb3, 0x20, 0x00, 0xcc},       {0xb3, 0x21, 0x00, 0xcc},
+       {0xb3, 0x22, 0x01, 0xcc},
+       {0xb3, 0x23, 0xe0, 0xcc},       {0xb3, 0x14, 0x00, 0xcc},
+       {0xb3, 0x15, 0x00, 0xcc},       {0xb3, 0x16, 0x02, 0xcc},
+       {0xb3, 0x17, 0x7f, 0xcc},
+       {0xb3, 0x34, 0x01, 0xcc},       {0xb3, 0x35, 0x91, 0xcc},
+       {0xb3, 0x00, 0x27, 0xcc},       {0xbc, 0x00, 0xd1, 0xcc},
+       {0xb8, 0x00, 0x21, 0xcc},
+       {0x00, 0x01, 0x0c, 0xaa},       {0x00, 0x14, 0x01, 0xaa},
+       {0x00, 0x15, 0xe6, 0xaa},       {0x00, 0x16, 0x02, 0xaa},
+       {0x00, 0x17, 0x86, 0xaa},
+       {0x00, 0x23, 0x00, 0xaa},       {0x00, 0x25, 0x01, 0xaa},
+       {0x00, 0x26, 0xd4, 0xaa},       {0x00, 0x27, 0xc0, 0xaa},
+       {0xbc, 0x02, 0x08, 0xcc},
+       {0xbc, 0x03, 0x70, 0xcc},       {0xbc, 0x04, 0x08, 0xcc},
+       {0xbc, 0x05, 0x00, 0xcc},       {0xbc, 0x06, 0x00, 0xcc},
+       {0xbc, 0x08, 0x3c, 0xcc},
+       {0xbc, 0x09, 0x40, 0xcc},       {0xbc, 0x0a, 0x04, 0xcc},
+       {0xbc, 0x0b, 0x00, 0xcc},       {0xbc, 0x0c, 0x00, 0xcc},
+       {0xb8, 0xfe, 0x02, 0xcc},
+       {0xb8, 0xff, 0x07, 0xcc},       {0xb9, 0x00, 0x14, 0xcc},
+       {0xb9, 0x01, 0x14, 0xcc},       {0xb9, 0x02, 0x14, 0xcc},
+       {0xb9, 0x03, 0x00, 0xcc},
+       {0xb9, 0x04, 0x02, 0xcc},       {0xb9, 0x05, 0x05, 0xcc},
+       {0xb9, 0x06, 0x0f, 0xcc},       {0xb9, 0x07, 0x0f, 0xcc},
+       {0xb9, 0x08, 0x0f, 0xcc},
+       {0xb8, 0x2c, 0x60, 0xcc},       {0xb8, 0x2d, 0xf8, 0xcc},
+       {0xb8, 0x2e, 0xf8, 0xcc},       {0xb8, 0x2f, 0xf8, 0xcc},
+       {0xb8, 0x30, 0x50, 0xcc},
+       {0xb8, 0x31, 0xf8, 0xcc},       {0xb8, 0x32, 0xf8, 0xcc},
+       {0xb8, 0x33, 0xf8, 0xcc},
+       {0xb8, 0x34, 0x65, 0xcc},       {0xb8, 0x35, 0x00, 0xcc},
+       {0xb8, 0x36, 0x00, 0xcc},       {0xb8, 0x37, 0x00, 0xcc},
+       {0xb8, 0x27, 0x20, 0xcc},
+       {0xb8, 0x01, 0x7d, 0xcc},       {0xb8, 0x81, 0x09, 0xcc},
+       {0xb3, 0x01, 0x41, 0xcc},       {0xb8, 0xfe, 0x00, 0xcc},
+       {0xb8, 0xff, 0x28, 0xcc},
+       {0xb9, 0x00, 0x28, 0xcc},       {0xb9, 0x01, 0x28, 0xcc},
+       {0xb9, 0x02, 0x28, 0xcc},       {0xb9, 0x03, 0x00, 0xcc},
+       {0xb9, 0x04, 0x00, 0xcc},
+       {0xb9, 0x05, 0x3c, 0xcc},       {0xb9, 0x06, 0x3c, 0xcc},
+       {0xb9, 0x07, 0x3c, 0xcc},       {0xb9, 0x08, 0x3c, 0xcc},
+       {0xb8, 0x8e, 0x00, 0xcc},
+       {0xb8, 0x8f, 0xff, 0xcc},       {0x00, 0x30, 0x18, 0xaa},
+       {}
+};
+
+static __u8 ov7660_gamma[17] = {
+       0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
+       0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff
+};
+static __u8 ov7660_matrix[9] = {
+       0x5a, 0xf0, 0xf6, 0xf3, 0x57, 0xf6, 0xf3, 0xef, 0x62
+};
+static __u8 ov7660_initVGA_data[][4] = {
+       {0xb0, 0x4d, 0x00, 0xcc},       {0xb3, 0x01, 0x01, 0xcc},
+       {0x00, 0x00, 0x50, 0xdd},
+       {0xb0, 0x03, 0x01, 0xcc},
+       {0xb3, 0x00, 0x21, 0xcc},       {0xb3, 0x00, 0x26, 0xcc},
+       {0xb3, 0x05, 0x01, 0xcc},
+       {0xb3, 0x06, 0x03, 0xcc},
+       {0xb3, 0x03, 0x1f, 0xcc},       {0xb3, 0x04, 0x05, 0xcc},
+       {0xb3, 0x05, 0x00, 0xcc},
+       {0xb3, 0x06, 0x01, 0xcc},
+       {0xb3, 0x15, 0x00, 0xcc},/* 0xb315  <-0 href startl */
+       {0xb3, 0x16, 0x02, 0xcc},       {0xb3, 0x17, 0x7f, 0xcc},
+       {0xb3, 0x21, 0x00, 0xcc},
+       {0xb3, 0x23, 0xe0, 0xcc},       {0xb3, 0x1d, 0x01, 0xcc},
+       {0xb3, 0x1f, 0x02, 0xcc},
+       {0xb3, 0x34, 0x01, 0xcc},
+       {0xb3, 0x35, 0xa1, 0xcc},       {0xb3, 0x00, 0x26, 0xcc},
+       {0xb8, 0x00, 0x33, 0xcc}, /* 13 */
+       {0xb8, 0x01, 0x7d, 0xcc},
+       {0xbc, 0x00, 0x73, 0xcc},       {0xb8, 0x81, 0x09, 0xcc},
+       {0xb8, 0x27, 0x20, 0xcc},
+       {0xb8, 0x8f, 0x50, 0xcc},
+       {0x00, 0x01, 0x80, 0xaa},       {0x00, 0x02, 0x80, 0xaa},
+       {0x00, 0x12, 0x80, 0xaa},
+       {0x00, 0x12, 0x05, 0xaa},
+       {0x00, 0x1e, 0x01, 0xaa},
+       {0x00, 0x3d, 0x40, 0xaa}, /* 0x3d <-40 gamma 01 */
+       {0x00, 0x41, 0x00, 0xaa}, /* edge 00 */
+       {0x00, 0x0d, 0x48, 0xaa},       {0x00, 0x0e, 0x04, 0xaa},
+       {0x00, 0x13, 0xa7, 0xaa},
+       {0x00, 0x40, 0xc1, 0xaa},       {0x00, 0x35, 0x00, 0xaa},
+       {0x00, 0x36, 0x00, 0xaa},
+       {0x00, 0x3c, 0x68, 0xaa},       {0x00, 0x1b, 0x05, 0xaa},
+       {0x00, 0x39, 0x43, 0xaa},
+       {0x00, 0x8d, 0xcf, 0xaa},
+       {0x00, 0x8b, 0xcc, 0xaa},       {0x00, 0x8c, 0xcc, 0xaa},
+       {0x00, 0x0f, 0x62, 0xaa},
+       {0x00, 0x35, 0x84, 0xaa},
+       {0x00, 0x3b, 0x08, 0xaa}, /* 0 * Nightframe 1/4 + 50Hz -> 0xC8 */
+       {0x00, 0x3a, 0x00, 0xaa}, /* mx change yuyv format 00, 04, 01; 08, 0c*/
+       {0x00, 0x14, 0x2a, 0xaa}, /* agc ampli */
+       {0x00, 0x9e, 0x40, 0xaa},       {0xb8, 0x8f, 0x50, 0xcc},
+       {0x00, 0x01, 0x80, 0xaa},
+       {0x00, 0x02, 0x80, 0xaa},
+       {0xb8, 0xfe, 0x00, 0xcc},       {0xb8, 0xff, 0x28, 0xcc},
+       {0xb9, 0x00, 0x28, 0xcc},
+       {0xb9, 0x01, 0x28, 0xcc},       {0xb9, 0x02, 0x28, 0xcc},
+       {0xb9, 0x03, 0x00, 0xcc},
+       {0xb9, 0x04, 0x00, 0xcc},
+       {0xb9, 0x05, 0x3c, 0xcc},       {0xb9, 0x06, 0x3c, 0xcc},
+       {0xb9, 0x07, 0x3c, 0xcc},
+       {0xb9, 0x08, 0x3c, 0xcc},
+
+       {0xb8, 0x8e, 0x00, 0xcc},       {0xb8, 0x8f, 0xff, 0xcc},
+
+       {0x00, 0x29, 0x3c, 0xaa},       {0xb3, 0x01, 0x45, 0xcc},
+       {}
+};
+static __u8 ov7660_initQVGA_data[][4] = {
+       {0xb0, 0x4d, 0x00, 0xcc},       {0xb3, 0x01, 0x01, 0xcc},
+       {0x00, 0x00, 0x50, 0xdd},       {0xb0, 0x03, 0x01, 0xcc},
+       {0xb3, 0x00, 0x21, 0xcc},       {0xb3, 0x00, 0x26, 0xcc},
+       {0xb3, 0x05, 0x01, 0xcc},       {0xb3, 0x06, 0x03, 0xcc},
+       {0xb3, 0x03, 0x1f, 0xcc},       {0xb3, 0x04, 0x05, 0xcc},
+       {0xb3, 0x05, 0x00, 0xcc},       {0xb3, 0x06, 0x01, 0xcc},
+       {0xb3, 0x15, 0x00, 0xcc},/* 0xb315  <-0 href startl */
+       {0xb3, 0x16, 0x02, 0xcc},       {0xb3, 0x17, 0x7f, 0xcc},
+       {0xb3, 0x21, 0x00, 0xcc},
+       {0xb3, 0x23, 0xe0, 0xcc},       {0xb3, 0x1d, 0x01, 0xcc},
+       {0xb3, 0x1f, 0x02, 0xcc},       {0xb3, 0x34, 0x01, 0xcc},
+       {0xb3, 0x35, 0xa1, 0xcc},       {0xb3, 0x00, 0x26, 0xcc},
+       {0xb8, 0x00, 0x33, 0xcc}, /* 13 */
+       {0xb8, 0x01, 0x7d, 0xcc},
+/* sizer */
+       {0xbc, 0x00, 0xd3, 0xcc},
+       {0xb8, 0x81, 0x09, 0xcc},       {0xb8, 0x81, 0x09, 0xcc},
+       {0xb8, 0x27, 0x20, 0xcc},       {0xb8, 0x8f, 0x50, 0xcc},
+       {0x00, 0x01, 0x80, 0xaa},       {0x00, 0x02, 0x80, 0xaa},
+       {0x00, 0x12, 0x80, 0xaa},       {0x00, 0x12, 0x05, 0xaa},
+       {0x00, 0x1e, 0x01, 0xaa},
+       {0x00, 0x3d, 0x40, 0xaa}, /* 0x3d <-40 gamma 01 */
+       {0x00, 0x41, 0x00, 0xaa}, /* edge 00 */
+       {0x00, 0x0d, 0x48, 0xaa},       {0x00, 0x0e, 0x04, 0xaa},
+       {0x00, 0x13, 0xa7, 0xaa},
+       {0x00, 0x40, 0xc1, 0xaa},       {0x00, 0x35, 0x00, 0xaa},
+       {0x00, 0x36, 0x00, 0xaa},
+       {0x00, 0x3c, 0x68, 0xaa},       {0x00, 0x1b, 0x05, 0xaa},
+       {0x00, 0x39, 0x43, 0xaa},       {0x00, 0x8d, 0xcf, 0xaa},
+       {0x00, 0x8b, 0xcc, 0xaa},       {0x00, 0x8c, 0xcc, 0xaa},
+       {0x00, 0x0f, 0x62, 0xaa},       {0x00, 0x35, 0x84, 0xaa},
+       {0x00, 0x3b, 0x08, 0xaa}, /* 0  * Nightframe 1/4 + 50Hz -> 0xC8 */
+       {0x00, 0x3a, 0x00, 0xaa}, /* mx change yuyv format 00, 04, 01; 08, 0c*/
+       {0x00, 0x14, 0x2a, 0xaa}, /* agc ampli */
+       {0x00, 0x9e, 0x40, 0xaa},       {0xb8, 0x8f, 0x50, 0xcc},
+       {0x00, 0x01, 0x80, 0xaa},
+       {0x00, 0x02, 0x80, 0xaa},
+/* sizer filters */
+       {0xbc, 0x02, 0x08, 0xcc},
+       {0xbc, 0x03, 0x70, 0xcc},
+       {0xb8, 0x35, 0x00, 0xcc},
+       {0xb8, 0x36, 0x00, 0xcc},
+       {0xb8, 0x37, 0x00, 0xcc},
+       {0xbc, 0x04, 0x08, 0xcc},
+       {0xbc, 0x05, 0x00, 0xcc},
+       {0xbc, 0x06, 0x00, 0xcc},
+       {0xbc, 0x08, 0x3c, 0xcc},
+       {0xbc, 0x09, 0x40, 0xcc},
+       {0xbc, 0x0a, 0x04, 0xcc},
+       {0xbc, 0x0b, 0x00, 0xcc},
+       {0xbc, 0x0c, 0x00, 0xcc},
+/* */
+       {0xb8, 0xfe, 0x00, 0xcc},
+       {0xb8, 0xff, 0x28, 0xcc},
+/* */
+       {0xb9, 0x00, 0x28, 0xcc},       {0xb9, 0x01, 0x28, 0xcc},
+       {0xb9, 0x02, 0x28, 0xcc},       {0xb9, 0x03, 0x00, 0xcc},
+       {0xb9, 0x04, 0x00, 0xcc},       {0xb9, 0x05, 0x3c, 0xcc},
+       {0xb9, 0x06, 0x3c, 0xcc},       {0xb9, 0x07, 0x3c, 0xcc},
+       {0xb9, 0x08, 0x3c, 0xcc},
+/* */
+       {0xb8, 0x8e, 0x00, 0xcc},
+       {0xb8, 0x8f, 0xff, 0xcc}, /* ff */
+       {0x00, 0x29, 0x3c, 0xaa},
+       {0xb3, 0x01, 0x45, 0xcc}, /* 45 */
+       {0x00, 0x00, 0x00, 0x00}
+};
+
+static __u8 ov7660_50HZ[][4] = {
+       {0x00, 0x3b, 0x08, 0xaa},
+       {0x00, 0x9d, 0x40, 0xaa},
+       {0x00, 0x13, 0xa7, 0xaa},
+       {0x00, 0x00, 0x00, 0x00}
+};
+
+static __u8 ov7660_60HZ[][4] = {
+       {0x00, 0x3b, 0x00, 0xaa},
+       {0x00, 0x9e, 0x40, 0xaa},
+       {0x00, 0x13, 0xa7, 0xaa},
+       {}
+};
+
+static __u8 ov7660_NoFliker[][4] = {
+       {0x00, 0x13, 0x87, 0xaa},
+       {}
+};
+
+static __u8 ov7670_initVGA_JPG[][4] = {
+       {0xb3, 0x01, 0x05, 0xcc},
+       {0x00, 0x00, 0x30, 0xdd},       {0xb0, 0x03, 0x19, 0xcc},
+       {0x00, 0x00, 0x10, 0xdd},
+       {0xb0, 0x04, 0x02, 0xcc},       {0x00, 0x00, 0x10, 0xdd},
+       {0xb3, 0x00, 0x66, 0xcc},       {0xb3, 0x00, 0x67, 0xcc},
+       {0xb3, 0x35, 0xa1, 0xcc},       {0xb3, 0x34, 0x01, 0xcc},
+       {0xb3, 0x05, 0x01, 0xcc},       {0xb3, 0x06, 0x01, 0xcc},
+       {0xb3, 0x08, 0x01, 0xcc},       {0xb3, 0x09, 0x0c, 0xcc},
+       {0xb3, 0x02, 0x02, 0xcc},       {0xb3, 0x03, 0x1f, 0xcc},
+       {0xb3, 0x14, 0x00, 0xcc},       {0xb3, 0x15, 0x00, 0xcc},
+       {0xb3, 0x16, 0x02, 0xcc},       {0xb3, 0x17, 0x7f, 0xcc},
+       {0xb3, 0x04, 0x05, 0xcc},       {0xb3, 0x20, 0x00, 0xcc},
+       {0xb3, 0x21, 0x00, 0xcc},       {0xb3, 0x22, 0x01, 0xcc},
+       {0xb3, 0x23, 0xe0, 0xcc},       {0xbc, 0x00, 0x41, 0xcc},
+       {0xbc, 0x01, 0x01, 0xcc},       {0x00, 0x12, 0x80, 0xaa},
+       {0x00, 0x00, 0x20, 0xdd},       {0x00, 0x12, 0x00, 0xaa},
+       {0x00, 0x11, 0x40, 0xaa},       {0x00, 0x6b, 0x0a, 0xaa},
+       {0x00, 0x3a, 0x04, 0xaa},       {0x00, 0x40, 0xc0, 0xaa},
+       {0x00, 0x8c, 0x00, 0xaa},       {0x00, 0x7a, 0x29, 0xaa},
+       {0x00, 0x7b, 0x0e, 0xaa},       {0x00, 0x7c, 0x1a, 0xaa},
+       {0x00, 0x7d, 0x31, 0xaa},       {0x00, 0x7e, 0x53, 0xaa},
+       {0x00, 0x7f, 0x60, 0xaa},       {0x00, 0x80, 0x6b, 0xaa},
+       {0x00, 0x81, 0x73, 0xaa},       {0x00, 0x82, 0x7b, 0xaa},
+       {0x00, 0x83, 0x82, 0xaa},       {0x00, 0x84, 0x89, 0xaa},
+       {0x00, 0x85, 0x96, 0xaa},       {0x00, 0x86, 0xa1, 0xaa},
+       {0x00, 0x87, 0xb7, 0xaa},       {0x00, 0x88, 0xcc, 0xaa},
+       {0x00, 0x89, 0xe1, 0xaa},       {0x00, 0x13, 0xe0, 0xaa},
+       {0x00, 0x00, 0x00, 0xaa},       {0x00, 0x10, 0x00, 0xaa},
+       {0x00, 0x0d, 0x40, 0xaa},       {0x00, 0x14, 0x28, 0xaa},
+       {0x00, 0xa5, 0x05, 0xaa},       {0x00, 0xab, 0x07, 0xaa},
+       {0x00, 0x24, 0x95, 0xaa},       {0x00, 0x25, 0x33, 0xaa},
+       {0x00, 0x26, 0xe3, 0xaa},       {0x00, 0x9f, 0x88, 0xaa},
+       {0x00, 0xa0, 0x78, 0xaa},       {0x00, 0x55, 0x90, 0xaa},
+       {0x00, 0xa1, 0x03, 0xaa},       {0x00, 0xa6, 0xe0, 0xaa},
+       {0x00, 0xa7, 0xd8, 0xaa},       {0x00, 0xa8, 0xf0, 0xaa},
+       {0x00, 0xa9, 0x90, 0xaa},       {0x00, 0xaa, 0x14, 0xaa},
+       {0x00, 0x13, 0xe5, 0xaa},       {0x00, 0x0e, 0x61, 0xaa},
+       {0x00, 0x0f, 0x4b, 0xaa},       {0x00, 0x16, 0x02, 0xaa},
+       {0x00, 0x1e, 0x07, 0xaa},       {0x00, 0x21, 0x02, 0xaa},
+       {0x00, 0x22, 0x91, 0xaa},       {0x00, 0x29, 0x07, 0xaa},
+       {0x00, 0x33, 0x0b, 0xaa},       {0x00, 0x35, 0x0b, 0xaa},
+       {0x00, 0x37, 0x1d, 0xaa},       {0x00, 0x38, 0x71, 0xaa},
+       {0x00, 0x39, 0x2a, 0xaa},       {0x00, 0x3c, 0x78, 0xaa},
+       {0x00, 0x4d, 0x40, 0xaa},       {0x00, 0x4e, 0x20, 0xaa},
+       {0x00, 0x74, 0x19, 0xaa},       {0x00, 0x8d, 0x4f, 0xaa},
+       {0x00, 0x8e, 0x00, 0xaa},       {0x00, 0x8f, 0x00, 0xaa},
+       {0x00, 0x90, 0x00, 0xaa},       {0x00, 0x91, 0x00, 0xaa},
+       {0x00, 0x96, 0x00, 0xaa},       {0x00, 0x9a, 0x80, 0xaa},
+       {0x00, 0xb0, 0x84, 0xaa},       {0x00, 0xb1, 0x0c, 0xaa},
+       {0x00, 0xb2, 0x0e, 0xaa},       {0x00, 0xb3, 0x82, 0xaa},
+       {0x00, 0xb8, 0x0a, 0xaa},       {0x00, 0x43, 0x14, 0xaa},
+       {0x00, 0x44, 0xf0, 0xaa},       {0x00, 0x45, 0x45, 0xaa},
+       {0x00, 0x46, 0x63, 0xaa},       {0x00, 0x47, 0x2d, 0xaa},
+       {0x00, 0x48, 0x46, 0xaa},       {0x00, 0x59, 0x88, 0xaa},
+       {0x00, 0x5a, 0xa0, 0xaa},       {0x00, 0x5b, 0xc6, 0xaa},
+       {0x00, 0x5c, 0x7d, 0xaa},       {0x00, 0x5d, 0x5f, 0xaa},
+       {0x00, 0x5e, 0x19, 0xaa},       {0x00, 0x6c, 0x0a, 0xaa},
+       {0x00, 0x6d, 0x55, 0xaa},       {0x00, 0x6e, 0x11, 0xaa},
+       {0x00, 0x6f, 0x9e, 0xaa},       {0x00, 0x69, 0x00, 0xaa},
+       {0x00, 0x6a, 0x40, 0xaa},       {0x00, 0x01, 0x40, 0xaa},
+       {0x00, 0x02, 0x40, 0xaa},       {0x00, 0x13, 0xe7, 0xaa},
+       {0x00, 0x5f, 0xf0, 0xaa},       {0x00, 0x60, 0xf0, 0xaa},
+       {0x00, 0x61, 0xf0, 0xaa},       {0x00, 0x27, 0xa0, 0xaa},
+       {0x00, 0x28, 0x80, 0xaa},       {0x00, 0x2c, 0x90, 0xaa},
+       {0x00, 0x4f, 0x66, 0xaa},       {0x00, 0x50, 0x66, 0xaa},
+       {0x00, 0x51, 0x00, 0xaa},       {0x00, 0x52, 0x22, 0xaa},
+       {0x00, 0x53, 0x5e, 0xaa},       {0x00, 0x54, 0x80, 0xaa},
+       {0x00, 0x58, 0x9e, 0xaa},       {0x00, 0x41, 0x08, 0xaa},
+       {0x00, 0x3f, 0x00, 0xaa},       {0x00, 0x75, 0x85, 0xaa},
+       {0x00, 0x76, 0xe1, 0xaa},       {0x00, 0x4c, 0x00, 0xaa},
+       {0x00, 0x77, 0x0a, 0xaa},       {0x00, 0x3d, 0x88, 0xaa},
+       {0x00, 0x4b, 0x09, 0xaa},       {0x00, 0xc9, 0x60, 0xaa},
+       {0x00, 0x41, 0x38, 0xaa},       {0x00, 0x62, 0x30, 0xaa},
+       {0x00, 0x63, 0x30, 0xaa},       {0x00, 0x64, 0x08, 0xaa},
+       {0x00, 0x94, 0x07, 0xaa},       {0x00, 0x95, 0x0b, 0xaa},
+       {0x00, 0x65, 0x00, 0xaa},       {0x00, 0x66, 0x05, 0xaa},
+       {0x00, 0x56, 0x50, 0xaa},       {0x00, 0x34, 0x11, 0xaa},
+       {0x00, 0xa4, 0x88, 0xaa},       {0x00, 0x96, 0x00, 0xaa},
+       {0x00, 0x97, 0x30, 0xaa},       {0x00, 0x98, 0x20, 0xaa},
+       {0x00, 0x99, 0x30, 0xaa},       {0x00, 0x9a, 0x84, 0xaa},
+       {0x00, 0x9b, 0x29, 0xaa},       {0x00, 0x9c, 0x03, 0xaa},
+       {0x00, 0x78, 0x04, 0xaa},       {0x00, 0x79, 0x01, 0xaa},
+       {0x00, 0xc8, 0xf0, 0xaa},       {0x00, 0x79, 0x0f, 0xaa},
+       {0x00, 0xc8, 0x00, 0xaa},       {0x00, 0x79, 0x10, 0xaa},
+       {0x00, 0xc8, 0x7e, 0xaa},       {0x00, 0x79, 0x0a, 0xaa},
+       {0x00, 0xc8, 0x80, 0xaa},       {0x00, 0x79, 0x0b, 0xaa},
+       {0x00, 0xc8, 0x01, 0xaa},       {0x00, 0x79, 0x0c, 0xaa},
+       {0x00, 0xc8, 0x0f, 0xaa},       {0x00, 0x79, 0x0d, 0xaa},
+       {0x00, 0xc8, 0x20, 0xaa},       {0x00, 0x79, 0x09, 0xaa},
+       {0x00, 0xc8, 0x80, 0xaa},       {0x00, 0x79, 0x02, 0xaa},
+       {0x00, 0xc8, 0xc0, 0xaa},       {0x00, 0x79, 0x03, 0xaa},
+       {0x00, 0xc8, 0x40, 0xaa},       {0x00, 0x79, 0x05, 0xaa},
+       {0x00, 0xc8, 0x30, 0xaa},       {0x00, 0x79, 0x26, 0xaa},
+       {0x00, 0x11, 0x40, 0xaa},       {0x00, 0x3a, 0x04, 0xaa},
+       {0x00, 0x12, 0x00, 0xaa},       {0x00, 0x40, 0xc0, 0xaa},
+       {0x00, 0x8c, 0x00, 0xaa},       {0x00, 0x17, 0x14, 0xaa},
+       {0x00, 0x18, 0x02, 0xaa},       {0x00, 0x32, 0x92, 0xaa},
+       {0x00, 0x19, 0x02, 0xaa},       {0x00, 0x1a, 0x7a, 0xaa},
+       {0x00, 0x03, 0x0a, 0xaa},       {0x00, 0x0c, 0x00, 0xaa},
+       {0x00, 0x3e, 0x00, 0xaa},       {0x00, 0x70, 0x3a, 0xaa},
+       {0x00, 0x71, 0x35, 0xaa},       {0x00, 0x72, 0x11, 0xaa},
+       {0x00, 0x73, 0xf0, 0xaa},       {0x00, 0xa2, 0x02, 0xaa},
+       {0x00, 0xb1, 0x00, 0xaa},       {0x00, 0xb1, 0x0c, 0xaa},
+       {0x00, 0x1e, 0x37, 0xaa},       {0x00, 0xaa, 0x14, 0xaa},
+       {0x00, 0x24, 0x80, 0xaa},       {0x00, 0x25, 0x74, 0xaa},
+       {0x00, 0x26, 0xd3, 0xaa},       {0x00, 0x0d, 0x00, 0xaa},
+       {0x00, 0x14, 0x18, 0xaa},       {0x00, 0x9d, 0x99, 0xaa},
+       {0x00, 0x9e, 0x7f, 0xaa},       {0x00, 0x64, 0x08, 0xaa},
+       {0x00, 0x94, 0x07, 0xaa},       {0x00, 0x95, 0x06, 0xaa},
+       {0x00, 0x66, 0x05, 0xaa},       {0x00, 0x41, 0x08, 0xaa},
+       {0x00, 0x3f, 0x00, 0xaa},       {0x00, 0x75, 0x07, 0xaa},
+       {0x00, 0x76, 0xe1, 0xaa},       {0x00, 0x4c, 0x00, 0xaa},
+       {0x00, 0x77, 0x00, 0xaa},       {0x00, 0x3d, 0xc2, 0xaa},
+       {0x00, 0x4b, 0x09, 0xaa},       {0x00, 0xc9, 0x60, 0xaa},
+       {0x00, 0x41, 0x38, 0xaa},       {0xb6, 0x00, 0x00, 0xcc},
+       {0xb6, 0x03, 0x02, 0xcc},       {0xb6, 0x02, 0x80, 0xcc},
+       {0xb6, 0x05, 0x01, 0xcc},       {0xb6, 0x04, 0xe0, 0xcc},
+       {0xb6, 0x12, 0xf8, 0xcc},       {0xb6, 0x13, 0x13, 0xcc},
+       {0xb6, 0x18, 0x02, 0xcc},       {0xb6, 0x17, 0x58, 0xcc},
+       {0xb6, 0x16, 0x00, 0xcc},       {0xb6, 0x22, 0x12, 0xcc},
+       {0xb6, 0x23, 0x0b, 0xcc},       {0xbf, 0xc0, 0x39, 0xcc},
+       {0xbf, 0xc1, 0x04, 0xcc},       {0xbf, 0xcc, 0x00, 0xcc},
+       {0xb3, 0x5c, 0x01, 0xcc},       {0xb3, 0x01, 0x45, 0xcc},
+       {0x00, 0x77, 0x05, 0xaa},
+       {},
+};
+
+static __u8 ov7670_initQVGA_JPG[][4] = {
+       {0xb3, 0x01, 0x05, 0xcc},       {0x00, 0x00, 0x30, 0xdd},
+       {0xb0, 0x03, 0x19, 0xcc},       {0x00, 0x00, 0x10, 0xdd},
+       {0xb0, 0x04, 0x02, 0xcc},       {0x00, 0x00, 0x10, 0xdd},
+       {0xb3, 0x00, 0x66, 0xcc},       {0xb3, 0x00, 0x67, 0xcc},
+       {0xb3, 0x35, 0xa1, 0xcc},       {0xb3, 0x34, 0x01, 0xcc},
+       {0xb3, 0x05, 0x01, 0xcc},       {0xb3, 0x06, 0x01, 0xcc},
+       {0xb3, 0x08, 0x01, 0xcc},       {0xb3, 0x09, 0x0c, 0xcc},
+       {0xb3, 0x02, 0x02, 0xcc},       {0xb3, 0x03, 0x1f, 0xcc},
+       {0xb3, 0x14, 0x00, 0xcc},       {0xb3, 0x15, 0x00, 0xcc},
+       {0xb3, 0x16, 0x02, 0xcc},       {0xb3, 0x17, 0x7f, 0xcc},
+       {0xb3, 0x04, 0x05, 0xcc},       {0xb3, 0x20, 0x00, 0xcc},
+       {0xb3, 0x21, 0x00, 0xcc},       {0xb3, 0x22, 0x01, 0xcc},
+       {0xb3, 0x23, 0xe0, 0xcc},       {0xbc, 0x00, 0xd1, 0xcc},
+       {0xbc, 0x01, 0x01, 0xcc},       {0x00, 0x12, 0x80, 0xaa},
+       {0x00, 0x00, 0x20, 0xdd},       {0x00, 0x12, 0x00, 0xaa},
+       {0x00, 0x11, 0x40, 0xaa},       {0x00, 0x6b, 0x0a, 0xaa},
+       {0x00, 0x3a, 0x04, 0xaa},       {0x00, 0x40, 0xc0, 0xaa},
+       {0x00, 0x8c, 0x00, 0xaa},       {0x00, 0x7a, 0x29, 0xaa},
+       {0x00, 0x7b, 0x0e, 0xaa},       {0x00, 0x7c, 0x1a, 0xaa},
+       {0x00, 0x7d, 0x31, 0xaa},       {0x00, 0x7e, 0x53, 0xaa},
+       {0x00, 0x7f, 0x60, 0xaa},       {0x00, 0x80, 0x6b, 0xaa},
+       {0x00, 0x81, 0x73, 0xaa},       {0x00, 0x82, 0x7b, 0xaa},
+       {0x00, 0x83, 0x82, 0xaa},       {0x00, 0x84, 0x89, 0xaa},
+       {0x00, 0x85, 0x96, 0xaa},       {0x00, 0x86, 0xa1, 0xaa},
+       {0x00, 0x87, 0xb7, 0xaa},       {0x00, 0x88, 0xcc, 0xaa},
+       {0x00, 0x89, 0xe1, 0xaa},       {0x00, 0x13, 0xe0, 0xaa},
+       {0x00, 0x00, 0x00, 0xaa},       {0x00, 0x10, 0x00, 0xaa},
+       {0x00, 0x0d, 0x40, 0xaa},       {0x00, 0x14, 0x28, 0xaa},
+       {0x00, 0xa5, 0x05, 0xaa},       {0x00, 0xab, 0x07, 0xaa},
+       {0x00, 0x24, 0x95, 0xaa},       {0x00, 0x25, 0x33, 0xaa},
+       {0x00, 0x26, 0xe3, 0xaa},       {0x00, 0x9f, 0x88, 0xaa},
+       {0x00, 0xa0, 0x78, 0xaa},       {0x00, 0x55, 0x90, 0xaa},
+       {0x00, 0xa1, 0x03, 0xaa},       {0x00, 0xa6, 0xe0, 0xaa},
+       {0x00, 0xa7, 0xd8, 0xaa},       {0x00, 0xa8, 0xf0, 0xaa},
+       {0x00, 0xa9, 0x90, 0xaa},       {0x00, 0xaa, 0x14, 0xaa},
+       {0x00, 0x13, 0xe5, 0xaa},       {0x00, 0x0e, 0x61, 0xaa},
+       {0x00, 0x0f, 0x4b, 0xaa},       {0x00, 0x16, 0x02, 0xaa},
+       {0x00, 0x1e, 0x07, 0xaa},       {0x00, 0x21, 0x02, 0xaa},
+       {0x00, 0x22, 0x91, 0xaa},       {0x00, 0x29, 0x07, 0xaa},
+       {0x00, 0x33, 0x0b, 0xaa},       {0x00, 0x35, 0x0b, 0xaa},
+       {0x00, 0x37, 0x1d, 0xaa},       {0x00, 0x38, 0x71, 0xaa},
+       {0x00, 0x39, 0x2a, 0xaa},       {0x00, 0x3c, 0x78, 0xaa},
+       {0x00, 0x4d, 0x40, 0xaa},       {0x00, 0x4e, 0x20, 0xaa},
+       {0x00, 0x74, 0x19, 0xaa},       {0x00, 0x8d, 0x4f, 0xaa},
+       {0x00, 0x8e, 0x00, 0xaa},       {0x00, 0x8f, 0x00, 0xaa},
+       {0x00, 0x90, 0x00, 0xaa},       {0x00, 0x91, 0x00, 0xaa},
+       {0x00, 0x96, 0x00, 0xaa},       {0x00, 0x9a, 0x80, 0xaa},
+       {0x00, 0xb0, 0x84, 0xaa},       {0x00, 0xb1, 0x0c, 0xaa},
+       {0x00, 0xb2, 0x0e, 0xaa},       {0x00, 0xb3, 0x82, 0xaa},
+       {0x00, 0xb8, 0x0a, 0xaa},       {0x00, 0x43, 0x14, 0xaa},
+       {0x00, 0x44, 0xf0, 0xaa},       {0x00, 0x45, 0x45, 0xaa},
+       {0x00, 0x46, 0x63, 0xaa},       {0x00, 0x47, 0x2d, 0xaa},
+       {0x00, 0x48, 0x46, 0xaa},       {0x00, 0x59, 0x88, 0xaa},
+       {0x00, 0x5a, 0xa0, 0xaa},       {0x00, 0x5b, 0xc6, 0xaa},
+       {0x00, 0x5c, 0x7d, 0xaa},       {0x00, 0x5d, 0x5f, 0xaa},
+       {0x00, 0x5e, 0x19, 0xaa},       {0x00, 0x6c, 0x0a, 0xaa},
+       {0x00, 0x6d, 0x55, 0xaa},       {0x00, 0x6e, 0x11, 0xaa},
+       {0x00, 0x6f, 0x9e, 0xaa},       {0x00, 0x69, 0x00, 0xaa},
+       {0x00, 0x6a, 0x40, 0xaa},       {0x00, 0x01, 0x40, 0xaa},
+       {0x00, 0x02, 0x40, 0xaa},       {0x00, 0x13, 0xe7, 0xaa},
+       {0x00, 0x5f, 0xf0, 0xaa},       {0x00, 0x60, 0xf0, 0xaa},
+       {0x00, 0x61, 0xf0, 0xaa},       {0x00, 0x27, 0xa0, 0xaa},
+       {0x00, 0x28, 0x80, 0xaa},       {0x00, 0x2c, 0x90, 0xaa},
+       {0x00, 0x4f, 0x66, 0xaa},       {0x00, 0x50, 0x66, 0xaa},
+       {0x00, 0x51, 0x00, 0xaa},       {0x00, 0x52, 0x22, 0xaa},
+       {0x00, 0x53, 0x5e, 0xaa},       {0x00, 0x54, 0x80, 0xaa},
+       {0x00, 0x58, 0x9e, 0xaa},       {0x00, 0x41, 0x08, 0xaa},
+       {0x00, 0x3f, 0x00, 0xaa},       {0x00, 0x75, 0x85, 0xaa},
+       {0x00, 0x76, 0xe1, 0xaa},       {0x00, 0x4c, 0x00, 0xaa},
+       {0x00, 0x77, 0x0a, 0xaa},       {0x00, 0x3d, 0x88, 0xaa},
+       {0x00, 0x4b, 0x09, 0xaa},       {0x00, 0xc9, 0x60, 0xaa},
+       {0x00, 0x41, 0x38, 0xaa},       {0x00, 0x62, 0x30, 0xaa},
+       {0x00, 0x63, 0x30, 0xaa},       {0x00, 0x64, 0x08, 0xaa},
+       {0x00, 0x94, 0x07, 0xaa},       {0x00, 0x95, 0x0b, 0xaa},
+       {0x00, 0x65, 0x00, 0xaa},       {0x00, 0x66, 0x05, 0xaa},
+       {0x00, 0x56, 0x50, 0xaa},       {0x00, 0x34, 0x11, 0xaa},
+       {0x00, 0xa4, 0x88, 0xaa},       {0x00, 0x96, 0x00, 0xaa},
+       {0x00, 0x97, 0x30, 0xaa},       {0x00, 0x98, 0x20, 0xaa},
+       {0x00, 0x99, 0x30, 0xaa},       {0x00, 0x9a, 0x84, 0xaa},
+       {0x00, 0x9b, 0x29, 0xaa},       {0x00, 0x9c, 0x03, 0xaa},
+       {0x00, 0x78, 0x04, 0xaa},       {0x00, 0x79, 0x01, 0xaa},
+       {0x00, 0xc8, 0xf0, 0xaa},       {0x00, 0x79, 0x0f, 0xaa},
+       {0x00, 0xc8, 0x00, 0xaa},       {0x00, 0x79, 0x10, 0xaa},
+       {0x00, 0xc8, 0x7e, 0xaa},       {0x00, 0x79, 0x0a, 0xaa},
+       {0x00, 0xc8, 0x80, 0xaa},       {0x00, 0x79, 0x0b, 0xaa},
+       {0x00, 0xc8, 0x01, 0xaa},       {0x00, 0x79, 0x0c, 0xaa},
+       {0x00, 0xc8, 0x0f, 0xaa},       {0x00, 0x79, 0x0d, 0xaa},
+       {0x00, 0xc8, 0x20, 0xaa},       {0x00, 0x79, 0x09, 0xaa},
+       {0x00, 0xc8, 0x80, 0xaa},       {0x00, 0x79, 0x02, 0xaa},
+       {0x00, 0xc8, 0xc0, 0xaa},       {0x00, 0x79, 0x03, 0xaa},
+       {0x00, 0xc8, 0x40, 0xaa},       {0x00, 0x79, 0x05, 0xaa},
+       {0x00, 0xc8, 0x30, 0xaa},       {0x00, 0x79, 0x26, 0xaa},
+       {0x00, 0x11, 0x40, 0xaa},       {0x00, 0x3a, 0x04, 0xaa},
+       {0x00, 0x12, 0x00, 0xaa},       {0x00, 0x40, 0xc0, 0xaa},
+       {0x00, 0x8c, 0x00, 0xaa},       {0x00, 0x17, 0x14, 0xaa},
+       {0x00, 0x18, 0x02, 0xaa},       {0x00, 0x32, 0x92, 0xaa},
+       {0x00, 0x19, 0x02, 0xaa},       {0x00, 0x1a, 0x7a, 0xaa},
+       {0x00, 0x03, 0x0a, 0xaa},       {0x00, 0x0c, 0x00, 0xaa},
+       {0x00, 0x3e, 0x00, 0xaa},       {0x00, 0x70, 0x3a, 0xaa},
+       {0x00, 0x71, 0x35, 0xaa},       {0x00, 0x72, 0x11, 0xaa},
+       {0x00, 0x73, 0xf0, 0xaa},       {0x00, 0xa2, 0x02, 0xaa},
+       {0x00, 0xb1, 0x00, 0xaa},       {0x00, 0xb1, 0x0c, 0xaa},
+       {0x00, 0x1e, 0x37, 0xaa},       {0x00, 0xaa, 0x14, 0xaa},
+       {0x00, 0x24, 0x80, 0xaa},       {0x00, 0x25, 0x74, 0xaa},
+       {0x00, 0x26, 0xd3, 0xaa},       {0x00, 0x0d, 0x00, 0xaa},
+       {0x00, 0x14, 0x18, 0xaa},       {0x00, 0x9d, 0x99, 0xaa},
+       {0x00, 0x9e, 0x7f, 0xaa},       {0x00, 0x64, 0x08, 0xaa},
+       {0x00, 0x94, 0x07, 0xaa},       {0x00, 0x95, 0x06, 0xaa},
+       {0x00, 0x66, 0x05, 0xaa},       {0x00, 0x41, 0x08, 0xaa},
+       {0x00, 0x3f, 0x00, 0xaa},       {0x00, 0x75, 0x07, 0xaa},
+       {0x00, 0x76, 0xe1, 0xaa},       {0x00, 0x4c, 0x00, 0xaa},
+       {0x00, 0x77, 0x00, 0xaa},       {0x00, 0x3d, 0xc2, 0xaa},
+       {0x00, 0x4b, 0x09, 0xaa},       {0x00, 0xc9, 0x60, 0xaa},
+       {0x00, 0x41, 0x38, 0xaa},       {0xb6, 0x00, 0x00, 0xcc},
+       {0xb6, 0x03, 0x01, 0xcc},       {0xb6, 0x02, 0x40, 0xcc},
+       {0xb6, 0x05, 0x00, 0xcc},       {0xb6, 0x04, 0xf0, 0xcc},
+       {0xb6, 0x12, 0xf8, 0xcc},       {0xb6, 0x13, 0x21, 0xcc},
+       {0xb6, 0x18, 0x00, 0xcc},       {0xb6, 0x17, 0x96, 0xcc},
+       {0xb6, 0x16, 0x00, 0xcc},       {0xb6, 0x22, 0x12, 0xcc},
+       {0xb6, 0x23, 0x0b, 0xcc},       {0xbf, 0xc0, 0x39, 0xcc},
+       {0xbf, 0xc1, 0x04, 0xcc},       {0xbf, 0xcc, 0x00, 0xcc},
+       {0xbc, 0x02, 0x18, 0xcc},       {0xbc, 0x03, 0x50, 0xcc},
+       {0xbc, 0x04, 0x18, 0xcc},       {0xbc, 0x05, 0x00, 0xcc},
+       {0xbc, 0x06, 0x00, 0xcc},       {0xbc, 0x08, 0x30, 0xcc},
+       {0xbc, 0x09, 0x40, 0xcc},       {0xbc, 0x0a, 0x10, 0xcc},
+       {0xbc, 0x0b, 0x00, 0xcc},       {0xbc, 0x0c, 0x00, 0xcc},
+       {0xb3, 0x5c, 0x01, 0xcc},       {0xb3, 0x01, 0x45, 0xcc},
+       {0x00, 0x77, 0x05, 0xaa },
+       {},
+};
+
+struct sensor_info {
+       int sensorId;
+       __u8 I2cAdd;
+       __u8 IdAdd;
+       __u16 VpId;
+       __u8 m1;
+       __u8 m2;
+       __u8 op;
+       };
+
+static struct sensor_info sensor_info_data[] = {
+/*      sensorId,         I2cAdd,      IdAdd,  VpId,  m1,    m2,  op */
+       {SENSOR_HV7131R,    0x80 | 0x11, 0x00, 0x0209, 0x24, 0x25, 0x01},
+       {SENSOR_OV7660,     0x80 | 0x21, 0x0a, 0x7660, 0x26, 0x26, 0x05},
+       {SENSOR_PO3130NC,   0x80 | 0x76, 0x00, 0x3130, 0x24, 0x25, 0x01},
+       {SENSOR_MI1320,     0x80 | 0xc8, 0x00, 0x148c, 0x64, 0x65, 0x01},
+       {SENSOR_OV7670,     0x80 | 0x21, 0x0a, 0x7673, 0x66, 0x67, 0x05},
+       {SENSOR_MI1310_SOC, 0x80 | 0x5d, 0x00, 0x143a, 0x24, 0x25, 0x01},
+};
+
+static void reg_r(struct usb_device *dev,
+                          __u16 req,
+                          __u16 index,
+                          __u8 *buffer, __u16 length)
+{
+       usb_control_msg(dev,
+                       usb_rcvctrlpipe(dev, 0),
+                       req,
+                       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       1,                      /* value */
+                       index, buffer, length,
+                       500);
+}
+
+static void reg_w(struct usb_device *dev,
+                           __u16 req,
+                           __u16 value,
+                           __u16 index)
+{
+       usb_control_msg(dev,
+                       usb_sndctrlpipe(dev, 0),
+                       req,
+                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       value, index, NULL, 0,
+                       500);
+}
+
+static void vc032x_read_sensor_register(struct usb_device *dev,
+                               __u16 address, __u16 *value)
+{
+       __u8 ldata, mdata, hdata;
+       __u8 tmpvalue = 0;
+       int retry = 50;
+       ldata = 0;
+       mdata = 0;
+       hdata = 0;
+       *value = 0;
+
+       reg_r(dev, 0xa1, 0xb33f, &tmpvalue, 1);
+       /*PDEBUG(D_PROBE, " I2c Bus Busy Wait  0x%02X ", tmpvalue); */
+       if (!(tmpvalue & 0x02)) {
+               PDEBUG(D_ERR, "I2c Bus Busy Wait %d", tmpvalue & 0x02);
+               return;
+       }
+       reg_w(dev, 0xa0, address, 0xb33a);
+       reg_w(dev, 0xa0, 0x02, 0xb339);
+
+       tmpvalue = 0;
+       reg_r(dev, 0xa1, 0xb33b, &tmpvalue, 1);
+       while (retry-- && tmpvalue) {
+               reg_r(dev, 0xa1, 0xb33b, &tmpvalue, 1);
+/*             PDEBUG(D_PROBE, "Read again 0xb33b %d", tmpvalue); */
+               msleep(1);
+       }
+       reg_r(dev, 0xa1, 0xb33e, &hdata, 1);
+       reg_r(dev, 0xa1, 0xb33d, &mdata, 1);
+       reg_r(dev, 0xa1, 0xb33c, &ldata, 1);
+       PDEBUG(D_PROBE, "Read Sensor h (0x%02X) m (0x%02X) l (0x%02X)",
+               hdata, mdata, ldata);
+       tmpvalue = 0;
+       reg_r(dev, 0xa1, 0xb334, &tmpvalue, 1);
+       if (tmpvalue == 0x02)
+               *value = (ldata << 8) + mdata;
+       else
+               *value = ldata;
+}
+static int vc032x_probe_sensor(struct gspca_dev *gspca_dev)
+{
+       struct usb_device *dev = gspca_dev->dev;
+       int i;
+       __u8 data;
+       __u16 value;
+       struct sensor_info *ptsensor_info;
+
+       reg_r(dev, 0xa1, 0xbfcf, &data, 1);
+       PDEBUG(D_PROBE, "check sensor header %d", data);
+       for (i = 0; i < ARRAY_SIZE(sensor_info_data); i++) {
+               ptsensor_info = &sensor_info_data[i];
+               reg_w(dev, 0xa0, 0x02, 0xb334);
+               reg_w(dev, 0xa0, ptsensor_info->m1, 0xb300);
+               reg_w(dev, 0xa0, ptsensor_info->m2, 0xb300);
+               reg_w(dev, 0xa0, 0x01, 0xb308);
+               reg_w(dev, 0xa0, 0x0c, 0xb309);
+               reg_w(dev, 0xa0, ptsensor_info->I2cAdd, 0xb335);
+/*             PDEBUG(D_PROBE,
+                       "check sensor VC032X -> %d Add -> ox%02X!",
+                       i, ptsensor_info->I2cAdd); */
+               reg_w(dev, 0xa0, ptsensor_info->op, 0xb301);
+               vc032x_read_sensor_register(dev, ptsensor_info->IdAdd, &value);
+               if (value == ptsensor_info->VpId) {
+/*                     PDEBUG(D_PROBE, "find sensor VC032X -> ox%04X!",
+                               ptsensor_info->VpId); */
+                       return ptsensor_info->sensorId;
+               }
+       }
+       return -1;
+}
+
+static __u8 i2c_write(struct usb_device *dev,
+                               __u8 reg, __u8 *val, __u8 size)
+{
+       __u8 retbyte;
+
+       if (size > 3 || size < 1)
+               return -EINVAL;
+       reg_r(dev, 0xa1, 0xb33f, &retbyte, 1);
+       reg_w(dev, 0xa0, size , 0xb334);
+       reg_w(dev, 0xa0, reg , 0xb33a);
+       switch (size) {
+       case 1:
+               reg_w(dev, 0xa0, val[0] , 0xb336);
+               break;
+       case 2:
+               reg_w(dev, 0xa0, val[0] , 0xb336);
+               reg_w(dev, 0xa0, val[1] , 0xb337);
+               break;
+       case 3:
+               reg_w(dev, 0xa0, val[0] , 0xb336);
+               reg_w(dev, 0xa0, val[1] , 0xb337);
+               reg_w(dev, 0xa0, val[2] , 0xb338);
+               break;
+       default:
+               reg_w(dev, 0xa0, 0x01, 0xb334);
+               return -EINVAL;
+       }
+       reg_w(dev, 0xa0, 0x01, 0xb339);
+       reg_r(dev, 0xa1, 0xb33b, &retbyte, 1);
+       return retbyte == 0;
+}
+
+static void put_tab_to_reg(struct gspca_dev *gspca_dev,
+                       __u8 *tab, __u8 tabsize, __u16 addr)
+{
+       int j;
+       __u16 ad = addr;
+
+       for (j = 0; j < tabsize; j++)
+               reg_w(gspca_dev->dev, 0xa0, tab[j], ad++);
+}
+
+static void usb_exchange(struct gspca_dev *gspca_dev,
+                               __u8 data[][4])
+{
+       struct usb_device *dev = gspca_dev->dev;
+       int i = 0;
+
+       for (;;) {
+               switch (data[i][3]) {
+               default:
+                       return;
+               case 0xcc:                      /* normal write */
+                       reg_w(dev, 0xa0, data[i][2],
+                                       ((data[i][0])<<8) | data[i][1]);
+                       break;
+               case 0xaa:                      /* i2c op */
+                       i2c_write(dev, data[i][1], &data[i][2], 1);
+                       break;
+               case 0xbb:                      /* i2c op */
+                       i2c_write(dev, data[i][0], &data[i][1], 2);
+                       break;
+               case 0xdd:
+                       msleep(data[i][2] + 10);
+                       break;
+               }
+               i++;
+       }
+       /*not reached*/
+}
+
+/*
+ "GammaT"=hex:04,17,31,4f,6a,83,99,ad,bf,ce,da,e5,ee,f5,fb,ff,ff
+ "MatrixT"=hex:60,f9,e5,e7,50,05,f3,e6,66
+ */
+
+static void vc0321_reset(struct gspca_dev *gspca_dev)
+{
+       reg_w(gspca_dev->dev, 0xa0, 0x00, 0xb04d);
+       reg_w(gspca_dev->dev, 0xa0, 0x01, 0xb301);
+       msleep(100);
+       reg_w(gspca_dev->dev, 0xa0, 0x01, 0xb003);
+       msleep(100);
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+                       const struct usb_device_id *id)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct usb_device *dev = gspca_dev->dev;
+       struct cam *cam;
+       __u8 tmp2[4];
+       int sensor;
+       __u16 vendor;
+       __u16 product;
+
+       vendor = id->idVendor;
+       product = id->idProduct;
+       switch (vendor) {
+       case 0x046d:            /* Logitech Labtec */
+/*             switch (product) { */
+/*             case 0x0892: */
+/*             case 0x0896: */
+                       sd->bridge = BRIDGE_VC0321;
+/*                     break; */
+/*             } */
+               break;
+       case 0x0ac8:            /* Vimicro z-star */
+               switch (product) {
+               case 0x0321:
+               case 0x0328:
+               case 0xc001:
+               case 0xc002:
+                       sd->bridge = BRIDGE_VC0321;
+                       break;
+               case 0x0323:
+                       sd->bridge = BRIDGE_VC0323;
+                       break;
+               }
+               break;
+       case 0x17ef:            /* Lenovo */
+/*             switch (product) { */
+/*             case 0x4802:     * Lenovo MI1310_SOC */
+                       sd->bridge = BRIDGE_VC0323;
+/*                     break; */
+/*             } */
+               break;
+       }
+
+       cam = &gspca_dev->cam;
+       cam->dev_name = (char *) id->driver_info;
+       cam->epaddr = 0x02;
+       if (sd->bridge == BRIDGE_VC0321) {
+               cam->cam_mode = vc0321_mode;
+               cam->nmodes = sizeof vc0321_mode / sizeof vc0321_mode[0];
+       } else {
+               cam->cam_mode = vc0323_mode;
+               cam->nmodes = sizeof vc0323_mode / sizeof vc0323_mode[0];
+       }
+
+       vc0321_reset(gspca_dev);
+       sensor = vc032x_probe_sensor(gspca_dev);
+       switch (sensor) {
+       case -1:
+               PDEBUG(D_PROBE, "Unknown sensor...");
+               return -EINVAL;
+       case SENSOR_HV7131R:
+               PDEBUG(D_PROBE, "Find Sensor HV7131R");
+               sd->sensor = SENSOR_HV7131R;
+               break;
+       case SENSOR_MI1310_SOC:
+               PDEBUG(D_PROBE, "Find Sensor MI1310_SOC");
+               sd->sensor = SENSOR_MI1310_SOC;
+               break;
+       case SENSOR_MI1320:
+               PDEBUG(D_PROBE, "Find Sensor MI1320");
+               sd->sensor = SENSOR_MI1320;
+               break;
+       case SENSOR_OV7660:
+               PDEBUG(D_PROBE, "Find Sensor OV7660");
+               sd->sensor = SENSOR_OV7660;
+               break;
+       case SENSOR_OV7670:
+               PDEBUG(D_PROBE, "Find Sensor OV7670");
+               sd->sensor = SENSOR_OV7670;
+               break;
+       case SENSOR_PO3130NC:
+               PDEBUG(D_PROBE, "Find Sensor PO3130NC");
+               sd->sensor = SENSOR_PO3130NC;
+               break;
+       }
+
+       sd->qindex = 7;
+       sd->autogain = sd_ctrls[SD_AUTOGAIN].qctrl.default_value;
+
+       if (sd->bridge == BRIDGE_VC0321) {
+               reg_r(dev, 0x8a, 0, tmp2, 3);
+               reg_w(dev, 0x87, 0x00, 0x0f0f);
+
+               reg_r(dev, 0x8b, 0, tmp2, 3);
+               reg_w(dev, 0x88, 0x00, 0x0202);
+       }
+       return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+       return 0;
+}
+
+static void setquality(struct gspca_dev *gspca_dev)
+{
+}
+
+static void setautogain(struct gspca_dev *gspca_dev)
+{
+}
+
+static void setlightfreq(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       static __u8 (*ov7660_freq_tb[3])[4] =
+               {ov7660_NoFliker, ov7660_50HZ, ov7660_60HZ};
+
+       if (sd->sensor != SENSOR_OV7660)
+               return;
+       usb_exchange(gspca_dev, ov7660_freq_tb[sd->lightfreq]);
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+/*     __u8 tmp2; */
+       __u8 *GammaT = NULL;
+       __u8 *MatrixT = NULL;
+       int mode;
+
+       /* Assume start use the good resolution from gspca_dev->mode */
+       if (sd->bridge == BRIDGE_VC0321) {
+               reg_w(gspca_dev->dev, 0xa0, 0xff, 0xbfec);
+               reg_w(gspca_dev->dev, 0xa0, 0xff, 0xbfed);
+               reg_w(gspca_dev->dev, 0xa0, 0xff, 0xbfee);
+               reg_w(gspca_dev->dev, 0xa0, 0xff, 0xbfef);
+       }
+
+       mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].mode;
+       switch (sd->sensor) {
+       case SENSOR_HV7131R:
+               GammaT = hv7131r_gamma;
+               MatrixT = hv7131r_matrix;
+               if (mode) {
+                       /* 320x240 */
+                       usb_exchange(gspca_dev, hv7131r_initQVGA_data);
+               } else {
+                       /* 640x480 */
+                       usb_exchange(gspca_dev, hv7131r_initVGA_data);
+               }
+               break;
+       case SENSOR_OV7660:
+               GammaT = ov7660_gamma;
+               MatrixT = ov7660_matrix;
+               if (mode) {
+                       /* 320x240 */
+                       usb_exchange(gspca_dev, ov7660_initQVGA_data);
+               } else {
+                       /* 640x480 */
+                       usb_exchange(gspca_dev, ov7660_initVGA_data);
+               }
+               break;
+       case SENSOR_OV7670:
+               /*GammaT = ov7660_gamma; */
+               /*MatrixT = ov7660_matrix; */
+               if (mode) {
+                       /* 320x240 */
+                       usb_exchange(gspca_dev, ov7670_initQVGA_JPG);
+               } else {
+                       /* 640x480 */
+                       usb_exchange(gspca_dev, ov7670_initVGA_JPG);
+               }
+               break;
+       case SENSOR_MI1310_SOC:
+               if (mode) {
+                       /* 320x240 */
+                       usb_exchange(gspca_dev, mi1310_socinitQVGA_JPG);
+               } else {
+                       /* 640x480 */
+                       usb_exchange(gspca_dev, mi1310_socinitVGA_JPG);
+               }
+               break;
+       case SENSOR_MI1320:
+               GammaT = mi1320_gamma;
+               MatrixT = mi1320_matrix;
+               if (mode) {
+                       /* 320x240 */
+                       usb_exchange(gspca_dev, mi1320_initQVGA_data);
+               } else {
+                       /* 640x480 */
+                       usb_exchange(gspca_dev, mi1320_initVGA_data);
+               }
+               break;
+       case SENSOR_PO3130NC:
+               GammaT = po3130_gamma;
+               MatrixT = po3130_matrix;
+               if (mode) {
+                       /* 320x240 */
+                       usb_exchange(gspca_dev, po3130_initQVGA_data);
+               } else {
+                       /* 640x480 */
+                       usb_exchange(gspca_dev, po3130_initVGA_data);
+               }
+               usb_exchange(gspca_dev, po3130_rundata);
+               break;
+       default:
+               PDEBUG(D_PROBE, "Damned !! no sensor found Bye");
+               return;
+       }
+       if (GammaT && MatrixT) {
+               put_tab_to_reg(gspca_dev, GammaT, 17, 0xb84a);
+               put_tab_to_reg(gspca_dev, GammaT, 17, 0xb85b);
+               put_tab_to_reg(gspca_dev, GammaT, 17, 0xb86c);
+               put_tab_to_reg(gspca_dev, MatrixT, 9, 0xb82c);
+
+               /* Seem SHARPNESS */
+               /*
+               reg_w(gspca_dev->dev, 0xa0, 0x80, 0xb80a);
+               reg_w(gspca_dev->dev, 0xa0, 0xff, 0xb80b);
+               reg_w(gspca_dev->dev, 0xa0, 0xff, 0xb80e);
+               */
+               /* all 0x40 ??? do nothing
+               reg_w(gspca_dev->dev, 0xa0, 0x40, 0xb822);
+               reg_w(gspca_dev->dev, 0xa0, 0x40, 0xb823);
+               reg_w(gspca_dev->dev, 0xa0, 0x40, 0xb824);
+               */
+               /* Only works for HV7131R ??
+               reg_r (gspca_dev->dev, 0xa1, 0xb881, &tmp2, 1);
+               reg_w(gspca_dev->dev, 0xa0, 0xfe01, 0xb881);
+               reg_w(gspca_dev->dev, 0xa0, 0x79, 0xb801);
+               */
+               /* only hv7131r et ov7660
+               reg_w(gspca_dev->dev, 0xa0, 0x20, 0xb827);
+               reg_w(gspca_dev->dev, 0xa0, 0xff, 0xb826); * ISP_GAIN 80
+               reg_w(gspca_dev->dev, 0xa0, 0x23, 0xb800); * ISP CTRL_BAS
+               */
+               /* set the led on 0x0892 0x0896 */
+               reg_w(gspca_dev->dev, 0x89, 0xffff, 0xfdff);
+               msleep(100);
+               setquality(gspca_dev);
+               setautogain(gspca_dev);
+               setlightfreq(gspca_dev);
+       }
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+       struct usb_device *dev = gspca_dev->dev;
+
+       reg_w(dev, 0x89, 0xffff, 0xffff);
+       reg_w(dev, 0xa0, 0x01, 0xb301);
+       reg_w(dev, 0xa0, 0x09, 0xb003);
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+       struct usb_device *dev = gspca_dev->dev;
+
+       reg_w(dev, 0x89, 0xffff, 0xffff);
+}
+
+/* this function is called at close time */
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+/*     struct usb_device *dev = gspca_dev->dev;
+       __u8 buffread;
+
+       reg_w(dev, 0x89, 0xffff, 0xffff);
+       reg_w(dev, 0xa0, 0x01, 0xb301);
+       reg_w(dev, 0xa0, 0x09, 0xb303);
+       reg_w(dev, 0x89, 0xffff, 0xffff);
+*/
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+                       struct gspca_frame *frame,      /* target */
+                       unsigned char *data,            /* isoc packet */
+                       int len)                        /* iso pkt length */
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       if (data[0] == 0xff && data[1] == 0xd8) {
+               PDEBUG(D_PACK,
+                       "vc032x header packet found len %d", len);
+               frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+                                               data, 0);
+               if (sd->bridge == BRIDGE_VC0321) {
+#define VCHDRSZ 46
+                       data += VCHDRSZ;
+                       len -= VCHDRSZ;
+#undef VCHDRSZ
+               }
+               gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+                               data, len);
+               return;
+       }
+       gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+}
+
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->autogain = val;
+       if (gspca_dev->streaming)
+               setautogain(gspca_dev);
+       return 0;
+}
+
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->autogain;
+       return 0;
+}
+
+static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->lightfreq = val;
+       if (gspca_dev->streaming)
+               setlightfreq(gspca_dev);
+       return 0;
+}
+
+static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->lightfreq;
+       return 0;
+}
+
+static int sd_querymenu(struct gspca_dev *gspca_dev,
+                       struct v4l2_querymenu *menu)
+{
+       switch (menu->id) {
+       case V4L2_CID_POWER_LINE_FREQUENCY:
+               switch (menu->index) {
+               case 0:         /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */
+                       strcpy(menu->name, "NoFliker");
+                       return 0;
+               case 1:         /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
+                       strcpy(menu->name, "50 Hz");
+                       return 0;
+               case 2:         /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
+                       strcpy(menu->name, "60 Hz");
+                       return 0;
+               }
+               break;
+       }
+       return -EINVAL;
+}
+
+/* sub-driver description */
+static struct sd_desc sd_desc = {
+       .name = MODULE_NAME,
+       .ctrls = sd_ctrls,
+       .nctrls = ARRAY_SIZE(sd_ctrls),
+       .config = sd_config,
+       .open = sd_open,
+       .start = sd_start,
+       .stopN = sd_stopN,
+       .stop0 = sd_stop0,
+       .close = sd_close,
+       .pkt_scan = sd_pkt_scan,
+       .querymenu = sd_querymenu,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static __devinitdata struct usb_device_id device_table[] = {
+       {USB_DEVICE(0x046d, 0x0892), DVNM("Logitech Orbicam")},
+       {USB_DEVICE(0x046d, 0x0896), DVNM("Logitech Orbicam")},
+       {USB_DEVICE(0x0ac8, 0x0321), DVNM("Vimicro generic vc0321")},
+       {USB_DEVICE(0x0ac8, 0x0323), DVNM("Vimicro Vc0323")},
+       {USB_DEVICE(0x0ac8, 0x0328), DVNM("A4Tech PK-130MG")},
+       {USB_DEVICE(0x0ac8, 0xc001), DVNM("Sony embedded vimicro")},
+       {USB_DEVICE(0x0ac8, 0xc002), DVNM("Sony embedded vimicro")},
+       {USB_DEVICE(0x17ef, 0x4802), DVNM("Lenovo Vc0323+MI1310_SOC")},
+       {}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+                       const struct usb_device_id *id)
+{
+       return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+                               THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+       .name = MODULE_NAME,
+       .id_table = device_table,
+       .probe = sd_probe,
+       .disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+       if (usb_register(&sd_driver) < 0)
+               return -1;
+       PDEBUG(D_PROBE, "v%s registered", version);
+       return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+       usb_deregister(&sd_driver);
+       PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
index 03cc7fc58dbcfdf8cb7606fa3f990d4f7eb4a56d..b767f32511bb6fc931aaaaaeb8b04e985f8054b9 100644 (file)
@@ -3,7 +3,7 @@
  *     Copyright (C) 2004 2005 2006 Michel Xhaard
  *             mxhaard@magic.fr
  *
- * V4L2 by Jean-François Moine <http://moinejf.free.fr>
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 
 #include "gspca.h"
 
-#define DRIVER_VERSION_NUMBER  KERNEL_VERSION(0, 2, 13)
-static const char version[] = "0.2.13";
+#define DRIVER_VERSION_NUMBER  KERNEL_VERSION(2, 1, 0)
+static const char version[] = "2.1.0";
 
 MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>, "
                "Serge A. Suchkov <Serge.A.S@tochka.ru>");
 MODULE_DESCRIPTION("GSPCA ZC03xx/VC3xx USB Camera Driver");
 MODULE_LICENSE("GPL");
 
-static int lightfreq = 50;
 static int force_sensor = -1;
 
 #include "jpeg.h"
@@ -41,10 +40,12 @@ static int force_sensor = -1;
 struct sd {
        struct gspca_dev gspca_dev;     /* !! must be the first item */
 
-       unsigned char brightness;
-       unsigned char contrast;
-       unsigned char autogain;
-       unsigned char gamma;
+       __u8 brightness;
+       __u8 contrast;
+       __u8 gamma;
+       __u8 autogain;
+       __u8 lightfreq;
+       __u8 sharpness;
 
        char qindex;
        char sensor;                    /* Type of image sensor chip */
@@ -61,14 +62,13 @@ struct sd {
 #define SENSOR_OV7620 9
 /*#define SENSOR_OV7648 9 - same values */
 #define SENSOR_OV7630C 10
-/*#define SENSOR_free 11 */
-#define SENSOR_PAS106 12
-#define SENSOR_PB0330 13
-#define SENSOR_PO2030 14
-#define SENSOR_TAS5130CK 15
-#define SENSOR_TAS5130CXX 16
-#define SENSOR_TAS5130C_VF0250 17
-#define SENSOR_MAX 18
+#define SENSOR_PAS106 11
+#define SENSOR_PB0330 12
+#define SENSOR_PO2030 13
+#define SENSOR_TAS5130CK 14
+#define SENSOR_TAS5130CXX 15
+#define SENSOR_TAS5130C_VF0250 16
+#define SENSOR_MAX 17
        unsigned short chip_revision;
 };
 
@@ -79,7 +79,12 @@ static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
 static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val);
 
 static struct ctrl sd_ctrls[] = {
 #define SD_BRIGHTNESS 0
@@ -110,7 +115,21 @@ static struct ctrl sd_ctrls[] = {
            .set = sd_setcontrast,
            .get = sd_getcontrast,
        },
-#define SD_AUTOGAIN 2
+#define SD_GAMMA 2
+       {
+           {
+               .id      = V4L2_CID_GAMMA,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Gamma",
+               .minimum = 1,
+               .maximum = 6,
+               .step    = 1,
+               .default_value = 4,
+           },
+           .set = sd_setgamma,
+           .get = sd_getgamma,
+       },
+#define SD_AUTOGAIN 3
        {
            {
                .id      = V4L2_CID_AUTOGAIN,
@@ -124,19 +143,33 @@ static struct ctrl sd_ctrls[] = {
            .set = sd_setautogain,
            .get = sd_getautogain,
        },
-#define SD_GAMMA 3
+#define SD_FREQ 4
        {
            {
-               .id      = V4L2_CID_GAMMA,
+               .id      = V4L2_CID_POWER_LINE_FREQUENCY,
+               .type    = V4L2_CTRL_TYPE_MENU,
+               .name    = "Light frequency filter",
+               .minimum = 0,
+               .maximum = 2,   /* 0: 0, 1: 50Hz, 2:60Hz */
+               .step    = 1,
+               .default_value = 1,
+           },
+           .set = sd_setfreq,
+           .get = sd_getfreq,
+       },
+#define SD_SHARPNESS 5
+       {
+           {
+               .id      = V4L2_CID_SHARPNESS,
                .type    = V4L2_CTRL_TYPE_INTEGER,
-               .name    = "Gamma",
-               .minimum = 1,
-               .maximum = 6,
+               .name    = "Sharpness",
+               .minimum = 0,
+               .maximum = 3,
                .step    = 1,
-               .default_value = 4,
+               .default_value = 2,
            },
-           .set = sd_setcontrast,
-           .get = sd_getgamma,
+           .set = sd_setsharpness,
+           .get = sd_getsharpness,
        },
 };
 
@@ -211,11 +244,11 @@ static struct usb_action cs2102_Initial[] = {
        {0xa1, 0x01, 0x0002},
        {0xa1, 0x01, 0x0008},
        {0xa0, 0x03, 0x0008},   /* 00 */
-       {0xa0, 0x08, 0x01c6},   /* clock ? */
+       {0xa0, 0x08, 0x01c6},   /* sharpness+ */
        {0xa1, 0x01, 0x01c8},
        {0xa1, 0x01, 0x01c9},
        {0xa1, 0x01, 0x01ca},
-       {0xa0, 0x0f, 0x01cb},
+       {0xa0, 0x0f, 0x01cb},   /* sharpness- */
        {0xa0, 0x24, 0x0120},   /* gamma 5 */
        {0xa0, 0x44, 0x0121},
        {0xa0, 0x64, 0x0122},
@@ -284,7 +317,7 @@ static struct usb_action cs2102_Initial[] = {
        {0xa0, 0x40, 0x0116},
        {0xa0, 0x40, 0x0117},
        {0xa0, 0x40, 0x0118},
-       {0, 0, 0}
+       {}
 };
 
 static struct usb_action cs2102_InitialScale[] = {
@@ -341,11 +374,11 @@ static struct usb_action cs2102_InitialScale[] = {
        {0xa1, 0x01, 0x0002},
        {0xa1, 0x01, 0x0008},
        {0xa0, 0x03, 0x0008},   /* 00 */
-       {0xa0, 0x08, 0x01c6},   /* clock ? */
+       {0xa0, 0x08, 0x01c6},   /* sharpness+ */
        {0xa1, 0x01, 0x01c8},
        {0xa1, 0x01, 0x01c9},
        {0xa1, 0x01, 0x01ca},
-       {0xa0, 0x0f, 0x01cb},
+       {0xa0, 0x0f, 0x01cb},   /* sharpness- */
        {0xa0, 0x24, 0x0120},   /* gamma 5 */
        {0xa0, 0x44, 0x0121},
        {0xa0, 0x64, 0x0122},
@@ -414,7 +447,7 @@ static struct usb_action cs2102_InitialScale[] = {
        {0xa0, 0x40, 0x0116},
        {0xa0, 0x40, 0x0117},
        {0xa0, 0x40, 0x0118},
-       {0, 0, 0}
+       {}
 };
 static struct usb_action cs2102_50HZ[] = {
        {0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
@@ -439,7 +472,7 @@ static struct usb_action cs2102_50HZ[] = {
        {0xa0, 0x8c, 0x001d}, /* 00,1d,8c,cc */
        {0xa0, 0xb0, 0x001e}, /* 00,1e,b0,cc */
        {0xa0, 0xd0, 0x001f}, /* 00,1f,d0,cc */
-       {0, 0, 0}
+       {}
 };
 static struct usb_action cs2102_50HZScale[] = {
        {0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
@@ -464,7 +497,7 @@ static struct usb_action cs2102_50HZScale[] = {
        {0xa0, 0x93, 0x001d}, /* 00,1d,93,cc */
        {0xa0, 0xb0, 0x001e}, /* 00,1e,b0,cc */
        {0xa0, 0xd0, 0x001f}, /* 00,1f,d0,cc */
-       {0, 0, 0}
+       {}
 };
 static struct usb_action cs2102_60HZ[] = {
        {0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
@@ -489,7 +522,7 @@ static struct usb_action cs2102_60HZ[] = {
        {0xa0, 0x5d, 0x001d}, /* 00,1d,5d,cc */
        {0xa0, 0x90, 0x001e}, /* 00,1e,90,cc */
        {0xa0, 0xd0, 0x00c8}, /* 00,c8,d0,cc */
-       {0, 0, 0}
+       {}
 };
 static struct usb_action cs2102_60HZScale[] = {
        {0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
@@ -514,7 +547,7 @@ static struct usb_action cs2102_60HZScale[] = {
        {0xa0, 0xb7, 0x001d}, /* 00,1d,b7,cc */
        {0xa0, 0xd0, 0x001e}, /* 00,1e,d0,cc */
        {0xa0, 0xe8, 0x001f}, /* 00,1f,e8,cc */
-       {0, 0, 0}
+       {}
 };
 static struct usb_action cs2102_NoFliker[] = {
        {0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
@@ -539,7 +572,7 @@ static struct usb_action cs2102_NoFliker[] = {
        {0xa0, 0x59, 0x001d}, /* 00,1d,59,cc */
        {0xa0, 0x90, 0x001e}, /* 00,1e,90,cc */
        {0xa0, 0xc8, 0x001f}, /* 00,1f,c8,cc */
-       {0, 0, 0}
+       {}
 };
 static struct usb_action cs2102_NoFlikerScale[] = {
        {0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
@@ -564,7 +597,7 @@ static struct usb_action cs2102_NoFlikerScale[] = {
        {0xa0, 0x59, 0x001d}, /* 00,1d,59,cc */
        {0xa0, 0x90, 0x001e}, /* 00,1e,90,cc */
        {0xa0, 0xc8, 0x001f}, /* 00,1f,c8,cc */
-       {0, 0, 0}
+       {}
 };
 
 /* CS2102_KOCOM */
@@ -676,8 +709,8 @@ static struct usb_action cs2102K_Initial[] = {
        {0xa0, 0x40, 0x0117},
        {0xa0, 0x4c, 0x0118},
        {0xa0, 0x03, 0x0008},   /* clock ? */
-       {0xa0, 0x08, 0x01c6},
-       {0xa0, 0x0f, 0x01cb},
+       {0xa0, 0x08, 0x01c6},   /* sharpness+ */
+       {0xa0, 0x0f, 0x01cb},   /* sharpness- */
        {0xa0, 0x13, 0x0120},   /* gamma 4 */
        {0xa0, 0x38, 0x0121},
        {0xa0, 0x59, 0x0122},
@@ -824,7 +857,7 @@ static struct usb_action cs2102K_Initial[] = {
        {0xa0, 0x00, 0x01a7},
        {0xa0, 0x04, 0x01a7},
        {0xa0, 0x00, 0x01a7},
-       {0, 0, 0}
+       {}
 };
 
 static struct usb_action cs2102K_InitialScale[] = {
@@ -936,8 +969,8 @@ static struct usb_action cs2102K_InitialScale[] = {
        {0xa0, 0x40, 0x0117},
        {0xa0, 0x4c, 0x0118},
        {0xa0, 0x03, 0x0008},   /* clock ? */
-       {0xa0, 0x08, 0x01c6},
-       {0xa0, 0x0f, 0x01cb},
+       {0xa0, 0x08, 0x01c6},   /* sharpness+ */
+       {0xa0, 0x0f, 0x01cb},   /* sharpness- */
        {0xa0, 0x13, 0x0120},   /* gamma 4 */
        {0xa0, 0x38, 0x0121},
        {0xa0, 0x59, 0x0122},
@@ -1137,8 +1170,8 @@ static struct usb_action cs2102K_InitialScale[] = {
        {0xa0, 0x40, 0x0117},
        {0xa0, 0x4c, 0x0118},
        {0xa0, 0x03, 0x0008},   /* clock ? */
-       {0xa0, 0x08, 0x01c6},
-       {0xa0, 0x0f, 0x01cb},
+       {0xa0, 0x08, 0x01c6},   /* sharpness+ */
+       {0xa0, 0x0f, 0x01cb},   /* sharpness- */
        {0xa0, 0x13, 0x0120},   /* gamma 4 */
        {0xa0, 0x38, 0x0121},
        {0xa0, 0x59, 0x0122},
@@ -1401,7 +1434,7 @@ static struct usb_action cs2102K_InitialScale[] = {
        {0xa0, 0x04, 0x01a7},
        {0xa0, 0x00, 0x01a7},
        {0xa0, 0x04, 0x01a7},
-       {0, 0, 0}
+       {}
 };
 
 static struct usb_action gc0305_Initial[] = {          /* 640x480 */
@@ -1466,7 +1499,7 @@ static struct usb_action gc0305_Initial[] = {             /* 640x480 */
        {0xa0, 0x40, 0x0117},   /* 01,17,40,cc */
        {0xa0, 0x52, 0x0118},   /* 01,18,52,cc */
        {0xa0, 0x03, 0x0113},   /* 01,13,03,cc */
-       {0,0,0}
+       {}
 };
 static struct usb_action gc0305_InitialScale[] = {     /* 320x240 */
        {0xa0, 0x01, 0x0000},   /* 00,00,01,cc */
@@ -1529,7 +1562,7 @@ static struct usb_action gc0305_InitialScale[] = {        /* 320x240 */
        {0xa0, 0x40, 0x0117},   /* 01,17,40,cc */
        {0xa0, 0x52, 0x0118},   /* 01,18,52,cc */
        {0xa0, 0x03, 0x0113},   /* 01,13,03,cc */
-       {0,0,0}
+       {}
 };
 static struct usb_action gc0305_50HZ[] = {
        {0xaa, 0x82, 0x0000},   /* 00,82,00,aa */
@@ -1552,7 +1585,7 @@ static struct usb_action gc0305_50HZ[] = {
        {0xa0, 0x60, 0x011d},   /* 01,1d,60,cc */
        {0xa0, 0x42, 0x0180},   /* 01,80,42,cc */
 /*     {0xa0, 0x85, 0x018d},    * 01,8d,85,cc *         * if 640x480 */
-       {0,0,0}
+       {}
 };
 static struct usb_action gc0305_60HZ[] = {
        {0xaa, 0x82, 0x0000},   /* 00,82,00,aa */
@@ -1575,7 +1608,7 @@ static struct usb_action gc0305_60HZ[] = {
        {0xa0, 0x60, 0x011d},   /* 01,1d,60,cc */
        {0xa0, 0x42, 0x0180},   /* 01,80,42,cc */
        {0xa0, 0x80, 0x018d},   /* 01,8d,80,cc */
-       {0,0,0}
+       {}
 };
 
 static struct usb_action gc0305_NoFliker[] = {
@@ -1598,7 +1631,7 @@ static struct usb_action gc0305_NoFliker[] = {
        {0xa0, 0x60, 0x011d},   /* 01,1d,60,cc */
        {0xa0, 0x03, 0x0180},   /* 01,80,03,cc */
        {0xa0, 0x80, 0x018d},   /* 01,8d,80,cc */
-       {0,0,0}
+       {}
 };
 
 /* play poker with registers at your own risk !! */
@@ -1647,11 +1680,11 @@ static struct usb_action hdcs2020xx_Initial[] = {
        {0xa1, 0x01, 0x0002},
        {0xa1, 0x01, 0x0008},
        {0xa0, 0x03, 0x0008},   /* clock ? */
-       {0xa0, 0x04, 0x01c6},
+       {0xa0, 0x04, 0x01c6},   /* sharpness+ */
        {0xa1, 0x01, 0x01c8},
        {0xa1, 0x01, 0x01c9},
        {0xa1, 0x01, 0x01ca},
-       {0xa0, 0x07, 0x01cb},
+       {0xa0, 0x07, 0x01cb},   /* sharpness- */
        {0xa0, 0x11, 0x0120},   /* gamma ~4 */
        {0xa0, 0x37, 0x0121},
        {0xa0, 0x58, 0x0122},
@@ -1744,7 +1777,7 @@ static struct usb_action hdcs2020xx_Initial[] = {
        {0xa1, 0x01, 0x0118},
 /*     {0xa0, 0x02, 0x0008}, */
        {0xa0, 0x00, 0x0007},
-       {0, 0, 0}
+       {}
 };
 
 static struct usb_action hdcs2020xx_InitialScale[] = {
@@ -1792,11 +1825,11 @@ static struct usb_action hdcs2020xx_InitialScale[] = {
        {0xa1, 0x01, 0x0002},
        {0xa1, 0x01, 0x0008},
        {0xa0, 0x03, 0x0008},   /* clock ? */
-       {0xa0, 0x04, 0x01c6},
+       {0xa0, 0x04, 0x01c6},   /* sharpness+ */
        {0xa1, 0x01, 0x01c8},
        {0xa1, 0x01, 0x01c9},
        {0xa1, 0x01, 0x01ca},
-       {0xa0, 0x07, 0x01cb},
+       {0xa0, 0x07, 0x01cb},   /* sharpness- */
        {0xa0, 0x11, 0x0120},   /* gamma ~4*/
        {0xa0, 0x37, 0x0121},
        {0xa0, 0x58, 0x0122},
@@ -1887,7 +1920,7 @@ static struct usb_action hdcs2020xx_InitialScale[] = {
 /*     {0xa0, 0x02, 0x0008}, */
        {0xa0, 0x00, 0x0007},
 /*     {0xa0, 0x18, 0x00fe}, */
-       {0, 0, 0}
+       {}
 };
 static struct usb_action hdcs2020xb_Initial[] = {
        {0xa0, 0x01, 0x0000},
@@ -1942,11 +1975,11 @@ static struct usb_action hdcs2020xb_Initial[] = {
        {0xa0, 0x40, 0x0118},
        {0xa1, 0x01, 0x0008},
        {0xa0, 0x03, 0x0008},   /* clock ? */
-       {0xa0, 0x08, 0x01c6},
+       {0xa0, 0x08, 0x01c6},   /* sharpness+ */
        {0xa1, 0x01, 0x01c8},
        {0xa1, 0x01, 0x01c9},
        {0xa1, 0x01, 0x01ca},
-       {0xa0, 0x0f, 0x01cb},
+       {0xa0, 0x0f, 0x01cb},   /* sharpness- */
        {0xa0, 0x13, 0x0120},   /* gamma 4 */
        {0xa0, 0x38, 0x0121},
        {0xa0, 0x59, 0x0122},
@@ -2019,7 +2052,7 @@ static struct usb_action hdcs2020xb_Initial[] = {
        {0xa0, 0x40, 0x0116},
        {0xa0, 0x40, 0x0117},
        {0xa0, 0x40, 0x0118},
-       {0, 0, 0}
+       {}
 };
 static struct usb_action hdcs2020xb_InitialScale[] = {
        {0xa0, 0x01, 0x0000},
@@ -2072,11 +2105,11 @@ static struct usb_action hdcs2020xb_InitialScale[] = {
        {0xa0, 0x40, 0x0118},
        {0xa1, 0x01, 0x0008},
        {0xa0, 0x03, 0x0008},   /* clock ? */
-       {0xa0, 0x08, 0x01c6},
+       {0xa0, 0x08, 0x01c6},   /* sharpness+ */
        {0xa1, 0x01, 0x01c8},
        {0xa1, 0x01, 0x01c9},
        {0xa1, 0x01, 0x01ca},
-       {0xa0, 0x0f, 0x01cb},
+       {0xa0, 0x0f, 0x01cb},   /* sharpness- */
        {0xa0, 0x13, 0x0120},   /* gamma 4 */
        {0xa0, 0x38, 0x0121},
        {0xa0, 0x59, 0x0122},
@@ -2147,7 +2180,7 @@ static struct usb_action hdcs2020xb_InitialScale[] = {
        {0xa0, 0x40, 0x0116},
        {0xa0, 0x40, 0x0117},
        {0xa0, 0x40, 0x0118},
-       {0, 0, 0}
+       {}
 };
 static struct usb_action hdcs2020b_50HZ[] = {
        {0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
@@ -2168,7 +2201,7 @@ static struct usb_action hdcs2020b_50HZ[] = {
        {0xa0, 0x05, 0x001d}, /* 00,1d,05,cc */
        {0xa0, 0x1a, 0x001e}, /* 00,1e,1a,cc */
        {0xa0, 0x2f, 0x001f}, /* 00,1f,2f,cc */
-       {0, 0, 0}
+       {}
 };
 static struct usb_action hdcs2020b_60HZ[] = {
        {0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
@@ -2189,7 +2222,7 @@ static struct usb_action hdcs2020b_60HZ[] = {
        {0xa0, 0x04, 0x001d}, /* 00,1d,04,cc */
        {0xa0, 0x18, 0x001e}, /* 00,1e,18,cc */
        {0xa0, 0x2c, 0x001f}, /* 00,1f,2c,cc */
-       {0, 0, 0}
+       {}
 };
 static struct usb_action hdcs2020b_NoFliker[] = {
        {0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
@@ -2210,7 +2243,7 @@ static struct usb_action hdcs2020b_NoFliker[] = {
        {0xa0, 0x04, 0x001d}, /* 00,1d,04,cc */
        {0xa0, 0x17, 0x001e}, /* 00,1e,17,cc */
        {0xa0, 0x2a, 0x001f}, /* 00,1f,2a,cc */
-       {0, 0, 0}
+       {}
 };
 
 static struct usb_action hv7131bxx_Initial[] = {
@@ -2266,11 +2299,11 @@ static struct usb_action hv7131bxx_Initial[] = {
 
        {0xa1, 0x01, 0x0008},
        {0xa0, 0x03, 0x0008},   /* clock ? */
-       {0xa0, 0x08, 0x01c6},
+       {0xa0, 0x08, 0x01c6},   /* sharpness+ */
        {0xa1, 0x01, 0x01c8},
        {0xa1, 0x01, 0x01c9},
        {0xa1, 0x01, 0x01ca},
-       {0xa0, 0x0f, 0x01cb},
+       {0xa0, 0x0f, 0x01cb},   /* sharpness- */
 
        {0xa0, 0x50, 0x010a},   /* matrix */
        {0xa0, 0xf8, 0x010b},
@@ -2318,7 +2351,7 @@ static struct usb_action hv7131bxx_Initial[] = {
        {0xa0, 0x40, 0x0117},
        {0xa0, 0x40, 0x0118},
 /*     {0xa0, 0x02, 0x0008}, */
-       {0, 0, 0}
+       {}
 };
 
 static struct usb_action hv7131bxx_InitialScale[] = {
@@ -2373,11 +2406,11 @@ static struct usb_action hv7131bxx_InitialScale[] = {
        {0xa1, 0x01, 0x0096},
        {0xa1, 0x01, 0x0008},
        {0xa0, 0x03, 0x0008},   /* clock ? */
-       {0xa0, 0x08, 0x01c6},
+       {0xa0, 0x08, 0x01c6},   /* sharpness+ */
        {0xa1, 0x01, 0x01c8},
        {0xa1, 0x01, 0x01c9},
        {0xa1, 0x01, 0x01ca},
-       {0xa0, 0x0f, 0x01cb},
+       {0xa0, 0x0f, 0x01cb},   /* sharpness- */
 
        {0xa0, 0x50, 0x010a},   /* matrix */
        {0xa0, 0xf8, 0x010b},
@@ -2424,7 +2457,7 @@ static struct usb_action hv7131bxx_InitialScale[] = {
        {0xa0, 0x40, 0x0117},
        {0xa0, 0x40, 0x0118},
 /*     {0xa0, 0x02, 0x0008}, */
-       {0, 0, 0}
+       {}
 };
 
 static struct usb_action hv7131cxx_Initial[] = {
@@ -2478,11 +2511,11 @@ static struct usb_action hv7131cxx_Initial[] = {
 
        {0xa1, 0x01, 0x0008},
        {0xa0, 0x03, 0x0008},   /* clock ? */
-       {0xa0, 0x08, 0x01c6},
+       {0xa0, 0x08, 0x01c6},   /* sharpness+ */
        {0xa1, 0x01, 0x01c8},
        {0xa1, 0x01, 0x01c9},
        {0xa1, 0x01, 0x01ca},
-       {0xa0, 0x0f, 0x01cb},
+       {0xa0, 0x0f, 0x01cb},   /* sharpness- */
 
        {0xa0, 0x60, 0x010a},   /* matrix */
        {0xa0, 0xf0, 0x010b},
@@ -2518,7 +2551,7 @@ static struct usb_action hv7131cxx_Initial[] = {
        {0xa0, 0x40, 0x0180},
        {0xa1, 0x01, 0x0180},
        {0xa0, 0x42, 0x0180},
-       {0, 0, 0}
+       {}
 };
 
 static struct usb_action hv7131cxx_InitialScale[] = {
@@ -2577,11 +2610,11 @@ static struct usb_action hv7131cxx_InitialScale[] = {
 
        {0xa1, 0x01, 0x0008},
        {0xa0, 0x03, 0x0008},   /* clock ? */
-       {0xa0, 0x08, 0x01c6},
+       {0xa0, 0x08, 0x01c6},   /* sharpness+ */
        {0xa1, 0x01, 0x01c8},
        {0xa1, 0x01, 0x01c9},
        {0xa1, 0x01, 0x01ca},
-       {0xa0, 0x0f, 0x01cb},
+       {0xa0, 0x0f, 0x01cb},   /* sharpness- */
 
        {0xa0, 0x60, 0x010a},   /* matrix */
        {0xa0, 0xf0, 0x010b},
@@ -2619,7 +2652,7 @@ static struct usb_action hv7131cxx_InitialScale[] = {
        {0xa0, 0x40, 0x0180},
        {0xa1, 0x01, 0x0180},
        {0xa0, 0x42, 0x0180},
-       {0, 0, 0}
+       {}
 };
 
 static struct usb_action icm105axx_Initial[] = {
@@ -2743,11 +2776,11 @@ static struct usb_action icm105axx_Initial[] = {
        {0xa1, 0x01, 0x0008},
 
        {0xa0, 0x03, 0x0008},   /* clock ? */
-       {0xa0, 0x08, 0x01c6},
+       {0xa0, 0x08, 0x01c6},   /* sharpness+ */
        {0xa1, 0x01, 0x01c8},
        {0xa1, 0x01, 0x01c9},
        {0xa1, 0x01, 0x01ca},
-       {0xa0, 0x0f, 0x01cb},
+       {0xa0, 0x0f, 0x01cb},   /* sharpness- */
        {0xa0, 0x52, 0x010a},   /* matrix */
        {0xa0, 0xf7, 0x010b},
        {0xa0, 0xf7, 0x010c},
@@ -2796,7 +2829,7 @@ static struct usb_action icm105axx_Initial[] = {
        {0xa0, 0x40, 0x0116},
        {0xa0, 0x40, 0x0117},
        {0xa0, 0x40, 0x0118},
-       {0, 0, 0}
+       {}
 };
 
 static struct usb_action icm105axx_InitialScale[] = {
@@ -2924,11 +2957,11 @@ static struct usb_action icm105axx_InitialScale[] = {
        {0xa1, 0x01, 0x0008},
 
        {0xa0, 0x03, 0x0008},   /* clock ? */
-       {0xa0, 0x08, 0x01c6},
+       {0xa0, 0x08, 0x01c6},   /* sharpness+ */
        {0xa1, 0x01, 0x01c8},
        {0xa1, 0x01, 0x01c9},
        {0xa1, 0x01, 0x01ca},
-       {0xa0, 0x0f, 0x01cb},
+       {0xa0, 0x0f, 0x01cb},   /* sharpness- */
 
        {0xa0, 0x52, 0x010a},   /* matrix */
        {0xa0, 0xf7, 0x010b},
@@ -2976,7 +3009,7 @@ static struct usb_action icm105axx_InitialScale[] = {
        {0xa0, 0x40, 0x0116},
        {0xa0, 0x40, 0x0117},
        {0xa0, 0x40, 0x0118},
-       {0, 0, 0}
+       {}
 };
 static struct usb_action icm105a_50HZ[] = {
        {0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
@@ -3007,7 +3040,7 @@ static struct usb_action icm105a_50HZ[] = {
        {0xa0, 0xd8, 0x001e}, /* 00,1e,d8,cc */
        {0xa0, 0xea, 0x001f}, /* 00,1f,ea,cc */
        {0xa0, 0xff, 0x0020}, /* 00,20,ff,cc */
-       {0, 0, 0}
+       {}
 };
 static struct usb_action icm105a_50HZScale[] = {
        {0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
@@ -3040,7 +3073,7 @@ static struct usb_action icm105a_50HZScale[] = {
        {0xa0, 0xff, 0x0020}, /* 00,20,ff,cc */
        {0xa0, 0x00, 0x01a7}, /* 01,a7,00,cc */
        {0xa0, 0xc0, 0x01a8}, /* 01,a8,c0,cc */
-       {0, 0, 0}
+       {}
 };
 static struct usb_action icm105a_60HZ[] = {
        {0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
@@ -3071,7 +3104,7 @@ static struct usb_action icm105a_60HZ[] = {
        {0xa0, 0xd4, 0x001e}, /* 00,1e,d4,cc */
        {0xa0, 0xe8, 0x001f}, /* 00,1f,e8,cc */
        {0xa0, 0xff, 0x0020}, /* 00,20,ff,cc */
-       {0, 0, 0}
+       {}
 };
 static struct usb_action icm105a_60HZScale[] = {
        {0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
@@ -3104,7 +3137,7 @@ static struct usb_action icm105a_60HZScale[] = {
        {0xa0, 0xff, 0x0020}, /* 00,20,ff,cc */
        {0xa0, 0x00, 0x01a7}, /* 01,a7,00,cc */
        {0xa0, 0xc0, 0x01a8}, /* 01,a8,c0,cc */
-       {0, 0, 0}
+       {}
 };
 static struct usb_action icm105a_NoFliker[] = {
        {0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
@@ -3135,7 +3168,7 @@ static struct usb_action icm105a_NoFliker[] = {
        {0xa0, 0xd4, 0x001e}, /* 00,1e,d4,cc */
        {0xa0, 0xe8, 0x001f}, /* 00,1f,e8,cc */
        {0xa0, 0xff, 0x0020}, /* 00,20,ff,cc */
-       {0, 0, 0}
+       {}
 };
 static struct usb_action icm105a_NoFlikerScale[] = {
        {0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
@@ -3168,7 +3201,7 @@ static struct usb_action icm105a_NoFlikerScale[] = {
        {0xa0, 0xff, 0x0020}, /* 00,20,ff,cc */
        {0xa0, 0x00, 0x01a7}, /* 01,a7,00,cc */
        {0xa0, 0xc0, 0x01a8}, /* 01,a8,c0,cc */
-       {0, 0, 0}
+       {}
 };
 
 static struct usb_action MC501CB_InitialScale[] = {
@@ -3288,7 +3321,7 @@ static struct usb_action MC501CB_InitialScale[] = {
        {0xaa, 0x36, 0x001d}, /* 00,36,1D,aa */
        {0xaa, 0x37, 0x004c}, /* 00,37,4C,aa */
        {0xaa, 0x3b, 0x001d}, /* 00,3B,1D,aa */
-       {0, 0, 0}
+       {}
 };
 
 static struct usb_action MC501CB_Initial[] = {  /* 320x240 */
@@ -3407,7 +3440,7 @@ static struct usb_action MC501CB_Initial[] = {     /* 320x240 */
        {0xaa, 0x36, 0x001d}, /* 00,36,1D,aa */
        {0xaa, 0x37, 0x004c}, /* 00,37,4C,aa */
        {0xaa, 0x3b, 0x001d}, /* 00,3B,1D,aa */
-       {0, 0, 0}
+       {}
 };
 
 static struct usb_action MC501CB_50HZ[] = {
@@ -3424,7 +3457,7 @@ static struct usb_action MC501CB_50HZ[] = {
        {0xaa, 0x36, 0x003a}, /* 00,36,3A,aa */
        {0xaa, 0x37, 0x0098}, /* 00,37,98,aa */
        {0xaa, 0x3b, 0x003a}, /* 00,3B,3A,aa */
-       {0, 0, 0}
+       {}
 };
 
 static struct usb_action MC501CB_50HZScale[] = {
@@ -3441,7 +3474,7 @@ static struct usb_action MC501CB_50HZScale[] = {
        {0xaa, 0x36, 0x0018}, /* 00,36,18,aa */
        {0xaa, 0x37, 0x006a}, /* 00,37,6A,aa */
        {0xaa, 0x3d, 0x0018}, /* 00,3D,18,aa */
-       {0, 0, 0}
+       {}
 };
 
 static struct usb_action MC501CB_60HZ[] = {
@@ -3458,7 +3491,7 @@ static struct usb_action MC501CB_60HZ[] = {
        {0xaa, 0x36, 0x0030}, /* 00,36,30,aa */
        {0xaa, 0x37, 0x00d4}, /* 00,37,D4,aa */
        {0xaa, 0x3d, 0x0030}, /* 00,3D,30,aa */
-       {0, 0, 0}
+       {}
 };
 
 static struct usb_action MC501CB_60HZScale[] = {
@@ -3475,7 +3508,7 @@ static struct usb_action MC501CB_60HZScale[] = {
        {0xaa, 0x36, 0x0018}, /* 00,36,18,aa */
        {0xaa, 0x37, 0x006a}, /* 00,37,6A,aa */
        {0xaa, 0x3d, 0x0018}, /* 00,3D,18,aa */
-       {0, 0, 0}
+       {}
 };
 
 static struct usb_action MC501CB_NoFliker[] = {
@@ -3492,7 +3525,7 @@ static struct usb_action MC501CB_NoFliker[] = {
        {0xaa, 0x36, 0x0030}, /* 00,36,30,aa */
        {0xaa, 0x37, 0x00d4}, /* 00,37,D4,aa */
        {0xaa, 0x3d, 0x0030}, /* 00,3D,30,aa */
-       {0, 0, 0}
+       {}
 };
 
 static struct usb_action MC501CB_NoFlikerScale[] = {
@@ -3504,7 +3537,7 @@ static struct usb_action MC501CB_NoFlikerScale[] = {
        {0xaa, 0x3e, 0x00d4}, /* 00,3E,D4,aa */
        {0xaa, 0x3b, 0x0030}, /* 00,3B,30,aa */
        {0xaa, 0x3c, 0x00d4}, /* 00,3C,D4,aa */
-       {0, 0, 0}
+       {}
 };
 
 /* from zs211.inf - HKR,%OV7620%,Initial - 640x480 */
@@ -3575,7 +3608,7 @@ static struct usb_action OV7620_mode0[] = {
        {0xa0, 0x40, 0x011d}, /* 01,1d,40,cc */
        {0xa0, 0x02, 0x0180}, /* 01,80,02,cc */
        {0xa0, 0x50, 0x01a8}, /* 01,a8,50,cc */
-       {0, 0, 0}
+       {}
 };
 
 /* from zs211.inf - HKR,%OV7620%,InitialScale - 320x240 */
@@ -3646,7 +3679,7 @@ static struct usb_action OV7620_mode1[] = {
        {0xa0, 0x50, 0x011d}, /* 01,1d,50,cc */
        {0xa0, 0x02, 0x0180}, /* 01,80,02,cc */
        {0xa0, 0x50, 0x01a8}, /* 01,a8,50,cc */
-       {0, 0, 0}
+       {}
 };
 
 /* from zs211.inf - HKR,%OV7620%\AE,50HZ */
@@ -3665,7 +3698,7 @@ static struct usb_action OV7620_50HZ[] = {
        {0xaa, 0x10, 0x0082},   /* 00,10,82,aa */
        {0xaa, 0x76, 0x0003},   /* 00,76,03,aa */
 /*     {0xa0, 0x40, 0x0002},    * 00,02,40,cc - if mode0 (640x480) */
-       {0, 0, 0}
+       {}
 };
 
 /* from zs211.inf - HKR,%OV7620%\AE,60HZ */
@@ -3687,7 +3720,7 @@ static struct usb_action OV7620_60HZ[] = {
 /* ?? in gspca v1, it was
        {0xa0, 0x00, 0x0039},  * 00,00,00,dd *
        {0xa1, 0x01, 0x0037},           */
-       {0, 0, 0}
+       {}
 };
 
 /* from zs211.inf - HKR,%OV7620%\AE,NoFliker */
@@ -3707,7 +3740,7 @@ static struct usb_action OV7620_NoFliker[] = {
 /* ?? was
        {0xa0, 0x00, 0x0039},  * 00,00,00,dd *
        {0xa1, 0x01, 0x0037},           */
-       {0, 0, 0}
+       {}
 };
 
 static struct usb_action ov7630c_Initial[] = {
@@ -3795,14 +3828,11 @@ static struct usb_action ov7630c_Initial[] = {
 /* 0x03, */
        {0xa1, 0x01, 0x0008},
        {0xa0, 0x03, 0x0008},   /* clock ? */
-       {0xa0, 0x08, 0x01c6},
-/* 0x05, */
+       {0xa0, 0x08, 0x01c6},   /* sharpness+ */
        {0xa1, 0x01, 0x01c8},
-/* 0x07, */
        {0xa1, 0x01, 0x01c9},
-/* 0x0f, */
        {0xa1, 0x01, 0x01ca},
-       {0xa0, 0x0f, 0x01cb},
+       {0xa0, 0x0f, 0x01cb},   /* sharpness- */
        {0xa0, 0x01, 0x0120},   /* gamma 2 ?*/
        {0xa0, 0x0c, 0x0121},
        {0xa0, 0x1f, 0x0122},
@@ -3867,7 +3897,7 @@ static struct usb_action ov7630c_Initial[] = {
        {0xaa, 0x13, 0x0083},   /* 40 */
        {0xa1, 0x01, 0x0180},
        {0xa0, 0x42, 0x0180},
-       {0, 0, 0}
+       {}
 };
 
 static struct usb_action ov7630c_InitialScale[] = {
@@ -3954,14 +3984,11 @@ static struct usb_action ov7630c_InitialScale[] = {
 
        {0xa1, 0x01, 0x0008},
        {0xa0, 0x03, 0x0008},   /* clock ? */
-       {0xa0, 0x08, 0x01c6},
-
+       {0xa0, 0x08, 0x01c6},   /* sharpness+ */
        {0xa1, 0x01, 0x01c8},
-
        {0xa1, 0x01, 0x01c9},
-
        {0xa1, 0x01, 0x01ca},
-       {0xa0, 0x0f, 0x01cb},
+       {0xa0, 0x0f, 0x01cb},   /* sharpness- */
        {0xa0, 0x16, 0x0120},   /* gamma ~4 */
        {0xa0, 0x3a, 0x0121},
        {0xa0, 0x5b, 0x0122},
@@ -4027,7 +4054,7 @@ static struct usb_action ov7630c_InitialScale[] = {
 
        {0xa1, 0x01, 0x0180},
        {0xa0, 0x42, 0x0180},
-       {0, 0, 0}
+       {}
 };
 
 static struct usb_action pas106b_Initial_com[] = {
@@ -4041,7 +4068,7 @@ static struct usb_action pas106b_Initial_com[] = {
        {0xa0, 0x03, 0x003a},
        {0xa0, 0x0c, 0x003b},
        {0xa0, 0x04, 0x0038},
-       {0, 0, 0}
+       {}
 };
 
 static struct usb_action pas106b_Initial[] = { /* 176x144 */
@@ -4099,10 +4126,8 @@ static struct usb_action pas106b_Initial[] = {   /* 176x144 */
        {0xa0, 0x08, 0x0301},   /* EEPROMAccess */
 /* JPEG control */
        {0xa0, 0x03, 0x0008},   /* ClockSetting */
-/* Unknown */
-       {0xa0, 0x08, 0x01c6},
-/* Sharpness */
-       {0xa0, 0x0f, 0x01cb},   /* Sharpness05 */
+       {0xa0, 0x08, 0x01c6},   /* sharpness+ */
+       {0xa0, 0x0f, 0x01cb},   /* sharpness- */
 /* Other registers */
        {0xa0, 0x0d, 0x0100},   /* OperationMode */
 /* Auto exposure and white balance */
@@ -4113,9 +4138,8 @@ static struct usb_action pas106b_Initial[] = {    /* 176x144 */
        {0xa0, 0x08, 0x0301},   /* EEPROMAccess */
 /* JPEG control */
        {0xa0, 0x03, 0x0008},   /* ClockSetting */
-/* Sharpness */
-       {0xa0, 0x08, 0x01c6},   /* Sharpness00 */
-       {0xa0, 0x0f, 0x01cb},   /* Sharpness05 */
+       {0xa0, 0x08, 0x01c6},   /* sharpness+ */
+       {0xa0, 0x0f, 0x01cb},   /* sharpness- */
 
        {0xa0, 0x58, 0x010a},   /* matrix */
        {0xa0, 0xf4, 0x010b},
@@ -4162,7 +4186,7 @@ static struct usb_action pas106b_Initial[] = {    /* 176x144 */
        {0xa0, 0x40, 0x0116},   /* RGain */
        {0xa0, 0x40, 0x0117},   /* GGain */
        {0xa0, 0x40, 0x0118},   /* BGain */
-       {0, 0, 0}
+       {}
 };
 
 static struct usb_action pas106b_InitialScale[] = {    /* 352x288 */
@@ -4221,10 +4245,8 @@ static struct usb_action pas106b_InitialScale[] = {      /* 352x288 */
        {0xa0, 0x08, 0x0301},   /* EEPROMAccess */
 /* JPEG control */
        {0xa0, 0x03, 0x0008},   /* ClockSetting */
-/* Unknown */
-       {0xa0, 0x08, 0x01c6},
-/* Sharpness */
-       {0xa0, 0x0f, 0x01cb},   /* Sharpness05 */
+       {0xa0, 0x08, 0x01c6},   /* sharpness+ */
+       {0xa0, 0x0f, 0x01cb},   /* sharpness- */
 /* Other registers */
        {0xa0, 0x0d, 0x0100},   /* OperationMode */
 /* Auto exposure and white balance */
@@ -4235,9 +4257,8 @@ static struct usb_action pas106b_InitialScale[] = {       /* 352x288 */
        {0xa0, 0x08, 0x0301},   /* EEPROMAccess */
 /* JPEG control */
        {0xa0, 0x03, 0x0008},   /* ClockSetting */
-/* Sharpness */
-       {0xa0, 0x08, 0x01c6},   /* Sharpness00 */
-       {0xa0, 0x0f, 0x01cb},   /* Sharpness05 */
+       {0xa0, 0x08, 0x01c6},   /* sharpness+ */
+       {0xa0, 0x0f, 0x01cb},   /* sharpness- */
 
        {0xa0, 0x58, 0x010a},   /* matrix */
        {0xa0, 0xf4, 0x010b},
@@ -4289,7 +4310,7 @@ static struct usb_action pas106b_InitialScale[] = {       /* 352x288 */
 
        {0xa0, 0x00, 0x0007},   /* AutoCorrectEnable */
        {0xa0, 0xff, 0x0018},   /* Frame adjust */
-       {0, 0, 0}
+       {}
 };
 static struct usb_action pas106b_50HZ[] = {
        {0xa0, 0x00, 0x0190}, /* 01,90,00,cc */
@@ -4305,7 +4326,7 @@ static struct usb_action pas106b_50HZ[] = {
        {0xaa, 0x05, 0x0002}, /* 00,05,02,aa */
        {0xaa, 0x07, 0x001c}, /* 00,07,1c,aa */
        {0xa0, 0x04, 0x01a9}, /* 01,a9,04,cc */
-       {0, 0, 0}
+       {}
 };
 static struct usb_action pas106b_60HZ[] = {
        {0xa0, 0x00, 0x0190}, /* 01,90,00,cc */
@@ -4321,7 +4342,7 @@ static struct usb_action pas106b_60HZ[] = {
        {0xaa, 0x05, 0x0001}, /* 00,05,01,aa */
        {0xaa, 0x07, 0x00c4}, /* 00,07,c4,aa */
        {0xa0, 0x04, 0x01a9}, /* 01,a9,04,cc */
-       {0, 0, 0}
+       {}
 };
 static struct usb_action pas106b_NoFliker[] = {
        {0xa0, 0x00, 0x0190}, /* 01,90,00,cc */
@@ -4337,10 +4358,9 @@ static struct usb_action pas106b_NoFliker[] = {
        {0xaa, 0x05, 0x0001}, /* 00,05,01,aa */
        {0xaa, 0x07, 0x0030}, /* 00,07,30,aa */
        {0xa0, 0x00, 0x01a9}, /* 01,a9,00,cc */
-       {0, 0, 0}
+       {}
 };
 
-/* Aurelien setting from snoop */
 static struct usb_action pb03303x_Initial[] = {
        {0xa0, 0x01, 0x0000},
        {0xa0, 0x03, 0x0008},
@@ -4411,11 +4431,11 @@ static struct usb_action pb03303x_Initial[] = {
 
        {0xa1, 0x01, 0x0008},
        {0xa0, 0x03, 0x0008},   /* clock ? */
-       {0xa0, 0x08, 0x01c6},
+       {0xa0, 0x08, 0x01c6},   /* sharpness+ */
        {0xa1, 0x01, 0x01c8},
        {0xa1, 0x01, 0x01c9},
        {0xa1, 0x01, 0x01ca},
-       {0xa0, 0x0f, 0x01cb},
+       {0xa0, 0x0f, 0x01cb},   /* sharpness- */
        {0xa0, 0x13, 0x0120},   /* gamma 4 */
        {0xa0, 0x38, 0x0121},
        {0xa0, 0x59, 0x0122},
@@ -4484,7 +4504,7 @@ static struct usb_action pb03303x_Initial[] = {
        {0xa0, 0x40, 0x0180},
        {0xa1, 0x01, 0x0180},
        {0xa0, 0x42, 0x0180},
-       {0, 0, 0}
+       {}
 };
 
 static struct usb_action pb03303x_InitialScale[] = {
@@ -4559,11 +4579,11 @@ static struct usb_action pb03303x_InitialScale[] = {
 
        {0xa1, 0x01, 0x0008},
        {0xa0, 0x03, 0x0008},   /* clock ? */
-       {0xa0, 0x08, 0x01c6},
+       {0xa0, 0x08, 0x01c6},   /* sharpness+ */
        {0xa1, 0x01, 0x01c8},
        {0xa1, 0x01, 0x01c9},
        {0xa1, 0x01, 0x01ca},
-       {0xa0, 0x0f, 0x01cb},
+       {0xa0, 0x0f, 0x01cb},   /* sharpness- */
 
        {0xa0, 0x13, 0x0120},   /* gamma 4 */
        {0xa0, 0x38, 0x0121},
@@ -4633,7 +4653,7 @@ static struct usb_action pb03303x_InitialScale[] = {
        {0xa0, 0x40, 0x0180},
        {0xa1, 0x01, 0x0180},
        {0xa0, 0x42, 0x0180},
-       {0, 0, 0}
+       {}
 };
 static struct usb_action pb0330xx_Initial[] = {
        {0xa1, 0x01, 0x0008},
@@ -4701,11 +4721,11 @@ static struct usb_action pb0330xx_Initial[] = {
        {0xa0, 0x50, 0x0112},
        {0xa1, 0x01, 0x0008},
        {0xa0, 0x03, 0x0008},   /* clock ? */
-       {0xa0, 0x08, 0x01c6},
+       {0xa0, 0x08, 0x01c6},   /* sharpness+ */
        {0xa1, 0x01, 0x01c8},
        {0xa1, 0x01, 0x01c9},
        {0xa1, 0x01, 0x01ca},
-       {0xa0, 0x0f, 0x01cb},
+       {0xa0, 0x0f, 0x01cb},   /* sharpness- */
 
        {0xa0, 0x50, 0x010a},   /* matrix */
        {0xa0, 0xf8, 0x010b},
@@ -4747,7 +4767,7 @@ static struct usb_action pb0330xx_Initial[] = {
        {0xa1, 0x01, 0x0007},
 /*     {0xa0, 0x30, 0x0007}, */
 /*     {0xa0, 0x00, 0x0007}, */
-       {0, 0, 0}
+       {}
 };
 
 static struct usb_action pb0330xx_InitialScale[] = {
@@ -4816,11 +4836,11 @@ static struct usb_action pb0330xx_InitialScale[] = {
        {0xa0, 0x50, 0x0112},
        {0xa1, 0x01, 0x0008},
        {0xa0, 0x03, 0x0008},   /* clock ? */
-       {0xa0, 0x08, 0x01c6},
+       {0xa0, 0x08, 0x01c6},   /* sharpness+ */
        {0xa1, 0x01, 0x01c8},
        {0xa1, 0x01, 0x01c9},
        {0xa1, 0x01, 0x01ca},
-       {0xa0, 0x0f, 0x01cb},
+       {0xa0, 0x0f, 0x01cb},   /* sharpness- */
 
        {0xa0, 0x50, 0x010a},   /* matrix */
        {0xa0, 0xf8, 0x010b},
@@ -4861,7 +4881,7 @@ static struct usb_action pb0330xx_InitialScale[] = {
        {0xa1, 0x01, 0x0007},
 /*     {0xa0, 0x30, 0x0007}, */
 /*     {0xa0, 0x00, 0x0007}, */
-       {0, 0, 0}
+       {}
 };
 static struct usb_action pb0330_50HZ[] = {
        {0xa0, 0x00, 0x0190}, /* 01,90,00,cc */
@@ -4877,7 +4897,7 @@ static struct usb_action pb0330_50HZ[] = {
        {0xa0, 0x68, 0x001d}, /* 00,1d,68,cc */
        {0xa0, 0x90, 0x001e}, /* 00,1e,90,cc */
        {0xa0, 0xc8, 0x001f}, /* 00,1f,c8,cc */
-       {0, 0, 0}
+       {}
 };
 static struct usb_action pb0330_50HZScale[] = {
        {0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
@@ -4894,7 +4914,7 @@ static struct usb_action pb0330_50HZScale[] = {
        {0xa0, 0xe5, 0x001d}, /* 00,1d,e5,cc */
        {0xa0, 0xf0, 0x001e}, /* 00,1e,f0,cc */
        {0xa0, 0xf8, 0x001f}, /* 00,1f,f8,cc */
-       {0, 0, 0}
+       {}
 };
 static struct usb_action pb0330_60HZ[] = {
        {0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
@@ -4911,7 +4931,7 @@ static struct usb_action pb0330_60HZ[] = {
        {0xa0, 0x43, 0x001d}, /* 00,1d,43,cc */
        {0xa0, 0x50, 0x001e}, /* 00,1e,50,cc */
        {0xa0, 0x90, 0x001f}, /* 00,1f,90,cc */
-       {0, 0, 0}
+       {}
 };
 static struct usb_action pb0330_60HZScale[] = {
        {0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
@@ -4928,7 +4948,7 @@ static struct usb_action pb0330_60HZScale[] = {
        {0xa0, 0x41, 0x001d}, /* 00,1d,41,cc */
        {0xa0, 0x50, 0x001e}, /* 00,1e,50,cc */
        {0xa0, 0x90, 0x001f}, /* 00,1f,90,cc */
-       {0, 0, 0}
+       {}
 };
 static struct usb_action pb0330_NoFliker[] = {
        {0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
@@ -4945,7 +4965,7 @@ static struct usb_action pb0330_NoFliker[] = {
        {0xa0, 0x09, 0x001d}, /* 00,1d,09,cc */
        {0xa0, 0x40, 0x001e}, /* 00,1e,40,cc */
        {0xa0, 0x90, 0x001f}, /* 00,1f,90,cc */
-       {0, 0, 0}
+       {}
 };
 static struct usb_action pb0330_NoFlikerScale[] = {
        {0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
@@ -4962,7 +4982,7 @@ static struct usb_action pb0330_NoFlikerScale[] = {
        {0xa0, 0x09, 0x001d}, /* 00,1d,09,cc */
        {0xa0, 0x40, 0x001e}, /* 00,1e,40,cc */
        {0xa0, 0x90, 0x001f}, /* 00,1f,90,cc */
-       {0, 0, 0}
+       {}
 };
 
 /* from oem9.inf - HKR,%PO2030%,Initial - 640x480 - (close to CS2102) */
@@ -5039,7 +5059,7 @@ static struct usb_action PO2030_mode0[] = {
        {0xa0, 0x08, 0x0301}, /* 03,01,08,cc */
        {0xa0, 0x7a, 0x0116}, /* 01,16,7a,cc */
        {0xa0, 0x4a, 0x0118}, /* 01,18,4a,cc */
-       {0, 0, 0}
+       {}
 };
 
 /* from oem9.inf - HKR,%PO2030%,InitialScale - 320x240 */
@@ -5116,7 +5136,7 @@ static struct usb_action PO2030_mode1[] = {
        {0xa0, 0x08, 0x0301}, /* 03,01,08,cc */
        {0xa0, 0x7a, 0x0116}, /* 01,16,7a,cc */
        {0xa0, 0x4a, 0x0118}, /* 01,18,4a,cc */
-       {0, 0, 0}
+       {}
 };
 
 static struct usb_action PO2030_50HZ[] = {
@@ -5138,7 +5158,7 @@ static struct usb_action PO2030_50HZ[] = {
        {0xa0, 0x88, 0x018d}, /* 01,8d,88,cc */
        {0xa0, 0x58, 0x011d}, /* 01,1d,58,cc */
        {0xa0, 0x42, 0x0180}, /* 01,80,42,cc */
-       {0, 0, 0}
+       {}
 };
 
 static struct usb_action PO2030_60HZ[] = {
@@ -5160,7 +5180,7 @@ static struct usb_action PO2030_60HZ[] = {
        {0xa0, 0x88, 0x018d}, /* 01,8d,88,cc */ /* win: 01,8d,80 */
        {0xa0, 0x58, 0x011d}, /* 01,1d,58,cc */
        {0xa0, 0x42, 0x0180}, /* 01,80,42,cc */
-       {0, 0, 0}
+       {}
 };
 
 static struct usb_action PO2030_NoFliker[] = {
@@ -5171,7 +5191,7 @@ static struct usb_action PO2030_NoFliker[] = {
        {0xaa, 0x1c, 0x0078}, /* 00,1c,78,aa */
        {0xaa, 0x46, 0x0000}, /* 00,46,00,aa */
        {0xaa, 0x15, 0x0000}, /* 00,15,00,aa */
-       {0, 0, 0}
+       {}
 };
 
 /* TEST */
@@ -5302,8 +5322,8 @@ static struct usb_action tas5130CK_Initial[] = {
        {0xa0, 0x03, 0x0111},
        {0xa0, 0x51, 0x0112},
        {0xa0, 0x03, 0x0008},
-       {0xa0, 0x08, 0x01c6},
-       {0xa0, 0x0f, 0x01cb},
+       {0xa0, 0x08, 0x01c6},   /* sharpness+ */
+       {0xa0, 0x0f, 0x01cb},   /* sharpness- */
        {0xa0, 0x38, 0x0120},   /* gamma > 5 */
        {0xa0, 0x51, 0x0121},
        {0xa0, 0x6e, 0x0122},
@@ -5375,7 +5395,7 @@ static struct usb_action tas5130CK_Initial[] = {
        {0xa0, 0x15, 0x01ae},
        {0xa0, 0x40, 0x0180},
        {0xa0, 0x42, 0x0180},
-       {0, 0, 0}
+       {}
 };
 
 static struct usb_action tas5130CK_InitialScale[] = {
@@ -5505,8 +5525,8 @@ static struct usb_action tas5130CK_InitialScale[] = {
        {0xa0, 0x03, 0x0111},
        {0xa0, 0x51, 0x0112},
        {0xa0, 0x03, 0x0008},
-       {0xa0, 0x08, 0x01c6},
-       {0xa0, 0x0f, 0x01cb},
+       {0xa0, 0x08, 0x01c6},   /* sharpness+ */
+       {0xa0, 0x0f, 0x01cb},   /* sharpness- */
        {0xa0, 0x38, 0x0120},   /* gamma > 5 */
        {0xa0, 0x51, 0x0121},
        {0xa0, 0x6e, 0x0122},
@@ -5583,7 +5603,7 @@ static struct usb_action tas5130CK_InitialScale[] = {
        {0xa0, 0x02, 0x0008},
        {0xa0, 0x00, 0x0007},
        {0xa0, 0x03, 0x0008},
-       {0, 0, 0}
+       {}
 };
 
 static struct usb_action tas5130cxx_Initial[] = {
@@ -5625,11 +5645,11 @@ static struct usb_action tas5130cxx_Initial[] = {
        {0xa1, 0x01, 0x0002},
        {0xa1, 0x01, 0x0008},
        {0xa0, 0x03, 0x0008},   /* clock ? */
-       {0xa0, 0x08, 0x01c6},
+       {0xa0, 0x08, 0x01c6},   /* sharpness+ */
        {0xa1, 0x01, 0x01c8},
        {0xa1, 0x01, 0x01c9},
        {0xa1, 0x01, 0x01ca},
-       {0xa0, 0x0f, 0x01cb},
+       {0xa0, 0x0f, 0x01cb},   /* sharpness- */
 
        {0xa0, 0x68, 0x010a},   /* matrix */
        {0xa0, 0xec, 0x010b},
@@ -5673,7 +5693,7 @@ static struct usb_action tas5130cxx_Initial[] = {
        {0xa0, 0x40, 0x0180},
        {0xa1, 0x01, 0x0180},
        {0xa0, 0x42, 0x0180},
-       {0, 0, 0}
+       {}
 };
 static struct usb_action tas5130cxx_InitialScale[] = {
        {0xa0, 0x01, 0x0000},
@@ -5718,11 +5738,11 @@ static struct usb_action tas5130cxx_InitialScale[] = {
 
        {0xa0, 0x03, 0x0008},
        {0xa1, 0x01, 0x0008},   /* clock ? */
-       {0xa0, 0x08, 0x01c6},
+       {0xa0, 0x08, 0x01c6},   /* sharpness+ */
        {0xa1, 0x01, 0x01c8},
        {0xa1, 0x01, 0x01c9},
        {0xa1, 0x01, 0x01ca},
-       {0xa0, 0x0f, 0x01cb},
+       {0xa0, 0x0f, 0x01cb},   /* sharpness- */
 
        {0xa0, 0x68, 0x010a},   /* matrix */
        {0xa0, 0xec, 0x010b},
@@ -5763,7 +5783,7 @@ static struct usb_action tas5130cxx_InitialScale[] = {
        {0xa0, 0x40, 0x0180},
        {0xa1, 0x01, 0x0180},
        {0xa0, 0x42, 0x0180},
-       {0, 0, 0}
+       {}
 };
 static struct usb_action tas5130cxx_50HZ[] = {
        {0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
@@ -5786,7 +5806,7 @@ static struct usb_action tas5130cxx_50HZ[] = {
        {0xa0, 0xea, 0x001f}, /* 00,1f,ea,cc */
        {0xa0, 0xff, 0x0020}, /* 00,20,ff,cc */
        {0xa0, 0x03, 0x009f}, /* 00,9f,03,cc */
-       {0, 0, 0}
+       {}
 };
 static struct usb_action tas5130cxx_50HZScale[] = {
        {0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
@@ -5809,7 +5829,7 @@ static struct usb_action tas5130cxx_50HZScale[] = {
        {0xa0, 0xf8, 0x001f}, /* 00,1f,f8,cc */
        {0xa0, 0xff, 0x0020}, /* 00,20,ff,cc */
        {0xa0, 0x03, 0x009f}, /* 00,9f,03,cc */
-       {0, 0, 0}
+       {}
 };
 static struct usb_action tas5130cxx_60HZ[] = {
        {0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
@@ -5832,7 +5852,7 @@ static struct usb_action tas5130cxx_60HZ[] = {
        {0xa0, 0xe0, 0x001f}, /* 00,1f,e0,cc */
        {0xa0, 0xff, 0x0020}, /* 00,20,ff,cc */
        {0xa0, 0x03, 0x009f}, /* 00,9f,03,cc */
-       {0, 0, 0}
+       {}
 };
 static struct usb_action tas5130cxx_60HZScale[] = {
        {0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
@@ -5855,7 +5875,7 @@ static struct usb_action tas5130cxx_60HZScale[] = {
        {0xa0, 0xe0, 0x001f}, /* 00,1f,e0,cc */
        {0xa0, 0xff, 0x0020}, /* 00,20,ff,cc */
        {0xa0, 0x03, 0x009f}, /* 00,9f,03,cc */
-       {0, 0, 0}
+       {}
 };
 static struct usb_action tas5130cxx_NoFliker[] = {
        {0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
@@ -5878,7 +5898,7 @@ static struct usb_action tas5130cxx_NoFliker[] = {
        {0xa0, 0xe0, 0x001f}, /* 00,1f,e0,cc */
        {0xa0, 0xff, 0x0020}, /* 00,20,ff,cc */
        {0xa0, 0x02, 0x009f}, /* 00,9f,02,cc */
-       {0, 0, 0}
+       {}
 };
 
 static struct usb_action tas5130cxx_NoFlikerScale[] = {
@@ -5902,7 +5922,7 @@ static struct usb_action tas5130cxx_NoFlikerScale[] = {
        {0xa0, 0xe0, 0x001f}, /* 00,1f,e0,cc */
        {0xa0, 0xff, 0x0020}, /* 00,20,ff,cc */
        {0xa0, 0x02, 0x009f}, /* 00,9f,02,cc */
-       {0, 0, 0}
+       {}
 };
 
 static struct usb_action tas5130c_vf0250_Initial[] = {
@@ -5966,7 +5986,7 @@ static struct usb_action tas5130c_vf0250_Initial[] = {
        {0xa0, 0x60, 0x01a8},           /* 01,a8,60,cc, */
        {0xa0, 0x61, 0x0116},           /* 01,16,61,cc, */
        {0xa0, 0x65, 0x0118},           /* 01,18,65,cc */
-       {0, 0, 0}
+       {}
 };
 
 static struct usb_action tas5130c_vf0250_InitialScale[] = {
@@ -6030,7 +6050,7 @@ static struct usb_action tas5130c_vf0250_InitialScale[] = {
        {0xa0, 0x60, 0x01a8},           /* 01,a8,60,cc, */
        {0xa0, 0x61, 0x0116},           /* 01,16,61,cc, */
        {0xa0, 0x65, 0x0118},           /* 01,18,65,cc */
-       {0, 0, 0}
+       {}
 };
 /* "50HZ" light frequency banding filter */
 static struct usb_action tas5130c_vf0250_50HZ[] = {
@@ -6054,7 +6074,7 @@ static struct usb_action tas5130c_vf0250_50HZ[] = {
        {0xa0, 0x58, 0x011d},           /* 01,1d,58,cc, */
        {0xa0, 0x42, 0x0180},           /* 01,80,42,cc, */
        {0xa0, 0x78, 0x018d},           /* 01,8d,78,cc */
-       {0, 0, 0}
+       {}
 };
 
 /* "50HZScale" light frequency banding filter */
@@ -6079,7 +6099,7 @@ static struct usb_action tas5130c_vf0250_50HZScale[] = {
        {0xa0, 0x58, 0x011d},           /* 01,1d,58,cc, */
        {0xa0, 0x42, 0x0180},           /* 01,80,42,cc, */
        {0xa0, 0x78, 0x018d},           /* 01,8d,78,cc */
-       {0, 0, 0}
+       {}
 };
 
 /* "60HZ" light frequency banding filter */
@@ -6104,7 +6124,7 @@ static struct usb_action tas5130c_vf0250_60HZ[] = {
        {0xa0, 0x58, 0x011d},           /* 01,1d,58,cc, */
        {0xa0, 0x42, 0x0180},           /* 01,80,42,cc, */
        {0xa0, 0x78, 0x018d},           /* 01,8d,78,cc */
-       {0, 0, 0}
+       {}
 };
 
 /* "60HZScale" light frequency banding ilter */
@@ -6129,7 +6149,7 @@ static struct usb_action tas5130c_vf0250_60HZScale[] = {
        {0xa0, 0x58, 0x011d},           /* 01,d,58,cc, */
        {0xa0, 0x42, 0x0180},           /* 01,80,42,cc, */
        {0xa0, 0x78, 0x018d},           /* 01,d,78,cc */
-       {0, 0, 0}
+       {}
 };
 
 /* "NoFliker" light frequency banding flter */
@@ -6152,7 +6172,7 @@ static struct usb_action tas5130c_vf0250_NoFliker[] = {
        {0xa0, 0xff, 0x0020},           /* 00,20,ff,cc, */
        {0xa0, 0x58, 0x011d},           /* 01,1d,58,cc, */
        {0xa0, 0x03, 0x0180},           /* 01,80,03,cc */
-       {0, 0, 0}
+       {}
 };
 
 /* "NoFlikerScale" light frequency banding filter */
@@ -6175,7 +6195,7 @@ static struct usb_action tas5130c_vf0250_NoFlikerScale[] = {
        {0xa0, 0xff, 0x0020},           /* 00,20,ff,cc, */
        {0xa0, 0x58, 0x011d},           /* 01,1d,58,cc, */
        {0xa0, 0x03, 0x0180},           /* 01,80,03,cc */
-       {0, 0, 0}
+       {}
 };
 
 static void reg_r_i(struct usb_device *dev,
@@ -6325,7 +6345,7 @@ static void setbrightness(struct gspca_dev *gspca_dev)
        case SENSOR_PO2030:
                return;
        }
-/*fixme: is it really 011d 018d for all other sensors? */
+/*fixme: is it really write to 011d and 018d for all other sensors? */
        brightness = sd->brightness;
        reg_w(gspca_dev->dev, brightness, 0x011d);
        if (brightness < 0x70)
@@ -6348,20 +6368,7 @@ static void setsharpness(struct gspca_dev *gspca_dev)
                {0x10, 0x1e}
        };
 
-       switch (sd->sensor) {
-       case SENSOR_GC0305:
-               sharpness = 3;
-               break;
-       case SENSOR_OV7620:
-               sharpness = 2;
-               break;
-       case SENSOR_PO2030:
-               sharpness = 0;
-               break;
-       default:
-               return;
-       }
-/*fixme: sharpness set by V4L2_CID_SATURATION?*/
+       sharpness = sd->sharpness;
        reg_w(dev, sharpness_tb[sharpness][0], 0x01c6);
        reg_r(dev, 0x01c8, &retbyte);
        reg_r(dev, 0x01c9, &retbyte);
@@ -6411,7 +6418,7 @@ static void setcontrast(struct gspca_dev *gspca_dev)
        static __u8 Tgradient_5[16] =
                {0x37, 0x26, 0x20, 0x1a, 0x14, 0x10, 0x0e, 0x0b,
                 0x09, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x02};
-       static __u8 Tgamma_6[16] =              /* ?? was gama 5 */
+       static __u8 Tgamma_6[16] =              /* ?? was gamma 5 */
                {0x24, 0x44, 0x64, 0x84, 0x9d, 0xb2, 0xc4, 0xd3,
                 0xe0, 0xeb, 0xf4, 0xff, 0xff, 0xff, 0xff, 0xff};
        static __u8 Tgradient_6[16] =
@@ -6425,7 +6432,7 @@ static void setcontrast(struct gspca_dev *gspca_dev)
                0, Tgradient_1, Tgradient_2,
                Tgradient_3, Tgradient_4, Tgradient_5, Tgradient_6
        };
-#ifdef GSPCA_DEBUG
+#ifdef VIDEO_ADV_DEBUG
        __u8 v[16];
 #endif
 
@@ -6443,7 +6450,7 @@ static void setcontrast(struct gspca_dev *gspca_dev)
                else if (g <= 0)
                        g = 1;
                reg_w(dev, g, 0x0120 + i);      /* gamma */
-#ifdef GSPCA_DEBUG
+#ifdef VIDEO_ADV_DEBUG
                if (gspca_debug & D_CONF)
                        v[i] = g;
 #endif
@@ -6463,7 +6470,7 @@ static void setcontrast(struct gspca_dev *gspca_dev)
                                g = 1;
                }
                reg_w(dev, g, 0x0130 + i);      /* gradient */
-#ifdef GSPCA_DEBUG
+#ifdef VIDEO_ADV_DEBUG
                if (gspca_debug & D_CONF)
                        v[i] = g;
 #endif
@@ -6488,7 +6495,7 @@ static void setquality(struct gspca_dev *gspca_dev)
                return;
        }
 /*fixme: is it really 0008 0007 0018 for all other sensors? */
-       quality = sd->qindex & 0x0f;
+       quality = sd->qindex;
        reg_w(dev, quality, 0x0008);
        frxt = 0x30;
        reg_w(dev, frxt, 0x0007);
@@ -6525,25 +6532,25 @@ static int setlightfreq(struct gspca_dev *gspca_dev)
        struct usb_action *zc3_freq;
        static struct usb_action *freq_tb[SENSOR_MAX][6] = {
 /* SENSOR_CS2102 0 */
-               {cs2102_50HZ, cs2102_50HZScale,
-                cs2102_60HZ, cs2102_60HZScale,
-                cs2102_NoFliker, cs2102_NoFlikerScale},
+               {cs2102_NoFliker, cs2102_NoFlikerScale,
+                cs2102_50HZ, cs2102_50HZScale,
+                cs2102_60HZ, cs2102_60HZScale},
 /* SENSOR_CS2102K 1 */
-               {cs2102_50HZ, cs2102_50HZScale,
-                cs2102_60HZ, cs2102_60HZScale,
-                cs2102_NoFliker, cs2102_NoFlikerScale},
+               {cs2102_NoFliker, cs2102_NoFlikerScale,
+                cs2102_50HZ, cs2102_50HZScale,
+                cs2102_60HZ, cs2102_60HZScale},
 /* SENSOR_GC0305 2 */
-               {gc0305_50HZ, gc0305_50HZ,
-                gc0305_60HZ, gc0305_60HZ,
-                gc0305_NoFliker, gc0305_NoFliker},
+               {gc0305_NoFliker, gc0305_NoFliker,
+                gc0305_50HZ, gc0305_50HZ,
+                gc0305_60HZ, gc0305_60HZ},
 /* SENSOR_HDCS2020 3 */
                {0, 0,
                 0, 0,
                 0, 0},
 /* SENSOR_HDCS2020b 4 */
-               {hdcs2020b_50HZ, hdcs2020b_50HZ,
-                hdcs2020b_60HZ, hdcs2020b_60HZ,
-                hdcs2020b_NoFliker, hdcs2020b_NoFliker},
+               {hdcs2020b_NoFliker, hdcs2020b_NoFliker,
+                hdcs2020b_50HZ, hdcs2020b_50HZ,
+                hdcs2020b_60HZ, hdcs2020b_60HZ},
 /* SENSOR_HV7131B 5 */
                {0, 0,
                 0, 0,
@@ -6553,66 +6560,48 @@ static int setlightfreq(struct gspca_dev *gspca_dev)
                 0, 0,
                 0, 0},
 /* SENSOR_ICM105A 7 */
-               {icm105a_50HZ, icm105a_50HZScale,
-                icm105a_60HZ, icm105a_60HZScale,
-                icm105a_NoFliker, icm105a_NoFlikerScale},
+               {icm105a_NoFliker, icm105a_NoFlikerScale,
+                icm105a_50HZ, icm105a_50HZScale,
+                icm105a_60HZ, icm105a_60HZScale},
 /* SENSOR_MC501CB 8 */
-               {MC501CB_50HZ, MC501CB_50HZScale,
-                MC501CB_60HZ, MC501CB_60HZScale,
-                MC501CB_NoFliker, MC501CB_NoFlikerScale},
+               {MC501CB_NoFliker, MC501CB_NoFlikerScale,
+                MC501CB_50HZ, MC501CB_50HZScale,
+                MC501CB_60HZ, MC501CB_60HZScale},
 /* SENSOR_OV7620 9 */
-               {OV7620_50HZ, OV7620_50HZ,
-                OV7620_60HZ, OV7620_60HZ,
-                OV7620_NoFliker, OV7620_NoFliker},
+               {OV7620_NoFliker, OV7620_NoFliker,
+                OV7620_50HZ, OV7620_50HZ,
+                OV7620_60HZ, OV7620_60HZ},
 /* SENSOR_OV7630C 10 */
                {0, 0,
                 0, 0,
                 0, 0},
-/* SENSOR_free 11 */
-               {0, 0,
-                0, 0,
-                0, 0},
-/* SENSOR_PAS106 12 */
-               {pas106b_50HZ, pas106b_50HZ,
-                pas106b_60HZ, pas106b_60HZ,
-                pas106b_NoFliker, pas106b_NoFliker},
-/* SENSOR_PB0330 13 */
-               {pb0330_50HZ, pb0330_50HZScale,
-                pb0330_60HZ, pb0330_60HZScale,
-                pb0330_NoFliker, pb0330_NoFlikerScale},
-/* SENSOR_PO2030 14 */
-               {PO2030_50HZ, PO2030_50HZ,
-                PO2030_60HZ, PO2030_60HZ,
-                PO2030_NoFliker, PO2030_NoFliker},
-/* SENSOR_TAS5130CK 15 */
-               {tas5130cxx_50HZ, tas5130cxx_50HZScale,
-                tas5130cxx_60HZ, tas5130cxx_60HZScale,
-                tas5130cxx_NoFliker, tas5130cxx_NoFlikerScale},
-/* SENSOR_TAS5130CXX 16 */
-               {tas5130cxx_50HZ, tas5130cxx_50HZScale,
-                tas5130cxx_60HZ, tas5130cxx_60HZScale,
-                tas5130cxx_NoFliker, tas5130cxx_NoFlikerScale},
-/* SENSOR_TAS5130C_VF0250 17 */
-               {tas5130c_vf0250_50HZ, tas5130c_vf0250_50HZScale,
-                tas5130c_vf0250_60HZ, tas5130c_vf0250_60HZScale,
-                tas5130c_vf0250_NoFliker, tas5130c_vf0250_NoFlikerScale},
+/* SENSOR_PAS106 11 */
+               {pas106b_NoFliker, pas106b_NoFliker,
+                pas106b_50HZ, pas106b_50HZ,
+                pas106b_60HZ, pas106b_60HZ},
+/* SENSOR_PB0330 12 */
+               {pb0330_NoFliker, pb0330_NoFlikerScale,
+                pb0330_50HZ, pb0330_50HZScale,
+                pb0330_60HZ, pb0330_60HZScale},
+/* SENSOR_PO2030 13 */
+               {PO2030_NoFliker, PO2030_NoFliker,
+                PO2030_50HZ, PO2030_50HZ,
+                PO2030_60HZ, PO2030_60HZ},
+/* SENSOR_TAS5130CK 14 */
+               {tas5130cxx_NoFliker, tas5130cxx_NoFlikerScale,
+                tas5130cxx_50HZ, tas5130cxx_50HZScale,
+                tas5130cxx_60HZ, tas5130cxx_60HZScale},
+/* SENSOR_TAS5130CXX 15 */
+               {tas5130cxx_NoFliker, tas5130cxx_NoFlikerScale,
+                tas5130cxx_50HZ, tas5130cxx_50HZScale,
+                tas5130cxx_60HZ, tas5130cxx_60HZScale},
+/* SENSOR_TAS5130C_VF0250 16 */
+               {tas5130c_vf0250_NoFliker, tas5130c_vf0250_NoFlikerScale,
+                tas5130c_vf0250_50HZ, tas5130c_vf0250_50HZScale,
+                tas5130c_vf0250_60HZ, tas5130c_vf0250_60HZScale},
        };
 
-       switch (lightfreq) {
-       case 50:
-               i = 0;
-               break;
-       case 60:
-               i = 2;
-               break;
-       default:
-               PDEBUG(D_ERR, "Invalid light freq value %d", lightfreq);
-               lightfreq = 0;          /* set to default filter value */
-               /* fall thru */
-       case 0:
-               i = 4;
-               break;
-       }
+       i = sd->lightfreq * 2;
        mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].mode;
        if (!mode)
                i++;                    /* 640x480 */
@@ -6622,13 +6611,13 @@ static int setlightfreq(struct gspca_dev *gspca_dev)
                switch (sd->sensor) {
                case SENSOR_GC0305:
                        if (mode                        /* if 320x240 */
-                           && lightfreq == 50)
+                           && sd->lightfreq == 1)      /* and 50Hz */
                                reg_w(gspca_dev->dev, 0x85, 0x018d);
                                                /* win: 0x80, 0x018d */
                        break;
                case SENSOR_OV7620:
                        if (!mode) {                    /* if 640x480 */
-                               if (lightfreq != 0)     /* 50 or 60 Hz */
+                               if (sd->lightfreq != 0) /* and 50 or 60 Hz */
                                        reg_w(gspca_dev->dev, 0x40, 0x0002);
                                else
                                        reg_w(gspca_dev->dev, 0x44, 0x0002);
@@ -6653,9 +6642,9 @@ static void setautogain(struct gspca_dev *gspca_dev)
 
 static void send_unknown(struct usb_device *dev, int sensor)
 {
+       reg_w(dev, 0x01, 0x0000);               /* led off */
        switch (sensor) {
        case SENSOR_PAS106:
-               reg_w(dev, 0x01, 0x0000);
                reg_w(dev, 0x03, 0x003a);
                reg_w(dev, 0x0c, 0x003b);
                reg_w(dev, 0x08, 0x0038);
@@ -6664,7 +6653,6 @@ static void send_unknown(struct usb_device *dev, int sensor)
        case SENSOR_OV7620:
        case SENSOR_PB0330:
        case SENSOR_PO2030:
-               reg_w(dev, 0x01, 0x0000);
                reg_w(dev, 0x0d, 0x003a);
                reg_w(dev, 0x02, 0x003b);
                reg_w(dev, 0x00, 0x0038);
@@ -6817,7 +6805,7 @@ static int vga_3wr_probe(struct gspca_dev *gspca_dev)
 
 /*fixme: lack of 8b=b3 (11,12)-> 10, 8b=e0 (14,15,16)-> 12 found in gspcav1*/
        reg_w(dev, 0x02, 0x0010);
-       reg_r(dev, 0x0010, &retbyte);
+       reg_r(dev, 0x10, &retbyte);
        reg_w(dev, 0x01, 0x0000);
        reg_w(dev, 0x00, 0x0010);
        reg_w(dev, 0x01, 0x0001);
@@ -6964,7 +6952,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
        int sensor;
        __u8 bsensor;
        int vga = 1;            /* 1: vga, 0: sif */
-       static unsigned char gamma[SENSOR_MAX] = {
+       static __u8 gamma[SENSOR_MAX] = {
                5,      /* SENSOR_CS2102 0 */
                5,      /* SENSOR_CS2102K 1 */
                4,      /* SENSOR_GC0305 2 */
@@ -6976,16 +6964,16 @@ static int sd_config(struct gspca_dev *gspca_dev,
                4,      /* SENSOR_MC501CB 8 */
                3,      /* SENSOR_OV7620 9 */
                4,      /* SENSOR_OV7630C 10 */
-               4,      /* SENSOR_free 11 */
-               4,      /* SENSOR_PAS106 12 */
-               4,      /* SENSOR_PB0330 13 */
-               4,      /* SENSOR_PO2030 14 */
-               4,      /* SENSOR_TAS5130CK 15 */
-               4,      /* SENSOR_TAS5130CXX 16 */
-               3,      /* SENSOR_TAS5130C_VF0250 17 */
+               4,      /* SENSOR_PAS106 11 */
+               4,      /* SENSOR_PB0330 12 */
+               4,      /* SENSOR_PO2030 13 */
+               4,      /* SENSOR_TAS5130CK 14 */
+               4,      /* SENSOR_TAS5130CXX 15 */
+               3,      /* SENSOR_TAS5130C_VF0250 16 */
        };
 
        /* define some sensors from the vendor/product */
+       sd->sharpness = 2;
        switch (id->idVendor) {
        case 0x041e:                            /* Creative */
                switch (id->idProduct) {
@@ -7055,8 +7043,9 @@ static int sd_config(struct gspca_dev *gspca_dev,
                        sd->sensor = SENSOR_ICM105A;
                        break;
                case 0x0e:
-                       PDEBUG(D_PROBE, "Find Sensor PAS202BCB");
+                       PDEBUG(D_PROBE, "Find Sensor HDCS2020");
                        sd->sensor = SENSOR_HDCS2020;
+                       sd->sharpness = 1;
                        break;
                case 0x0f:
                        PDEBUG(D_PROBE, "Find Sensor PAS106");
@@ -7097,6 +7086,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
                case 0x2030:
                        PDEBUG(D_PROBE, "Find Sensor PO2030");
                        sd->sensor = SENSOR_PO2030;
+                       sd->sharpness = 0;              /* from win traces */
                        break;
                case 0x7620:
                        PDEBUG(D_PROBE, "Find Sensor OV7620");
@@ -7134,13 +7124,13 @@ static int sd_config(struct gspca_dev *gspca_dev,
        sd->qindex = 1;
        sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
        sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
-       sd->autogain = sd_ctrls[SD_AUTOGAIN].qctrl.default_value;
        sd->gamma = gamma[(int) sd->sensor];
+       sd->autogain = sd_ctrls[SD_AUTOGAIN].qctrl.default_value;
+       sd->lightfreq = sd_ctrls[SD_FREQ].qctrl.default_value;
+       sd->sharpness = sd_ctrls[SD_SHARPNESS].qctrl.default_value;
 
        /* switch the led off */
-/*fixme: other sensors? */
-       if (sensor == 0x06 || sensor == 0x11)
-               reg_w(gspca_dev->dev, 0x01, 0x0000);
+       reg_w(gspca_dev->dev, 0x01, 0x0000);
        return 0;
 }
 
@@ -7170,15 +7160,14 @@ static void sd_start(struct gspca_dev *gspca_dev)
                {MC501CB_InitialScale, MC501CB_Initial},        /* 9 */
                {OV7620_mode0, OV7620_mode1},                   /* 9 */
                {ov7630c_InitialScale, ov7630c_Initial},        /* 10 */
-               {0, 0},                                         /* 11 */
-               {pas106b_InitialScale, pas106b_Initial},        /* 12 */
-               {pb0330xx_InitialScale, pb0330xx_Initial},      /* 13 */
+               {pas106b_InitialScale, pas106b_Initial},        /* 11 */
+               {pb0330xx_InitialScale, pb0330xx_Initial},      /* 12 */
 /* or          {pb03303x_InitialScale, pb03303x_Initial}, */
-               {PO2030_mode0, PO2030_mode1},                   /* 14 */
-               {tas5130CK_InitialScale, tas5130CK_Initial},    /* 15 */
-               {tas5130cxx_InitialScale, tas5130cxx_Initial},  /* 16 */
+               {PO2030_mode0, PO2030_mode1},                   /* 13 */
+               {tas5130CK_InitialScale, tas5130CK_Initial},    /* 14 */
+               {tas5130cxx_InitialScale, tas5130cxx_Initial},  /* 15 */
                {tas5130c_vf0250_InitialScale, tas5130c_vf0250_Initial},
-                                                               /* 17 */
+                                                               /* 16 */
        };
 
        mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].mode;
@@ -7324,7 +7313,7 @@ static void sd_close(struct gspca_dev *gspca_dev)
 
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                        struct gspca_frame *frame,
-                       unsigned char *data,
+                       __u8 *data,
                        int len)
 {
 
@@ -7401,6 +7390,16 @@ static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
        return 0;
 }
 
+static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->gamma = val;
+       if (gspca_dev->streaming)
+               setcontrast(gspca_dev);
+       return 0;
+}
+
 static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
@@ -7409,6 +7408,63 @@ static int sd_getgamma(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->lightfreq = val;
+       if (gspca_dev->streaming)
+               setlightfreq(gspca_dev);
+       return 0;
+}
+
+static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->lightfreq;
+       return 0;
+}
+
+static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->sharpness = val;
+       if (gspca_dev->streaming)
+               setsharpness(gspca_dev);
+       return 0;
+}
+
+static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->sharpness;
+       return 0;
+}
+
+static int sd_querymenu(struct gspca_dev *gspca_dev,
+                       struct v4l2_querymenu *menu)
+{
+       switch (menu->id) {
+       case V4L2_CID_POWER_LINE_FREQUENCY:
+               switch (menu->index) {
+               case 0:         /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */
+                       strcpy(menu->name, "NoFliker");
+                       return 0;
+               case 1:         /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
+                       strcpy(menu->name, "50 Hz");
+                       return 0;
+               case 2:         /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
+                       strcpy(menu->name, "60 Hz");
+                       return 0;
+               }
+               break;
+       }
+       return -EINVAL;
+}
+
 static struct sd_desc sd_desc = {
        .name = MODULE_NAME,
        .ctrls = sd_ctrls,
@@ -7420,6 +7476,7 @@ static struct sd_desc sd_desc = {
        .stop0 = sd_stop0,
        .close = sd_close,
        .pkt_scan = sd_pkt_scan,
+       .querymenu = sd_querymenu,
 };
 
 #define DVNM(name) .driver_info = (kernel_ulong_t) name
@@ -7514,10 +7571,6 @@ static void __exit sd_mod_exit(void)
 module_init(sd_mod_init);
 module_exit(sd_mod_exit);
 
-module_param(lightfreq, int, 0644);
-MODULE_PARM_DESC(lightfreq,
-       "Light frequency banding filter: 50, 60 Hz or"
-       " 0 to NoFliker (default=50)");
 module_param(force_sensor, int, 0644);
 MODULE_PARM_DESC(force_sensor,
        "Force sensor. Only for experts!!!");
index 9385c823a978a1e43e9764283783d1bb7779e316..43a6c81a53ef384f68e0a938554c470cf78cf129 100644 (file)
@@ -324,6 +324,8 @@ struct v4l2_pix_format
 #define V4L2_PIX_FMT_PWC1     v4l2_fourcc('P','W','C','1') /* pwc older webcam */
 #define V4L2_PIX_FMT_PWC2     v4l2_fourcc('P','W','C','2') /* pwc newer webcam */
 #define V4L2_PIX_FMT_ET61X251 v4l2_fourcc('E','6','2','5') /* ET61X251 compression */
+#define V4L2_PIX_FMT_SPCA501  v4l2_fourcc('S','5','0','1') /* YUYV per line */
+#define V4L2_PIX_FMT_SPCA561  v4l2_fourcc('S','5','6','1') /* compressed BGGR bayer */
 
 /*
  *     F O R M A T   E N U M E R A T I O N