V4L/DVB (8157): gspca: all subdrivers
Jean-Francois Moine [Mon, 30 Jun 2008 18:50:11 +0000 (15:50 -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 9c404b5..37996e5 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 2ec920d..d5f6eea 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 a04e413..42b9074 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 d959f77..e68a896 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 423ebbd..5583c53 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 e69d847..1581fa8 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 482ef4a..72a5b89 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)&nbs