V4L/DVB (8157): gspca: all subdrivers

- 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>
diff --git a/Documentation/video4linux/gspca.txt b/Documentation/video4linux/gspca.txt
index 9c404b5..37996e5 100644
--- a/Documentation/video4linux/gspca.txt
+++ b/Documentation/video4linux/gspca.txt
@@ -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,203 +6,50 @@
 
 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
-ov519		041e:4052	Creative Live! VISTA 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
-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
-spca500		046d:0890	Logitech QuickCam traveler
-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
-spca561		046d:0928	Logitech QC Express Etch2
-spca561		046d:0929	Labtec Webcam Elch2
-spca561		046d:092a	Logitech QC for Notebook
-spca561		046d:092b	Labtec Webcam Plus
-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
+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
-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
-sunplus		04a5:3003	Benq DC 1300
-sunplus		04a5:3008	Benq DC 1500
-sunplus		04a5:300a	Benq DC3410
-sunplus		04f1:1001	JVC GC A50
-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
-sunplus		04fc:ffff	Pure DigitalDakota
-sunplus		052b:1513	Megapix V4
-sunplus		0546:3155	Polaroid PDC3070
-sunplus		0546:3191	Polaroid Ion 80
-sunplus		0546:3273	Polaroid PDC2030
-sunplus		055f:c211	Kowa Bs888e Microcamera
-sunplus		055f:c230	Mustek Digicam 330K
-sunplus		055f:c232	Mustek MDC3500
-sunplus		055f:c360	Mustek DV4000 Mpeg4
-sunplus		055f:c420	Mustek gSmart Mini 2
-sunplus		055f:c430	Mustek Gsmart LCD 2
-sunplus		055f:c440	Mustek DV 3000
-sunplus		055f:c520	Mustek gSmart Mini 3
-sunplus		055f:c530	Mustek Gsmart LCD 3
-sunplus		055f:c540	Gsmart D30
-sunplus		055f:c630	Mustek MDC4000
-sunplus		055f:c650	Mustek MDC5500Z
-sunplus		05da:1018	Digital Dream Enigma 1.3
-sunplus		06d6:0031	Trust 610 LCD PowerC@m Zoom
-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
-sunplus		08ca:0104	Aiptek PocketDVII 1.3
-sunplus		08ca:0106	Aiptek Pocket DV3100+
-sunplus		08ca:2008	Aiptek Mini PenCam 2 M
-sunplus		08ca:2010	Aiptek PocketCam 3M
-sunplus		08ca:2016	Aiptek PocketCam 2 Mega
-sunplus		08ca:2018	Aiptek Pencam SD 2M
-sunplus		08ca:2020	Aiptek Slim 3000F
-sunplus		08ca:2022	Aiptek Slim 3200
-sunplus		08ca:2024	Aiptek DV3500 Mpeg4
-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
-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
+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
+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
+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
@@ -221,18 +68,173 @@
 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
+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
+spca561		046d:092b	Labtec Webcam Plus
+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
+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
+sunplus		055f:c420	Mustek gSmart Mini 2
+sunplus		055f:c430	Mustek Gsmart LCD 2
+sunplus		055f:c440	Mustek DV 3000
+sunplus		055f:c520	Mustek gSmart Mini 3
+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
+sunplus		08ca:2010	Aiptek PocketCam 3M
+sunplus		08ca:2016	Aiptek PocketCam 2 Mega
+sunplus		08ca:2018	Aiptek Pencam SD 2M
+sunplus		08ca:2020	Aiptek Slim 3000F
+sunplus		08ca:2022	Aiptek Slim 3200
+sunplus		08ca:2024	Aiptek DV3500 Mpeg4
+sunplus		08ca:2028	Aiptek PocketCam4M
+sunplus		08ca:2040	Aiptek PocketDV4100M
+sunplus		08ca:2042	Aiptek PocketDV5100
+sunplus		08ca:2060	Aiptek PocketDV5300
+tv8532		0923:010f	ICM532 cams
+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
 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
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 2ec920d..d5f6eea 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -117,6 +117,7 @@
 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/
diff --git a/drivers/media/video/gspca/Kconfig b/drivers/media/video/gspca/Kconfig
index a04e413..42b9074 100644
--- a/drivers/media/video/gspca/Kconfig
+++ b/drivers/media/video/gspca/Kconfig
@@ -2,7 +2,7 @@
 	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.
 
diff --git a/drivers/media/video/gspca/Makefile b/drivers/media/video/gspca/Makefile
index d959f77..e68a896 100644
--- a/drivers/media/video/gspca/Makefile
+++ b/drivers/media/video/gspca/Makefile
@@ -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
index 0000000..b0294c9
--- /dev/null
+++ b/drivers/media/video/gspca/conex.c
@@ -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
index 0000000..c479f63
--- /dev/null
+++ b/drivers/media/video/gspca/etoms.c
@@ -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);
diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c
index 423ebbd..5583c53 100644
--- a/drivers/media/video/gspca/gspca.c
+++ b/drivers/media/video/gspca/gspca.c
@@ -35,24 +35,24 @@
 
 #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 @@
 #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 @@
 			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 @@
 
 		/* 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 @@
  *	  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 @@
 	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 @@
 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 @@
 	/* 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 __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 @@
 	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 @@
 		(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 @@
 		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 @@
 		}
 	}
 	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 @@
 	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 @@
 		"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 @@
 {
 	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 @@
 				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 @@
 	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 @@
 {
 	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 @@
 {
 	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 @@
 		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 @@
 	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 @@
 		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 @@
 	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 @@
 	}
 	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 @@
 		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 @@
 	return 0;
 }
 
+/* the use of V4L2_CTRL_FLAG_NEXT_CTRL asks for the controls to be sorted */
 static int vidioc_queryctrl(struct file *file, void *priv,
 			   struct v4l2_queryctrl *q_ctrl)
 {
 	struct gspca_dev *gspca_dev = priv;
 	int i;
+	u32 id;
 
-	PDEBUG(D_CONF, "queryctrl");
+	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 @@
 		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 @@
 		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 @@
 {
 	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 @@
 	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 @@
 
 	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 @@
 
 	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 @@
 	.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 @@
 	.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 @@
 	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 @@
 /* -- 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");
diff --git a/drivers/media/video/gspca/gspca.h b/drivers/media/video/gspca/gspca.h
index e69d847..1581fa8 100644
--- a/drivers/media/video/gspca/gspca.h
+++ b/drivers/media/video/gspca/gspca.h
@@ -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 @@
 
 #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 @@
 			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 @@
 #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 @@
 
 	__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 @@
 
 	__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 @@
 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
index 0000000..48b861d
--- /dev/null
+++ b/drivers/media/video/gspca/mars.c
@@ -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
index 0000000..7d6237f
--- /dev/null
+++ b/drivers/media/video/gspca/ov519.c
@@ -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)");
diff --git a/drivers/media/video/gspca/pac207.c b/drivers/media/video/gspca/pac207.c
index 482ef4a..72a5b89 100644
--- a/drivers/media/video/gspca/pac207.c
+++ b/drivers/media/video/gspca/pac207.c
@@ -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 @@
 	struct sd *sd = (struct sd *) gspca_dev;
 
 	sd->autogain = 1;
-
 	return 0;
 }
 
@@ -338,7 +337,7 @@
 
 	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 @@
 				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
index 0000000..8f51976
--- /dev/null
+++ b/drivers/media/video/gspca/pac7311.c
@@ -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
index 0000000..d26255d
--- /dev/null
+++ b/drivers/media/video/gspca/sonixb.c
@@ -0,0 +1,879 @@
+/*
+ *		sonix sn9c102 (bayer) library
+ *		Copyright (C) 2003 2004 Michel Xhaard mxhaard@magic.fr
+ * Add Pas106 Stefano Mozzi (C) 2004
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define MODULE_NAME "sonixb"
+
+#include "gspca.h"
+
+#define DRIVER_VERSION_NUMBER	KERNEL_VERSION(2, 1, 0)
+static const char version[] = "2.1.0";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("GSPCA/SN9C102 USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+	struct gspca_dev gspca_dev;	/* !! must be the first item */
+
+	unsigned char brightness;
+	unsigned char contrast;
+
+	char sensor;			/* Type of image sensor chip */
+#define SENSOR_HV7131R 0
+#define SENSOR_OV6650 1
+#define SENSOR_OV7630 2
+#define SENSOR_OV7630_3 3
+#define SENSOR_PAS106 4
+#define SENSOR_PAS202 5
+#define SENSOR_TAS5110 6
+#define SENSOR_TAS5130CXX 7
+};
+
+#define COMP2 0x8f
+#define COMP 0xc7		/* 0x87 //0x07 */
+#define COMP1 0xc9		/* 0x89 //0x09 */
+
+#define MCK_INIT 0x63
+#define MCK_INIT1 0x20		/*fixme: Bayer - 0x50 for JPEG ??*/
+
+#define SYS_CLK 0x04
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+#define SD_BRIGHTNESS 0
+	{
+	    {
+		.id      = V4L2_CID_BRIGHTNESS,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Brightness",
+		.minimum = 0,
+		.maximum = 255,
+		.step    = 1,
+		.default_value = 127,
+	    },
+	    .set = sd_setbrightness,
+	    .get = sd_getbrightness,
+	},
+#define SD_CONTRAST 1
+	{
+	    {
+		.id      = V4L2_CID_CONTRAST,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Contrast",
+		.minimum = 0,
+		.maximum = 255,
+		.step    = 1,
+		.default_value = 127,
+	    },
+	    .set = sd_setcontrast,
+	    .get = sd_getcontrast,
+	},
+};
+
+/* fixme: should have V4L2_PIX_FMT_SN9C10X */
+static struct cam_mode vga_mode[] = {
+	{V4L2_PIX_FMT_SN9C10X, 160, 120, 2},
+	{V4L2_PIX_FMT_SN9C10X, 320, 240, 1},
+	{V4L2_PIX_FMT_SN9C10X, 640, 480, 0},
+};
+static struct cam_mode sif_mode[] = {
+	{V4L2_PIX_FMT_SN9C10X, 176, 144, 1},
+	{V4L2_PIX_FMT_SN9C10X, 352, 288, 0},
+};
+
+static const __u8 probe_ov7630[] = {0x08, 0x44};
+
+static const __u8 initHv7131[] = {
+	0x46, 0x77, 0x00, 0x04, 0x00, 0x00, 0x00, 0x80, 0x11, 0x00, 0x00, 0x00,
+	0x00, 0x00,
+	0x00, 0x00, 0x00, 0x03, 0x01, 0x00,	/* shift from 0x02 0x01 0x00 */
+	0x28, 0x1e, 0x60, 0x8a, 0x20,
+	0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c
+};
+static const __u8 hv7131_sensor_init[][8] = {
+	{0xc0, 0x11, 0x31, 0x38, 0x2a, 0x2e, 0x00, 0x10},
+	{0xa0, 0x11, 0x01, 0x08, 0x2a, 0x2e, 0x00, 0x10},
+	{0xb0, 0x11, 0x20, 0x00, 0xd0, 0x2e, 0x00, 0x10},
+	{0xc0, 0x11, 0x25, 0x03, 0x0e, 0x28, 0x00, 0x16},
+	{0xa0, 0x11, 0x30, 0x10, 0x0e, 0x28, 0x00, 0x15},
+};
+static const __u8 initOv6650[] = {
+	0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+	0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x02, 0x01, 0x0a, 0x16, 0x12, 0x68, 0x0b,
+	0x10, 0x1d, 0x10, 0x00, 0x06, 0x1f, 0x00
+};
+static const __u8 ov6650_sensor_init[][8] =
+{
+	/* Bright, contrast, etc are set througth SCBB interface.
+	 * AVCAP on win2 do not send any data on this 	controls. */
+	/* Anyway, some registers appears to alter bright and constrat */
+	{0xa0, 0x60, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10},
+	{0xd0, 0x60, 0x11, 0xc0, 0x1b, 0x18, 0xc1, 0x10},
+	{0xb0, 0x60, 0x15, 0x00, 0x02, 0x18, 0xc1, 0x10},
+/*	{0xa0, 0x60, 0x1b, 0x01, 0x02, 0x18, 0xc1, 0x10},
+		 * THIS SET GREEN SCREEN
+		 * (pixels could be innverted in decode kind of "brg",
+		 * but blue wont be there. Avoid this data ... */
+	{0xd0, 0x60, 0x26, 0x01, 0x14, 0xd8, 0xa4, 0x10}, /* format out? */
+	{0xd0, 0x60, 0x26, 0x01, 0x14, 0xd8, 0xa4, 0x10},
+	{0xa0, 0x60, 0x30, 0x3d, 0x0A, 0xd8, 0xa4, 0x10},
+	{0xb0, 0x60, 0x60, 0x66, 0x68, 0xd8, 0xa4, 0x10},
+	{0xa0, 0x60, 0x68, 0x04, 0x68, 0xd8, 0xa4, 0x10},
+	{0xd0, 0x60, 0x17, 0x24, 0xd6, 0x04, 0x94, 0x10}, /* Clipreg */
+	{0xa0, 0x60, 0x10, 0x5d, 0x99, 0x04, 0x94, 0x16},
+	{0xa0, 0x60, 0x2d, 0x0a, 0x99, 0x04, 0x94, 0x16},
+	{0xa0, 0x60, 0x32, 0x00, 0x99, 0x04, 0x94, 0x16},
+	{0xa0, 0x60, 0x33, 0x40, 0x99, 0x04, 0x94, 0x16},
+	{0xa0, 0x60, 0x11, 0xc0, 0x99, 0x04, 0x94, 0x16},
+	{0xa0, 0x60, 0x00, 0x16, 0x99, 0x04, 0x94, 0x15}, /* bright / Lumino */
+	{0xa0, 0x60, 0x2b, 0xab, 0x99, 0x04, 0x94, 0x15},
+							/* ?flicker o brillo */
+	{0xa0, 0x60, 0x2d, 0x2a, 0x99, 0x04, 0x94, 0x15},
+	{0xa0, 0x60, 0x2d, 0x2b, 0x99, 0x04, 0x94, 0x16},
+	{0xa0, 0x60, 0x32, 0x00, 0x99, 0x04, 0x94, 0x16},
+	{0xa0, 0x60, 0x33, 0x00, 0x99, 0x04, 0x94, 0x16},
+	{0xa0, 0x60, 0x10, 0x57, 0x99, 0x04, 0x94, 0x16},
+	{0xa0, 0x60, 0x2d, 0x2b, 0x99, 0x04, 0x94, 0x16},
+	{0xa0, 0x60, 0x32, 0x00, 0x99, 0x04, 0x94, 0x16},
+		/* Low Light (Enabled: 0x32 0x1 | Disabled: 0x32 0x00) */
+	{0xa0, 0x60, 0x33, 0x29, 0x99, 0x04, 0x94, 0x16},
+		/* Low Ligth (Enabled: 0x33 0x13 | Disabled: 0x33 0x29) */
+/*	{0xa0, 0x60, 0x11, 0xc1, 0x99, 0x04, 0x94, 0x16}, */
+	{0xa0, 0x60, 0x00, 0x17, 0x99, 0x04, 0x94, 0x15}, /* clip? r */
+	{0xa0, 0x60, 0x00, 0x18, 0x99, 0x04, 0x94, 0x15}, /* clip? r */
+};
+static const __u8 initOv7630[] = {
+	0x04, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,	/* r01 .. r08 */
+	0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* r09 .. r10 */
+	0x00, 0x02, 0x01, 0x0a,				/* r11 .. r14 */
+	0x28, 0x1e,			/* H & V sizes     r15 .. r16 */
+	0x68, COMP1, MCK_INIT1,				/* r17 .. r19 */
+	0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c		/* r1a .. r1f */
+};
+static const __u8 initOv7630_3[] = {
+	0x44, 0x44, 0x00, 0x1a, 0x20, 0x20, 0x20, 0x80,	/* r01 .. r08 */
+	0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,	/* r09 .. r10 */
+	0x00, 0x02, 0x01, 0x0a,				/* r11 .. r14 */
+	0x28, 0x1e,			/* H & V sizes     r15 .. r16 */
+	0x68, COMP1, MCK_INIT1,				/* r17 .. r19 */
+	0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c		/* r1a .. r1f */
+};
+static const __u8 ov7630_sensor_init_com[][8] = {
+	{0xa0, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10},
+	{0xb0, 0x21, 0x01, 0x77, 0x3a, 0x00, 0x00, 0x10},
+/*	{0xd0, 0x21, 0x12, 0x7c, 0x01, 0x80, 0x34, 0x10},	   jfm */
+	{0xd0, 0x21, 0x12, 0x78, 0x00, 0x80, 0x34, 0x10},	/* jfm */
+	{0xa0, 0x21, 0x1b, 0x04, 0x00, 0x80, 0x34, 0x10},
+	{0xa0, 0x21, 0x20, 0x44, 0x00, 0x80, 0x34, 0x10},
+	{0xa0, 0x21, 0x23, 0xee, 0x00, 0x80, 0x34, 0x10},
+	{0xd0, 0x21, 0x26, 0xa0, 0x9a, 0xa0, 0x30, 0x10},
+	{0xb0, 0x21, 0x2a, 0x80, 0x00, 0xa0, 0x30, 0x10},
+	{0xb0, 0x21, 0x2f, 0x3d, 0x24, 0xa0, 0x30, 0x10},
+	{0xa0, 0x21, 0x32, 0x86, 0x24, 0xa0, 0x30, 0x10},
+/*	{0xb0, 0x21, 0x60, 0xa9, 0x4a, 0xa0, 0x30, 0x10},	   jfm */
+	{0xb0, 0x21, 0x60, 0xa9, 0x42, 0xa0, 0x30, 0x10},	/* jfm */
+	{0xa0, 0x21, 0x65, 0x00, 0x42, 0xa0, 0x30, 0x10},
+	{0xa0, 0x21, 0x69, 0x38, 0x42, 0xa0, 0x30, 0x10},
+	{0xc0, 0x21, 0x6f, 0x88, 0x0b, 0x00, 0x30, 0x10},
+	{0xc0, 0x21, 0x74, 0x21, 0x8e, 0x00, 0x30, 0x10},
+	{0xa0, 0x21, 0x7d, 0xf7, 0x8e, 0x00, 0x30, 0x10},
+	{0xd0, 0x21, 0x17, 0x1c, 0xbd, 0x06, 0xf6, 0x10},
+};
+static const __u8 ov7630_sensor_init[][8] = {
+	{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 200ms */
+	{0xa0, 0x21, 0x11, 0x01, 0xbd, 0x06, 0xf6, 0x10},	/* jfm */
+	{0xa0, 0x21, 0x10, 0x57, 0xbd, 0x06, 0xf6, 0x16},
+	{0xa0, 0x21, 0x76, 0x02, 0xbd, 0x06, 0xf6, 0x16},
+	{0xa0, 0x21, 0x00, 0x10, 0xbd, 0x06, 0xf6, 0x15},	/* gain */
+};
+static const __u8 ov7630_sensor_init_3[][8] = {
+	{0xa0, 0x21, 0x10, 0x36, 0xbd, 0x06, 0xf6, 0x16},	/* exposure */
+	{0xa0, 0x21, 0x76, 0x03, 0xbd, 0x06, 0xf6, 0x16},
+	{0xa0, 0x21, 0x11, 0x01, 0xbd, 0x06, 0xf6, 0x16},
+	{0xa0, 0x21, 0x00, 0x10, 0xbd, 0x06, 0xf6, 0x15},	/* gain */
+/*	{0xb0, 0x21, 0x2a, 0xc0, 0x3c, 0x06, 0xf6, 0x1d},
+		* a0 1c,a0 1f,c0 3c frame rate ?line interval from ov6630 */
+/*	{0xb0, 0x21, 0x2a, 0xa0, 0x1f, 0x06, 0xf6, 0x1d},	 * from win */
+	{0xb0, 0x21, 0x2a, 0xa0, 0x1c, 0x06, 0xf6, 0x1d},
+};
+
+static const __u8 initPas106[] = {
+	0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x40, 0x00, 0x00, 0x00,
+	0x00, 0x00,
+	0x00, 0x00, 0x00, 0x05, 0x01, 0x00,
+	0x16, 0x12, 0x28, COMP1, MCK_INIT1,
+	0x18, 0x10, 0x04, 0x03, 0x11, 0x0c
+};
+/* compression 0x86 mckinit1 0x2b */
+static const __u8 pas106_data[][2] = {
+	{0x02, 0x04},		/* Pixel Clock Divider 6 */
+	{0x03, 0x13},		/* Frame Time MSB */
+/*	{0x03, 0x12},		 * Frame Time MSB */
+	{0x04, 0x06},		/* Frame Time LSB */
+/*	{0x04, 0x05},		 * Frame Time LSB */
+	{0x05, 0x65},		/* Shutter Time Line Offset */
+/*	{0x05, 0x6d},		 * Shutter Time Line Offset */
+/*	{0x06, 0xb1},		 * Shutter Time Pixel Offset */
+	{0x06, 0xcd},		/* Shutter Time Pixel Offset */
+	{0x07, 0xc1},		/* Black Level Subtract Sign */
+/*	{0x07, 0x00},		 * Black Level Subtract Sign */
+	{0x08, 0x06},		/* Black Level Subtract Level */
+	{0x08, 0x06},		/* Black Level Subtract Level */
+/*	{0x08, 0x01},		 * Black Level Subtract Level */
+	{0x09, 0x05},		/* Color Gain B Pixel 5 a */
+	{0x0a, 0x04},		/* Color Gain G1 Pixel 1 5 */
+	{0x0b, 0x04},		/* Color Gain G2 Pixel 1 0 5 */
+	{0x0c, 0x05},		/* Color Gain R Pixel 3 1 */
+	{0x0d, 0x00},		/* Color GainH  Pixel */
+	{0x0e, 0x0e},		/* Global Gain */
+	{0x0f, 0x00},		/* Contrast */
+	{0x10, 0x06},		/* H&V synchro polarity */
+	{0x11, 0x06},		/* ?default */
+	{0x12, 0x06},		/* DAC scale */
+	{0x14, 0x02},		/* ?default */
+	{0x13, 0x01},		/* Validate Settings */
+};
+static const __u8 initPas202[] = {
+	0x44, 0x44, 0x21, 0x30, 0x00, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, 0x00,
+	0x00, 0x00,
+	0x00, 0x00, 0x00, 0x07, 0x03, 0x0a,	/* 6 */
+	0x28, 0x1e, 0x28, 0x89, 0x30,
+	0x00, 0x00, 0x02, 0x03, 0x0f, 0x0c
+};
+static const __u8 pas202_sensor_init[][8] = {
+	{0xa0, 0x40, 0x02, 0x03, 0x00, 0x00, 0x00, 0x10},
+	{0xd0, 0x40, 0x04, 0x07, 0x34, 0x00, 0x09, 0x10},
+	{0xd0, 0x40, 0x08, 0x01, 0x00, 0x00, 0x01, 0x10},
+	{0xd0, 0x40, 0x0C, 0x00, 0x0C, 0x00, 0x32, 0x10},
+	{0xd0, 0x40, 0x10, 0x00, 0x01, 0x00, 0x63, 0x10},
+	{0xa0, 0x40, 0x15, 0x70, 0x01, 0x00, 0x63, 0x10},
+	{0xa0, 0x40, 0x18, 0x00, 0x01, 0x00, 0x63, 0x10},
+	{0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10},
+	{0xa0, 0x40, 0x03, 0x56, 0x01, 0x00, 0x63, 0x10},
+	{0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10},
+	{0xb0, 0x40, 0x04, 0x07, 0x2a, 0x00, 0x63, 0x10},
+	{0xb0, 0x40, 0x0e, 0x00, 0x3d, 0x00, 0x63, 0x10},
+
+	{0xa0, 0x40, 0x11, 0x01, 0x3d, 0x00, 0x63, 0x16},
+	{0xa0, 0x40, 0x10, 0x08, 0x3d, 0x00, 0x63, 0x15},
+	{0xa0, 0x40, 0x02, 0x04, 0x3d, 0x00, 0x63, 0x16},
+	{0xa0, 0x40, 0x11, 0x01, 0x3d, 0x00, 0x63, 0x16},
+	{0xb0, 0x40, 0x0e, 0x00, 0x31, 0x00, 0x63, 0x16},
+	{0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16},
+	{0xa0, 0x40, 0x10, 0x0e, 0x31, 0x00, 0x63, 0x15},
+	{0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16},
+};
+
+static const __u8 initTas5110[] = {
+	0x44, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00,
+	0x00, 0x00,
+	0x00, 0x01, 0x00, 0x46, 0x09, 0x0a,	/* shift from 0x45 0x09 0x0a */
+	0x16, 0x12, 0x60, 0x86, 0x2b,
+	0x14, 0x0a, 0x02, 0x02, 0x09, 0x07
+};
+static const __u8 tas5110_sensor_init[][8] = {
+	{0x30, 0x11, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x10},
+	{0x30, 0x11, 0x02, 0x20, 0xa9, 0x00, 0x00, 0x10},
+	{0xa0, 0x61, 0x9a, 0xca, 0x00, 0x00, 0x00, 0x17},
+};
+
+static const __u8 initTas5130[] = {
+	0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00,
+	0x00, 0x00,
+	0x00, 0x01, 0x00, 0x69, 0x0c, 0x0a,
+	0x28, 0x1e, 0x60, COMP, MCK_INIT,
+	0x18, 0x10, 0x04, 0x03, 0x11, 0x0c
+};
+static const __u8 tas5130_sensor_init[][8] = {
+/* 	{0x30, 0x11, 0x00, 0x40, 0x47, 0x00, 0x00, 0x10},
+					* shutter 0x47 short exposure? */
+	{0x30, 0x11, 0x00, 0x40, 0x01, 0x00, 0x00, 0x10},
+					/* shutter 0x01 long exposure */
+	{0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10},
+};
+
+static void reg_r(struct usb_device *dev,
+			 __u16 value, __u8 *buffer)
+{
+	usb_control_msg(dev,
+			usb_rcvctrlpipe(dev, 0),
+			0,			/* request */
+			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+			value,
+			0,			/* index */
+			buffer, 1,
+			500);
+}
+
+static void reg_w(struct usb_device *dev,
+			  __u16 value,
+			  const __u8 *buffer,
+			  __u16 len)
+{
+	usb_control_msg(dev,
+			usb_sndctrlpipe(dev, 0),
+			0x08,			/* request */
+			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+			value,
+			0,			/* index */
+			(__u8 *) buffer, len,
+			500);
+}
+
+static int i2c_w(struct usb_device *dev, const __u8 *buffer)
+{
+	int retry = 60;
+	__u8 ByteReceive;
+
+	/* is i2c ready */
+	reg_w(dev, 0x08, buffer, 8);
+	while (retry--) {
+		msleep(10);
+		reg_r(dev, 0x08, &ByteReceive);
+		if (ByteReceive == 4)
+			return 0;
+	}
+	return -1;
+}
+
+static void i2c_w_vector(struct usb_device *dev,
+			const __u8 buffer[][8], int len)
+{
+	for (;;) {
+		reg_w(dev, 0x08, *buffer, 8);
+		len -= 8;
+		if (len <= 0)
+			break;
+		buffer++;
+	}
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	__u8 value;
+
+	switch (sd->sensor) {
+	case SENSOR_OV6650: {
+		__u8 i2cOV6650[] =
+			{0xa0, 0x60, 0x06, 0x11, 0x99, 0x04, 0x94, 0x15};
+
+		i2cOV6650[3] = sd->brightness;
+		if (i2c_w(gspca_dev->dev, i2cOV6650) < 0)
+			 goto err;
+		break;
+	    }
+	case  SENSOR_OV7630: {
+		__u8 i2cOV[] =
+			{0xa0, 0x21, 0x06, 0x36, 0xbd, 0x06, 0xf6, 0x16};
+
+		/* change reg 0x06 */
+		i2cOV[3] = sd->brightness;
+		if (i2c_w(gspca_dev->dev, i2cOV) < 0)
+			goto err;
+		break;
+	    }
+	case SENSOR_PAS106: {
+		__u8 i2c1[] =
+			{0xa1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14};
+
+		i2c1[3] = sd->brightness >> 3;
+		i2c1[2] = 0x0e;
+		if (i2c_w(gspca_dev->dev, i2c1) < 0)
+			goto err;
+		i2c1[3] = 0x01;
+		i2c1[2] = 0x13;
+		if (i2c_w(gspca_dev->dev, i2c1) < 0)
+			goto err;
+		break;
+	    }
+	case SENSOR_PAS202: {
+		/* __u8 i2cpexpo1[] =
+			{0xb0, 0x40, 0x04, 0x07, 0x2a, 0x00, 0x63, 0x16}; */
+		__u8 i2cpexpo[] =
+			{0xb0, 0x40, 0x0e, 0x01, 0xab, 0x00, 0x63, 0x16};
+		__u8 i2cp202[] =
+			{0xa0, 0x40, 0x10, 0x0e, 0x31, 0x00, 0x63, 0x15};
+		static __u8 i2cpdoit[] =
+			{0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16};
+
+		/* change reg 0x10 */
+		i2cpexpo[4] = 0xff - sd->brightness;
+/*		if(i2c_w(gspca_dev->dev,i2cpexpo1) < 0)
+			goto err; */
+/*		if(i2c_w(gspca_dev->dev,i2cpdoit) < 0)
+			goto err; */
+		if (i2c_w(gspca_dev->dev, i2cpexpo) < 0)
+			goto err;
+		if (i2c_w(gspca_dev->dev, i2cpdoit) < 0)
+			goto err;
+		i2cp202[3] = sd->brightness >> 3;
+		if (i2c_w(gspca_dev->dev, i2cp202) < 0)
+			goto err;
+		if (i2c_w(gspca_dev->dev, i2cpdoit) < 0)
+			goto err;
+		break;
+	    }
+	case SENSOR_TAS5130CXX:
+	case SENSOR_TAS5110: {
+		__u8 i2c[] =
+			{0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10};
+
+		value = 0xff - sd->brightness;
+		i2c[4] = value;
+		PDEBUG(D_CONF, "brightness %d : %d", value, i2c[4]);
+		if (i2c_w(gspca_dev->dev, i2c) < 0)
+			goto err;
+		break;
+	    }
+	}
+	return;
+err:
+	PDEBUG(D_ERR, "i2c error brightness");
+}
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	__u8 gain;
+	__u8 rgb_value;
+
+	gain = sd->contrast >> 4;
+	/* red and blue gain */
+	rgb_value = gain << 4 | gain;
+	reg_w(gspca_dev->dev, 0x10, &rgb_value, 1);
+	/* green gain */
+	rgb_value = gain;
+	reg_w(gspca_dev->dev, 0x11, &rgb_value, 1);
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+			const struct usb_device_id *id)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct cam *cam;
+/*	__u16 vendor; */
+	__u16 product;
+	int sif = 0;
+
+/*	vendor = id->idVendor; */
+	product = id->idProduct;
+/*	switch (vendor) { */
+/*	case 0x0c45:				 * Sonix */
+		switch (product) {
+		case 0x6001:			/* SN9C102 */
+		case 0x6005:			/* SN9C101 */
+		case 0x6007:			/* SN9C101 */
+			sd->sensor = SENSOR_TAS5110;
+			sif = 1;
+			break;
+		case 0x6009:			/* SN9C101 */
+		case 0x600d:			/* SN9C101 */
+		case 0x6029:			/* SN9C101 */
+			sd->sensor = SENSOR_PAS106;
+			sif = 1;
+			break;
+		case 0x6011:			/* SN9C101 - SN9C101G */
+			sd->sensor = SENSOR_OV6650;
+			sif = 1;
+			break;
+		case 0x6019:			/* SN9C101 */
+		case 0x602c:			/* SN9C102 */
+		case 0x602e:			/* SN9C102 */
+			sd->sensor = SENSOR_OV7630;
+			break;
+		case 0x60b0:			/* SN9C103 */
+			sd->sensor = SENSOR_OV7630_3;
+			break;
+		case 0x6024:			/* SN9C102 */
+		case 0x6025:			/* SN9C102 */
+			sd->sensor = SENSOR_TAS5130CXX;
+			break;
+		case 0x6028:			/* SN9C102 */
+			sd->sensor = SENSOR_PAS202;
+			break;
+		case 0x602d:			/* SN9C102 */
+			sd->sensor = SENSOR_HV7131R;
+			break;
+		case 0x60af:			/* SN9C103 */
+			sd->sensor = SENSOR_PAS202;
+			break;
+		}
+/*		break; */
+/*	} */
+
+	cam = &gspca_dev->cam;
+	cam->dev_name = (char *) id->driver_info;
+	cam->epaddr = 0x01;
+	if (!sif) {
+		cam->cam_mode = vga_mode;
+		cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+	} else {
+		cam->cam_mode = sif_mode;
+		cam->nmodes = sizeof sif_mode / sizeof sif_mode[0];
+	}
+	sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
+	sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
+	if (sd->sensor == SENSOR_OV7630_3)	/* jfm: from win trace */
+		reg_w(gspca_dev->dev, 0x01, probe_ov7630, sizeof probe_ov7630);
+	return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+	__u8 ByteReceive;
+
+	reg_r(gspca_dev->dev, 0x00, &ByteReceive);
+	if (ByteReceive != 0x10)
+		return -ENODEV;
+	return 0;
+}
+
+static void pas106_i2cinit(struct usb_device *dev)
+{
+	int i;
+	const __u8 *data;
+	__u8 i2c1[] = { 0xa1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14 };
+
+	i = ARRAY_SIZE(pas106_data);
+	data = pas106_data[0];
+	while (--i >= 0) {
+		memcpy(&i2c1[2], data, 2);
+					/* copy 2 bytes from the template */
+		if (i2c_w(dev, i2c1) < 0)
+			PDEBUG(D_ERR, "i2c error pas106");
+		data += 2;
+	}
+}
+
+/* -- start the camera -- */
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct usb_device *dev = gspca_dev->dev;
+	int mode, l;
+	const __u8 *sn9c10x;
+	__u8 reg01, reg17;
+	__u8 reg17_19[3];
+
+	mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].mode;
+	switch (sd->sensor) {
+	case SENSOR_HV7131R:
+		sn9c10x = initHv7131;
+		reg17_19[0] = 0x60;
+		reg17_19[1] = (mode << 4) | 0x8a;
+		reg17_19[2] = 0x20;
+		break;
+	case SENSOR_OV6650:
+		sn9c10x = initOv6650;
+		reg17_19[0] = 0x68;
+		reg17_19[1] = (mode << 4) | 0x8b;
+		reg17_19[2] = 0x20;
+		break;
+	case SENSOR_OV7630:
+		sn9c10x = initOv7630;
+		reg17_19[0] = 0x68;
+		reg17_19[1] = (mode << 4) | COMP2;
+		reg17_19[2] = MCK_INIT1;
+		break;
+	case SENSOR_OV7630_3:
+		sn9c10x = initOv7630_3;
+		reg17_19[0] = 0x68;
+		reg17_19[1] = (mode << 4) | COMP2;
+		reg17_19[2] = MCK_INIT1;
+		break;
+	case SENSOR_PAS106:
+		sn9c10x = initPas106;
+		reg17_19[0] = 0x24;		/* 0x28 */
+		reg17_19[1] = (mode << 4) | COMP1;
+		reg17_19[2] = MCK_INIT1;
+		break;
+	case SENSOR_PAS202:
+		sn9c10x = initPas202;
+		reg17_19[0] = mode ? 0x24 : 0x20;
+		reg17_19[1] = (mode << 4) | 0x89;
+		reg17_19[2] = 0x20;
+		break;
+	case SENSOR_TAS5110:
+		sn9c10x = initTas5110;
+		reg17_19[0] = 0x60;
+		reg17_19[1] = (mode << 4) | 0x86;
+		reg17_19[2] = 0x2b;		/* 0xf3; */
+		break;
+	default:
+/*	case SENSOR_TAS5130CXX: */
+		sn9c10x = initTas5130;
+		reg17_19[0] = 0x60;
+		reg17_19[1] = (mode << 4) | COMP;
+		reg17_19[2] = mode ? 0x23 : 0x43;
+		break;
+	}
+	switch (sd->sensor) {
+	case SENSOR_OV7630:
+		reg01 = 0x06;
+		reg17 = 0x29;
+		l = 0x10;
+		break;
+	case SENSOR_OV7630_3:
+		reg01 = 0x44;
+		reg17 = 0x68;
+		l = 0x10;
+		break;
+	default:
+		reg01 = sn9c10x[0];
+		reg17 = sn9c10x[0x17 - 1];
+		l = 0x1f;
+		break;
+	}
+
+	/* reg 0x01 bit 2 video transfert on */
+	reg_w(dev, 0x01, &reg01, 1);
+	/* reg 0x17 SensorClk enable inv Clk 0x60 */
+	reg_w(dev, 0x17, &reg17, 1);
+/*fixme: for ov7630 102
+	reg_w(dev, 0x01, {0x06, sn9c10x[1]}, 2); */
+	/* Set the registers from the template */
+	reg_w(dev, 0x01, sn9c10x, l);
+	switch (sd->sensor) {
+	case SENSOR_HV7131R:
+		i2c_w_vector(dev, hv7131_sensor_init,
+				sizeof hv7131_sensor_init);
+		break;
+	case SENSOR_OV6650:
+		i2c_w_vector(dev, ov6650_sensor_init,
+				sizeof ov6650_sensor_init);
+		break;
+	case SENSOR_OV7630:
+		i2c_w_vector(dev, ov7630_sensor_init_com,
+				sizeof ov7630_sensor_init_com);
+		msleep(200);
+		i2c_w_vector(dev, ov7630_sensor_init,
+				sizeof ov7630_sensor_init);
+		break;
+	case SENSOR_OV7630_3:
+		i2c_w_vector(dev, ov7630_sensor_init_com,
+				sizeof ov7630_sensor_init_com);
+		msleep(200);
+		i2c_w_vector(dev, ov7630_sensor_init_3,
+				sizeof ov7630_sensor_init_3);
+		break;
+	case SENSOR_PAS106:
+		pas106_i2cinit(dev);
+		break;
+	case SENSOR_PAS202:
+		i2c_w_vector(dev, pas202_sensor_init,
+				sizeof pas202_sensor_init);
+		break;
+	case SENSOR_TAS5110:
+		i2c_w_vector(dev, tas5110_sensor_init,
+				sizeof tas5110_sensor_init);
+		break;
+	default:
+/*	case SENSOR_TAS5130CXX: */
+		i2c_w_vector(dev, tas5130_sensor_init,
+				sizeof tas5130_sensor_init);
+		break;
+	}
+	/* H_size V_size  0x28, 0x1e maybe 640x480 */
+	reg_w(dev, 0x15, &sn9c10x[0x15 - 1], 2);
+	/* compression register */
+	reg_w(dev, 0x18, &reg17_19[1], 1);
+	/* H_start */		/*fixme: not ov7630*/
+	reg_w(dev, 0x12, &sn9c10x[0x12 - 1], 1);
+	/* V_START */		/*fixme: not ov7630*/
+	reg_w(dev, 0x13, &sn9c10x[0x13 - 1], 1);
+	/* reset 0x17 SensorClk enable inv Clk 0x60 */
+				/*fixme: ov7630 [17]=68 8f (+20 if 102)*/
+	reg_w(dev, 0x17, &reg17_19[0], 1);
+	/*MCKSIZE ->3 */	/*fixme: not ov7630*/
+	reg_w(dev, 0x19, &reg17_19[2], 1);
+	/* AE_STRX AE_STRY AE_ENDX AE_ENDY */
+	reg_w(dev, 0x1c, &sn9c10x[0x1c - 1], 4);
+	/* Enable video transfert */
+	reg_w(dev, 0x01, &sn9c10x[0], 1);
+	/* Compression */
+	reg_w(dev, 0x18, &reg17_19[1], 2);
+	msleep(20);
+
+	setcontrast(gspca_dev);
+	setbrightness(gspca_dev);
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+	__u8 ByteSend = 0;
+
+	ByteSend = 0x09;	/* 0X00 */
+	reg_w(gspca_dev->dev, 0x01, &ByteSend, 1);
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+			struct gspca_frame *frame,	/* target */
+			unsigned char *data,		/* isoc packet */
+			int len)			/* iso packet length */
+{
+	int p;
+
+	if (len > 6 && len < 24) {
+		for (p = 0; p < len - 6; p++) {
+			if (data[0 + p] == 0xff
+			    && data[1 + p] == 0xff
+			    && data[2 + p] == 0x00
+			    && data[3 + p] == 0xc4
+			    && data[4 + p] == 0xc4
+			    && data[5 + p] == 0x96) {	/* start of frame */
+				frame = gspca_frame_add(gspca_dev,
+							LAST_PACKET,
+							frame,
+							data, 0);
+				data += 12;
+				len -= 12;
+				gspca_frame_add(gspca_dev, FIRST_PACKET,
+						frame, data, len);
+				return;
+			}
+		}
+	}
+	gspca_frame_add(gspca_dev, INTER_PACKET,
+			frame, data, len);
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->brightness = val;
+	if (gspca_dev->streaming)
+		setbrightness(gspca_dev);
+	return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->brightness;
+	return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->contrast = val;
+	if (gspca_dev->streaming)
+		setcontrast(gspca_dev);
+	return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->contrast;
+	return 0;
+}
+
+/* sub-driver description */
+static struct sd_desc sd_desc = {
+	.name = MODULE_NAME,
+	.ctrls = sd_ctrls,
+	.nctrls = ARRAY_SIZE(sd_ctrls),
+	.config = sd_config,
+	.open = sd_open,
+	.start = sd_start,
+	.stopN = sd_stopN,
+	.stop0 = sd_stop0,
+	.close = sd_close,
+	.pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static __devinitdata struct usb_device_id device_table[] = {
+	{USB_DEVICE(0x0c45, 0x6001), DVNM("Genius VideoCAM NB")},
+	{USB_DEVICE(0x0c45, 0x6005), DVNM("Sweex Tas5110")},
+	{USB_DEVICE(0x0c45, 0x6007), DVNM("Sonix sn9c101 + Tas5110D")},
+	{USB_DEVICE(0x0c45, 0x6009), DVNM("spcaCam@120")},
+	{USB_DEVICE(0x0c45, 0x600d), DVNM("spcaCam@120")},
+	{USB_DEVICE(0x0c45, 0x6011), DVNM("MAX Webcam Microdia-OV6650-SN9C101G")},
+	{USB_DEVICE(0x0c45, 0x6019), DVNM("Generic Sonix OV7630")},
+	{USB_DEVICE(0x0c45, 0x6024), DVNM("Generic Sonix Tas5130c")},
+	{USB_DEVICE(0x0c45, 0x6025), DVNM("Xcam Shanga")},
+	{USB_DEVICE(0x0c45, 0x6028), DVNM("Sonix Btc Pc380")},
+	{USB_DEVICE(0x0c45, 0x6029), DVNM("spcaCam@150")},
+	{USB_DEVICE(0x0c45, 0x602c), DVNM("Generic Sonix OV7630")},
+	{USB_DEVICE(0x0c45, 0x602d), DVNM("LIC-200 LG")},
+	{USB_DEVICE(0x0c45, 0x602e), DVNM("Genius VideoCam Messenger")},
+	{USB_DEVICE(0x0c45, 0x60af), DVNM("Trust WB3100P")},
+	{USB_DEVICE(0x0c45, 0x60b0), DVNM("Genius VideoCam Look")},
+	{}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+			const struct usb_device_id *id)
+{
+	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+				THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+	.name = MODULE_NAME,
+	.id_table = device_table,
+	.probe = sd_probe,
+	.disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+	if (usb_register(&sd_driver) < 0)
+		return -1;
+	PDEBUG(D_PROBE, "v%s registered", version);
+	return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+	usb_deregister(&sd_driver);
+	PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c
new file mode 100644
index 0000000..6180bc5
--- /dev/null
+++ b/drivers/media/video/gspca/sonixj.c
@@ -0,0 +1,1629 @@
+/*
+ *		Sonix sn9c102p sn9c105 sn9c120 (jpeg) library
+ *		Copyright (C) 2005 Michel Xhaard mxhaard@magic.fr
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define MODULE_NAME "sonixj"
+
+#include "gspca.h"
+#include "jpeg.h"
+
+#define DRIVER_VERSION_NUMBER	KERNEL_VERSION(2, 1, 0)
+static const char version[] = "2.1.0";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("GSPCA/SONIX JPEG USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+	struct gspca_dev gspca_dev;	/* !! must be the first item */
+
+	int avg_lum;
+	unsigned int exposure;
+
+	unsigned short brightness;
+	unsigned char contrast;
+	unsigned char colors;
+	unsigned char autogain;
+
+	signed char ag_cnt;
+#define AG_CNT_START 13
+
+	char qindex;
+	char sensor;			/* Type of image sensor chip */
+#define SENSOR_HV7131R 0
+#define SENSOR_MI0360 1
+#define SENSOR_MO4000 2
+#define SENSOR_OV7648 3
+#define SENSOR_OV7660 4
+	unsigned char customid;
+#define SN9C102P 0
+#define SN9C105 1
+#define SN9C110 2
+#define SN9C120 3
+#define SN9C325 4
+	unsigned char i2c_base;
+	unsigned char i2c_ctrl_reg;
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+#define SD_BRIGHTNESS 0
+	{
+	    {
+		.id      = V4L2_CID_BRIGHTNESS,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Brightness",
+		.minimum = 0,
+		.maximum = 0xffff,
+		.step    = 1,
+		.default_value = 0x7fff,
+	    },
+	    .set = sd_setbrightness,
+	    .get = sd_getbrightness,
+	},
+#define SD_CONTRAST 1
+	{
+	    {
+		.id      = V4L2_CID_CONTRAST,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Contrast",
+		.minimum = 0,
+		.maximum = 127,
+		.step    = 1,
+		.default_value = 63,
+	    },
+	    .set = sd_setcontrast,
+	    .get = sd_getcontrast,
+	},
+#define SD_COLOR 2
+	{
+	    {
+		.id      = V4L2_CID_SATURATION,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Color",
+		.minimum = 0,
+		.maximum = 255,
+		.step    = 1,
+		.default_value = 127,
+	    },
+	    .set = sd_setcolors,
+	    .get = sd_getcolors,
+	},
+#define SD_AUTOGAIN 3
+	{
+	    {
+		.id      = V4L2_CID_AUTOGAIN,
+		.type    = V4L2_CTRL_TYPE_BOOLEAN,
+		.name    = "Auto Gain",
+		.minimum = 0,
+		.maximum = 1,
+		.step    = 1,
+		.default_value = 1,
+	    },
+	    .set = sd_setautogain,
+	    .get = sd_getautogain,
+	},
+};
+
+static struct cam_mode vga_mode[] = {
+	{V4L2_PIX_FMT_JPEG, 160, 120, 2},
+	{V4L2_PIX_FMT_JPEG, 320, 240, 1},
+	{V4L2_PIX_FMT_JPEG, 640, 480, 0},
+};
+
+/*Data from sn9c102p+hv71331r */
+static __u8 sn_hv7131[] = {
+	0x00, 0x03, 0x64, 0x00, 0x1A, 0x20, 0x20, 0x20, 0xA1, 0x11,
+/*	reg0  reg1  reg2  reg3  reg4  reg5  reg6  reg7  reg8  reg9 */
+	0x02, 0x09, 0x00, 0x00, 0x00, 0x10, 0x03, 0x00,		/* 00 */
+/*	rega  regb  regc  regd  rege  regf  reg10 reg11 */
+	0x00, 0x01, 0x03, 0x28, 0x1e, 0x41, 0x0a, 0x00, 0x00, 0x00,
+/*	reg12 reg13 reg14 reg15 reg16 reg17 reg18 reg19 reg1a reg1b */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+/*	reg1c reg1d reg1e reg1f reg20 reg21 reg22 reg23 */
+};
+
+static __u8 sn_mi0360[] = {
+	0x00, 0x61, 0x44, 0x00, 0x1a, 0x20, 0x20, 0x20, 0xb1, 0x5d,
+/*	reg0  reg1  reg2  reg3  reg4  reg5  reg6  reg7  reg8  reg9 */
+	0x07, 0x00, 0x00, 0x00, 0x00, 0x10, 0x03, 0x00,
+/*	rega  regb  regc  regd  rege  regf  reg10 reg11 */
+	0x00, 0x02, 0x0a, 0x28, 0x1e, 0x61, 0x06, 0x00, 0x00, 0x00,
+/*	reg12 reg13 reg14 reg15 reg16 reg17 reg18 reg19 reg1a reg1b */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+/*	reg1c reg1d reg1e reg1f reg20 reg21 reg22 reg23 */
+};
+
+static __u8 sn_mo4000[] = {
+	0x12,	0x23,	0x60,	0x00,	0x1A,	0x00,	0x20,	0x18,	0x81,
+/*	reg0	reg1	reg2	reg3	reg4	reg5	reg6	reg7	reg8 */
+	0x21,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x03,	0x00,
+/*	reg9	rega	regb	regc	regd	rege	regf	reg10	reg11*/
+	0x0b,	0x0f,	0x14,	0x28,	0x1e,	0x40,	0x08,	0x00,	0x00,
+/*	reg12	reg13	reg14	reg15	reg16	reg17	reg18	reg19	reg1a*/
+	0x00,	0x00,	0x00,	0x00,	0x00,	0x08,	0x25,	0x39,	0x4b,
+/*	reg1b	reg1c	reg1d	reg1e	reg1f	reg20	reg21	reg22	reg23*/
+	0x5c,	0x6b,	0x79,	0x87,	0x95,	0xa2,	0xaf,	0xbb,	0xc7,
+	0xd3,	0xdf,	0xea,	0xf5
+};
+
+static __u8 sn_ov7648[] = {
+	0x00, 0x21, 0x62, 0x00, 0x1a, 0x20, 0x20, 0x20, 0xA1, 0x6E, 0x18, 0x65,
+	0x00, 0x00, 0x00, 0x10, 0x03, 0x00, 0x00, 0x06, 0x06, 0x28, 0x1E, 0x82,
+	0x07, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static __u8 sn_ov7660[]	= {
+/*	reg0	reg1	reg2	reg3	reg4	reg5	reg6	reg7	reg8 */
+	0x00,	0x61,	0x40,	0x00,	0x1a,	0x00,	0x00,	0x00,	0x81,
+/* 	reg9	rega	regb	regc	regd	rege	regf	reg10	reg11*/
+	0x21,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x03,	0x00,
+/*	reg12	reg13	reg14	reg15	reg16	reg17	reg18	reg19	reg1a*/
+	0x01,	0x01,	0x08,	0x28,	0x1e,	0x20,	0x07,	0x00,	0x00,
+/*	reg1b	reg1c	reg1d	reg1e	reg1f	reg20	reg21	reg22	reg23*/
+	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00
+};
+
+/* sequence specific to the sensors - !! index = SENSOR_xxx */
+static __u8 *sn_tb[] = {
+	sn_hv7131,
+	sn_mi0360,
+	sn_mo4000,
+	sn_ov7648,
+	sn_ov7660
+};
+
+static __u8 regsn20[] = {
+	0x00, 0x2d, 0x46, 0x5a, 0x6c, 0x7c, 0x8b, 0x99,
+	0xa6, 0xb2, 0xbf, 0xca, 0xd5, 0xe0, 0xeb, 0xf5, 0xff
+};
+static __u8 regsn20_sn9c325[] = {
+	0x0a, 0x3a, 0x56, 0x6c, 0x7e, 0x8d, 0x9a, 0xa4,
+	0xaf, 0xbb, 0xc5, 0xcd, 0xd5, 0xde, 0xe8, 0xed, 0xf5
+};
+
+static __u8 reg84[] = {
+	0x14, 0x00, 0x27, 0x00, 0x07, 0x00, 0xe5, 0x0f,
+	0xe4, 0x0f, 0x38, 0x00, 0x3e, 0x00, 0xc3, 0x0f,
+/*	0x00, 0x00, 0x00, 0x00, 0x00 */
+	0xf7, 0x0f, 0x0a, 0x00, 0x00
+};
+static __u8 reg84_sn9c325[] = {
+	0x14, 0x00, 0x27, 0x00, 0x07, 0x00, 0xe4, 0x0f,
+	0xd3, 0x0f, 0x4b, 0x00, 0x48, 0x00, 0xc0, 0x0f,
+	0xf8, 0x0f, 0x00, 0x00, 0x00
+};
+
+static __u8 hv7131r_sensor_init[][8] = {
+	{0xC1, 0x11, 0x01, 0x08, 0x01, 0x00, 0x00, 0x10},
+	{0xB1, 0x11, 0x34, 0x17, 0x7F, 0x00, 0x00, 0x10},
+	{0xD1, 0x11, 0x40, 0xFF, 0x7F, 0x7F, 0x7F, 0x10},
+	{0x91, 0x11, 0x44, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xD1, 0x11, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xD1, 0x11, 0x14, 0x01, 0xE2, 0x02, 0x82, 0x10},
+	{0x91, 0x11, 0x18, 0x00, 0x00, 0x00, 0x00, 0x10},
+
+	{0xA1, 0x11, 0x01, 0x08, 0x00, 0x00, 0x00, 0x10},
+	{0xA1, 0x11, 0x01, 0x08, 0x00, 0x00, 0x00, 0x10},
+	{0xC1, 0x11, 0x25, 0x00, 0x61, 0xA8, 0x00, 0x10},
+	{0xA1, 0x11, 0x30, 0x22, 0x00, 0x00, 0x00, 0x10},
+	{0xC1, 0x11, 0x31, 0x20, 0x2E, 0x20, 0x00, 0x10},
+	{0xC1, 0x11, 0x25, 0x00, 0xC3, 0x50, 0x00, 0x10},
+	{0xA1, 0x11, 0x30, 0x07, 0x00, 0x00, 0x00, 0x10}, /* gain14 */
+	{0xC1, 0x11, 0x31, 0x10, 0x10, 0x10, 0x00, 0x10}, /* r g b 101a10 */
+
+	{0xA1, 0x11, 0x01, 0x08, 0x00, 0x00, 0x00, 0x10},
+	{0xA1, 0x11, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xA1, 0x11, 0x21, 0xD0, 0x00, 0x00, 0x00, 0x10},
+	{0xA1, 0x11, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xA1, 0x11, 0x23, 0x09, 0x00, 0x00, 0x00, 0x10},
+
+	{0xA1, 0x11, 0x01, 0x08, 0x00, 0x00, 0x00, 0x10},
+	{0xA1, 0x11, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xA1, 0x11, 0x21, 0xD0, 0x00, 0x00, 0x00, 0x10},
+	{0xA1, 0x11, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xA1, 0x11, 0x23, 0x10, 0x00, 0x00, 0x00, 0x10},
+	{0, 0, 0, 0, 0, 0, 0, 0}
+};
+static __u8 mi0360_sensor_init[][8] = {
+	{0xB1, 0x5D, 0x07, 0x00, 0x02, 0x00, 0x00, 0x10},
+	{0xB1, 0x5D, 0x0D, 0x00, 0x01, 0x00, 0x00, 0x10},
+	{0xB1, 0x5D, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xD1, 0x5D, 0x01, 0x00, 0x08, 0x00, 0x16, 0x10},
+	{0xD1, 0x5D, 0x03, 0x01, 0xE2, 0x02, 0x82, 0x10},
+	{0xD1, 0x5D, 0x05, 0x00, 0x09, 0x00, 0x53, 0x10},
+	{0xB1, 0x5D, 0x0D, 0x00, 0x02, 0x00, 0x00, 0x10},
+	{0xD1, 0x5D, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xD1, 0x5D, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xD1, 0x5D, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xD1, 0x5D, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xD1, 0x5D, 0x12, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xD1, 0x5D, 0x14, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xD1, 0x5D, 0x16, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xD1, 0x5D, 0x18, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xD1, 0x5D, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xD1, 0x5D, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xB1, 0x5D, 0x32, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xD1, 0x5D, 0x20, 0x91, 0x01, 0x00, 0x00, 0x10},
+	{0xD1, 0x5D, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xD1, 0x5D, 0x24, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xD1, 0x5D, 0x26, 0x00, 0x00, 0x00, 0x24, 0x10},
+	{0xD1, 0x5D, 0x2F, 0xF7, 0xB0, 0x00, 0x04, 0x10},
+	{0xD1, 0x5D, 0x31, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xD1, 0x5D, 0x33, 0x00, 0x00, 0x01, 0x00, 0x10},
+	{0xB1, 0x5D, 0x3D, 0x06, 0x8F, 0x00, 0x00, 0x10},
+	{0xD1, 0x5D, 0x40, 0x01, 0xE0, 0x00, 0xD1, 0x10},
+	{0xB1, 0x5D, 0x44, 0x00, 0x82, 0x00, 0x00, 0x10},
+	{0xD1, 0x5D, 0x58, 0x00, 0x78, 0x00, 0x43, 0x10},
+	{0xD1, 0x5D, 0x5A, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xD1, 0x5D, 0x5C, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xD1, 0x5D, 0x5E, 0x00, 0x00, 0xA3, 0x1D, 0x10},
+	{0xB1, 0x5D, 0x62, 0x04, 0x11, 0x00, 0x00, 0x10},
+
+	{0xB1, 0x5D, 0x20, 0x91, 0x01, 0x00, 0x00, 0x10},
+	{0xB1, 0x5D, 0x20, 0x11, 0x01, 0x00, 0x00, 0x10},
+	{0xB1, 0x5D, 0x09, 0x00, 0x64, 0x00, 0x00, 0x10},
+	{0xD1, 0x5D, 0x2B, 0x00, 0xA0, 0x00, 0xB0, 0x10},
+	{0xD1, 0x5D, 0x2D, 0x00, 0xA0, 0x00, 0xA0, 0x10},
+
+	{0xB1, 0x5D, 0x0A, 0x00, 0x02, 0x00, 0x00, 0x10}, /* sensor clck ?2 */
+	{0xB1, 0x5D, 0x06, 0x00, 0x30, 0x00, 0x00, 0x10},
+	{0xB1, 0x5D, 0x05, 0x00, 0x0A, 0x00, 0x00, 0x10},
+	{0xB1, 0x5D, 0x09, 0x02, 0x35, 0x00, 0x00, 0x10}, /* exposure 2 */
+
+	{0xD1, 0x5D, 0x2B, 0x00, 0xB9, 0x00, 0xE3, 0x10},
+	{0xD1, 0x5D, 0x2D, 0x00, 0x5f, 0x00, 0xB9, 0x10}, /* 42 */
+/*	{0xB1, 0x5D, 0x35, 0x00, 0x67, 0x00, 0x00, 0x10}, * gain orig */
+/*	{0xB1, 0x5D, 0x35, 0x00, 0x20, 0x00, 0x00, 0x10}, * gain */
+	{0xB1, 0x5D, 0x07, 0x00, 0x03, 0x00, 0x00, 0x10}, /* update */
+	{0xB1, 0x5D, 0x07, 0x00, 0x02, 0x00, 0x00, 0x10}, /* sensor on */
+	{0, 0, 0, 0, 0, 0, 0, 0}
+};
+static __u8 mo4000_sensor_init[][8] = {
+	{0xa1, 0x21, 0x01, 0x02, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x02, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x04, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x05, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x05, 0x04, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x06, 0x80, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x06, 0x81, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x11, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x11, 0x20, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x11, 0x30, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x11, 0x38, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x11, 0x38, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x12, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x0f, 0x20, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x10, 0x20, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x11, 0x38, 0x00, 0x00, 0x00, 0x10},
+	{0, 0, 0, 0, 0, 0, 0, 0}
+};
+static __u8 ov7660_sensor_init[][8] = {
+	{0xa1, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10}, /* reset SCCB */
+	{0xa1, 0x21, 0x12, 0x05, 0x00, 0x00, 0x00, 0x10},
+						/* Outformat ?? rawRGB */
+	{0xa1, 0x21, 0x13, 0xb8, 0x00, 0x00, 0x00, 0x10}, /* init COM8 */
+/*	{0xd1, 0x21, 0x00, 0x01, 0x74, 0x92, 0x00, 0x10},
+						 * GAIN BLUE RED VREF */
+	{0xd1, 0x21, 0x00, 0x01, 0x74, 0x74, 0x00, 0x10},
+						/* GAIN BLUE RED VREF */
+	{0xd1, 0x21, 0x04, 0x00, 0x7d, 0x62, 0x00, 0x10},
+						/* COM 1 BAVE GEAVE AECHH */
+	{0xb1, 0x21, 0x08, 0x83, 0x01, 0x00, 0x00, 0x10}, /* RAVE COM2 */
+	{0xd1, 0x21, 0x0c, 0x00, 0x08, 0x04, 0x4f, 0x10}, /* COM 3 4 5 6 */
+/*	{0xd1, 0x21, 0x10, 0x7f, 0x40, 0x05, 0xf8, 0x10},
+						 * AECH CLKRC COM7 COM8 */
+	{0xd1, 0x21, 0x10, 0x7f, 0x40, 0x05, 0xff, 0x10},
+						/* AECH CLKRC COM7 COM8 */
+	{0xc1, 0x21, 0x14, 0x2c, 0x00, 0x02, 0x00, 0x10}, /* COM9 COM10 */
+	{0xd1, 0x21, 0x17, 0x10, 0x60, 0x02, 0x7b, 0x10},
+						/* HSTART HSTOP VSTRT VSTOP */
+	{0xa1, 0x21, 0x1b, 0x02, 0x00, 0x00, 0x00, 0x10}, /* PSHFT */
+	{0xb1, 0x21, 0x1e, 0x01, 0x0e, 0x00, 0x00, 0x10}, /* MVFP LAEC */
+	{0xd1, 0x21, 0x20, 0x07, 0x07, 0x07, 0x07, 0x10},
+					/* BOS GBOS GROS ROS (BGGR offset) */
+/*	{0xd1, 0x21, 0x24, 0x68, 0x58, 0xd4, 0x80, 0x10},
+						 * AEW AEB VPT BBIAS */
+	{0xd1, 0x21, 0x24, 0x78, 0x68, 0xd4, 0x80, 0x10},
+						/* AEW AEB VPT BBIAS */
+	{0xd1, 0x21, 0x28, 0x80, 0x30, 0x00, 0x00, 0x10},
+						/* GbBIAS RSVD EXHCH EXHCL */
+	{0xd1, 0x21, 0x2c, 0x80, 0x00, 0x00, 0x62, 0x10},
+						/* RBIAS ADVFL ASDVFH YAVE */
+	{0xc1, 0x21, 0x30, 0x08, 0x30, 0xb4, 0x00, 0x10},
+						/* HSYST HSYEN HREF */
+	{0xd1, 0x21, 0x33, 0x00, 0x07, 0x84, 0x00, 0x10}, /* reserved */
+	{0xd1, 0x21, 0x37, 0x0c, 0x02, 0x43, 0x00, 0x10},
+						/* ADC ACOM OFON TSLB */
+	{0xd1, 0x21, 0x3b, 0x02, 0x6c, 0x19, 0x0e, 0x10},
+						/* COM11 COM12 COM13 COM14 */
+	{0xd1, 0x21, 0x3f, 0x41, 0xc1, 0x22, 0x08, 0x10},
+						/* EDGE COM15 COM16 COM17 */
+	{0xd1, 0x21, 0x43, 0xf0, 0x10, 0x78, 0xa8, 0x10}, /* reserved */
+	{0xd1, 0x21, 0x47, 0x60, 0x80, 0x00, 0x00, 0x10}, /* reserved */
+	{0xd1, 0x21, 0x4b, 0x00, 0x00, 0x00, 0x00, 0x10}, /* reserved */
+	{0xd1, 0x21, 0x4f, 0x46, 0x36, 0x0f, 0x17, 0x10}, /* MTX 1 2 3 4 */
+	{0xd1, 0x21, 0x53, 0x7f, 0x96, 0x40, 0x40, 0x10}, /* MTX 5 6 7 8 */
+	{0xb1, 0x21, 0x57, 0x40, 0x0f, 0x00, 0x00, 0x10}, /* MTX9 MTXS */
+	{0xd1, 0x21, 0x59, 0xba, 0x9a, 0x22, 0xb9, 0x10}, /* reserved */
+	{0xd1, 0x21, 0x5d, 0x9b, 0x10, 0xf0, 0x05, 0x10}, /* reserved */
+	{0xa1, 0x21, 0x61, 0x60, 0x00, 0x00, 0x00, 0x10}, /* reserved */
+	{0xd1, 0x21, 0x62, 0x00, 0x00, 0x50, 0x30, 0x10},
+						/* LCC1 LCC2 LCC3 LCC4 */
+	{0xa1, 0x21, 0x66, 0x00, 0x00, 0x00, 0x00, 0x10}, /* LCC5 */
+	{0xd1, 0x21, 0x67, 0x80, 0x7a, 0x90, 0x80, 0x10},
+	{0xa1, 0x21, 0x6b, 0x0a, 0x00, 0x00, 0x00, 0x10},
+					/* band gap reference [0..3] DBLV */
+	{0xd1, 0x21, 0x6c, 0x30, 0x48, 0x80, 0x74, 0x10}, /* gamma curve */
+	{0xd1, 0x21, 0x70, 0x64, 0x60, 0x5c, 0x58, 0x10}, /* gamma curve */
+	{0xd1, 0x21, 0x74, 0x54, 0x4c, 0x40, 0x38, 0x10}, /* gamma curve */
+	{0xd1, 0x21, 0x78, 0x34, 0x30, 0x2f, 0x2b, 0x10}, /* gamma curve */
+	{0xd1, 0x21, 0x7c, 0x03, 0x07, 0x17, 0x34, 0x10}, /* gamma curve */
+	{0xd1, 0x21, 0x80, 0x41, 0x4d, 0x58, 0x63, 0x10}, /* gamma curve */
+	{0xd1, 0x21, 0x84, 0x6e, 0x77, 0x87, 0x95, 0x10}, /* gamma curve */
+	{0xc1, 0x21, 0x88, 0xaf, 0xc7, 0xdf, 0x00, 0x10}, /* gamma curve */
+	{0xc1, 0x21, 0x8b, 0x99, 0x99, 0xcf, 0x00, 0x10}, /* reserved */
+	{0xb1, 0x21, 0x92, 0x00, 0x00, 0x00, 0x00, 0x10},
+/****** (some exchanges in the win trace) ******/
+	{0xa1, 0x21, 0x1e, 0x01, 0x00, 0x00, 0x00, 0x10},
+						/* bits[3..0]reserved */
+	{0xa1, 0x21, 0x1e, 0x01, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10},
+						/* VREF vertical frame ctrl */
+	{0xa1, 0x21, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x10, 0x20, 0x00, 0x00, 0x00, 0x10}, /* 0x20 */
+	{0xa1, 0x21, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x10},
+/*	{0xb1, 0x21, 0x01, 0x78, 0x78, 0x00, 0x00, 0x10}, */
+/****** (some exchanges in the win trace) ******/
+	{0xa1, 0x21, 0x93, 0x00, 0x00, 0x00, 0x00, 0x10},/* dummy line hight */
+	{0xa1, 0x21, 0x92, 0x25, 0x00, 0x00, 0x00, 0x10},/* dummy line low */
+	{0xa1, 0x21, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x10},
+/*	{0xa1, 0x21, 0x02, 0x90, 0x00, 0x00, 0x00, 0x10}, */
+/****** (some exchanges in the win trace) ******/
+/**********startsensor KO if changed !!****/
+	{0xa1, 0x21, 0x93, 0x01, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x92, 0xff, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x2b, 0xc3, 0x00, 0x00, 0x00, 0x10},
+/* here may start the isoc exchanges */
+	{0, 0, 0, 0, 0, 0, 0, 0}
+};
+/* reg0x04		reg0x07		reg 0x10 */
+/* expo  = (COM1 & 0x02) | (AECHH & 0x2f <<10) [ (AECh << 2) */
+
+static __u8 ov7648_sensor_init[][8] = {
+	{0xC1, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00},
+	{0xC1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00},
+	{0xC1, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00},
+	{0xA1, 0x6E, 0x3F, 0x20, 0x00, 0x00, 0x00, 0x10},
+	{0xA1, 0x6E, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xA1, 0x6E, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xD1, 0x6E, 0x04, 0x02, 0xB1, 0x02, 0x39, 0x10},
+	{0xD1, 0x6E, 0x08, 0x00, 0x01, 0x00, 0x00, 0x10},
+	{0xD1, 0x6E, 0x0C, 0x02, 0x7F, 0x01, 0xE0, 0x10},
+	{0xD1, 0x6E, 0x12, 0x03, 0x02, 0x00, 0x03, 0x10},
+	{0xD1, 0x6E, 0x16, 0x85, 0x40, 0x4A, 0x40, 0x10},
+	{0xC1, 0x6E, 0x1A, 0x00, 0x80, 0x00, 0x00, 0x10},
+	{0xD1, 0x6E, 0x1D, 0x08, 0x03, 0x00, 0x00, 0x10},
+	{0xD1, 0x6E, 0x23, 0x00, 0xB0, 0x00, 0x94, 0x10},
+	{0xD1, 0x6E, 0x27, 0x58, 0x00, 0x00, 0x00, 0x10},
+	{0xD1, 0x6E, 0x2D, 0x14, 0x35, 0x61, 0x84, 0x10},
+	{0xD1, 0x6E, 0x31, 0xA2, 0xBD, 0xD8, 0xFF, 0x10},
+	{0xD1, 0x6E, 0x35, 0x06, 0x1E, 0x12, 0x02, 0x10},
+	{0xD1, 0x6E, 0x39, 0xAA, 0x53, 0x37, 0xD5, 0x10},
+	{0xA1, 0x6E, 0x3D, 0xF2, 0x00, 0x00, 0x00, 0x10},
+	{0xD1, 0x6E, 0x3E, 0x00, 0x00, 0x80, 0x03, 0x10},
+	{0xD1, 0x6E, 0x42, 0x03, 0x00, 0x00, 0x00, 0x10},
+	{0xC1, 0x6E, 0x46, 0x00, 0x80, 0x80, 0x00, 0x10},
+	{0xD1, 0x6E, 0x4B, 0x02, 0xEF, 0x08, 0xCD, 0x10},
+	{0xD1, 0x6E, 0x4F, 0x00, 0xD0, 0x00, 0xA0, 0x10},
+	{0xD1, 0x6E, 0x53, 0x01, 0xAA, 0x01, 0x40, 0x10},
+	{0xD1, 0x6E, 0x5A, 0x50, 0x04, 0x30, 0x03, 0x10},
+	{0xA1, 0x6E, 0x5E, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xD1, 0x6E, 0x5F, 0x10, 0x40, 0xFF, 0x00, 0x10},
+  /*	{0xD1, 0x6E, 0x63, 0x40, 0x40, 0x00, 0x00, 0x10},
+	{0xD1, 0x6E, 0x67, 0x00, 0x00, 0x00, 0x00, 0x10},
+ * This is currently setting a
+ * blue tint, and some things more , i leave it here for future test if
+ * somene is having problems with color on this sensor
+	{0xD1, 0x6E, 0x6B, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xD1, 0x6E, 0x6F, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xC1, 0x6E, 0x73, 0x10, 0x80, 0xEB, 0x00, 0x10},
+	{0xA1, 0x6E, 0x1E, 0x03, 0x00, 0x00, 0x00, 0x10},
+	{0xA1, 0x6E, 0x15, 0x01, 0x00, 0x00, 0x00, 0x10},
+	{0xC1, 0x6E, 0x16, 0x40, 0x40, 0x40, 0x00, 0x10},
+	{0xA1, 0x6E, 0x1D, 0x08, 0x00, 0x00, 0x00, 0x10},
+	{0xA1, 0x6E, 0x06, 0x02, 0x00, 0x00, 0x00, 0x10},
+	{0xA1, 0x6E, 0x07, 0xB5, 0x00, 0x00, 0x00, 0x10},
+	{0xA1, 0x6E, 0x18, 0x6B, 0x00, 0x00, 0x00, 0x10},
+	{0xA1, 0x6E, 0x1D, 0x08, 0x00, 0x00, 0x00, 0x10},
+	{0xA1, 0x6E, 0x06, 0x02, 0x00, 0x00, 0x00, 0x10},
+	{0xA1, 0x6E, 0x07, 0xB8, 0x00, 0x00, 0x00, 0x10},  */
+	{0xC1, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00},
+	{0xA1, 0x6E, 0x06, 0x03, 0x00, 0x00, 0x00, 0x10}, /* Bright... */
+	{0xA1, 0x6E, 0x07, 0x66, 0x00, 0x00, 0x00, 0x10}, /* B.. */
+	{0xC1, 0x6E, 0x1A, 0x03, 0x65, 0x90, 0x00, 0x10}, /* Bright/Witen....*/
+/*	{0xC1, 0x6E, 0x16, 0x45, 0x40, 0x60, 0x00, 0x10},  * Bright/Witene */
+	{0, 0, 0, 0, 0, 0, 0, 0}
+};
+
+static __u8 qtable4[] = {
+	0x06, 0x04, 0x04, 0x06, 0x04, 0x04, 0x06, 0x06, 0x06, 0x06, 0x08, 0x06,
+	0x06, 0x08, 0x0A, 0x11,
+	0x0A, 0x0A, 0x08, 0x08, 0x0A, 0x15, 0x0F, 0x0F, 0x0C, 0x11, 0x19, 0x15,
+	0x19, 0x19, 0x17, 0x15,
+	0x17, 0x17, 0x1B, 0x1D, 0x25, 0x21, 0x1B, 0x1D, 0x23, 0x1D, 0x17, 0x17,
+	0x21, 0x2E, 0x21, 0x23,
+	0x27, 0x29, 0x2C, 0x2C, 0x2C, 0x19, 0x1F, 0x30, 0x32, 0x2E, 0x29, 0x32,
+	0x25, 0x29, 0x2C, 0x29,
+	0x06, 0x08, 0x08, 0x0A, 0x08, 0x0A, 0x13, 0x0A, 0x0A, 0x13, 0x29, 0x1B,
+	0x17, 0x1B, 0x29, 0x29,
+	0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
+	0x29, 0x29, 0x29, 0x29,
+	0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
+	0x29, 0x29, 0x29, 0x29,
+	0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
+	0x29, 0x29, 0x29, 0x29
+};
+
+static void reg_r(struct usb_device *dev,
+		  __u16 value,
+		  __u8 *buffer, int len)
+{
+	usb_control_msg(dev,
+			usb_rcvctrlpipe(dev, 0),
+			0,
+			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+			value, 0,
+			buffer, len,
+			500);
+}
+
+static void reg_w(struct usb_device *dev,
+			  __u16 value,
+			  __u8 *buffer,
+			  int len)
+{
+	usb_control_msg(dev,
+			usb_sndctrlpipe(dev, 0),
+			0x08,
+			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+			value, 0,
+			buffer, len,
+			500);
+}
+
+/* write 2 bytes */
+static void i2c_w2(struct gspca_dev *gspca_dev,
+		   __u8 *buffer)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct usb_device *dev = gspca_dev->dev;
+	__u8 mode[8];
+
+	/* is i2c ready */
+	mode[0] = sd->i2c_ctrl_reg | (2 << 4);
+	mode[1] = sd->i2c_base;
+	mode[2] = buffer[0];
+	mode[3] = buffer[1];
+	mode[4] = 0;
+	mode[5] = 0;
+	mode[6] = 0;
+	mode[7] = 0x10;
+	reg_w(dev, 0x08, mode, 8);
+}
+
+/* write 8 bytes */
+static void i2c_w8(struct usb_device *dev, __u8 *buffer)
+{
+	reg_w(dev, 0x08, buffer, 8);
+	msleep(1);
+}
+
+/* read 5 bytes */
+static void i2c_r5(struct gspca_dev *gspca_dev, __u8 reg,
+			     __u8 *buffer)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct usb_device *dev = gspca_dev->dev;
+	__u8 mode[8];
+
+	mode[0] = sd->i2c_ctrl_reg | 0x10;
+	mode[1] = sd->i2c_base;
+	mode[2] = reg;
+	mode[3] = 0;
+	mode[4] = 0;
+	mode[5] = 0;
+	mode[6] = 0;
+	mode[7] = 0x10;
+	i2c_w8(dev, mode);
+	mode[0] = sd->i2c_ctrl_reg | (5 << 4) | 0x02;
+	mode[2] = 0;
+	i2c_w8(dev, mode);
+	reg_r(dev, 0x0a, buffer, 5);
+}
+
+static int probesensor(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct usb_device *dev = gspca_dev->dev;
+	__u8 reg02;
+	static __u8 datasend[] = { 2, 0 };
+	/* reg val1 val2 val3 val4 */
+	__u8 datarecd[6];
+
+	i2c_w2(gspca_dev, datasend);
+/* should write 0xa1 0x11 0x02 0x00 0x00 0x00 0x00 the 0x10 is add by i2cw */
+	msleep(10);
+	reg02 = 0x66;
+	reg_w(dev, 0x02, &reg02, 1);		/* Gpio on */
+	msleep(10);
+	i2c_r5(gspca_dev, 0, datarecd);		/* read sensor id */
+	if (datarecd[0] == 0x02
+	    && datarecd[1] == 0x09
+	    && datarecd[2] == 0x01
+	    && datarecd[3] == 0x00
+	    && datarecd[4] == 0x00) {
+		PDEBUG(D_PROBE, "Find Sensor sn9c102P HV7131R");
+		sd->sensor = SENSOR_HV7131R;
+		return SENSOR_HV7131R;
+	}
+	PDEBUG(D_PROBE, "Find Sensor %d %d %d",
+		datarecd[0], datarecd[1], datarecd[2]);
+	PDEBUG(D_PROBE, "Sensor sn9c102P Not found");
+	return -ENODEV;
+}
+
+static int configure_gpio(struct gspca_dev *gspca_dev,
+			  __u8 *sn9c1xx)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct usb_device *dev = gspca_dev->dev;
+	__u8 data;
+	__u8 regF1;
+	__u8 *reg9a;
+	static __u8 reg9a_def[] =
+		{0x08, 0x40, 0x20, 0x10, 0x00, 0x04};
+	static __u8 reg9a_sn9c120[] =			/* from win trace */
+		{0x00, 0x40, 0x38, 0x30, 0x00, 0x20};
+	static __u8 reg9a_sn9c325[] =
+		{0x0a, 0x40, 0x38, 0x30, 0x00, 0x20};
+
+
+	regF1 = 0x00;
+	reg_w(dev, 0xf1, &regF1, 1);
+
+	reg_w(dev, 0x01, &sn9c1xx[0], 1);	/*fixme:jfm was [1] en v1*/
+
+	/* configure gpio */
+	reg_w(dev, 0x01, &sn9c1xx[1], 2);
+	reg_w(dev, 0x08, &sn9c1xx[8], 2);
+	reg_w(dev, 0x17, &sn9c1xx[0x17], 3);
+	switch (sd->customid) {
+	case SN9C325:
+		reg9a = reg9a_sn9c325;
+		break;
+	case SN9C120:
+		reg9a = reg9a_sn9c120;
+		break;
+	default:
+		reg9a = reg9a_def;
+		break;
+	}
+	reg_w(dev, 0x9a, reg9a, 6);
+
+	data = 0x60;				/*fixme:jfm 60 00 00 (3) */
+	reg_w(dev, 0xd4, &data, 1);
+
+	reg_w(dev, 0x03, &sn9c1xx[3], 0x0f);
+
+	switch (sd->customid) {
+	case SN9C120:				/* from win trace */
+		data = 0x61;
+		reg_w(dev, 0x01, &data, 1);
+		data = 0x20;
+		reg_w(dev, 0x17, &data, 1);
+		data = 0x60;
+		reg_w(dev, 0x01, &data, 1);
+		break;
+	case SN9C325:
+		data = 0x43;
+		reg_w(dev, 0x01, &data, 1);
+		data = 0xae;
+		reg_w(dev, 0x17, &data, 1);
+		data = 0x42;
+		reg_w(dev, 0x01, &data, 1);
+		break;
+	default:
+		data = 0x43;
+		reg_w(dev, 0x01, &data, 1);
+		data = 0x61;
+		reg_w(dev, 0x17, &data, 1);
+		data = 0x42;
+		reg_w(dev, 0x01, &data, 1);
+	}
+
+	if (sd->sensor == SENSOR_HV7131R) {
+		if (probesensor(gspca_dev) < 0)
+			return -ENODEV;
+	}
+	return 0;
+}
+
+static void hv7131R_InitSensor(struct gspca_dev *gspca_dev)
+{
+	int i = 0;
+	struct usb_device *dev = gspca_dev->dev;
+	static __u8 SetSensorClk[] =		/* 0x08 Mclk */
+		{ 0xa1, 0x11, 0x01, 0x18, 0x00, 0x00, 0x00, 0x10 };
+
+	while (hv7131r_sensor_init[i][0]) {
+		i2c_w8(dev, hv7131r_sensor_init[i]);
+		i++;
+	}
+	i2c_w8(dev, SetSensorClk);
+}
+
+static void mi0360_InitSensor(struct gspca_dev *gspca_dev)
+{
+	int i = 0;
+	struct usb_device *dev = gspca_dev->dev;
+
+	while (mi0360_sensor_init[i][0]) {
+		i2c_w8(dev, mi0360_sensor_init[i]);
+		i++;
+	}
+}
+
+static void mo4000_InitSensor(struct gspca_dev *gspca_dev)
+{
+	int i = 0;
+	struct usb_device *dev = gspca_dev->dev;
+
+	while (mo4000_sensor_init[i][0]) {
+		i2c_w8(dev, mo4000_sensor_init[i]);
+		i++;
+	}
+}
+
+static void ov7648_InitSensor(struct gspca_dev *gspca_dev)
+{
+	struct usb_device *dev = gspca_dev->dev;
+	int i = 0;
+
+	while (ov7648_sensor_init[i][0]) {
+		i2c_w8(dev, ov7648_sensor_init[i]);
+		i++;
+	}
+}
+
+static void ov7660_InitSensor(struct gspca_dev *gspca_dev)
+{
+	int i = 0;
+	struct usb_device *dev = gspca_dev->dev;
+
+	while (ov7660_sensor_init[i][0]) {
+		i2c_w8(dev, ov7660_sensor_init[i]);
+		i++;
+	}
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+			const struct usb_device_id *id)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct cam *cam;
+	__u16 vendor;
+	__u16 product;
+
+	vendor = id->idVendor;
+	product = id->idProduct;
+	sd->sensor = -1;
+	switch (vendor) {
+	case 0x0458:				/* Genius */
+/*		switch (product) {
+		case 0x7025: */
+			sd->customid = SN9C120;
+			sd->sensor = SENSOR_MI0360;
+			sd->i2c_ctrl_reg = 0x81;
+			sd->i2c_base = 0x5d;
+/*			break;
+		} */
+		break;
+	case 0x045e:
+/*		switch (product) {
+		case 0x00f5:
+		case 0x00f7: */
+			sd->customid = SN9C105;
+			sd->sensor = SENSOR_OV7660;
+			sd->i2c_ctrl_reg = 0x81;
+			sd->i2c_base = 0x21;
+/*			break;
+		} */
+		break;
+	case 0x0471:				/* Philips */
+/*		switch (product) {
+		case 0x0327:
+		case 0x0328:
+		case 0x0330: */
+			sd->customid = SN9C105;
+			sd->sensor = SENSOR_MI0360;
+			sd->i2c_ctrl_reg = 0x81;
+			sd->i2c_base = 0x5d;
+/*			break;
+		} */
+		break;
+	case 0x0c45:				/* Sonix */
+		switch (product) {
+		case 0x6040:
+			sd->customid = SN9C102P;
+			sd->sensor = SENSOR_MI0360;	/* from BW600.inf */
+/*			sd->sensor = SENSOR_HV7131R;	 * gspcav1 value */
+			sd->i2c_ctrl_reg = 0x81;
+			sd->i2c_base = 0x11;
+			break;
+/*		case 0x607a:				* from BW600.inf
+			sd->customid = SN9C102P;
+			sd->sensor = SENSOR_OV7648;
+			sd->i2c_ctrl_reg = 0x??;
+			sd->i2c_base = 0x??;
+			break; */
+		case 0x607c:
+			sd->customid = SN9C102P;
+			sd->sensor = SENSOR_HV7131R;
+			sd->i2c_ctrl_reg = 0x81;
+			sd->i2c_base = 0x11;
+			break;
+/*		case 0x607e:				* from BW600.inf
+			sd->customid = SN9C102P;
+			sd->sensor = SENSOR_OV7630;
+			sd->i2c_ctrl_reg = 0x??;
+			sd->i2c_base = 0x??;
+			break; */
+		case 0x60c0:
+			sd->customid = SN9C105;
+			sd->sensor = SENSOR_MI0360;
+			sd->i2c_ctrl_reg = 0x81;
+			sd->i2c_base = 0x5d;
+			break;
+/*		case 0x60c8:				* from BW600.inf
+			sd->customid = SN9C105;
+			sd->sensor = SENSOR_OM6801;
+			sd->i2c_ctrl_reg = 0x??;
+			sd->i2c_base = 0x??;
+			break; */
+/*		case 0x60cc:				* from BW600.inf
+			sd->customid = SN9C105;
+			sd->sensor = SENSOR_HV7131GP;
+			sd->i2c_ctrl_reg = 0x??;
+			sd->i2c_base = 0x??;
+			break; */
+		case 0x60ec:
+			sd->customid = SN9C105;
+			sd->sensor = SENSOR_MO4000;
+			sd->i2c_ctrl_reg = 0x81;
+			sd->i2c_base = 0x21;
+			break;
+/*		case 0x60ef:				* from BW600.inf
+			sd->customid = SN9C105;
+			sd->sensor = SENSOR_ICM105C;
+			sd->i2c_ctrl_reg = 0x??;
+			sd->i2c_base = 0x??;
+			break; */
+/*		case 0x60fa:				* from BW600.inf
+			sd->customid = SN9C105;
+			sd->sensor = SENSOR_OV7648;
+			sd->i2c_ctrl_reg = 0x??;
+			sd->i2c_base = 0x??;
+			break; */
+		case 0x60fb:
+			sd->customid = SN9C105;
+			sd->sensor = SENSOR_OV7660;
+			sd->i2c_ctrl_reg = 0x81;
+			sd->i2c_base = 0x21;
+			break;
+		case 0x60fc:
+			sd->customid = SN9C105;
+			sd->sensor = SENSOR_HV7131R;
+			sd->i2c_ctrl_reg = 0x81;
+			sd->i2c_base = 0x11;
+			break;
+/*		case 0x60fe:				* from BW600.inf
+			sd->customid = SN9C105;
+			sd->sensor = SENSOR_OV7630;
+			sd->i2c_ctrl_reg = 0x??;
+			sd->i2c_base = 0x??;
+			break; */
+/*		case 0x6108:				* from BW600.inf
+			sd->customid = SN9C120;
+			sd->sensor = SENSOR_OM6801;
+			sd->i2c_ctrl_reg = 0x??;
+			sd->i2c_base = 0x??;
+			break; */
+/*		case 0x6122:				* from BW600.inf
+			sd->customid = SN9C110;
+			sd->sensor = SENSOR_ICM105C;
+			sd->i2c_ctrl_reg = 0x??;
+			sd->i2c_base = 0x??;
+			break; */
+		case 0x612a:
+/*			sd->customid = SN9C110;		 * in BW600.inf */
+			sd->customid = SN9C325;
+			sd->sensor = SENSOR_OV7648;
+			sd->i2c_ctrl_reg = 0x81;
+			sd->i2c_base = 0x21;
+			break;
+/*		case 0x6123:				* from BW600.inf
+			sd->customid = SN9C110;
+			sd->sensor = SENSOR_SanyoCCD;
+			sd->i2c_ctrl_reg = 0x??;
+			sd->i2c_base = 0x??;
+			break; */
+		case 0x612c:
+			sd->customid = SN9C110;
+			sd->sensor = SENSOR_MO4000;
+			sd->i2c_ctrl_reg = 0x81;
+			sd->i2c_base = 0x21;
+			break;
+/*		case 0x612e:				* from BW600.inf
+			sd->customid = SN9C110;
+			sd->sensor = SENSOR_OV7630;
+			sd->i2c_ctrl_reg = 0x??;
+			sd->i2c_base = 0x??;
+			break; */
+/*		case 0x612f:				* from BW600.inf
+			sd->customid = SN9C110;
+			sd->sensor = SENSOR_ICM105C;
+			sd->i2c_ctrl_reg = 0x??;
+			sd->i2c_base = 0x??;
+			break; */
+		case 0x6130:
+			sd->customid = SN9C120;
+			sd->sensor = SENSOR_MI0360;
+			sd->i2c_ctrl_reg = 0x81;
+			sd->i2c_base = 0x5d;
+			break;
+		case 0x6138:
+			sd->customid = SN9C120;
+			sd->sensor = SENSOR_MO4000;
+			sd->i2c_ctrl_reg = 0x81;
+			sd->i2c_base = 0x21;
+			break;
+/*		case 0x613a:				* from BW600.inf
+			sd->customid = SN9C120;
+			sd->sensor = SENSOR_OV7648;
+			sd->i2c_ctrl_reg = 0x??;
+			sd->i2c_base = 0x??;
+			break; */
+		case 0x613b:
+			sd->customid = SN9C120;
+			sd->sensor = SENSOR_OV7660;
+			sd->i2c_ctrl_reg = 0x81;
+			sd->i2c_base = 0x21;
+			break;
+		case 0x613c:
+			sd->customid = SN9C120;
+			sd->sensor = SENSOR_HV7131R;
+			sd->i2c_ctrl_reg = 0x81;
+			sd->i2c_base = 0x11;
+			break;
+/*		case 0x613e:				* from BW600.inf
+			sd->customid = SN9C120;
+			sd->sensor = SENSOR_OV7630;
+			sd->i2c_ctrl_reg = 0x??;
+			sd->i2c_base = 0x??;
+			break; */
+		}
+		break;
+	}
+	if (sd->sensor < 0) {
+		PDEBUG(D_ERR, "Invalid vendor/product %04x:%04x",
+			vendor, product);
+		return -EINVAL;
+	}
+
+	cam = &gspca_dev->cam;
+	cam->dev_name = (char *) id->driver_info;
+	cam->epaddr = 0x01;
+	cam->cam_mode = vga_mode;
+	cam->nmodes = ARRAY_SIZE(vga_mode);
+	sd->qindex = 4;			/* set the quantization table */
+	sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
+	sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
+	sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value;
+	sd->autogain = sd_ctrls[SD_AUTOGAIN].qctrl.default_value;
+	return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct usb_device *dev = gspca_dev->dev;
+/*	__u8 *sn9c1xx; */
+	__u8 regF1;
+	__u8 regGpio[] = { 0x29, 0x74 };
+
+	/* setup a selector by customid */
+	regF1 = 0x01;
+	reg_w(dev, 0xf1, &regF1, 1);
+	reg_r(dev, 0x00, &regF1, 1);	/* -> regF1 = 0x00 */
+	reg_w(dev, 0xf1, &regF1, 1);
+	reg_r(dev, 0x00, &regF1, 1);
+	switch (sd->customid) {
+	case SN9C102P:
+		if (regF1 != 0x11)
+			return -ENODEV;
+		reg_w(dev, 0x02, &regGpio[1], 1);
+		break;
+	case SN9C105:
+		if (regF1 != 0x11)
+			return -ENODEV;
+		reg_w(dev, 0x02, regGpio, 2);
+		break;
+	case SN9C110:
+		if (regF1 != 0x12)
+			return -ENODEV;
+		regGpio[1] = 0x62;
+		reg_w(dev, 0x02, &regGpio[1], 1);
+		break;
+	case SN9C120:
+		if (regF1 != 0x12)
+			return -ENODEV;
+		regGpio[1] = 0x70;
+		reg_w(dev, 0x02, regGpio, 2);
+		break;
+	default:
+/*	case SN9C325: */
+		if (regF1 != 0x12)
+			return -ENODEV;
+		regGpio[1] = 0x62;
+		reg_w(dev, 0x02, &regGpio[1], 1);
+		break;
+	}
+
+	regF1 = 0x01;
+	reg_w(dev, 0xf1, &regF1, 1);
+
+	return 0;
+}
+
+static unsigned int setexposure(struct gspca_dev *gspca_dev,
+				unsigned int expo)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	static __u8 doit[] =			/* update sensor */
+		{ 0xb1, 0x5d, 0x07, 0x00, 0x03, 0x00, 0x00, 0x10 };
+	static __u8 sensorgo[] =		/* sensor on */
+		{ 0xb1, 0x5d, 0x07, 0x00, 0x02, 0x00, 0x00, 0x10 };
+	static __u8 gainMo[] =
+		{ 0xa1, 0x21, 0x00, 0x10, 0x00, 0x00, 0x00, 0x1d };
+
+	switch (sd->sensor) {
+	case SENSOR_HV7131R: {
+		__u8 Expodoit[] =
+			{ 0xc1, 0x11, 0x25, 0x07, 0x27, 0xc0, 0x00, 0x16 };
+
+		Expodoit[3] = expo >> 16;
+		Expodoit[4] = expo >> 8;
+		Expodoit[5] = expo;
+		i2c_w8(gspca_dev->dev, Expodoit);
+		break;
+	    }
+	case SENSOR_MI0360: {
+		__u8 expoMi[] =	 /* exposure 0x0635 -> 4 fp/s 0x10 */
+			{ 0xb1, 0x5d, 0x09, 0x06, 0x35, 0x00, 0x00, 0x16 };
+
+		if (expo > 0x0635)
+			expo = 0x0635;
+		else if (expo < 0x0001)
+			expo = 0x0001;
+		expoMi[3] = expo >> 8;
+		expoMi[4] = expo;
+		i2c_w8(gspca_dev->dev, expoMi);
+		i2c_w8(gspca_dev->dev, doit);
+		i2c_w8(gspca_dev->dev, sensorgo);
+		break;
+	    }
+	case SENSOR_MO4000: {
+		__u8 expoMof[] =
+			{ 0xa1, 0x21, 0x0f, 0x20, 0x00, 0x00, 0x00, 0x10 };
+		__u8 expoMo10[] =
+			{ 0xa1, 0x21, 0x10, 0x20, 0x00, 0x00, 0x00, 0x10 };
+
+		if (expo > 0x1fff)
+			expo = 0x1fff;
+		else if (expo < 0x0001)
+			expo = 0x0001;
+		expoMof[3] = (expo & 0x03fc) >> 2;
+		i2c_w8(gspca_dev->dev, expoMof);
+		expoMo10[3] = ((expo & 0x1c00) >> 10)
+				| ((expo & 0x0003) << 4);
+		i2c_w8(gspca_dev->dev, expoMo10);
+		i2c_w8(gspca_dev->dev, gainMo);
+		PDEBUG(D_CONF," set exposure %d",
+			((expoMo10[3] & 0x07) << 10)
+			| (expoMof[3] << 2)
+			| ((expoMo10[3] & 0x30) >> 4));
+		break;
+	    }
+	}
+	return expo;
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	unsigned int expo;
+	__u8 k2;
+
+	switch (sd->sensor) {
+	case SENSOR_HV7131R:
+		expo = sd->brightness << 4;
+		if (expo > 0x002dc6c0)
+			expo = 0x002dc6c0;
+		else if (expo < 0x02a0)
+			expo = 0x02a0;
+		sd->exposure = setexposure(gspca_dev, expo);
+		break;
+	case SENSOR_MI0360:
+		expo = sd->brightness >> 4;
+		sd->exposure = setexposure(gspca_dev, expo);
+		break;
+	case SENSOR_MO4000:
+		expo = sd->brightness >> 4;
+		sd->exposure = setexposure(gspca_dev, expo);
+		break;
+	case SENSOR_OV7660:
+		return;				/*jfm??*/
+	}
+
+	k2 = sd->brightness >> 10;
+	reg_w(gspca_dev->dev, 0x96, &k2, 1);
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	__u8 k2;
+	__u8 contrast[] = { 0x00, 0x00, 0x28, 0x00, 0x07, 0x00 };
+
+	if (sd->sensor == SENSOR_OV7660)
+		return;				/*jfm??*/
+	k2 = sd->contrast;
+	contrast[2] = k2;
+	contrast[0] = (k2 + 1) >> 1;
+	contrast[4] = (k2 + 1) / 5;
+	reg_w(gspca_dev->dev, 0x84, contrast, 6);
+}
+
+static void setcolors(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	__u8 data;
+	int colour;
+
+	colour = sd->colors - 128;
+	if (colour > 0)
+		data = (colour + 32) & 0x7f;	/* blue */
+	else
+		data = (-colour + 32) & 0x7f;	/* red */
+	reg_w(gspca_dev->dev, 0x05, &data, 1);
+}
+
+/* -- start the camera -- */
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct usb_device *dev = gspca_dev->dev;
+	int i;
+	__u8 data;
+	__u8 reg1;
+	__u8 reg17;
+	__u8 *sn9c1xx;
+	int mode;
+	static __u8 DC29[] = { 0x6a, 0x50, 0x00, 0x00, 0x50, 0x3c };
+	static __u8 C0[] = { 0x2d, 0x2d, 0x3a, 0x05, 0x04, 0x3f };
+	static __u8 CA[] = { 0x28, 0xd8, 0x14, 0xec };
+	static __u8 CA_sn9c120[] = { 0x14, 0xec, 0x0a, 0xf6 }; /* SN9C120 */
+	static __u8 CE[] = { 0x32, 0xdd, 0x2d, 0xdd };	/* MI0360 */
+	static __u8 CE_sn9c325[] =
+			{ 0x32, 0xdd, 0x32, 0xdd };	/* OV7648 - SN9C325 */
+
+	sn9c1xx = sn_tb[(int) sd->sensor];
+	configure_gpio(gspca_dev, sn9c1xx);
+
+/*fixme:jfm this sequence should appear at end of sd_start */
+/* with
+	data = 0x44;
+	reg_w(dev, 0x01, &data, 1); */
+	reg_w(dev, 0x15, &sn9c1xx[0x15], 1);
+	reg_w(dev, 0x16, &sn9c1xx[0x16], 1);
+	reg_w(dev, 0x12, &sn9c1xx[0x12], 1);
+	reg_w(dev, 0x13, &sn9c1xx[0x13], 1);
+	reg_w(dev, 0x18, &sn9c1xx[0x18], 1);
+	reg_w(dev, 0xd2, &DC29[0], 1);
+	reg_w(dev, 0xd3, &DC29[1], 1);
+	reg_w(dev, 0xc6, &DC29[2], 1);
+	reg_w(dev, 0xc7, &DC29[3], 1);
+	reg_w(dev, 0xc8, &DC29[4], 1);
+	reg_w(dev, 0xc9, &DC29[5], 1);
+/*fixme:jfm end of ending sequence */
+	reg_w(dev, 0x18, &sn9c1xx[0x18], 1);
+	if (sd->customid == SN9C325)
+		data = 0xae;
+	else
+		data = 0x60;
+	reg_w(dev, 0x17, &data, 1);
+	reg_w(dev, 0x05, &sn9c1xx[5], 1);
+	reg_w(dev, 0x07, &sn9c1xx[7], 1);
+	reg_w(dev, 0x06, &sn9c1xx[6], 1);
+	reg_w(dev, 0x14, &sn9c1xx[0x14], 1);
+	if (sd->customid == SN9C325) {
+		reg_w(dev, 0x20, regsn20_sn9c325, 0x11);
+		for (i = 0; i < 8; i++)
+			reg_w(dev, 0x84, reg84_sn9c325, 0x15);
+		data = 0x0a;
+		reg_w(dev, 0x9a, &data, 1);
+		data = 0x60;
+		reg_w(dev, 0x99, &data, 1);
+	} else {
+		reg_w(dev, 0x20, regsn20, 0x11);
+		for (i = 0; i < 8; i++)
+			reg_w(dev, 0x84, reg84, 0x15);
+		data = 0x08;
+		reg_w(dev, 0x9a, &data, 1);
+		data = 0x59;
+		reg_w(dev, 0x99, &data, 1);
+	}
+
+	mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].mode;
+	reg1 = 0x02;
+	reg17 = 0x61;
+	switch (sd->sensor) {
+	case SENSOR_HV7131R:
+		hv7131R_InitSensor(gspca_dev);
+		if (mode)
+			reg1 = 0x46;	/* 320 clk 48Mhz */
+		else
+			reg1 = 0x06;	/* 640 clk 24Mz */
+		break;
+	case SENSOR_MI0360:
+		mi0360_InitSensor(gspca_dev);
+		if (mode)
+			reg1 = 0x46;	/* 320 clk 48Mhz */
+		else
+			reg1 = 0x06;	/* 640 clk 24Mz */
+		break;
+	case SENSOR_MO4000:
+		mo4000_InitSensor(gspca_dev);
+		if (mode) {
+/*			reg1 = 0x46;	 * 320 clk 48Mhz 60fp/s */
+			reg1 = 0x06;	/* clk 24Mz */
+		} else {
+			reg17 = 0x22;	/* 640 MCKSIZE */
+			reg1 = 0x06;	/* 640 clk 24Mz */
+		}
+		break;
+	case SENSOR_OV7648:
+		reg17 = 0xa2;
+		reg1 = 0x44;
+		ov7648_InitSensor(gspca_dev);
+/*		if (mode)
+			;		 * 320x2...
+		else
+			;		 * 640x... */
+		break;
+	default:
+/*	case SENSOR_OV7660: */
+		ov7660_InitSensor(gspca_dev);
+		if (mode) {
+/*			reg17 = 0x21;	 * 320 */
+/*			reg1 = 0x44; */
+			reg1 = 0x46;
+		} else {
+			reg17 = 0xa2;	/* 640 */
+			reg1 = 0x40;
+		}
+		break;
+	}
+	reg_w(dev, 0xc0, C0, 6);
+	switch (sd->customid) {
+	case SN9C120:			/*jfm ?? */
+		reg_w(dev, 0xca, CA_sn9c120, 4);
+		break;
+	default:
+		reg_w(dev, 0xca, CA, 4);
+		break;
+	}
+	switch (sd->customid) {
+	case SN9C120:			/*jfm ?? */
+	case SN9C325:
+		reg_w(dev, 0xce, CE_sn9c325, 4);
+		break;
+	default:
+		reg_w(dev, 0xce, CE, 4);
+					/* ?? {0x1e, 0xdd, 0x2d, 0xe7} */
+		break;
+	}
+
+	/* here change size mode 0 -> VGA; 1 -> CIF */
+	data = 0x40 | sn9c1xx[0x18] | (mode << 4);
+	reg_w(dev, 0x18, &data, 1);
+
+	reg_w(dev, 0x100, qtable4, 0x40);
+	reg_w(dev, 0x140, qtable4 + 0x40, 0x40);
+
+	data = sn9c1xx[0x18] | (mode << 4);
+	reg_w(dev, 0x18, &data, 1);
+
+	reg_w(dev, 0x17, &reg17, 1);
+	reg_w(dev, 0x01, &reg1, 1);
+	setbrightness(gspca_dev);
+	setcontrast(gspca_dev);
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct usb_device *dev = gspca_dev->dev;
+	static __u8 stophv7131[] =
+		{ 0xa1, 0x11, 0x02, 0x09, 0x00, 0x00, 0x00, 0x10 };
+	static __u8 stopmi0360[] =
+		{ 0xb1, 0x5d, 0x07, 0x00, 0x00, 0x00, 0x00, 0x10 };
+	__u8 regF1;
+	__u8 data;
+	__u8 *sn9c1xx;
+
+	data = 0x0b;
+	switch (sd->sensor) {
+	case SENSOR_HV7131R:
+		i2c_w8(dev, stophv7131);
+		data = 0x2b;
+		break;
+	case SENSOR_MI0360:
+		i2c_w8(dev, stopmi0360);
+		data = 0x29;
+		break;
+	case SENSOR_MO4000:
+		break;
+	case SENSOR_OV7648:
+		data = 0x29;
+		break;
+	default:
+/*	case SENSOR_OV7660: */
+		break;
+	}
+	sn9c1xx = sn_tb[(int) sd->sensor];
+	reg_w(dev, 0x01, &sn9c1xx[1], 1);
+	reg_w(dev, 0x17, &sn9c1xx[0x17], 1);
+	reg_w(dev, 0x01, &sn9c1xx[1], 1);
+	reg_w(dev, 0x01, &data, 1);
+	regF1 = 0x01;
+	reg_w(dev, 0xf1, &regF1, 1);
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+static void setautogain(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	/* Thanks S., without your advice, autobright should not work :) */
+	int delta;
+	int expotimes = 0;
+	__u8 luma_mean = 130;
+	__u8 luma_delta = 20;
+
+	delta = sd->avg_lum;
+	if (delta < luma_mean - luma_delta ||
+	    delta > luma_mean + luma_delta) {
+		switch (sd->sensor) {
+		case SENSOR_HV7131R:
+			expotimes = sd->exposure >> 8;
+			expotimes += (luma_mean - delta) >> 4;
+			if (expotimes < 0)
+				expotimes = 0;
+			sd->exposure = setexposure(gspca_dev,
+					(unsigned int) (expotimes << 8));
+			break;
+		case SENSOR_MO4000:
+		case SENSOR_MI0360:
+			expotimes = sd->exposure;
+			expotimes += (luma_mean - delta) >> 6;
+			if (expotimes < 0)
+				expotimes = 0;
+			sd->exposure = setexposure(gspca_dev,
+						   (unsigned int) expotimes);
+			setcolors(gspca_dev);
+			break;
+		}
+	}
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+			struct gspca_frame *frame,	/* target */
+			unsigned char *data,		/* isoc packet */
+			int len)			/* iso packet length */
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int sof, avg_lum;
+
+	sof = len - 64;
+	if (sof >= 0 && data[sof] == 0xff && data[sof + 1] == 0xd9) {
+
+		/* end of frame */
+		gspca_frame_add(gspca_dev, LAST_PACKET,
+				frame, data, sof + 2);
+		if (sd->ag_cnt < 0)
+			return;
+		if (--sd->ag_cnt >= 0)
+			return;
+		sd->ag_cnt = AG_CNT_START;
+/* w1 w2 w3 */
+/* w4 w5 w6 */
+/* w7 w8 */
+/* w4 */
+		avg_lum = ((data[sof + 29] << 8) | data[sof + 30]) >> 6;
+/* w6 */
+		avg_lum += ((data[sof + 33] << 8) | data[sof + 34]) >> 6;
+/* w2 */
+		avg_lum += ((data[sof + 25] << 8) | data[sof + 26]) >> 6;
+/* w8 */
+		avg_lum += ((data[sof + 37] << 8) | data[sof + 38]) >> 6;
+/* w5 */
+		avg_lum += ((data[sof + 31] << 8) | data[sof + 32]) >> 4;
+		avg_lum >>= 4;
+		sd->avg_lum = avg_lum;
+		PDEBUG(D_PACK, "mean lum %d", avg_lum);
+		setautogain(gspca_dev);
+		return;
+	}
+	if (gspca_dev->last_packet_type == LAST_PACKET) {
+
+		/* put the JPEG 422 header */
+		jpeg_put_header(gspca_dev, frame, sd->qindex, 0x21);
+	}
+	gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+}
+
+static unsigned int getexposure(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	__u8 hexpo, mexpo, lexpo;
+	__u8 expo[6];
+
+	switch (sd->sensor) {
+	case SENSOR_HV7131R:
+		/* read sensor exposure */
+		i2c_r5(gspca_dev, 0x25, expo);
+		return (expo[0] << 16) | (expo[1] << 8) | expo[2];
+	case SENSOR_MI0360:
+		/* read sensor exposure */
+		i2c_r5(gspca_dev, 0x09, expo);
+		return (expo[0] << 8) | expo[1];
+	case SENSOR_MO4000:
+		i2c_r5(gspca_dev, 0x0e, expo);
+		hexpo = 0;		/* expo[1] & 0x07; */
+		mexpo = 0x40;		/* expo[2] &0xff; */
+		lexpo = (expo[1] & 0x30) >> 4;
+		PDEBUG(D_CONF, "exposure %d",
+			(hexpo << 10) | (mexpo << 2) | lexpo);
+		return (hexpo << 10) | (mexpo << 2) | lexpo;
+	default:
+/*	case SENSOR_OV7660: */
+		/* read sensor exposure */
+		i2c_r5(gspca_dev, 0x04, expo);
+		hexpo = expo[3] & 0x2f;
+		lexpo = expo[0] & 0x02;
+		i2c_r5(gspca_dev, 0x08, expo);
+		mexpo = expo[2];
+		return (hexpo << 10) | (mexpo << 2) | lexpo;
+	}
+}
+
+static void getbrightness(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	/* hardcoded registers seem not readable */
+	switch (sd->sensor) {
+	case SENSOR_HV7131R:
+/*		sd->brightness = 0x7fff; */
+		sd->brightness = getexposure(gspca_dev) >> 4;
+		break;
+	case SENSOR_MI0360:
+		sd->brightness = getexposure(gspca_dev) << 4;
+		break;
+	case SENSOR_MO4000:
+/*		sd->brightness = 0x1fff; */
+		sd->brightness = getexposure(gspca_dev) << 4;
+		break;
+	}
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->brightness = val;
+	if (gspca_dev->streaming)
+		setbrightness(gspca_dev);
+	return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	getbrightness(gspca_dev);
+	*val = sd->brightness;
+	return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->contrast = val;
+	if (gspca_dev->streaming)
+		setcontrast(gspca_dev);
+	return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->contrast;
+	return 0;
+}
+
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->colors = val;
+	if (gspca_dev->streaming)
+		setcolors(gspca_dev);
+	return 0;
+}
+
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->colors;
+	return 0;
+}
+
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->autogain = val;
+	if (val)
+		sd->ag_cnt = AG_CNT_START;
+	else
+		sd->ag_cnt = -1;
+	return 0;
+}
+
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->autogain;
+	return 0;
+}
+
+/* sub-driver description */
+static struct sd_desc sd_desc = {
+	.name = MODULE_NAME,
+	.ctrls = sd_ctrls,
+	.nctrls = ARRAY_SIZE(sd_ctrls),
+	.config = sd_config,
+	.open = sd_open,
+	.start = sd_start,
+	.stopN = sd_stopN,
+	.stop0 = sd_stop0,
+	.close = sd_close,
+	.pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static __devinitdata struct usb_device_id device_table[] = {
+	{USB_DEVICE(0x0458, 0x7025), DVNM("Genius Eye 311Q")},
+	{USB_DEVICE(0x045e, 0x00f5), DVNM("MicroSoft VX3000")},
+	{USB_DEVICE(0x045e, 0x00f7), DVNM("MicroSoft VX1000")},
+	{USB_DEVICE(0x0471, 0x0327), DVNM("Philips SPC 600 NC")},
+	{USB_DEVICE(0x0471, 0x0328), DVNM("Philips SPC 700 NC")},
+	{USB_DEVICE(0x0471, 0x0330), DVNM("Philips SPC 710NC")},
+	{USB_DEVICE(0x0c45, 0x6040), DVNM("Speed NVC 350K")},
+	{USB_DEVICE(0x0c45, 0x607c), DVNM("Sonix sn9c102p Hv7131R")},
+	{USB_DEVICE(0x0c45, 0x60c0), DVNM("Sangha Sn535")},
+	{USB_DEVICE(0x0c45, 0x60ec), DVNM("SN9C105+MO4000")},
+	{USB_DEVICE(0x0c45, 0x60fb), DVNM("Surfer NoName")},
+	{USB_DEVICE(0x0c45, 0x60fc), DVNM("LG-LIC300")},
+	{USB_DEVICE(0x0c45, 0x612a), DVNM("Avant Camera")},
+	{USB_DEVICE(0x0c45, 0x612c), DVNM("Typhoon Rasy Cam 1.3MPix")},
+	{USB_DEVICE(0x0c45, 0x6130), DVNM("Sonix Pccam")},
+	{USB_DEVICE(0x0c45, 0x6138), DVNM("Sn9c120 Mo4000")},
+	{USB_DEVICE(0x0c45, 0x613b), DVNM("Surfer SN-206")},
+	{USB_DEVICE(0x0c45, 0x613c), DVNM("Sonix Pccam168")},
+	{}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+		    const struct usb_device_id *id)
+{
+	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+				THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+	.name = MODULE_NAME,
+	.id_table = device_table,
+	.probe = sd_probe,
+	.disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+	if (usb_register(&sd_driver) < 0)
+		return -1;
+	info("v%s registered", version);
+	return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+	usb_deregister(&sd_driver);
+	info("deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/spca500.c b/drivers/media/video/gspca/spca500.c
new file mode 100644
index 0000000..c0dd969
--- /dev/null
+++ b/drivers/media/video/gspca/spca500.c
@@ -0,0 +1,1195 @@
+/*
+ * SPCA500 chip based cameras initialization data
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#define MODULE_NAME "spca500"
+
+#include "gspca.h"
+#include "jpeg.h"
+
+#define DRIVER_VERSION_NUMBER	KERNEL_VERSION(2, 1, 0)
+static const char version[] = "2.1.0";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("GSPCA/SPCA500 USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+	struct gspca_dev gspca_dev;		/* !! must be the first item */
+
+	unsigned char packet[ISO_MAX_SIZE + 128];
+				 /* !! no more than 128 ff in an ISO packet */
+
+	unsigned char brightness;
+	unsigned char contrast;
+	unsigned char colors;
+
+	char qindex;
+	char subtype;
+#define AgfaCl20 0
+#define AiptekPocketDV 1
+#define BenqDC1016 2
+#define CreativePCCam300 3
+#define DLinkDSC350 4
+#define Gsmartmini 5
+#define IntelPocketPCCamera 6
+#define KodakEZ200 7
+#define LogitechClickSmart310 8
+#define LogitechClickSmart510 9
+#define LogitechTraveler 10
+#define MustekGsmart300 11
+#define Optimedia 12
+#define PalmPixDC85 13
+#define ToptroIndus 14
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+#define SD_BRIGHTNESS 0
+	{
+	    {
+		.id      = V4L2_CID_BRIGHTNESS,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Brightness",
+		.minimum = 0,
+		.maximum = 0xff,
+		.step    = 1,
+		.default_value = 0x7f,
+	    },
+	    .set = sd_setbrightness,
+	    .get = sd_getbrightness,
+	},
+#define SD_CONTRAST 1
+	{
+	    {
+		.id      = V4L2_CID_CONTRAST,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Contrast",
+		.minimum = 0,
+		.maximum = 255,
+		.step    = 1,
+		.default_value = 127,
+	    },
+	    .set = sd_setcontrast,
+	    .get = sd_getcontrast,
+	},
+#define SD_COLOR 2
+	{
+	    {
+		.id      = V4L2_CID_SATURATION,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Color",
+		.minimum = 0,
+		.maximum = 255,
+		.step    = 1,
+		.default_value = 127,
+	    },
+	    .set = sd_setcolors,
+	    .get = sd_getcolors,
+	},
+};
+
+static struct cam_mode vga_mode[] = {
+	{V4L2_PIX_FMT_JPEG, 320, 240, 1},
+	{V4L2_PIX_FMT_JPEG, 640, 480, 0},
+};
+
+static struct cam_mode sif_mode[] = {
+	{V4L2_PIX_FMT_JPEG, 176, 144, 1},
+	{V4L2_PIX_FMT_JPEG, 352, 288, 0},
+};
+
+/* Frame packet header offsets for the spca500 */
+#define SPCA500_OFFSET_PADDINGLB 2
+#define SPCA500_OFFSET_PADDINGHB 3
+#define SPCA500_OFFSET_MODE      4
+#define SPCA500_OFFSET_IMGWIDTH  5
+#define SPCA500_OFFSET_IMGHEIGHT 6
+#define SPCA500_OFFSET_IMGMODE   7
+#define SPCA500_OFFSET_QTBLINDEX 8
+#define SPCA500_OFFSET_FRAMSEQ   9
+#define SPCA500_OFFSET_CDSPINFO  10
+#define SPCA500_OFFSET_GPIO      11
+#define SPCA500_OFFSET_AUGPIO    12
+#define SPCA500_OFFSET_DATA      16
+
+
+static __u16 spca500_visual_defaults[][3] = {
+	{0x00, 0x0003, 0x816b},	/* SSI not active sync with vsync,
+				 * hue (H byte) = 0,
+				 * saturation/hue enable,
+				 * brightness/contrast enable.
+				 */
+	{0x00, 0x0000, 0x8167},	/* brightness = 0 */
+	{0x00, 0x0020, 0x8168},	/* contrast = 0 */
+	{0x00, 0x0003, 0x816b},	/* SSI not active sync with vsync,
+				 * hue (H byte) = 0, saturation/hue enable,
+				 * brightness/contrast enable.
+				 * was 0x0003, now 0x0000.
+				 */
+	{0x00, 0x0000, 0x816a},	/* hue (L byte) = 0 */
+	{0x00, 0x0020, 0x8169},	/* saturation = 0x20 */
+	{0x00, 0x0050, 0x8157},	/* edge gain high threshold */
+	{0x00, 0x0030, 0x8158},	/* edge gain low threshold */
+	{0x00, 0x0028, 0x8159},	/* edge bandwidth high threshold */
+	{0x00, 0x000a, 0x815a},	/* edge bandwidth low threshold */
+	{0x00, 0x0001, 0x8202},	/* clock rate compensation = 1/25 sec/frame */
+	{0x0c, 0x0004, 0x0000},
+	/* set interface */
+
+	{0, 0, 0}
+};
+static __u16 Clicksmart510_defaults[][3] = {
+	{0x00, 0x00, 0x8211},
+	{0x00, 0x01, 0x82c0},
+	{0x00, 0x10, 0x82cb},
+	{0x00, 0x0f, 0x800d},
+	{0x00, 0x82, 0x8225},
+	{0x00, 0x21, 0x8228},
+	{0x00, 0x00, 0x8203},
+	{0x00, 0x00, 0x8204},
+	{0x00, 0x08, 0x8205},
+	{0x00, 0xf8, 0x8206},
+	{0x00, 0x28, 0x8207},
+	{0x00, 0xa0, 0x8208},
+	{0x00, 0x08, 0x824a},
+	{0x00, 0x08, 0x8214},
+	{0x00, 0x80, 0x82c1},
+	{0x00, 0x00, 0x82c2},
+	{0x00, 0x00, 0x82ca},
+	{0x00, 0x80, 0x82c1},
+	{0x00, 0x04, 0x82c2},
+	{0x00, 0x00, 0x82ca},
+	{0x00, 0xfc, 0x8100},
+	{0x00, 0xfc, 0x8105},
+	{0x00, 0x30, 0x8101},
+	{0x00, 0x00, 0x8102},
+	{0x00, 0x00, 0x8103},
+	{0x00, 0x66, 0x8107},
+	{0x00, 0x00, 0x816b},
+	{0x00, 0x00, 0x8155},
+	{0x00, 0x01, 0x8156},
+	{0x00, 0x60, 0x8157},
+	{0x00, 0x40, 0x8158},
+	{0x00, 0x0a, 0x8159},
+	{0x00, 0x06, 0x815a},
+	{0x00, 0x00, 0x813f},
+	{0x00, 0x00, 0x8200},
+	{0x00, 0x19, 0x8201},
+	{0x00, 0x00, 0x82c1},
+	{0x00, 0xa0, 0x82c2},
+	{0x00, 0x00, 0x82ca},
+	{0x00, 0x00, 0x8117},
+	{0x00, 0x00, 0x8118},
+	{0x00, 0x65, 0x8119},
+	{0x00, 0x00, 0x811a},
+	{0x00, 0x00, 0x811b},
+	{0x00, 0x55, 0x811c},
+	{0x00, 0x65, 0x811d},
+	{0x00, 0x55, 0x811e},
+	{0x00, 0x16, 0x811f},
+	{0x00, 0x19, 0x8120},
+	{0x00, 0x80, 0x8103},
+	{0x00, 0x83, 0x816b},
+	{0x00, 0x25, 0x8168},
+	{0x00, 0x01, 0x820f},
+	{0x00, 0xff, 0x8115},
+	{0x00, 0x48, 0x8116},
+	{0x00, 0x50, 0x8151},
+	{0x00, 0x40, 0x8152},
+	{0x00, 0x78, 0x8153},
+	{0x00, 0x40, 0x8154},
+	{0x00, 0x00, 0x8167},
+	{0x00, 0x20, 0x8168},
+	{0x00, 0x00, 0x816a},
+	{0x00, 0x03, 0x816b},
+	{0x00, 0x20, 0x8169},
+	{0x00, 0x60, 0x8157},
+	{0x00, 0x00, 0x8190},
+	{0x00, 0x00, 0x81a1},
+	{0x00, 0x00, 0x81b2},
+	{0x00, 0x27, 0x8191},
+	{0x00, 0x27, 0x81a2},
+	{0x00, 0x27, 0x81b3},
+	{0x00, 0x4b, 0x8192},
+	{0x00, 0x4b, 0x81a3},
+	{0x00, 0x4b, 0x81b4},
+	{0x00, 0x66, 0x8193},
+	{0x00, 0x66, 0x81a4},
+	{0x00, 0x66, 0x81b5},
+	{0x00, 0x79, 0x8194},
+	{0x00, 0x79, 0x81a5},
+	{0x00, 0x79, 0x81b6},
+	{0x00, 0x8a, 0x8195},
+	{0x00, 0x8a, 0x81a6},
+	{0x00, 0x8a, 0x81b7},
+	{0x00, 0x9b, 0x8196},
+	{0x00, 0x9b, 0x81a7},
+	{0x00, 0x9b, 0x81b8},
+	{0x00, 0xa6, 0x8197},
+	{0x00, 0xa6, 0x81a8},
+	{0x00, 0xa6, 0x81b9},
+	{0x00, 0xb2, 0x8198},
+	{0x00, 0xb2, 0x81a9},
+	{0x00, 0xb2, 0x81ba},
+	{0x00, 0xbe, 0x8199},
+	{0x00, 0xbe, 0x81aa},
+	{0x00, 0xbe, 0x81bb},
+	{0x00, 0xc8, 0x819a},
+	{0x00, 0xc8, 0x81ab},
+	{0x00, 0xc8, 0x81bc},
+	{0x00, 0xd2, 0x819b},
+	{0x00, 0xd2, 0x81ac},
+	{0x00, 0xd2, 0x81bd},
+	{0x00, 0xdb, 0x819c},
+	{0x00, 0xdb, 0x81ad},
+	{0x00, 0xdb, 0x81be},
+	{0x00, 0xe4, 0x819d},
+	{0x00, 0xe4, 0x81ae},
+	{0x00, 0xe4, 0x81bf},
+	{0x00, 0xed, 0x819e},
+	{0x00, 0xed, 0x81af},
+	{0x00, 0xed, 0x81c0},
+	{0x00, 0xf7, 0x819f},
+	{0x00, 0xf7, 0x81b0},
+	{0x00, 0xf7, 0x81c1},
+	{0x00, 0xff, 0x81a0},
+	{0x00, 0xff, 0x81b1},
+	{0x00, 0xff, 0x81c2},
+	{0x00, 0x03, 0x8156},
+	{0x00, 0x00, 0x8211},
+	{0x00, 0x20, 0x8168},
+	{0x00, 0x01, 0x8202},
+	{0x00, 0x30, 0x8101},
+	{0x00, 0x00, 0x8111},
+	{0x00, 0x00, 0x8112},
+	{0x00, 0x00, 0x8113},
+	{0x00, 0x00, 0x8114},
+	{}
+};
+
+static unsigned char qtable_creative_pccam[2][64] = {
+	{				/* Q-table Y-components */
+	 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
+	 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
+	 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11,
+	 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13,
+	 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17,
+	 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c,
+	 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e,
+	 0x16, 0x1c, 0x1d, 0x1d, 0x22, 0x1e, 0x1f, 0x1e},
+	{				/* Q-table C-components */
+	 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e,
+	 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e,
+	 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+	 0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+	 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+	 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+	 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+	 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
+};
+
+static unsigned char qtable_kodak_ez200[2][64] = {
+	{				/* Q-table Y-components */
+	 0x02, 0x01, 0x01, 0x02, 0x02, 0x04, 0x05, 0x06,
+	 0x01, 0x01, 0x01, 0x02, 0x03, 0x06, 0x06, 0x06,
+	 0x01, 0x01, 0x02, 0x02, 0x04, 0x06, 0x07, 0x06,
+	 0x01, 0x02, 0x02, 0x03, 0x05, 0x09, 0x08, 0x06,
+	 0x02, 0x02, 0x04, 0x06, 0x07, 0x0b, 0x0a, 0x08,
+	 0x02, 0x04, 0x06, 0x06, 0x08, 0x0a, 0x0b, 0x09,
+	 0x05, 0x06, 0x08, 0x09, 0x0a, 0x0c, 0x0c, 0x0a,
+	 0x07, 0x09, 0x0a, 0x0a, 0x0b, 0x0a, 0x0a, 0x0a},
+	{				/* Q-table C-components */
+	 0x02, 0x02, 0x02, 0x05, 0x0a, 0x0a, 0x0a, 0x0a,
+	 0x02, 0x02, 0x03, 0x07, 0x0a, 0x0a, 0x0a, 0x0a,
+	 0x02, 0x03, 0x06, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+	 0x05, 0x07, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+	 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+	 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+	 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+	 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a}
+};
+
+static unsigned char qtable_pocketdv[2][64] = {
+	{			/* Q-table Y-components start registers 0x8800 */
+	 0x06, 0x04, 0x04, 0x06, 0x0a, 0x10, 0x14, 0x18,
+	 0x05, 0x05, 0x06, 0x08, 0x0a, 0x17, 0x18, 0x16,
+	 0x06, 0x05, 0x06, 0x0a, 0x10, 0x17, 0x1c, 0x16,
+	 0x06, 0x07, 0x09, 0x0c, 0x14, 0x23, 0x20, 0x19,
+	 0x07, 0x09, 0x0f, 0x16, 0x1b, 0x2c, 0x29, 0x1f,
+	 0x0a, 0x0e, 0x16, 0x1a, 0x20, 0x2a, 0x2d, 0x25,
+	 0x14, 0x1a, 0x1f, 0x23, 0x29, 0x30, 0x30, 0x28,
+	 0x1d, 0x25, 0x26, 0x27, 0x2d, 0x28, 0x29, 0x28,
+	 },
+	{			/* Q-table C-components start registers 0x8840 */
+	 0x07, 0x07, 0x0a, 0x13, 0x28, 0x28, 0x28, 0x28,
+	 0x07, 0x08, 0x0a, 0x1a, 0x28, 0x28, 0x28, 0x28,
+	 0x0a, 0x0a, 0x16, 0x28, 0x28, 0x28, 0x28, 0x28,
+	 0x13, 0x1a, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
+	 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
+	 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
+	 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
+	 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28}
+};
+
+static void spca5xxRegRead(struct usb_device *dev,
+			   __u16 index,
+			   __u8 *buffer, __u16 length)
+{
+	usb_control_msg(dev,
+			usb_rcvctrlpipe(dev, 0),
+			0,
+			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			0,		/* value */
+			index, buffer, length, 500);
+}
+
+static int reg_write(struct usb_device *dev,
+		     __u16 req, __u16 index, __u16 value)
+{
+	int ret;
+
+	ret = usb_control_msg(dev,
+			usb_sndctrlpipe(dev, 0),
+			req,
+			USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			value, index, NULL, 0, 500);
+	PDEBUG(D_USBO, "reg write: [0x%02x] = 0x%02x, 0x%x",
+		index, value, ret);
+	if (ret < 0)
+		PDEBUG(D_ERR, "reg write: error %d", ret);
+	return ret;
+}
+
+/* returns: negative is error, pos or zero is data */
+static int reg_read(struct usb_device *dev,
+			__u16 req,	/* bRequest */
+			__u16 index,	/* wIndex */
+			__u16 length)	/* wLength (1 or 2 only) */
+{
+	int ret;
+	__u8 buf[2];
+
+	buf[1] = 0;
+	ret = usb_control_msg(dev,
+			usb_rcvctrlpipe(dev, 0),
+			req,
+			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			0,		/* value */
+			index,
+			buf, length,
+			500);		/* timeout */
+	if (ret < 0) {
+		PDEBUG(D_ERR, "reg_read err %d", ret);
+		return -1;
+	}
+	return (buf[1] << 8) + buf[0];
+}
+
+/*
+ * Simple function to wait for a given 8-bit value to be returned from
+ * a reg_read call.
+ * Returns: negative is error or timeout, zero is success.
+ */
+static int reg_readwait(struct usb_device *dev,
+			__u16 reg, __u16 index, __u16 value)
+{
+	int ret, cnt = 20;
+
+	while (--cnt > 0) {
+		ret = reg_read(dev, reg, index, 1);
+		if (ret == value)
+			return 0;
+		msleep(50);
+	}
+	return -EIO;
+}
+
+static int write_vector(struct gspca_dev *gspca_dev,
+				__u16 data[][3])
+{
+	struct usb_device *dev = gspca_dev->dev;
+	int ret, i = 0;
+
+	while (data[i][0] != 0 || data[i][1] != 0 || data[i][2] != 0) {
+		ret = reg_write(dev, data[i][0], data[i][2], data[i][1]);
+		if (ret < 0)
+			return ret;
+		i++;
+	}
+	return 0;
+}
+
+static int spca50x_setup_qtable(struct gspca_dev *gspca_dev,
+				unsigned int request,
+				unsigned int ybase,
+				unsigned int cbase,
+				unsigned char qtable[2][64])
+{
+	struct usb_device *dev = gspca_dev->dev;
+	int i, err;
+
+	/* loop over y components */
+	for (i = 0; i < 64; i++) {
+		err = reg_write(dev, request, ybase + i, qtable[0][i]);
+		if (err < 0)
+			return err;
+	}
+
+	/* loop over c components */
+	for (i = 0; i < 64; i++) {
+		err = reg_write(dev, request, cbase + i, qtable[1][i]);
+		if (err < 0)
+			return err;
+	}
+	return 0;
+}
+
+static void spca500_ping310(struct gspca_dev *gspca_dev)
+{
+	__u8 Data[2];
+
+	spca5xxRegRead(gspca_dev->dev, 0x0d04, Data, 2);
+	PDEBUG(D_PACK, "ClickSmart310 ping 0x0d04 0x%02x 0x%02x",
+		Data[0], Data[1]);
+}
+
+static void spca500_clksmart310_init(struct gspca_dev *gspca_dev)
+{
+	__u8 Data[2];
+
+	spca5xxRegRead(gspca_dev->dev, 0x0d05, Data, 2);
+	PDEBUG(D_PACK, "ClickSmart310 init 0x0d05 0x%02x 0x%02x", Data[0],
+		Data[1]);
+	reg_write(gspca_dev->dev, 0x00, 0x8167, 0x5a);
+	spca500_ping310(gspca_dev);
+
+	reg_write(gspca_dev->dev, 0x00, 0x8168, 0x22);
+	reg_write(gspca_dev->dev, 0x00, 0x816a, 0xc0);
+	reg_write(gspca_dev->dev, 0x00, 0x816b, 0x0b);
+	reg_write(gspca_dev->dev, 0x00, 0x8169, 0x25);
+	reg_write(gspca_dev->dev, 0x00, 0x8157, 0x5b);
+	reg_write(gspca_dev->dev, 0x00, 0x8158, 0x5b);
+	reg_write(gspca_dev->dev, 0x00, 0x813f, 0x03);
+	reg_write(gspca_dev->dev, 0x00, 0x8151, 0x4a);
+	reg_write(gspca_dev->dev, 0x00, 0x8153, 0x78);
+	reg_write(gspca_dev->dev, 0x00, 0x0d01, 0x04);
+						/* 00 for adjust shutter */
+	reg_write(gspca_dev->dev, 0x00, 0x0d02, 0x01);
+	reg_write(gspca_dev->dev, 0x00, 0x8169, 0x25);
+	reg_write(gspca_dev->dev, 0x00, 0x0d01, 0x02);
+}
+
+static void spca500_setmode(struct gspca_dev *gspca_dev,
+			__u8 xmult, __u8 ymult)
+{
+	int mode;
+
+	/* set x multiplier */
+	reg_write(gspca_dev->dev, 0, 0x8001, xmult);
+
+	/* set y multiplier */
+	reg_write(gspca_dev->dev, 0, 0x8002, ymult);
+
+	/* use compressed mode, VGA, with mode specific subsample */
+	mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].mode;
+	reg_write(gspca_dev->dev, 0, 0x8003, mode << 4);
+}
+
+static int spca500_full_reset(struct gspca_dev *gspca_dev)
+{
+	int err;
+
+	/* send the reset command */
+	err = reg_write(gspca_dev->dev, 0xe0, 0x0001, 0x0000);
+	if (err < 0)
+		return err;
+
+	/* wait for the reset to complete */
+	err = reg_readwait(gspca_dev->dev, 0x06, 0x0000, 0x0000);
+	if (err < 0)
+		return err;
+	err = reg_write(gspca_dev->dev, 0xe0, 0x0000, 0x0000);
+	if (err < 0)
+		return err;
+	err = reg_readwait(gspca_dev->dev, 0x06, 0, 0);
+	if (err < 0) {
+		PDEBUG(D_ERR, "reg_readwait() failed");
+		return err;
+	}
+	/* all ok */
+	return 0;
+}
+
+/* Synchro the Bridge with sensor */
+/* Maybe that will work on all spca500 chip */
+/* because i only own a clicksmart310 try for that chip */
+/* using spca50x_set_packet_size() cause an Ooops here */
+/* usb_set_interface from kernel 2.6.x clear all the urb stuff */
+/* up-port the same feature as in 2.4.x kernel */
+static int spca500_synch310(struct gspca_dev *gspca_dev)
+{
+	__u8 Data;
+
+	if (usb_set_interface(gspca_dev->dev, gspca_dev->iface, 0) < 0) {
+		PDEBUG(D_ERR, "Set packet size: set interface error");
+		goto error;
+	}
+	spca500_ping310(gspca_dev);
+
+	spca5xxRegRead(gspca_dev->dev, 0x0d00, &Data, 1);
+
+	/* need alt setting here */
+	PDEBUG(D_PACK, "ClickSmart310 sync alt: %d", gspca_dev->alt);
+
+	/* Windoze use pipe with altsetting 6 why 7 here */
+	if (usb_set_interface(gspca_dev->dev,
+				gspca_dev->iface,
+				gspca_dev->alt) < 0) {
+		PDEBUG(D_ERR, "Set packet size: set interface error");
+		goto error;
+	}
+	return 0;
+error:
+	return -EBUSY;
+}
+
+static void spca500_reinit(struct gspca_dev *gspca_dev)
+{
+	int err;
+	__u8 Data;
+
+	/* some unknow command from Aiptek pocket dv and family300 */
+
+	reg_write(gspca_dev->dev, 0x00, 0x0d01, 0x01);
+	reg_write(gspca_dev->dev, 0x00, 0x0d03, 0x00);
+	reg_write(gspca_dev->dev, 0x00, 0x0d02, 0x01);
+
+	/* enable drop packet */
+	reg_write(gspca_dev->dev, 0x00, 0x850a, 0x0001);
+
+	err = spca50x_setup_qtable(gspca_dev, 0x00, 0x8800, 0x8840,
+				 qtable_pocketdv);
+	if (err < 0)
+		PDEBUG(D_ERR|D_STREAM, "spca50x_setup_qtable failed on init");
+
+	/* set qtable index */
+	reg_write(gspca_dev->dev, 0x00, 0x8880, 2);
+	/* family cam Quicksmart stuff */
+	reg_write(gspca_dev->dev, 0x00, 0x800a, 0x00);
+	/* Set agc transfer: synced inbetween frames */
+	reg_write(gspca_dev->dev, 0x00, 0x820f, 0x01);
+	/* Init SDRAM - needed for SDRAM access */
+	reg_write(gspca_dev->dev, 0x00, 0x870a, 0x04);
+	/*Start init sequence or stream */
+
+	reg_write(gspca_dev->dev, 0, 0x8003, 0x00);
+	/* switch to video camera mode */
+	reg_write(gspca_dev->dev, 0x00, 0x8000, 0x0004);
+	msleep(2000);
+	if (reg_readwait(gspca_dev->dev, 0, 0x8000, 0x44) != 0)
+		spca5xxRegRead(gspca_dev->dev, 0x816b, &Data, 1);
+	reg_write(gspca_dev->dev, 0x00, 0x816b, Data);
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+			const struct usb_device_id *id)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct cam *cam;
+	__u16 vendor;
+	__u16 product;
+
+	vendor = id->idVendor;
+	product = id->idProduct;
+	switch (vendor) {
+	case 0x040a:		/* Kodak cameras */
+/*		switch (product) { */
+/*		case 0x0300: */
+			sd->subtype = KodakEZ200;
+/*			break; */
+/*		} */
+		break;
+	case 0x041e:		/* Creative cameras */
+/*		switch (product) { */
+/*		case 0x400a: */
+			sd->subtype = CreativePCCam300;
+/*			break; */
+/*		} */
+		break;
+	case 0x046d:		/* Logitech Labtec */
+		switch (product) {
+		case 0x0890:
+			sd->subtype = LogitechTraveler;
+			break;
+		case 0x0900:
+			sd->subtype = LogitechClickSmart310;
+			break;
+		case 0x0901:
+			sd->subtype = LogitechClickSmart510;
+			break;
+		}
+		break;
+	case 0x04a5:		/* Benq */
+/*		switch (product) { */
+/*		case 0x300c: */
+			sd->subtype = BenqDC1016;
+/*			break; */
+/*		} */
+		break;
+	case 0x04fc:		/* SunPlus */
+/*		switch (product) { */
+/*		case 0x7333: */
+			sd->subtype = PalmPixDC85;
+/*			break; */
+/*		} */
+		break;
+	case 0x055f:		/* Mustek cameras */
+		switch (product) {
+		case 0xc200:
+			sd->subtype = MustekGsmart300;
+			break;
+		case 0xc220:
+			sd->subtype = Gsmartmini;
+			break;
+		}
+		break;
+	case 0x06bd:		/* Agfa Cl20 */
+/*		switch (product) { */
+/*		case 0x0404: */
+			sd->subtype = AgfaCl20;
+/*			break; */
+/*		} */
+		break;
+	case 0x06be:		/* Optimedia */
+/*		switch (product) { */
+/*		case 0x0800: */
+			sd->subtype = Optimedia;
+/*			break; */
+/*		} */
+		break;
+	case 0x084d:		/* D-Link / Minton */
+/*		switch (product) { */
+/*		case 0x0003:	 * DSC-350 / S-Cam F5 */
+			sd->subtype = DLinkDSC350;
+/*			break; */
+/*		} */
+		break;
+	case 0x08ca:		/* Aiptek */
+/*		switch (product) { */
+/*		case 0x0103: */
+			sd->subtype = AiptekPocketDV;
+/*			break; */
+/*		} */
+		break;
+	case 0x2899:		/* ToptroIndustrial */
+/*		switch (product) { */
+/*		case 0x012c: */
+			sd->subtype = ToptroIndus;
+/*			break; */
+/*		} */
+		break;
+	case 0x8086:		/* Intel */
+/*		switch (product) { */
+/*		case 0x0630:	 * Pocket PC Camera */
+			sd->subtype = IntelPocketPCCamera;
+/*			break; */
+/*		} */
+		break;
+	}
+	cam = &gspca_dev->cam;
+	cam->dev_name = (char *) id->driver_info;
+	cam->epaddr = 0x01;
+	if (sd->subtype != LogitechClickSmart310) {
+		cam->cam_mode = vga_mode;
+		cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+	} else {
+		cam->cam_mode = sif_mode;
+		cam->nmodes = sizeof sif_mode / sizeof sif_mode[0];
+	}
+	sd->qindex = 5;
+	sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
+	sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
+	sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value;
+	return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	/* initialisation of spca500 based cameras is deferred */
+	PDEBUG(D_STREAM, "SPCA500 init");
+	if (sd->subtype == LogitechClickSmart310)
+		spca500_clksmart310_init(gspca_dev);
+/*	else
+		spca500_initialise(gspca_dev); */
+	PDEBUG(D_STREAM, "SPCA500 init done");
+	return 0;
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int err;
+	__u8 Data;
+	__u8 xmult, ymult;
+
+	if (sd->subtype == LogitechClickSmart310) {
+		xmult = 0x16;
+		ymult = 0x12;
+	} else {
+		xmult = 0x28;
+		ymult = 0x1e;
+	}
+
+	/* is there a sensor here ? */
+	spca5xxRegRead(gspca_dev->dev, 0x8a04, &Data, 1);
+	PDEBUG(D_STREAM, "Spca500 Sensor Address 0x%02X", Data);
+	PDEBUG(D_STREAM, "Spca500 curr_mode: %d Xmult: 0x%02X, Ymult: 0x%02X",
+		gspca_dev->curr_mode, xmult, ymult);
+
+	/* setup qtable */
+	switch (sd->subtype) {
+	case LogitechClickSmart310:
+		 spca500_setmode(gspca_dev, xmult, ymult);
+
+		/* enable drop packet */
+		reg_write(gspca_dev->dev, 0x00, 0x850a, 0x0001);
+		reg_write(gspca_dev->dev, 0x00, 0x8880, 3);
+		err = spca50x_setup_qtable(gspca_dev,
+					   0x00, 0x8800, 0x8840,
+					   qtable_creative_pccam);
+		if (err < 0)
+			PDEBUG(D_ERR, "spca50x_setup_qtable failed");
+		/* Init SDRAM - needed for SDRAM access */
+		reg_write(gspca_dev->dev, 0x00, 0x870a, 0x04);
+
+		/* switch to video camera mode */
+		reg_write(gspca_dev->dev, 0x00, 0x8000, 0x0004);
+		msleep(500);
+		if (reg_readwait(gspca_dev->dev, 0, 0x8000, 0x44) != 0)
+			PDEBUG(D_ERR, "reg_readwait() failed");
+
+		spca5xxRegRead(gspca_dev->dev, 0x816b, &Data, 1);
+		reg_write(gspca_dev->dev, 0x00, 0x816b, Data);
+
+		spca500_synch310(gspca_dev);
+
+		write_vector(gspca_dev, spca500_visual_defaults);
+		spca500_setmode(gspca_dev, xmult, ymult);
+		/* enable drop packet */
+		reg_write(gspca_dev->dev, 0x00, 0x850a, 0x0001);
+			PDEBUG(D_ERR, "failed to enable drop packet");
+		reg_write(gspca_dev->dev, 0x00, 0x8880, 3);
+		err = spca50x_setup_qtable(gspca_dev,
+					   0x00, 0x8800, 0x8840,
+					   qtable_creative_pccam);
+		if (err < 0)
+			PDEBUG(D_ERR, "spca50x_setup_qtable failed");
+
+		/* Init SDRAM - needed for SDRAM access */
+		reg_write(gspca_dev->dev, 0x00, 0x870a, 0x04);
+
+		/* switch to video camera mode */
+		reg_write(gspca_dev->dev, 0x00, 0x8000, 0x0004);
+
+		if (reg_readwait(gspca_dev->dev, 0, 0x8000, 0x44) != 0)
+			PDEBUG(D_ERR, "reg_readwait() failed");
+
+		spca5xxRegRead(gspca_dev->dev, 0x816b, &Data, 1);
+		reg_write(gspca_dev->dev, 0x00, 0x816b, Data);
+		break;
+	case CreativePCCam300:		/* Creative PC-CAM 300 640x480 CCD */
+	case IntelPocketPCCamera:	/* FIXME: Temporary fix for
+					 *	Intel Pocket PC Camera
+					 *	- NWG (Sat 29th March 2003) */
+
+		/* do a full reset */
+		if ((err = spca500_full_reset(gspca_dev)) < 0)
+			PDEBUG(D_ERR, "spca500_full_reset failed");
+
+		/* enable drop packet */
+		err = reg_write(gspca_dev->dev, 0x00, 0x850a, 0x0001);
+		if (err < 0)
+			PDEBUG(D_ERR, "failed to enable drop packet");
+		reg_write(gspca_dev->dev, 0x00, 0x8880, 3);
+		err = spca50x_setup_qtable(gspca_dev,
+					   0x00, 0x8800, 0x8840,
+					   qtable_creative_pccam);
+		if (err < 0)
+			PDEBUG(D_ERR, "spca50x_setup_qtable failed");
+
+		spca500_setmode(gspca_dev, xmult, ymult);
+		reg_write(gspca_dev->dev, 0x20, 0x0001, 0x0004);
+
+		/* switch to video camera mode */
+		reg_write(gspca_dev->dev, 0x00, 0x8000, 0x0004);
+
+		if (reg_readwait(gspca_dev->dev, 0, 0x8000, 0x44) != 0)
+			PDEBUG(D_ERR, "reg_readwait() failed");
+
+		spca5xxRegRead(gspca_dev->dev, 0x816b, &Data, 1);
+		reg_write(gspca_dev->dev, 0x00, 0x816b, Data);
+
+		/* write_vector(gspca_dev, spca500_visual_defaults); */
+		break;
+	case KodakEZ200:		/* Kodak EZ200 */
+
+		/* do a full reset */
+		err = spca500_full_reset(gspca_dev);
+		if (err < 0)
+			PDEBUG(D_ERR, "spca500_full_reset failed");
+		/* enable drop packet */
+		reg_write(gspca_dev->dev, 0x00, 0x850a, 0x0001);
+		reg_write(gspca_dev->dev, 0x00, 0x8880, 0);
+		err = spca50x_setup_qtable(gspca_dev,
+					   0x00, 0x8800, 0x8840,
+					   qtable_kodak_ez200);
+		if (err < 0)
+			PDEBUG(D_ERR, "spca50x_setup_qtable failed");
+		spca500_setmode(gspca_dev, xmult, ymult);
+
+		reg_write(gspca_dev->dev, 0x20, 0x0001, 0x0004);
+
+		/* switch to video camera mode */
+		reg_write(gspca_dev->dev, 0x00, 0x8000, 0x0004);
+
+		if (reg_readwait(gspca_dev->dev, 0, 0x8000, 0x44) != 0)
+			PDEBUG(D_ERR, "reg_readwait() failed");
+
+		spca5xxRegRead(gspca_dev->dev, 0x816b, &Data, 1);
+		reg_write(gspca_dev->dev, 0x00, 0x816b, Data);
+
+		/* write_vector(gspca_dev, spca500_visual_defaults); */
+		break;
+
+	case BenqDC1016:
+	case DLinkDSC350:		/* FamilyCam 300 */
+	case AiptekPocketDV:		/* Aiptek PocketDV */
+	case Gsmartmini:		/*Mustek Gsmart Mini */
+	case MustekGsmart300:		/* Mustek Gsmart 300 */
+	case PalmPixDC85:
+	case Optimedia:
+	case ToptroIndus:
+	case AgfaCl20:
+		spca500_reinit(gspca_dev);
+		reg_write(gspca_dev->dev, 0x00, 0x0d01, 0x01);
+		/* enable drop packet */
+		reg_write(gspca_dev->dev, 0x00, 0x850a, 0x0001);
+
+		err = spca50x_setup_qtable(gspca_dev,
+				   0x00, 0x8800, 0x8840, qtable_pocketdv);
+		if (err < 0)
+			PDEBUG(D_ERR, "spca50x_setup_qtable failed");
+		reg_write(gspca_dev->dev, 0x00, 0x8880, 2);
+
+		/* familycam Quicksmart pocketDV stuff */
+		reg_write(gspca_dev->dev, 0x00, 0x800a, 0x00);
+		/* Set agc transfer: synced inbetween frames */
+		reg_write(gspca_dev->dev, 0x00, 0x820f, 0x01);
+		/* Init SDRAM - needed for SDRAM access */
+		reg_write(gspca_dev->dev, 0x00, 0x870a, 0x04);
+
+		spca500_setmode(gspca_dev,xmult,ymult);
+		/* switch to video camera mode */
+		reg_write(gspca_dev->dev, 0x00, 0x8000, 0x0004);
+
+		reg_readwait(gspca_dev->dev, 0, 0x8000, 0x44);
+
+		spca5xxRegRead(gspca_dev->dev, 0x816b, &Data, 1);
+		reg_write(gspca_dev->dev, 0x00, 0x816b, Data);
+		break;
+	case LogitechTraveler:
+	case LogitechClickSmart510:
+		reg_write(gspca_dev->dev, 0x02, 0x00, 0x00);
+		/* enable drop packet */
+		reg_write(gspca_dev->dev, 0x00, 0x850a, 0x0001);
+
+		err = spca50x_setup_qtable(gspca_dev,
+					0x00, 0x8800,
+					0x8840, qtable_creative_pccam);
+		if (err < 0)
+			PDEBUG(D_ERR, "spca50x_setup_qtable failed");
+		reg_write(gspca_dev->dev, 0x00, 0x8880, 3);
+		reg_write(gspca_dev->dev, 0x00, 0x800a, 0x00);
+		/* Init SDRAM - needed for SDRAM access */
+		reg_write(gspca_dev->dev, 0x00, 0x870a, 0x04);
+
+		spca500_setmode(gspca_dev, xmult, ymult);
+
+		/* switch to video camera mode */
+		reg_write(gspca_dev->dev, 0x00, 0x8000, 0x0004);
+		reg_readwait(gspca_dev->dev, 0, 0x8000, 0x44);
+
+		spca5xxRegRead(gspca_dev->dev, 0x816b, &Data, 1);
+		reg_write(gspca_dev->dev, 0x00, 0x816b, Data);
+		write_vector(gspca_dev, Clicksmart510_defaults);
+		break;
+	}
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+	__u8 data = 0;
+
+	reg_write(gspca_dev->dev, 0, 0x8003, 0x00);
+
+	/* switch to video camera mode */
+	reg_write(gspca_dev->dev, 0x00, 0x8000, 0x0004);
+	spca5xxRegRead(gspca_dev->dev, 0x8000, &data, 1);
+	PDEBUG(D_STREAM, "stop SPCA500 done reg8000: 0x%2x", data);
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+			struct gspca_frame *frame,	/* target */
+			unsigned char *data,		/* isoc packet */
+			int len)			/* iso packet length */
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int i;
+	unsigned char *s, *d;
+	static unsigned char ffd9[] = {0xff, 0xd9};
+
+/* frames are jpeg 4.1.1 without 0xff escape */
+	if (data[0] == 0xff) {
+		if (data[1] != 0x01) {	/* drop packet */
+/*			gspca_dev->last_packet_type = DISCARD_PACKET; */
+			return;
+		}
+		frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+					ffd9, 2);
+
+		/* put the JPEG header in the new frame */
+		jpeg_put_header(gspca_dev, frame,
+				((struct sd *) gspca_dev)->qindex,
+				0x22);
+
+		data += SPCA500_OFFSET_DATA;
+		len -= SPCA500_OFFSET_DATA;
+	} else {
+		data += 1;
+		len -= 1;
+	}
+
+	/* add 0x00 after 0xff */
+	for (i = len; --i >= 0; )
+		if (data[i] == 0xff)
+			break;
+	if (i < 0) {			/* no 0xff */
+		gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+		return;
+	}
+	s = data;
+	d = sd->packet;
+	for (i = 0; i < len; i++) {
+		*d++ = *s++;
+		if (s[-1] == 0xff)
+			*d++ = 0x00;
+	}
+	gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+			sd->packet, d - sd->packet);
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	reg_write(gspca_dev->dev, 0x00, 0x8167,
+			(__u8) (sd->brightness - 128));
+}
+
+static void getbrightness(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->brightness = reg_read(gspca_dev->dev, 0x00, 0x8167, 1) + 128;
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	reg_write(gspca_dev->dev, 0x00, 0x8168, sd->contrast >> 2);
+}
+
+static void getcontrast(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->contrast = reg_read(gspca_dev->dev, 0x0, 0x8168, 1) << 2;
+}
+
+static void setcolors(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	reg_write(gspca_dev->dev, 0x00, 0x8169, sd->colors >> 2);
+}
+
+static void getcolors(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->colors = reg_read(gspca_dev->dev, 0x0, 0x8169, 1) << 2;
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->brightness = val;
+	if (gspca_dev->streaming)
+		setbrightness(gspca_dev);
+	return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	getbrightness(gspca_dev);
+	*val = sd->brightness;
+	return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->contrast = val;
+	if (gspca_dev->streaming)
+		setcontrast(gspca_dev);
+	return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	getcontrast(gspca_dev);
+	*val = sd->contrast;
+	return 0;
+}
+
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->colors = val;
+	if (gspca_dev->streaming)
+		setcolors(gspca_dev);
+	return 0;
+}
+
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	getcolors(gspca_dev);
+	*val = sd->colors;
+	return 0;
+}
+
+/* sub-driver description */
+static struct sd_desc sd_desc = {
+	.name = MODULE_NAME,
+	.ctrls = sd_ctrls,
+	.nctrls = sizeof sd_ctrls / sizeof sd_ctrls[0],
+	.config = sd_config,
+	.open = sd_open,
+	.start = sd_start,
+	.stopN = sd_stopN,
+	.stop0 = sd_stop0,
+	.close = sd_close,
+	.pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static __devinitdata struct usb_device_id device_table[] = {
+	{USB_DEVICE(0x040a, 0x0300), DVNM("Kodak EZ200")},
+	{USB_DEVICE(0x041e, 0x400a), DVNM("Creative PC-CAM 300")},
+	{USB_DEVICE(0x046d, 0x0890), DVNM("Logitech QuickCam traveler")},
+	{USB_DEVICE(0x046d, 0x0900), DVNM("Logitech Inc. ClickSmart 310")},
+	{USB_DEVICE(0x046d, 0x0901), DVNM("Logitech Inc. ClickSmart 510")},
+	{USB_DEVICE(0x04a5, 0x300c), DVNM("Benq DC1016")},
+	{USB_DEVICE(0x04fc, 0x7333), DVNM("PalmPixDC85")},
+	{USB_DEVICE(0x055f, 0xc200), DVNM("Mustek Gsmart 300")},
+	{USB_DEVICE(0x055f, 0xc220), DVNM("Gsmart Mini")},
+	{USB_DEVICE(0x06bd, 0x0404), DVNM("Agfa CL20")},
+	{USB_DEVICE(0x06be, 0x0800), DVNM("Optimedia")},
+	{USB_DEVICE(0x084d, 0x0003), DVNM("D-Link DSC-350")},
+	{USB_DEVICE(0x08ca, 0x0103), DVNM("Aiptek PocketDV")},
+	{USB_DEVICE(0x2899, 0x012c), DVNM("Toptro Industrial")},
+	{USB_DEVICE(0x8086, 0x0630), DVNM("Intel Pocket PC Camera")},
+	{}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+			const struct usb_device_id *id)
+{
+	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+				THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+	.name = MODULE_NAME,
+	.id_table = device_table,
+	.probe = sd_probe,
+	.disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+	if (usb_register(&sd_driver) < 0)
+		return -1;
+	PDEBUG(D_PROBE, "v%s registered", version);
+	return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+	usb_deregister(&sd_driver);
+	PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/spca501.c b/drivers/media/video/gspca/spca501.c
new file mode 100644
index 0000000..c6468cf
--- /dev/null
+++ b/drivers/media/video/gspca/spca501.c
@@ -0,0 +1,2219 @@
+/*
+ * SPCA501 chip based cameras initialization data
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#define MODULE_NAME "spca501"
+
+#include "gspca.h"
+
+#define DRIVER_VERSION_NUMBER	KERNEL_VERSION(2, 1, 0)
+static const char version[] = "2.1.0";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("GSPCA/SPCA501 USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+	struct gspca_dev gspca_dev;	/* !! must be the first item */
+
+	unsigned short contrast;
+	__u8 brightness;
+	__u8 colors;
+
+	char subtype;
+#define Arowana300KCMOSCamera 0
+#define IntelCreateAndShare 1
+#define KodakDVC325 2
+#define MystFromOriUnknownCamera 3
+#define SmileIntlCamera 4
+#define ThreeComHomeConnectLite 5
+#define ViewQuestM318B 6
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+#define MY_BRIGHTNESS 0
+	{
+	    {
+		.id      = V4L2_CID_BRIGHTNESS,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Brightness",
+		.minimum = 0,
+		.maximum = 127,
+		.step    = 1,
+		.default_value = 63,
+	    },
+	    .set = sd_setbrightness,
+	    .get = sd_getbrightness,
+	},
+#define MY_CONTRAST 1
+	{
+	    {
+		.id      = V4L2_CID_CONTRAST,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Contrast",
+		.minimum = 0,
+		.maximum = 0xffff,
+		.step    = 1,
+		.default_value = 0xaa00,
+	    },
+	    .set = sd_setcontrast,
+	    .get = sd_getcontrast,
+	},
+#define MY_COLOR 2
+	{
+	    {
+		.id      = V4L2_CID_SATURATION,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Color",
+		.minimum = 0,
+		.maximum = 63,
+		.step    = 1,
+		.default_value = 31,
+	    },
+	    .set = sd_setcolors,
+	    .get = sd_getcolors,
+	},
+};
+
+static struct cam_mode vga_mode[] = {
+	{V4L2_PIX_FMT_SPCA501, 160, 120, 2},
+	{V4L2_PIX_FMT_SPCA501, 320, 240, 1},
+	{V4L2_PIX_FMT_SPCA501, 640, 480, 0},
+};
+
+#define SPCA50X_REG_USB 0x2	/* spca505 501 */
+/*
+ * Data to initialize a SPCA501. From a capture file provided by Bill Roehl
+ * With SPCA501 chip description
+ */
+#define CCDSP_SET		/* set CCDSP parameters */
+#define TG_SET			/* set time generator set */
+#undef DSPWIN_SET		/* set DSP windows parameters */
+#undef ALTER_GAMA	/* Set alternate set to YUV transform coeffs. */
+#define SPCA501_SNAPBIT 0x80
+#define SPCA501_SNAPCTRL 0x10
+/* Frame packet header offsets for the spca501 */
+#define SPCA501_OFFSET_GPIO   1
+#define SPCA501_OFFSET_TYPE   2
+#define SPCA501_OFFSET_TURN3A 3
+#define SPCA501_OFFSET_FRAMSEQ 4
+#define SPCA501_OFFSET_COMPRESS 5
+#define SPCA501_OFFSET_QUANT 6
+#define SPCA501_OFFSET_QUANT2 7
+#define SPCA501_OFFSET_DATA 8
+
+#define SPCA501_PROP_COMP_ENABLE(d) ((d) & 1)
+#define SPCA501_PROP_SNAP(d) ((d) & 0x40)
+#define SPCA501_PROP_SNAP_CTRL(d) ((d) & 0x10)
+#define SPCA501_PROP_COMP_THRESH(d) (((d) & 0x0e) >> 1)
+#define SPCA501_PROP_COMP_QUANT(d) (((d) & 0x70) >> 4)
+
+/* SPCA501 CCDSP control */
+#define SPCA501_REG_CCDSP 0x01
+/* SPCA501 control/status registers */
+#define SPCA501_REG_CTLRL 0x02
+
+/* registers for color correction and YUV transformation */
+#define SPCA501_A11 0x08
+#define SPCA501_A12 0x09
+#define SPCA501_A13 0x0A
+#define SPCA501_A21 0x0B
+#define SPCA501_A22 0x0C
+#define SPCA501_A23 0x0D
+#define SPCA501_A31 0x0E
+#define SPCA501_A32 0x0F
+#define SPCA501_A33 0x10
+
+/* Data for video camera initialization before capturing */
+static __u16 spca501_open_data[][3] = {
+	/* bmRequest,value,index */
+
+	{0x2, 0x50, 0x00},	/* C/S enable soft reset */
+	{0x2, 0x40, 0x00},	/* C/S disable soft reset */
+	{0x2, 0x02, 0x05},	/* C/S general purpose I/O data */
+	{0x2, 0x03, 0x05},	/* C/S general purpose I/O data */
+
+#ifdef CCDSP_SET
+	{0x1, 0x38, 0x01},	/* CCDSP options */
+	{0x1, 0x05, 0x02}, /* CCDSP Optical black level for user settings */
+	{0x1, 0xC0, 0x03},	/* CCDSP Optical black settings */
+
+	{0x1, 0x67, 0x07},
+	{0x1, 0x63, 0x3f},	/* CCDSP CCD gamma enable */
+	{0x1, 0x03, 0x56},	/* Add gamma correction */
+
+	{0x1, 0xFF, 0x15},	/* CCDSP High luminance for white balance */
+	{0x1, 0x01, 0x16},	/* CCDSP Low luminance for white balance */
+
+/* Color correction and RGB-to-YUV transformation coefficients changing */
+#ifdef ALTER_GAMA
+	{0x0, 0x00, 0x08},	/* A11 */
+	{0x0, 0x00, 0x09},	/* A12 */
+	{0x0, 0x90, 0x0A},	/* A13 */
+	{0x0, 0x12, 0x0B},	/* A21 */
+	{0x0, 0x00, 0x0C},	/* A22 */
+	{0x0, 0x00, 0x0D},	/* A23 */
+	{0x0, 0x00, 0x0E},	/* A31 */
+	{0x0, 0x02, 0x0F},	/* A32 */
+	{0x0, 0x00, 0x10},	/* A33 */
+#else
+	{0x1, 0x2a, 0x08},	/* A11 0x31 */
+	{0x1, 0xf8, 0x09},	/* A12 f8 */
+	{0x1, 0xf8, 0x0A},	/* A13 f8 */
+	{0x1, 0xf8, 0x0B},	/* A21 f8 */
+	{0x1, 0x14, 0x0C},	/* A22 0x14 */
+	{0x1, 0xf8, 0x0D},	/* A23 f8 */
+	{0x1, 0xf8, 0x0E},	/* A31 f8 */
+	{0x1, 0xf8, 0x0F},	/* A32 f8 */
+	{0x1, 0x20, 0x10},	/* A33 0x20 */
+#endif
+	{0x1, 0x00, 0x11},	/* R offset */
+	{0x1, 0x00, 0x12},	/* G offset */
+	{0x1, 0x00, 0x13},	/* B offset */
+	{0x1, 0x00, 0x14},	/* GB offset */
+
+#endif
+
+#ifdef TG_SET
+	/* Time generator manipulations */
+	{0x0, 0xfc, 0x0},	/* Set up high bits of shutter speed */
+	{0x0, 0x01, 0x1},	/* Set up low bits of shutter speed */
+
+	{0x0, 0xe4, 0x04},	/* DCLK*2 clock phase adjustment */
+	{0x0, 0x08, 0x05},	/* ADCK phase adjustment, inv. ext. VB */
+	{0x0, 0x03, 0x06},	/* FR phase adjustment */
+	{0x0, 0x01, 0x07},	/* FCDS phase adjustment */
+	{0x0, 0x39, 0x08},	/* FS phase adjustment */
+	{0x0, 0x88, 0x0a},	/* FH1 phase and delay adjustment */
+	{0x0, 0x03, 0x0f},	/* pixel identification */
+	{0x0, 0x00, 0x11},	/* clock source selection (default) */
+
+	/*VERY strange manipulations with
+	 * select DMCLP or OBPX to be ADCLP output (0x0C)
+	 * OPB always toggle or not (0x0D) but they allow
+	 * us to set up brightness
+	 */
+	{0x0, 0x01, 0x0c},
+	{0x0, 0xe0, 0x0d},
+	/* Done */
+#endif
+
+#ifdef DSPWIN_SET
+	{0x1, 0xa0, 0x01},	/* Setting image processing parameters */
+	{0x1, 0x1c, 0x17},	/* Changing Windows positions X1 */
+	{0x1, 0xe2, 0x19},	/* X2 */
+	{0x1, 0x1c, 0x1b},	/* X3 */
+	{0x1, 0xe2, 0x1d},	/* X4 */
+	{0x1, 0x5f, 0x1f},	/* X5 */
+	{0x1, 0x32, 0x20},	/* Y5 */
+	{0x1, 0x01, 0x10},	/* Changing A33 */
+#endif
+
+	{0x2, 0x204a, 0x07},/* Setting video compression & resolution 160x120 */
+	{0x2, 0x94, 0x06},	/* Setting video no compression */
+	{}
+};
+
+/*
+   The SPCAxxx docs from Sunplus document these values
+   in tables, one table per register number.  In the data
+   below, dmRequest is the register number, index is the Addr,
+   and value is a combination of Bit values.
+   Bit  Value (hex)
+   0    01
+   1    02
+   2    04
+   3    08
+   4    10
+   5    20
+   6    40
+   7    80
+ */
+
+/* Data for chip initialization (set default values) */
+static __u16 spca501_init_data[][3] = {
+	/* Set all the values to powerup defaults */
+	/* bmRequest,value,index */
+	{0x0, 0xAA, 0x00},
+	{0x0, 0x02, 0x01},
+	{0x0, 0x01, 0x02},
+	{0x0, 0x02, 0x03},
+	{0x0, 0xCE, 0x04},
+	{0x0, 0x00, 0x05},
+	{0x0, 0x00, 0x06},
+	{0x0, 0x00, 0x07},
+	{0x0, 0x00, 0x08},
+	{0x0, 0x00, 0x09},
+	{0x0, 0x90, 0x0A},
+	{0x0, 0x12, 0x0B},
+	{0x0, 0x00, 0x0C},
+	{0x0, 0x00, 0x0D},
+	{0x0, 0x00, 0x0E},
+	{0x0, 0x02, 0x0F},
+	{0x0, 0x00, 0x10},
+	{0x0, 0x00, 0x11},
+	{0x0, 0x00, 0x12},
+	{0x0, 0x00, 0x13},
+	{0x0, 0x00, 0x14},
+	{0x0, 0x00, 0x15},
+	{0x0, 0x00, 0x16},
+	{0x0, 0x00, 0x17},
+	{0x0, 0x00, 0x18},
+	{0x0, 0x00, 0x19},
+	{0x0, 0x00, 0x1A},
+	{0x0, 0x00, 0x1B},
+	{0x0, 0x00, 0x1C},
+	{0x0, 0x00, 0x1D},
+	{0x0, 0x00, 0x1E},
+	{0x0, 0x00, 0x1F},
+	{0x0, 0x00, 0x20},
+	{0x0, 0x00, 0x21},
+	{0x0, 0x00, 0x22},
+	{0x0, 0x00, 0x23},
+	{0x0, 0x00, 0x24},
+	{0x0, 0x00, 0x25},
+	{0x0, 0x00, 0x26},
+	{0x0, 0x00, 0x27},
+	{0x0, 0x00, 0x28},
+	{0x0, 0x00, 0x29},
+	{0x0, 0x00, 0x2A},
+	{0x0, 0x00, 0x2B},
+	{0x0, 0x00, 0x2C},
+	{0x0, 0x00, 0x2D},
+	{0x0, 0x00, 0x2E},
+	{0x0, 0x00, 0x2F},
+	{0x0, 0x00, 0x30},
+	{0x0, 0x00, 0x31},
+	{0x0, 0x00, 0x32},
+	{0x0, 0x00, 0x33},
+	{0x0, 0x00, 0x34},
+	{0x0, 0x00, 0x35},
+	{0x0, 0x00, 0x36},
+	{0x0, 0x00, 0x37},
+	{0x0, 0x00, 0x38},
+	{0x0, 0x00, 0x39},
+	{0x0, 0x00, 0x3A},
+	{0x0, 0x00, 0x3B},
+	{0x0, 0x00, 0x3C},
+	{0x0, 0x00, 0x3D},
+	{0x0, 0x00, 0x3E},
+	{0x0, 0x00, 0x3F},
+	{0x0, 0x00, 0x40},
+	{0x0, 0x00, 0x41},
+	{0x0, 0x00, 0x42},
+	{0x0, 0x00, 0x43},
+	{0x0, 0x00, 0x44},
+	{0x0, 0x00, 0x45},
+	{0x0, 0x00, 0x46},
+	{0x0, 0x00, 0x47},
+	{0x0, 0x00, 0x48},
+	{0x0, 0x00, 0x49},
+	{0x0, 0x00, 0x4A},
+	{0x0, 0x00, 0x4B},
+	{0x0, 0x00, 0x4C},
+	{0x0, 0x00, 0x4D},
+	{0x0, 0x00, 0x4E},
+	{0x0, 0x00, 0x4F},
+	{0x0, 0x00, 0x50},
+	{0x0, 0x00, 0x51},
+	{0x0, 0x00, 0x52},
+	{0x0, 0x00, 0x53},
+	{0x0, 0x00, 0x54},
+	{0x0, 0x00, 0x55},
+	{0x0, 0x00, 0x56},
+	{0x0, 0x00, 0x57},
+	{0x0, 0x00, 0x58},
+	{0x0, 0x00, 0x59},
+	{0x0, 0x00, 0x5A},
+	{0x0, 0x00, 0x5B},
+	{0x0, 0x00, 0x5C},
+	{0x0, 0x00, 0x5D},
+	{0x0, 0x00, 0x5E},
+	{0x0, 0x00, 0x5F},
+	{0x0, 0x00, 0x60},
+	{0x0, 0x00, 0x61},
+	{0x0, 0x00, 0x62},
+	{0x0, 0x00, 0x63},
+	{0x0, 0x00, 0x64},
+	{0x0, 0x00, 0x65},
+	{0x0, 0x00, 0x66},
+	{0x0, 0x00, 0x67},
+	{0x0, 0x00, 0x68},
+	{0x0, 0x00, 0x69},
+	{0x0, 0x00, 0x6A},
+	{0x0, 0x00, 0x6B},
+	{0x0, 0x00, 0x6C},
+	{0x0, 0x00, 0x6D},
+	{0x0, 0x00, 0x6E},
+	{0x0, 0x00, 0x6F},
+	{0x0, 0x00, 0x70},
+	{0x0, 0x00, 0x71},
+	{0x0, 0x00, 0x72},
+	{0x0, 0x00, 0x73},
+	{0x0, 0x00, 0x74},
+	{0x0, 0x00, 0x75},
+	{0x0, 0x00, 0x76},
+	{0x0, 0x00, 0x77},
+	{0x0, 0x00, 0x78},
+	{0x0, 0x00, 0x79},
+	{0x0, 0x00, 0x7A},
+	{0x0, 0x00, 0x7B},
+	{0x0, 0x00, 0x7C},
+	{0x0, 0x00, 0x7D},
+	{0x0, 0x00, 0x7E},
+	{0x0, 0x00, 0x7F},
+	{0x0, 0x00, 0x80},
+	{0x0, 0x00, 0x81},
+	{0x0, 0x00, 0x82},
+	{0x0, 0x00, 0x83},
+	{0x0, 0x00, 0x84},
+	{0x0, 0x00, 0x85},
+	{0x0, 0x00, 0x86},
+	{0x0, 0x00, 0x87},
+	{0x0, 0x00, 0x88},
+	{0x0, 0x00, 0x89},
+	{0x0, 0x00, 0x8A},
+	{0x0, 0x00, 0x8B},
+	{0x0, 0x00, 0x8C},
+	{0x0, 0x00, 0x8D},
+	{0x0, 0x00, 0x8E},
+	{0x0, 0x00, 0x8F},
+	{0x0, 0x00, 0x90},
+	{0x0, 0x00, 0x91},
+	{0x0, 0x00, 0x92},
+	{0x0, 0x00, 0x93},
+	{0x0, 0x00, 0x94},
+	{0x0, 0x00, 0x95},
+	{0x0, 0x00, 0x96},
+	{0x0, 0x00, 0x97},
+	{0x0, 0x00, 0x98},
+	{0x0, 0x00, 0x99},
+	{0x0, 0x00, 0x9A},
+	{0x0, 0x00, 0x9B},
+	{0x0, 0x00, 0x9C},
+	{0x0, 0x00, 0x9D},
+	{0x0, 0x00, 0x9E},
+	{0x0, 0x00, 0x9F},
+	{0x0, 0x00, 0xA0},
+	{0x0, 0x00, 0xA1},
+	{0x0, 0x00, 0xA2},
+	{0x0, 0x00, 0xA3},
+	{0x0, 0x00, 0xA4},
+	{0x0, 0x00, 0xA5},
+	{0x0, 0x00, 0xA6},
+	{0x0, 0x00, 0xA7},
+	{0x0, 0x00, 0xA8},
+	{0x0, 0x00, 0xA9},
+	{0x0, 0x00, 0xAA},
+	{0x0, 0x00, 0xAB},
+	{0x0, 0x00, 0xAC},
+	{0x0, 0x00, 0xAD},
+	{0x0, 0x00, 0xAE},
+	{0x0, 0x00, 0xAF},
+	{0x0, 0x00, 0xB0},
+	{0x0, 0x00, 0xB1},
+	{0x0, 0x00, 0xB2},
+	{0x0, 0x00, 0xB3},
+	{0x0, 0x00, 0xB4},
+	{0x0, 0x00, 0xB5},
+	{0x0, 0x00, 0xB6},
+	{0x0, 0x00, 0xB7},
+	{0x0, 0x00, 0xB8},
+	{0x0, 0x00, 0xB9},
+	{0x0, 0x00, 0xBA},
+	{0x0, 0x00, 0xBB},
+	{0x0, 0x00, 0xBC},
+	{0x0, 0x00, 0xBD},
+	{0x0, 0x00, 0xBE},
+	{0x0, 0x00, 0xBF},
+	{0x0, 0x00, 0xC0},
+	{0x0, 0x00, 0xC1},
+	{0x0, 0x00, 0xC2},
+	{0x0, 0x00, 0xC3},
+	{0x0, 0x00, 0xC4},
+	{0x0, 0x00, 0xC5},
+	{0x0, 0x00, 0xC6},
+	{0x0, 0x00, 0xC7},
+	{0x0, 0x00, 0xC8},
+	{0x0, 0x00, 0xC9},
+	{0x0, 0x00, 0xCA},
+	{0x0, 0x00, 0xCB},
+	{0x0, 0x00, 0xCC},
+	{0x1, 0xF4, 0x00},
+	{0x1, 0x38, 0x01},
+	{0x1, 0x40, 0x02},
+	{0x1, 0x0A, 0x03},
+	{0x1, 0x40, 0x04},
+	{0x1, 0x40, 0x05},
+	{0x1, 0x40, 0x06},
+	{0x1, 0x67, 0x07},
+	{0x1, 0x31, 0x08},
+	{0x1, 0x00, 0x09},
+	{0x1, 0x00, 0x0A},
+	{0x1, 0x00, 0x0B},
+	{0x1, 0x14, 0x0C},
+	{0x1, 0x00, 0x0D},
+	{0x1, 0x00, 0x0E},
+	{0x1, 0x00, 0x0F},
+	{0x1, 0x1E, 0x10},
+	{0x1, 0x00, 0x11},
+	{0x1, 0x00, 0x12},
+	{0x1, 0x00, 0x13},
+	{0x1, 0x00, 0x14},
+	{0x1, 0xFF, 0x15},
+	{0x1, 0x01, 0x16},
+	{0x1, 0x32, 0x17},
+	{0x1, 0x23, 0x18},
+	{0x1, 0xCE, 0x19},
+	{0x1, 0x23, 0x1A},
+	{0x1, 0x32, 0x1B},
+	{0x1, 0x8D, 0x1C},
+	{0x1, 0xCE, 0x1D},
+	{0x1, 0x8D, 0x1E},
+	{0x1, 0x00, 0x1F},
+	{0x1, 0x00, 0x20},
+	{0x1, 0xFF, 0x3E},
+	{0x1, 0x02, 0x3F},
+	{0x1, 0x00, 0x40},
+	{0x1, 0x00, 0x41},
+	{0x1, 0x00, 0x42},
+	{0x1, 0x00, 0x43},
+	{0x1, 0x00, 0x44},
+	{0x1, 0x00, 0x45},
+	{0x1, 0x00, 0x46},
+	{0x1, 0x00, 0x47},
+	{0x1, 0x00, 0x48},
+	{0x1, 0x00, 0x49},
+	{0x1, 0x00, 0x4A},
+	{0x1, 0x00, 0x4B},
+	{0x1, 0x00, 0x4C},
+	{0x1, 0x00, 0x4D},
+	{0x1, 0x00, 0x4E},
+	{0x1, 0x00, 0x4F},
+	{0x1, 0x00, 0x50},
+	{0x1, 0x00, 0x51},
+	{0x1, 0x00, 0x52},
+	{0x1, 0x00, 0x53},
+	{0x1, 0x00, 0x54},
+	{0x1, 0x00, 0x55},
+	{0x1, 0x00, 0x56},
+	{0x1, 0x00, 0x57},
+	{0x1, 0x00, 0x58},
+	{0x1, 0x00, 0x59},
+	{0x1, 0x00, 0x5A},
+	{0x2, 0x03, 0x00},
+	{0x2, 0x00, 0x01},
+	{0x2, 0x00, 0x05},
+	{0x2, 0x00, 0x06},
+	{0x2, 0x00, 0x07},
+	{0x2, 0x00, 0x10},
+	{0x2, 0x00, 0x11},
+	/* Strange - looks like the 501 driver doesn't do anything
+	 * at insert time except read the EEPROM
+	 */
+	{}
+};
+
+/* Data for video camera init before capture.
+ * Capture and decoding by Colin Peart.
+ * This is is for the 3com HomeConnect Lite which is spca501a based.
+ */
+static __u16 spca501_3com_open_data[][3] = {
+	/* bmRequest,value,index */
+	{0x2, 0x0050, 0x0000},	/* C/S Enable TG soft reset, timing mode=010 */
+	{0x2, 0x0043, 0x0000},	/* C/S Disable TG soft reset, timing mode=010 */
+	{0x2, 0x0002, 0x0005},	/* C/S GPIO */
+	{0x2, 0x0003, 0x0005},	/* C/S GPIO */
+
+#ifdef CCDSP_SET
+	{0x1, 0x0020, 0x0001},	/* CCDSP Options */
+
+	{0x1, 0x0020, 0x0002},	/* CCDSP Black Level */
+	{0x1, 0x006e, 0x0007},	/* CCDSP Gamma options */
+	{0x1, 0x0090, 0x0015},	/* CCDSP Luminance Low */
+	{0x1, 0x00ff, 0x0016},	/* CCDSP Luminance High */
+	{0x1, 0x0003, 0x003F},	/* CCDSP Gamma correction toggle */
+
+#ifdef ALTER_GAMMA
+	{0x1, 0x0010, 0x0008},	/* CCDSP YUV A11 */
+	{0x1, 0x0000, 0x0009},	/* CCDSP YUV A12 */
+	{0x1, 0x0000, 0x000a},	/* CCDSP YUV A13 */
+	{0x1, 0x0000, 0x000b},	/* CCDSP YUV A21 */
+	{0x1, 0x0010, 0x000c},	/* CCDSP YUV A22 */
+	{0x1, 0x0000, 0x000d},	/* CCDSP YUV A23 */
+	{0x1, 0x0000, 0x000e},	/* CCDSP YUV A31 */
+	{0x1, 0x0000, 0x000f},	/* CCDSP YUV A32 */
+	{0x1, 0x0010, 0x0010},	/* CCDSP YUV A33 */
+	{0x1, 0x0000, 0x0011},	/* CCDSP R Offset */
+	{0x1, 0x0000, 0x0012},	/* CCDSP G Offset */
+	{0x1, 0x0001, 0x0013},	/* CCDSP B Offset */
+	{0x1, 0x0001, 0x0014},	/* CCDSP BG Offset */
+	{0x1, 0x003f, 0x00C1},	/* CCDSP Gamma Correction Enable */
+#endif
+#endif
+
+#ifdef TG_SET
+	{0x0, 0x00fc, 0x0000},	/* TG Shutter Speed High Bits */
+	{0x0, 0x0000, 0x0001},	/* TG Shutter Speed Low Bits */
+	{0x0, 0x00e4, 0x0004},	/* TG DCLK*2 Adjust */
+	{0x0, 0x0008, 0x0005},	/* TG ADCK Adjust */
+	{0x0, 0x0003, 0x0006},	/* TG FR Phase Adjust */
+	{0x0, 0x0001, 0x0007},	/* TG FCDS Phase Adjust */
+	{0x0, 0x0039, 0x0008},	/* TG FS Phase Adjust */
+	{0x0, 0x0088, 0x000a},	/* TG MH1 */
+	{0x0, 0x0003, 0x000f},	/* TG Pixel ID */
+
+	/* Like below, unexplained toglleing */
+	{0x0, 0x0080, 0x000c},
+	{0x0, 0x0000, 0x000d},
+	{0x0, 0x0080, 0x000c},
+	{0x0, 0x0004, 0x000d},
+	{0x0, 0x0000, 0x000c},
+	{0x0, 0x0000, 0x000d},
+	{0x0, 0x0040, 0x000c},
+	{0x0, 0x0017, 0x000d},
+	{0x0, 0x00c0, 0x000c},
+	{0x0, 0x0000, 0x000d},
+	{0x0, 0x0080, 0x000c},
+	{0x0, 0x0006, 0x000d},
+	{0x0, 0x0080, 0x000c},
+	{0x0, 0x0004, 0x000d},
+	{0x0, 0x0002, 0x0003},
+#endif
+
+#ifdef DSPWIN_SET
+	{0x1, 0x001c, 0x0017},	/* CCDSP W1 Start X */
+	{0x1, 0x00e2, 0x0019},	/* CCDSP W2 Start X */
+	{0x1, 0x001c, 0x001b},	/* CCDSP W3 Start X */
+	{0x1, 0x00e2, 0x001d},	/* CCDSP W4 Start X */
+	{0x1, 0x00aa, 0x001f},	/* CCDSP W5 Start X */
+	{0x1, 0x0070, 0x0020},	/* CCDSP W5 Start Y */
+#endif
+	{0x0, 0x0001, 0x0010},	/* TG Start Clock */
+
+/*	{0x2, 0x006a, 0x0001},	 * C/S Enable ISOSYNCH Packet Engine */
+	{0x2, 0x0068, 0x0001},	/* C/S Diable ISOSYNCH Packet Engine */
+	{0x2, 0x0000, 0x0005},
+	{0x2, 0x0043, 0x0000},	/* C/S Set Timing Mode, Disable TG soft reset */
+	{0x2, 0x0043, 0x0000},	/* C/S Set Timing Mode, Disable TG soft reset */
+	{0x2, 0x0002, 0x0005},	/* C/S GPIO */
+	{0x2, 0x0003, 0x0005},	/* C/S GPIO */
+
+	{0x2, 0x006a, 0x0001},	/* C/S Enable ISOSYNCH Packet Engine */
+	{}
+};
+
+/*
+ * Data used to initialize a SPCA501C with HV7131B sensor.
+ * From a capture file taken with USBSnoop v 1.5
+ * I have a "SPCA501C pc camera chipset" manual by sunplus, but some
+ * of the value meanings are obscure or simply "reserved".
+ * to do list:
+ * 1) Understand what every value means
+ * 2) Understand why some values seem to appear more than once
+ * 3) Write a small comment for each line of the following arrays.
+ */
+static __u16 spca501c_arowana_open_data[][3] = {
+	/* bmRequest,value,index */
+	{0x02, 0x0007, 0x0005},
+	{0x02, 0xa048, 0x0000},
+	{0x05, 0x0022, 0x0004},
+	{0x01, 0x0006, 0x0011},
+	{0x01, 0x00ff, 0x0012},
+	{0x01, 0x0014, 0x0013},
+	{0x01, 0x0000, 0x0014},
+	{0x01, 0x0042, 0x0051},
+	{0x01, 0x0040, 0x0052},
+	{0x01, 0x0051, 0x0053},
+	{0x01, 0x0040, 0x0054},
+	{0x01, 0x0000, 0x0055},
+	{0x00, 0x0025, 0x0000},
+	{0x00, 0x0026, 0x0000},
+	{0x00, 0x0001, 0x0000},
+	{0x00, 0x0027, 0x0000},
+	{0x00, 0x008a, 0x0000},
+	{}
+};
+
+static __u16 spca501c_arowana_init_data[][3] = {
+	/* bmRequest,value,index */
+	{0x02, 0x0007, 0x0005},
+	{0x02, 0xa048, 0x0000},
+	{0x05, 0x0022, 0x0004},
+	{0x01, 0x0006, 0x0011},
+	{0x01, 0x00ff, 0x0012},
+	{0x01, 0x0014, 0x0013},
+	{0x01, 0x0000, 0x0014},
+	{0x01, 0x0042, 0x0051},
+	{0x01, 0x0040, 0x0052},
+	{0x01, 0x0051, 0x0053},
+	{0x01, 0x0040, 0x0054},
+	{0x01, 0x0000, 0x0055},
+	{0x00, 0x0025, 0x0000},
+	{0x00, 0x0026, 0x0000},
+	{0x00, 0x0001, 0x0000},
+	{0x00, 0x0027, 0x0000},
+	{0x00, 0x008a, 0x0000},
+	{0x02, 0x0000, 0x0005},
+	{0x02, 0x0007, 0x0005},
+	{0x02, 0x2000, 0x0000},
+	{0x05, 0x0022, 0x0004},
+	{0x05, 0x0015, 0x0001},
+	{0x05, 0x00ea, 0x0000},
+	{0x05, 0x0021, 0x0001},
+	{0x05, 0x00d2, 0x0000},
+	{0x05, 0x0023, 0x0001},
+	{0x05, 0x0003, 0x0000},
+	{0x05, 0x0030, 0x0001},
+	{0x05, 0x002b, 0x0000},
+	{0x05, 0x0031, 0x0001},
+	{0x05, 0x0023, 0x0000},
+	{0x05, 0x0032, 0x0001},
+	{0x05, 0x0023, 0x0000},
+	{0x05, 0x0033, 0x0001},
+	{0x05, 0x0023, 0x0000},
+	{0x05, 0x0034, 0x0001},
+	{0x05, 0x0002, 0x0000},
+	{0x05, 0x0050, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0051, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0052, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0054, 0x0001},
+	{0x05, 0x0001, 0x0000},
+	{0x00, 0x0000, 0x0001},
+	{0x00, 0x0000, 0x0002},
+	{0x00, 0x000c, 0x0003},
+	{0x00, 0x0000, 0x0004},
+	{0x00, 0x0090, 0x0005},
+	{0x00, 0x0000, 0x0006},
+	{0x00, 0x0040, 0x0007},
+	{0x00, 0x00c0, 0x0008},
+	{0x00, 0x004a, 0x0009},
+	{0x00, 0x0000, 0x000a},
+	{0x00, 0x0000, 0x000b},
+	{0x00, 0x0001, 0x000c},
+	{0x00, 0x0001, 0x000d},
+	{0x00, 0x0000, 0x000e},
+	{0x00, 0x0002, 0x000f},
+	{0x00, 0x0001, 0x0010},
+	{0x00, 0x0000, 0x0011},
+	{0x00, 0x0000, 0x0012},
+	{0x00, 0x0002, 0x0020},
+	{0x00, 0x0080, 0x0021},
+	{0x00, 0x0001, 0x0022},
+	{0x00, 0x00e0, 0x0023},
+	{0x00, 0x0000, 0x0024},
+	{0x00, 0x00d5, 0x0025},
+	{0x00, 0x0000, 0x0026},
+	{0x00, 0x000b, 0x0027},
+	{0x00, 0x0000, 0x0046},
+	{0x00, 0x0000, 0x0047},
+	{0x00, 0x0000, 0x0048},
+	{0x00, 0x0000, 0x0049},
+	{0x00, 0x0008, 0x004a},
+	{0xff, 0x0000, 0x00d0},
+	{0xff, 0x00d8, 0x00d1},
+	{0xff, 0x0000, 0x00d4},
+	{0xff, 0x0000, 0x00d5},
+	{0x01, 0x00a6, 0x0000},
+	{0x01, 0x0028, 0x0001},
+	{0x01, 0x0000, 0x0002},
+	{0x01, 0x000a, 0x0003},
+	{0x01, 0x0040, 0x0004},
+	{0x01, 0x0066, 0x0007},
+	{0x01, 0x0011, 0x0008},
+	{0x01, 0x0032, 0x0009},
+	{0x01, 0x00fd, 0x000a},
+	{0x01, 0x0038, 0x000b},
+	{0x01, 0x00d1, 0x000c},
+	{0x01, 0x00f7, 0x000d},
+	{0x01, 0x00ed, 0x000e},
+	{0x01, 0x00d8, 0x000f},
+	{0x01, 0x0038, 0x0010},
+	{0x01, 0x00ff, 0x0015},
+	{0x01, 0x0001, 0x0016},
+	{0x01, 0x0032, 0x0017},
+	{0x01, 0x0023, 0x0018},
+	{0x01, 0x00ce, 0x0019},
+	{0x01, 0x0023, 0x001a},
+	{0x01, 0x0032, 0x001b},
+	{0x01, 0x008d, 0x001c},
+	{0x01, 0x00ce, 0x001d},
+	{0x01, 0x008d, 0x001e},
+	{0x01, 0x0000, 0x001f},
+	{0x01, 0x0000, 0x0020},
+	{0x01, 0x00ff, 0x003e},
+	{0x01, 0x0003, 0x003f},
+	{0x01, 0x0000, 0x0040},
+	{0x01, 0x0035, 0x0041},
+	{0x01, 0x0053, 0x0042},
+	{0x01, 0x0069, 0x0043},
+	{0x01, 0x007c, 0x0044},
+	{0x01, 0x008c, 0x0045},
+	{0x01, 0x009a, 0x0046},
+	{0x01, 0x00a8, 0x0047},
+	{0x01, 0x00b4, 0x0048},
+	{0x01, 0x00bf, 0x0049},
+	{0x01, 0x00ca, 0x004a},
+	{0x01, 0x00d4, 0x004b},
+	{0x01, 0x00dd, 0x004c},
+	{0x01, 0x00e7, 0x004d},
+	{0x01, 0x00ef, 0x004e},
+	{0x01, 0x00f8, 0x004f},
+	{0x01, 0x00ff, 0x0050},
+	{0x01, 0x0001, 0x0056},
+	{0x01, 0x0060, 0x0057},
+	{0x01, 0x0040, 0x0058},
+	{0x01, 0x0011, 0x0059},
+	{0x01, 0x0001, 0x005a},
+	{0x02, 0x0007, 0x0005},
+	{0x02, 0xa048, 0x0000},
+	{0x02, 0x0007, 0x0005},
+	{0x02, 0x0015, 0x0006},
+	{0x02, 0x100a, 0x0007},
+	{0x02, 0xa048, 0x0000},
+	{0x02, 0xc002, 0x0001},
+	{0x02, 0x000f, 0x0005},
+	{0x02, 0xa048, 0x0000},
+	{0x05, 0x0022, 0x0004},
+	{0x05, 0x0025, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0026, 0x0001},
+	{0x05, 0x0001, 0x0000},
+	{0x05, 0x0027, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0001, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0021, 0x0001},
+	{0x05, 0x00d2, 0x0000},
+	{0x05, 0x0020, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x00, 0x0090, 0x0005},
+	{0x01, 0x00a6, 0x0000},
+	{0x02, 0x0007, 0x0005},
+	{0x02, 0x2000, 0x0000},
+	{0x05, 0x0022, 0x0004},
+	{0x05, 0x0015, 0x0001},
+	{0x05, 0x00ea, 0x0000},
+	{0x05, 0x0021, 0x0001},
+	{0x05, 0x00d2, 0x0000},
+	{0x05, 0x0023, 0x0001},
+	{0x05, 0x0003, 0x0000},
+	{0x05, 0x0030, 0x0001},
+	{0x05, 0x002b, 0x0000},
+	{0x05, 0x0031, 0x0001},
+	{0x05, 0x0023, 0x0000},
+	{0x05, 0x0032, 0x0001},
+	{0x05, 0x0023, 0x0000},
+	{0x05, 0x0033, 0x0001},
+	{0x05, 0x0023, 0x0000},
+	{0x05, 0x0034, 0x0001},
+	{0x05, 0x0002, 0x0000},
+	{0x05, 0x0050, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0051, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0052, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0054, 0x0001},
+	{0x05, 0x0001, 0x0000},
+	{0x00, 0x0000, 0x0001},
+	{0x00, 0x0000, 0x0002},
+	{0x00, 0x000c, 0x0003},
+	{0x00, 0x0000, 0x0004},
+	{0x00, 0x0090, 0x0005},
+	{0x00, 0x0000, 0x0006},
+	{0x00, 0x0040, 0x0007},
+	{0x00, 0x00c0, 0x0008},
+	{0x00, 0x004a, 0x0009},
+	{0x00, 0x0000, 0x000a},
+	{0x00, 0x0000, 0x000b},
+	{0x00, 0x0001, 0x000c},
+	{0x00, 0x0001, 0x000d},
+	{0x00, 0x0000, 0x000e},
+	{0x00, 0x0002, 0x000f},
+	{0x00, 0x0001, 0x0010},
+	{0x00, 0x0000, 0x0011},
+	{0x00, 0x0000, 0x0012},
+	{0x00, 0x0002, 0x0020},
+	{0x00, 0x0080, 0x0021},
+	{0x00, 0x0001, 0x0022},
+	{0x00, 0x00e0, 0x0023},
+	{0x00, 0x0000, 0x0024},
+	{0x00, 0x00d5, 0x0025},
+	{0x00, 0x0000, 0x0026},
+	{0x00, 0x000b, 0x0027},
+	{0x00, 0x0000, 0x0046},
+	{0x00, 0x0000, 0x0047},
+	{0x00, 0x0000, 0x0048},
+	{0x00, 0x0000, 0x0049},
+	{0x00, 0x0008, 0x004a},
+	{0xff, 0x0000, 0x00d0},
+	{0xff, 0x00d8, 0x00d1},
+	{0xff, 0x0000, 0x00d4},
+	{0xff, 0x0000, 0x00d5},
+	{0x01, 0x00a6, 0x0000},
+	{0x01, 0x0028, 0x0001},
+	{0x01, 0x0000, 0x0002},
+	{0x01, 0x000a, 0x0003},
+	{0x01, 0x0040, 0x0004},
+	{0x01, 0x0066, 0x0007},
+	{0x01, 0x0011, 0x0008},
+	{0x01, 0x0032, 0x0009},
+	{0x01, 0x00fd, 0x000a},
+	{0x01, 0x0038, 0x000b},
+	{0x01, 0x00d1, 0x000c},
+	{0x01, 0x00f7, 0x000d},
+	{0x01, 0x00ed, 0x000e},
+	{0x01, 0x00d8, 0x000f},
+	{0x01, 0x0038, 0x0010},
+	{0x01, 0x00ff, 0x0015},
+	{0x01, 0x0001, 0x0016},
+	{0x01, 0x0032, 0x0017},
+	{0x01, 0x0023, 0x0018},
+	{0x01, 0x00ce, 0x0019},
+	{0x01, 0x0023, 0x001a},
+	{0x01, 0x0032, 0x001b},
+	{0x01, 0x008d, 0x001c},
+	{0x01, 0x00ce, 0x001d},
+	{0x01, 0x008d, 0x001e},
+	{0x01, 0x0000, 0x001f},
+	{0x01, 0x0000, 0x0020},
+	{0x01, 0x00ff, 0x003e},
+	{0x01, 0x0003, 0x003f},
+	{0x01, 0x0000, 0x0040},
+	{0x01, 0x0035, 0x0041},
+	{0x01, 0x0053, 0x0042},
+	{0x01, 0x0069, 0x0043},
+	{0x01, 0x007c, 0x0044},
+	{0x01, 0x008c, 0x0045},
+	{0x01, 0x009a, 0x0046},
+	{0x01, 0x00a8, 0x0047},
+	{0x01, 0x00b4, 0x0048},
+	{0x01, 0x00bf, 0x0049},
+	{0x01, 0x00ca, 0x004a},
+	{0x01, 0x00d4, 0x004b},
+	{0x01, 0x00dd, 0x004c},
+	{0x01, 0x00e7, 0x004d},
+	{0x01, 0x00ef, 0x004e},
+	{0x01, 0x00f8, 0x004f},
+	{0x01, 0x00ff, 0x0050},
+	{0x01, 0x0001, 0x0056},
+	{0x01, 0x0060, 0x0057},
+	{0x01, 0x0040, 0x0058},
+	{0x01, 0x0011, 0x0059},
+	{0x01, 0x0001, 0x005a},
+	{0x02, 0x0007, 0x0005},
+	{0x02, 0xa048, 0x0000},
+	{0x02, 0x0007, 0x0005},
+	{0x02, 0x0015, 0x0006},
+	{0x02, 0x100a, 0x0007},
+	{0x02, 0xa048, 0x0000},
+	{0x02, 0xc002, 0x0001},
+	{0x02, 0x000f, 0x0005},
+	{0x02, 0xa048, 0x0000},
+	{0x05, 0x0022, 0x0004},
+	{0x05, 0x0025, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0026, 0x0001},
+	{0x05, 0x0001, 0x0000},
+	{0x05, 0x0027, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0001, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0021, 0x0001},
+	{0x05, 0x00d2, 0x0000},
+	{0x05, 0x0020, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x00, 0x0090, 0x0005},
+	{0x01, 0x00a6, 0x0000},
+	{0x01, 0x0003, 0x003f},
+	{0x01, 0x0001, 0x0056},
+	{0x01, 0x0011, 0x0008},
+	{0x01, 0x0032, 0x0009},
+	{0x01, 0xfffd, 0x000a},
+	{0x01, 0x0023, 0x000b},
+	{0x01, 0xffea, 0x000c},
+	{0x01, 0xfff4, 0x000d},
+	{0x01, 0xfffc, 0x000e},
+	{0x01, 0xffe3, 0x000f},
+	{0x01, 0x001f, 0x0010},
+	{0x01, 0x00a8, 0x0001},
+	{0x01, 0x0067, 0x0007},
+	{0x01, 0x0032, 0x0017},
+	{0x01, 0x0023, 0x0018},
+	{0x01, 0x00ce, 0x0019},
+	{0x01, 0x0023, 0x001a},
+	{0x01, 0x0032, 0x001b},
+	{0x01, 0x008d, 0x001c},
+	{0x01, 0x00ce, 0x001d},
+	{0x01, 0x008d, 0x001e},
+	{0x01, 0x00c8, 0x0015},
+	{0x01, 0x0032, 0x0016},
+	{0x01, 0x0000, 0x0011},
+	{0x01, 0x0000, 0x0012},
+	{0x01, 0x0000, 0x0013},
+	{0x01, 0x000a, 0x0003},
+	{0x02, 0xc002, 0x0001},
+	{0x02, 0x0007, 0x0005},
+	{0x02, 0xc000, 0x0001},
+	{0x02, 0x0000, 0x0005},
+	{0x02, 0x0007, 0x0005},
+	{0x02, 0x2000, 0x0000},
+	{0x05, 0x0022, 0x0004},
+	{0x05, 0x0015, 0x0001},
+	{0x05, 0x00ea, 0x0000},
+	{0x05, 0x0021, 0x0001},
+	{0x05, 0x00d2, 0x0000},
+	{0x05, 0x0023, 0x0001},
+	{0x05, 0x0003, 0x0000},
+	{0x05, 0x0030, 0x0001},
+	{0x05, 0x002b, 0x0000},
+	{0x05, 0x0031, 0x0001},
+	{0x05, 0x0023, 0x0000},
+	{0x05, 0x0032, 0x0001},
+	{0x05, 0x0023, 0x0000},
+	{0x05, 0x0033, 0x0001},
+	{0x05, 0x0023, 0x0000},
+	{0x05, 0x0034, 0x0001},
+	{0x05, 0x0002, 0x0000},
+	{0x05, 0x0050, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0051, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0052, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0054, 0x0001},
+	{0x05, 0x0001, 0x0000},
+	{0x00, 0x0000, 0x0001},
+	{0x00, 0x0000, 0x0002},
+	{0x00, 0x000c, 0x0003},
+	{0x00, 0x0000, 0x0004},
+	{0x00, 0x0090, 0x0005},
+	{0x00, 0x0000, 0x0006},
+	{0x00, 0x0040, 0x0007},
+	{0x00, 0x00c0, 0x0008},
+	{0x00, 0x004a, 0x0009},
+	{0x00, 0x0000, 0x000a},
+	{0x00, 0x0000, 0x000b},
+	{0x00, 0x0001, 0x000c},
+	{0x00, 0x0001, 0x000d},
+	{0x00, 0x0000, 0x000e},
+	{0x00, 0x0002, 0x000f},
+	{0x00, 0x0001, 0x0010},
+	{0x00, 0x0000, 0x0011},
+	{0x00, 0x0000, 0x0012},
+	{0x00, 0x0002, 0x0020},
+	{0x00, 0x0080, 0x0021},
+	{0x00, 0x0001, 0x0022},
+	{0x00, 0x00e0, 0x0023},
+	{0x00, 0x0000, 0x0024},
+	{0x00, 0x00d5, 0x0025},
+	{0x00, 0x0000, 0x0026},
+	{0x00, 0x000b, 0x0027},
+	{0x00, 0x0000, 0x0046},
+	{0x00, 0x0000, 0x0047},
+	{0x00, 0x0000, 0x0048},
+	{0x00, 0x0000, 0x0049},
+	{0x00, 0x0008, 0x004a},
+	{0xff, 0x0000, 0x00d0},
+	{0xff, 0x00d8, 0x00d1},
+	{0xff, 0x0000, 0x00d4},
+	{0xff, 0x0000, 0x00d5},
+	{0x01, 0x00a6, 0x0000},
+	{0x01, 0x0028, 0x0001},
+	{0x01, 0x0000, 0x0002},
+	{0x01, 0x000a, 0x0003},
+	{0x01, 0x0040, 0x0004},
+	{0x01, 0x0066, 0x0007},
+	{0x01, 0x0011, 0x0008},
+	{0x01, 0x0032, 0x0009},
+	{0x01, 0x00fd, 0x000a},
+	{0x01, 0x0038, 0x000b},
+	{0x01, 0x00d1, 0x000c},
+	{0x01, 0x00f7, 0x000d},
+	{0x01, 0x00ed, 0x000e},
+	{0x01, 0x00d8, 0x000f},
+	{0x01, 0x0038, 0x0010},
+	{0x01, 0x00ff, 0x0015},
+	{0x01, 0x0001, 0x0016},
+	{0x01, 0x0032, 0x0017},
+	{0x01, 0x0023, 0x0018},
+	{0x01, 0x00ce, 0x0019},
+	{0x01, 0x0023, 0x001a},
+	{0x01, 0x0032, 0x001b},
+	{0x01, 0x008d, 0x001c},
+	{0x01, 0x00ce, 0x001d},
+	{0x01, 0x008d, 0x001e},
+	{0x01, 0x0000, 0x001f},
+	{0x01, 0x0000, 0x0020},
+	{0x01, 0x00ff, 0x003e},
+	{0x01, 0x0003, 0x003f},
+	{0x01, 0x0000, 0x0040},
+	{0x01, 0x0035, 0x0041},
+	{0x01, 0x0053, 0x0042},
+	{0x01, 0x0069, 0x0043},
+	{0x01, 0x007c, 0x0044},
+	{0x01, 0x008c, 0x0045},
+	{0x01, 0x009a, 0x0046},
+	{0x01, 0x00a8, 0x0047},
+	{0x01, 0x00b4, 0x0048},
+	{0x01, 0x00bf, 0x0049},
+	{0x01, 0x00ca, 0x004a},
+	{0x01, 0x00d4, 0x004b},
+	{0x01, 0x00dd, 0x004c},
+	{0x01, 0x00e7, 0x004d},
+	{0x01, 0x00ef, 0x004e},
+	{0x01, 0x00f8, 0x004f},
+	{0x01, 0x00ff, 0x0050},
+	{0x01, 0x0001, 0x0056},
+	{0x01, 0x0060, 0x0057},
+	{0x01, 0x0040, 0x0058},
+	{0x01, 0x0011, 0x0059},
+	{0x01, 0x0001, 0x005a},
+	{0x02, 0x0007, 0x0005},
+	{0x02, 0xa048, 0x0000},
+	{0x02, 0x0007, 0x0005},
+	{0x02, 0x0015, 0x0006},
+	{0x02, 0x100a, 0x0007},
+	{0x02, 0xa048, 0x0000},
+	{0x02, 0xc002, 0x0001},
+	{0x02, 0x000f, 0x0005},
+	{0x02, 0xa048, 0x0000},
+	{0x05, 0x0022, 0x0004},
+	{0x05, 0x0025, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0026, 0x0001},
+	{0x05, 0x0001, 0x0000},
+	{0x05, 0x0027, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0001, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0021, 0x0001},
+	{0x05, 0x00d2, 0x0000},
+	{0x05, 0x0020, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x00, 0x0090, 0x0005},
+	{0x01, 0x00a6, 0x0000},
+	{0x02, 0x0007, 0x0005},
+	{0x02, 0x2000, 0x0000},
+	{0x05, 0x0022, 0x0004},
+	{0x05, 0x0015, 0x0001},
+	{0x05, 0x00ea, 0x0000},
+	{0x05, 0x0021, 0x0001},
+	{0x05, 0x00d2, 0x0000},
+	{0x05, 0x0023, 0x0001},
+	{0x05, 0x0003, 0x0000},
+	{0x05, 0x0030, 0x0001},
+	{0x05, 0x002b, 0x0000},
+	{0x05, 0x0031, 0x0001},
+	{0x05, 0x0023, 0x0000},
+	{0x05, 0x0032, 0x0001},
+	{0x05, 0x0023, 0x0000},
+	{0x05, 0x0033, 0x0001},
+	{0x05, 0x0023, 0x0000},
+	{0x05, 0x0034, 0x0001},
+	{0x05, 0x0002, 0x0000},
+	{0x05, 0x0050, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0051, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0052, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0054, 0x0001},
+	{0x05, 0x0001, 0x0000},
+	{0x00, 0x0000, 0x0001},
+	{0x00, 0x0000, 0x0002},
+	{0x00, 0x000c, 0x0003},
+	{0x00, 0x0000, 0x0004},
+	{0x00, 0x0090, 0x0005},
+	{0x00, 0x0000, 0x0006},
+	{0x00, 0x0040, 0x0007},
+	{0x00, 0x00c0, 0x0008},
+	{0x00, 0x004a, 0x0009},
+	{0x00, 0x0000, 0x000a},
+	{0x00, 0x0000, 0x000b},
+	{0x00, 0x0001, 0x000c},
+	{0x00, 0x0001, 0x000d},
+	{0x00, 0x0000, 0x000e},
+	{0x00, 0x0002, 0x000f},
+	{0x00, 0x0001, 0x0010},
+	{0x00, 0x0000, 0x0011},
+	{0x00, 0x0000, 0x0012},
+	{0x00, 0x0002, 0x0020},
+	{0x00, 0x0080, 0x0021},
+	{0x00, 0x0001, 0x0022},
+	{0x00, 0x00e0, 0x0023},
+	{0x00, 0x0000, 0x0024},
+	{0x00, 0x00d5, 0x0025},
+	{0x00, 0x0000, 0x0026},
+	{0x00, 0x000b, 0x0027},
+	{0x00, 0x0000, 0x0046},
+	{0x00, 0x0000, 0x0047},
+	{0x00, 0x0000, 0x0048},
+	{0x00, 0x0000, 0x0049},
+	{0x00, 0x0008, 0x004a},
+	{0xff, 0x0000, 0x00d0},
+	{0xff, 0x00d8, 0x00d1},
+	{0xff, 0x0000, 0x00d4},
+	{0xff, 0x0000, 0x00d5},
+	{0x01, 0x00a6, 0x0000},
+	{0x01, 0x0028, 0x0001},
+	{0x01, 0x0000, 0x0002},
+	{0x01, 0x000a, 0x0003},
+	{0x01, 0x0040, 0x0004},
+	{0x01, 0x0066, 0x0007},
+	{0x01, 0x0011, 0x0008},
+	{0x01, 0x0032, 0x0009},
+	{0x01, 0x00fd, 0x000a},
+	{0x01, 0x0038, 0x000b},
+	{0x01, 0x00d1, 0x000c},
+	{0x01, 0x00f7, 0x000d},
+	{0x01, 0x00ed, 0x000e},
+	{0x01, 0x00d8, 0x000f},
+	{0x01, 0x0038, 0x0010},
+	{0x01, 0x00ff, 0x0015},
+	{0x01, 0x0001, 0x0016},
+	{0x01, 0x0032, 0x0017},
+	{0x01, 0x0023, 0x0018},
+	{0x01, 0x00ce, 0x0019},
+	{0x01, 0x0023, 0x001a},
+	{0x01, 0x0032, 0x001b},
+	{0x01, 0x008d, 0x001c},
+	{0x01, 0x00ce, 0x001d},
+	{0x01, 0x008d, 0x001e},
+	{0x01, 0x0000, 0x001f},
+	{0x01, 0x0000, 0x0020},
+	{0x01, 0x00ff, 0x003e},
+	{0x01, 0x0003, 0x003f},
+	{0x01, 0x0000, 0x0040},
+	{0x01, 0x0035, 0x0041},
+	{0x01, 0x0053, 0x0042},
+	{0x01, 0x0069, 0x0043},
+	{0x01, 0x007c, 0x0044},
+	{0x01, 0x008c, 0x0045},
+	{0x01, 0x009a, 0x0046},
+	{0x01, 0x00a8, 0x0047},
+	{0x01, 0x00b4, 0x0048},
+	{0x01, 0x00bf, 0x0049},
+	{0x01, 0x00ca, 0x004a},
+	{0x01, 0x00d4, 0x004b},
+	{0x01, 0x00dd, 0x004c},
+	{0x01, 0x00e7, 0x004d},
+	{0x01, 0x00ef, 0x004e},
+	{0x01, 0x00f8, 0x004f},
+	{0x01, 0x00ff, 0x0050},
+	{0x01, 0x0001, 0x0056},
+	{0x01, 0x0060, 0x0057},
+	{0x01, 0x0040, 0x0058},
+	{0x01, 0x0011, 0x0059},
+	{0x01, 0x0001, 0x005a},
+	{0x02, 0x0007, 0x0005},
+	{0x02, 0xa048, 0x0000},
+	{0x02, 0x0007, 0x0005},
+	{0x02, 0x0015, 0x0006},
+	{0x02, 0x100a, 0x0007},
+	{0x02, 0xa048, 0x0000},
+	{0x02, 0xc002, 0x0001},
+	{0x02, 0x000f, 0x0005},
+	{0x02, 0xa048, 0x0000},
+	{0x05, 0x0022, 0x0004},
+	{0x05, 0x0025, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0026, 0x0001},
+	{0x05, 0x0001, 0x0000},
+	{0x05, 0x0027, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0001, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0021, 0x0001},
+	{0x05, 0x00d2, 0x0000},
+	{0x05, 0x0020, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x00, 0x0090, 0x0005},
+	{0x01, 0x00a6, 0x0000},
+	{0x05, 0x0026, 0x0001},
+	{0x05, 0x0001, 0x0000},
+	{0x05, 0x0027, 0x0001},
+	{0x05, 0x000f, 0x0000},
+	{0x01, 0x0003, 0x003f},
+	{0x01, 0x0001, 0x0056},
+	{0x01, 0x0011, 0x0008},
+	{0x01, 0x0032, 0x0009},
+	{0x01, 0xfffd, 0x000a},
+	{0x01, 0x0023, 0x000b},
+	{0x01, 0xffea, 0x000c},
+	{0x01, 0xfff4, 0x000d},
+	{0x01, 0xfffc, 0x000e},
+	{0x01, 0xffe3, 0x000f},
+	{0x01, 0x001f, 0x0010},
+	{0x01, 0x00a8, 0x0001},
+	{0x01, 0x0067, 0x0007},
+	{0x01, 0x0042, 0x0051},
+	{0x01, 0x0051, 0x0053},
+	{0x01, 0x000a, 0x0003},
+	{0x02, 0xc002, 0x0001},
+	{0x02, 0x0007, 0x0005},
+	{0x02, 0xc000, 0x0001},
+	{0x02, 0x0000, 0x0005},
+	{0x02, 0x0007, 0x0005},
+	{0x02, 0x2000, 0x0000},
+	{0x05, 0x0022, 0x0004},
+	{0x05, 0x0015, 0x0001},
+	{0x05, 0x00ea, 0x0000},
+	{0x05, 0x0021, 0x0001},
+	{0x05, 0x00d2, 0x0000},
+	{0x05, 0x0023, 0x0001},
+	{0x05, 0x0003, 0x0000},
+	{0x05, 0x0030, 0x0001},
+	{0x05, 0x002b, 0x0000},
+	{0x05, 0x0031, 0x0001},
+	{0x05, 0x0023, 0x0000},
+	{0x05, 0x0032, 0x0001},
+	{0x05, 0x0023, 0x0000},
+	{0x05, 0x0033, 0x0001},
+	{0x05, 0x0023, 0x0000},
+	{0x05, 0x0034, 0x0001},
+	{0x05, 0x0002, 0x0000},
+	{0x05, 0x0050, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0051, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0052, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0054, 0x0001},
+	{0x05, 0x0001, 0x0000},
+	{0x00, 0x0000, 0x0001},
+	{0x00, 0x0000, 0x0002},
+	{0x00, 0x000c, 0x0003},
+	{0x00, 0x0000, 0x0004},
+	{0x00, 0x0090, 0x0005},
+	{0x00, 0x0000, 0x0006},
+	{0x00, 0x0040, 0x0007},
+	{0x00, 0x00c0, 0x0008},
+	{0x00, 0x004a, 0x0009},
+	{0x00, 0x0000, 0x000a},
+	{0x00, 0x0000, 0x000b},
+	{0x00, 0x0001, 0x000c},
+	{0x00, 0x0001, 0x000d},
+	{0x00, 0x0000, 0x000e},
+	{0x00, 0x0002, 0x000f},
+	{0x00, 0x0001, 0x0010},
+	{0x00, 0x0000, 0x0011},
+	{0x00, 0x0000, 0x0012},
+	{0x00, 0x0002, 0x0020},
+	{0x00, 0x0080, 0x0021},
+	{0x00, 0x0001, 0x0022},
+	{0x00, 0x00e0, 0x0023},
+	{0x00, 0x0000, 0x0024},
+	{0x00, 0x00d5, 0x0025},
+	{0x00, 0x0000, 0x0026},
+	{0x00, 0x000b, 0x0027},
+	{0x00, 0x0000, 0x0046},
+	{0x00, 0x0000, 0x0047},
+	{0x00, 0x0000, 0x0048},
+	{0x00, 0x0000, 0x0049},
+	{0x00, 0x0008, 0x004a},
+	{0xff, 0x0000, 0x00d0},
+	{0xff, 0x00d8, 0x00d1},
+	{0xff, 0x0000, 0x00d4},
+	{0xff, 0x0000, 0x00d5},
+	{0x01, 0x00a6, 0x0000},
+	{0x01, 0x0028, 0x0001},
+	{0x01, 0x0000, 0x0002},
+	{0x01, 0x000a, 0x0003},
+	{0x01, 0x0040, 0x0004},
+	{0x01, 0x0066, 0x0007},
+	{0x01, 0x0011, 0x0008},
+	{0x01, 0x0032, 0x0009},
+	{0x01, 0x00fd, 0x000a},
+	{0x01, 0x0038, 0x000b},
+	{0x01, 0x00d1, 0x000c},
+	{0x01, 0x00f7, 0x000d},
+	{0x01, 0x00ed, 0x000e},
+	{0x01, 0x00d8, 0x000f},
+	{0x01, 0x0038, 0x0010},
+	{0x01, 0x00ff, 0x0015},
+	{0x01, 0x0001, 0x0016},
+	{0x01, 0x0032, 0x0017},
+	{0x01, 0x0023, 0x0018},
+	{0x01, 0x00ce, 0x0019},
+	{0x01, 0x0023, 0x001a},
+	{0x01, 0x0032, 0x001b},
+	{0x01, 0x008d, 0x001c},
+	{0x01, 0x00ce, 0x001d},
+	{0x01, 0x008d, 0x001e},
+	{0x01, 0x0000, 0x001f},
+	{0x01, 0x0000, 0x0020},
+	{0x01, 0x00ff, 0x003e},
+	{0x01, 0x0003, 0x003f},
+	{0x01, 0x0000, 0x0040},
+	{0x01, 0x0035, 0x0041},
+	{0x01, 0x0053, 0x0042},
+	{0x01, 0x0069, 0x0043},
+	{0x01, 0x007c, 0x0044},
+	{0x01, 0x008c, 0x0045},
+	{0x01, 0x009a, 0x0046},
+	{0x01, 0x00a8, 0x0047},
+	{0x01, 0x00b4, 0x0048},
+	{0x01, 0x00bf, 0x0049},
+	{0x01, 0x00ca, 0x004a},
+	{0x01, 0x00d4, 0x004b},
+	{0x01, 0x00dd, 0x004c},
+	{0x01, 0x00e7, 0x004d},
+	{0x01, 0x00ef, 0x004e},
+	{0x01, 0x00f8, 0x004f},
+	{0x01, 0x00ff, 0x0050},
+	{0x01, 0x0001, 0x0056},
+	{0x01, 0x0060, 0x0057},
+	{0x01, 0x0040, 0x0058},
+	{0x01, 0x0011, 0x0059},
+	{0x01, 0x0001, 0x005a},
+	{0x02, 0x0007, 0x0005},
+	{0x02, 0xa048, 0x0000},
+	{0x02, 0x0007, 0x0005},
+	{0x02, 0x0015, 0x0006},
+	{0x02, 0x100a, 0x0007},
+	{0x02, 0xa048, 0x0000},
+	{0x02, 0xc002, 0x0001},
+	{0x02, 0x000f, 0x0005},
+	{0x02, 0xa048, 0x0000},
+	{0x05, 0x0022, 0x0004},
+	{0x05, 0x0025, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0026, 0x0001},
+	{0x05, 0x0001, 0x0000},
+	{0x05, 0x0027, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0001, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0021, 0x0001},
+	{0x05, 0x00d2, 0x0000},
+	{0x05, 0x0020, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x00, 0x0090, 0x0005},
+	{0x01, 0x00a6, 0x0000},
+	{0x02, 0x0007, 0x0005},
+	{0x02, 0x2000, 0x0000},
+	{0x05, 0x0022, 0x0004},
+	{0x05, 0x0015, 0x0001},
+	{0x05, 0x00ea, 0x0000},
+	{0x05, 0x0021, 0x0001},
+	{0x05, 0x00d2, 0x0000},
+	{0x05, 0x0023, 0x0001},
+	{0x05, 0x0003, 0x0000},
+	{0x05, 0x0030, 0x0001},
+	{0x05, 0x002b, 0x0000},
+	{0x05, 0x0031, 0x0001},
+	{0x05, 0x0023, 0x0000},
+	{0x05, 0x0032, 0x0001},
+	{0x05, 0x0023, 0x0000},
+	{0x05, 0x0033, 0x0001},
+	{0x05, 0x0023, 0x0000},
+	{0x05, 0x0034, 0x0001},
+	{0x05, 0x0002, 0x0000},
+	{0x05, 0x0050, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0051, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0052, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0054, 0x0001},
+	{0x05, 0x0001, 0x0000},
+	{0x00, 0x0000, 0x0001},
+	{0x00, 0x0000, 0x0002},
+	{0x00, 0x000c, 0x0003},
+	{0x00, 0x0000, 0x0004},
+	{0x00, 0x0090, 0x0005},
+	{0x00, 0x0000, 0x0006},
+	{0x00, 0x0040, 0x0007},
+	{0x00, 0x00c0, 0x0008},
+	{0x00, 0x004a, 0x0009},
+	{0x00, 0x0000, 0x000a},
+	{0x00, 0x0000, 0x000b},
+	{0x00, 0x0001, 0x000c},
+	{0x00, 0x0001, 0x000d},
+	{0x00, 0x0000, 0x000e},
+	{0x00, 0x0002, 0x000f},
+	{0x00, 0x0001, 0x0010},
+	{0x00, 0x0000, 0x0011},
+	{0x00, 0x0000, 0x0012},
+	{0x00, 0x0002, 0x0020},
+	{0x00, 0x0080, 0x0021},
+	{0x00, 0x0001, 0x0022},
+	{0x00, 0x00e0, 0x0023},
+	{0x00, 0x0000, 0x0024},
+	{0x00, 0x00d5, 0x0025},
+	{0x00, 0x0000, 0x0026},
+	{0x00, 0x000b, 0x0027},
+	{0x00, 0x0000, 0x0046},
+	{0x00, 0x0000, 0x0047},
+	{0x00, 0x0000, 0x0048},
+	{0x00, 0x0000, 0x0049},
+	{0x00, 0x0008, 0x004a},
+	{0xff, 0x0000, 0x00d0},
+	{0xff, 0x00d8, 0x00d1},
+	{0xff, 0x0000, 0x00d4},
+	{0xff, 0x0000, 0x00d5},
+	{0x01, 0x00a6, 0x0000},
+	{0x01, 0x0028, 0x0001},
+	{0x01, 0x0000, 0x0002},
+	{0x01, 0x000a, 0x0003},
+	{0x01, 0x0040, 0x0004},
+	{0x01, 0x0066, 0x0007},
+	{0x01, 0x0011, 0x0008},
+	{0x01, 0x0032, 0x0009},
+	{0x01, 0x00fd, 0x000a},
+	{0x01, 0x0038, 0x000b},
+	{0x01, 0x00d1, 0x000c},
+	{0x01, 0x00f7, 0x000d},
+	{0x01, 0x00ed, 0x000e},
+	{0x01, 0x00d8, 0x000f},
+	{0x01, 0x0038, 0x0010},
+	{0x01, 0x00ff, 0x0015},
+	{0x01, 0x0001, 0x0016},
+	{0x01, 0x0032, 0x0017},
+	{0x01, 0x0023, 0x0018},
+	{0x01, 0x00ce, 0x0019},
+	{0x01, 0x0023, 0x001a},
+	{0x01, 0x0032, 0x001b},
+	{0x01, 0x008d, 0x001c},
+	{0x01, 0x00ce, 0x001d},
+	{0x01, 0x008d, 0x001e},
+	{0x01, 0x0000, 0x001f},
+	{0x01, 0x0000, 0x0020},
+	{0x01, 0x00ff, 0x003e},
+	{0x01, 0x0003, 0x003f},
+	{0x01, 0x0000, 0x0040},
+	{0x01, 0x0035, 0x0041},
+	{0x01, 0x0053, 0x0042},
+	{0x01, 0x0069, 0x0043},
+	{0x01, 0x007c, 0x0044},
+	{0x01, 0x008c, 0x0045},
+	{0x01, 0x009a, 0x0046},
+	{0x01, 0x00a8, 0x0047},
+	{0x01, 0x00b4, 0x0048},
+	{0x01, 0x00bf, 0x0049},
+	{0x01, 0x00ca, 0x004a},
+	{0x01, 0x00d4, 0x004b},
+	{0x01, 0x00dd, 0x004c},
+	{0x01, 0x00e7, 0x004d},
+	{0x01, 0x00ef, 0x004e},
+	{0x01, 0x00f8, 0x004f},
+	{0x01, 0x00ff, 0x0050},
+	{0x01, 0x0001, 0x0056},
+	{0x01, 0x0060, 0x0057},
+	{0x01, 0x0040, 0x0058},
+	{0x01, 0x0011, 0x0059},
+	{0x01, 0x0001, 0x005a},
+	{0x02, 0x0007, 0x0005},
+	{0x02, 0xa048, 0x0000},
+	{0x02, 0x0007, 0x0005},
+	{0x02, 0x0015, 0x0006},
+	{0x02, 0x100a, 0x0007},
+	{0x02, 0xa048, 0x0000},
+	{0x02, 0xc002, 0x0001},
+	{0x02, 0x000f, 0x0005},
+	{0x02, 0xa048, 0x0000},
+	{0x05, 0x0022, 0x0004},
+	{0x05, 0x0025, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0026, 0x0001},
+	{0x05, 0x0001, 0x0000},
+	{0x05, 0x0027, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0001, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0021, 0x0001},
+	{0x05, 0x00d2, 0x0000},
+	{0x05, 0x0020, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x00, 0x0090, 0x0005},
+	{0x01, 0x00a6, 0x0000},
+	{0x05, 0x0026, 0x0001},
+	{0x05, 0x0001, 0x0000},
+	{0x05, 0x0027, 0x0001},
+	{0x05, 0x001e, 0x0000},
+	{0x01, 0x0003, 0x003f},
+	{0x01, 0x0001, 0x0056},
+	{0x01, 0x0011, 0x0008},
+	{0x01, 0x0032, 0x0009},
+	{0x01, 0xfffd, 0x000a},
+	{0x01, 0x0023, 0x000b},
+	{0x01, 0xffea, 0x000c},
+	{0x01, 0xfff4, 0x000d},
+	{0x01, 0xfffc, 0x000e},
+	{0x01, 0xffe3, 0x000f},
+	{0x01, 0x001f, 0x0010},
+	{0x01, 0x00a8, 0x0001},
+	{0x01, 0x0067, 0x0007},
+	{0x01, 0x0042, 0x0051},
+	{0x01, 0x0051, 0x0053},
+	{0x01, 0x000a, 0x0003},
+	{0x02, 0xc002, 0x0001},
+	{0x02, 0x0007, 0x0005},
+	{0x01, 0x0042, 0x0051},
+	{0x01, 0x0051, 0x0053},
+	{0x05, 0x0026, 0x0001},
+	{0x05, 0x0001, 0x0000},
+	{0x05, 0x0027, 0x0001},
+	{0x05, 0x002d, 0x0000},
+	{0x01, 0x0003, 0x003f},
+	{0x01, 0x0001, 0x0056},
+	{0x02, 0xc000, 0x0001},
+	{0x02, 0x0000, 0x0005},
+	{}
+};
+
+/* Unknow camera from Ori Usbid 0x0000:0x0000 */
+/* Based on snoops from Ori Cohen */
+static __u16 spca501c_mysterious_open_data[][3] = {
+	{0x02, 0x000f, 0x0005},
+	{0x02, 0xa048, 0x0000},
+	{0x05, 0x0022, 0x0004},
+/* DSP Registers */
+	{0x01, 0x0016, 0x0011},	/* RGB offset */
+	{0x01, 0x0000, 0x0012},
+	{0x01, 0x0006, 0x0013},
+	{0x01, 0x0078, 0x0051},
+	{0x01, 0x0040, 0x0052},
+	{0x01, 0x0046, 0x0053},
+	{0x01, 0x0040, 0x0054},
+	{0x00, 0x0025, 0x0000},
+/*	{0x00, 0x0000, 0x0000 }, */
+/* Part 2 */
+/* TG Registers */
+	{0x00, 0x0026, 0x0000},
+	{0x00, 0x0001, 0x0000},
+	{0x00, 0x0027, 0x0000},
+	{0x00, 0x008a, 0x0000},
+	{0x02, 0x0007, 0x0005},
+	{0x02, 0x2000, 0x0000},
+	{0x05, 0x0022, 0x0004},
+	{0x05, 0x0015, 0x0001},
+	{0x05, 0x00ea, 0x0000},
+	{0x05, 0x0021, 0x0001},
+	{0x05, 0x00d2, 0x0000},
+	{0x05, 0x0023, 0x0001},
+	{0x05, 0x0003, 0x0000},
+	{0x05, 0x0030, 0x0001},
+	{0x05, 0x002b, 0x0000},
+	{0x05, 0x0031, 0x0001},
+	{0x05, 0x0023, 0x0000},
+	{0x05, 0x0032, 0x0001},
+	{0x05, 0x0023, 0x0000},
+	{0x05, 0x0033, 0x0001},
+	{0x05, 0x0023, 0x0000},
+	{0x05, 0x0034, 0x0001},
+	{0x05, 0x0002, 0x0000},
+	{0x05, 0x0050, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0051, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0052, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0054, 0x0001},
+	{0x05, 0x0001, 0x0000},
+	{}
+};
+
+/* Based on snoops from Ori Cohen */
+static __u16 spca501c_mysterious_init_data[][3] = {
+/* Part 3 */
+/* TG registers */
+/*	{0x00, 0x0000, 0x0000}, */
+	{0x00, 0x0000, 0x0001},
+	{0x00, 0x0000, 0x0002},
+	{0x00, 0x0006, 0x0003},
+	{0x00, 0x0000, 0x0004},
+	{0x00, 0x0090, 0x0005},
+	{0x00, 0x0000, 0x0006},
+	{0x00, 0x0040, 0x0007},
+	{0x00, 0x00c0, 0x0008},
+	{0x00, 0x004a, 0x0009},
+	{0x00, 0x0000, 0x000a},
+	{0x00, 0x0000, 0x000b},
+	{0x00, 0x0001, 0x000c},
+	{0x00, 0x0001, 0x000d},
+	{0x00, 0x0000, 0x000e},
+	{0x00, 0x0002, 0x000f},
+	{0x00, 0x0001, 0x0010},
+	{0x00, 0x0000, 0x0011},
+	{0x00, 0x0001, 0x0012},
+	{0x00, 0x0002, 0x0020},
+	{0x00, 0x0080, 0x0021},	/* 640 */
+	{0x00, 0x0001, 0x0022},
+	{0x00, 0x00e0, 0x0023},	/* 480 */
+	{0x00, 0x0000, 0x0024},	/* Offset H hight */
+	{0x00, 0x00d3, 0x0025},	/* low */
+	{0x00, 0x0000, 0x0026},	/* Offset V */
+	{0x00, 0x000d, 0x0027},	/* low */
+	{0x00, 0x0000, 0x0046},
+	{0x00, 0x0000, 0x0047},
+	{0x00, 0x0000, 0x0048},
+	{0x00, 0x0000, 0x0049},
+	{0x00, 0x0008, 0x004a},
+/* DSP Registers	 */
+	{0x01, 0x00a6, 0x0000},
+	{0x01, 0x0028, 0x0001},
+	{0x01, 0x0000, 0x0002},
+	{0x01, 0x000a, 0x0003},	/* Level Calc bit7 ->1 Auto */
+	{0x01, 0x0040, 0x0004},
+	{0x01, 0x0066, 0x0007},
+	{0x01, 0x000f, 0x0008},	/* A11 Color correction coeff */
+	{0x01, 0x002d, 0x0009},	/* A12 */
+	{0x01, 0x0005, 0x000a},	/* A13 */
+	{0x01, 0x0023, 0x000b},	/* A21 */
+	{0x01, 0x00e0, 0x000c},	/* A22 */
+	{0x01, 0x00fd, 0x000d},	/* A23 */
+	{0x01, 0x00f4, 0x000e},	/* A31 */
+	{0x01, 0x00e4, 0x000f},	/* A32 */
+	{0x01, 0x0028, 0x0010},	/* A33 */
+	{0x01, 0x00ff, 0x0015},	/* Reserved */
+	{0x01, 0x0001, 0x0016},	/* Reserved */
+	{0x01, 0x0032, 0x0017},	/* Win1 Start begin */
+	{0x01, 0x0023, 0x0018},
+	{0x01, 0x00ce, 0x0019},
+	{0x01, 0x0023, 0x001a},
+	{0x01, 0x0032, 0x001b},
+	{0x01, 0x008d, 0x001c},
+	{0x01, 0x00ce, 0x001d},
+	{0x01, 0x008d, 0x001e},
+	{0x01, 0x0000, 0x001f},
+	{0x01, 0x0000, 0x0020},	/* Win1 Start end */
+	{0x01, 0x00ff, 0x003e},	/* Reserved begin */
+	{0x01, 0x0002, 0x003f},
+	{0x01, 0x0000, 0x0040},
+	{0x01, 0x0035, 0x0041},
+	{0x01, 0x0053, 0x0042},
+	{0x01, 0x0069, 0x0043},
+	{0x01, 0x007c, 0x0044},
+	{0x01, 0x008c, 0x0045},
+	{0x01, 0x009a, 0x0046},
+	{0x01, 0x00a8, 0x0047},
+	{0x01, 0x00b4, 0x0048},
+	{0x01, 0x00bf, 0x0049},
+	{0x01, 0x00ca, 0x004a},
+	{0x01, 0x00d4, 0x004b},
+	{0x01, 0x00dd, 0x004c},
+	{0x01, 0x00e7, 0x004d},
+	{0x01, 0x00ef, 0x004e},
+	{0x01, 0x00f8, 0x004f},
+	{0x01, 0x00ff, 0x0050},
+	{0x01, 0x0003, 0x0056},	/* Reserved end */
+	{0x01, 0x0060, 0x0057},	/* Edge Gain */
+	{0x01, 0x0040, 0x0058},
+	{0x01, 0x0011, 0x0059},	/* Edge Bandwidth */
+	{0x01, 0x0001, 0x005a},
+	{0x02, 0x0007, 0x0005},
+	{0x02, 0xa048, 0x0000},
+	{0x02, 0x0007, 0x0005},
+	{0x02, 0x0015, 0x0006},
+	{0x02, 0x200a, 0x0007},
+	{0x02, 0xa048, 0x0000},
+	{0x02, 0xc000, 0x0001},
+	{0x02, 0x000f, 0x0005},
+	{0x02, 0xa048, 0x0000},
+	{0x05, 0x0022, 0x0004},
+	{0x05, 0x0025, 0x0001},
+	{0x05, 0x0000, 0x0000},
+/* Part 4             */
+	{0x05, 0x0026, 0x0001},
+	{0x05, 0x0001, 0x0000},
+	{0x05, 0x0027, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0001, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x05, 0x0021, 0x0001},
+	{0x05, 0x00d2, 0x0000},
+	{0x05, 0x0020, 0x0001},
+	{0x05, 0x0000, 0x0000},
+	{0x00, 0x0090, 0x0005},
+	{0x01, 0x00a6, 0x0000},
+	{0x02, 0x0000, 0x0005},
+	{0x05, 0x0026, 0x0001},
+	{0x05, 0x0001, 0x0000},
+	{0x05, 0x0027, 0x0001},
+	{0x05, 0x004e, 0x0000},
+/* Part 5        	 */
+	{0x01, 0x0003, 0x003f},
+	{0x01, 0x0001, 0x0056},
+	{0x01, 0x000f, 0x0008},
+	{0x01, 0x002d, 0x0009},
+	{0x01, 0x0005, 0x000a},
+	{0x01, 0x0023, 0x000b},
+	{0x01, 0xffe0, 0x000c},
+	{0x01, 0xfffd, 0x000d},
+	{0x01, 0xfff4, 0x000e},
+	{0x01, 0xffe4, 0x000f},
+	{0x01, 0x0028, 0x0010},
+	{0x01, 0x00a8, 0x0001},
+	{0x01, 0x0066, 0x0007},
+	{0x01, 0x0032, 0x0017},
+	{0x01, 0x0023, 0x0018},
+	{0x01, 0x00ce, 0x0019},
+	{0x01, 0x0023, 0x001a},
+	{0x01, 0x0032, 0x001b},
+	{0x01, 0x008d, 0x001c},
+	{0x01, 0x00ce, 0x001d},
+	{0x01, 0x008d, 0x001e},
+	{0x01, 0x00c8, 0x0015},	/* c8 Poids fort Luma */
+	{0x01, 0x0032, 0x0016},	/* 32 */
+	{0x01, 0x0016, 0x0011},	/* R 00 */
+	{0x01, 0x0016, 0x0012},	/* G 00 */
+	{0x01, 0x0016, 0x0013},	/* B 00 */
+	{0x01, 0x000a, 0x0003},
+	{0x02, 0xc002, 0x0001},
+	{0x02, 0x0007, 0x0005},
+	{}
+};
+
+static int reg_write(struct usb_device *dev,
+		     __u16 req, __u16 index, __u16 value)
+{
+	int ret;
+
+	ret = usb_control_msg(dev,
+			usb_sndctrlpipe(dev, 0),
+			req,
+			USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			value, index, NULL, 0, 500);
+	PDEBUG(D_USBO, "reg write: 0x%02x 0x%02x 0x%02x",
+		req, index, value);
+	if (ret < 0)
+		PDEBUG(D_ERR, "reg write: error %d", ret);
+	return ret;
+}
+
+/* returns: negative is error, pos or zero is data */
+static int reg_read(struct usb_device *dev,
+			__u16 req,	/* bRequest */
+			__u16 index,	/* wIndex */
+			__u16 length)	/* wLength (1 or 2 only) */
+{
+	int ret;
+	__u8 buf[2];
+
+	buf[1] = 0;
+	ret = usb_control_msg(dev,
+			usb_rcvctrlpipe(dev, 0),
+			req,
+			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			0,		/* value */
+			index,
+			buf, length,
+			500);			/* timeout */
+	if (ret < 0) {
+		PDEBUG(D_ERR, "reg_read err %d", ret);
+		return -1;
+	}
+	return (buf[1] << 8) + buf[0];
+}
+
+static int write_vector(struct gspca_dev *gspca_dev,
+				__u16 data[][3])
+{
+	struct usb_device *dev = gspca_dev->dev;
+	int ret, i = 0;
+
+	while (data[i][0] != 0 || data[i][1] != 0 || data[i][2] != 0) {
+		ret = reg_write(dev, data[i][0], data[i][2], data[i][1]);
+		if (ret < 0) {
+			PDEBUG(D_ERR,
+				"Reg write failed for 0x%02x,0x%02x,0x%02x",
+				data[i][0], data[i][1], data[i][2]);
+			return ret;
+		}
+		i++;
+	}
+	return 0;
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x11, sd->brightness);
+	reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x12, sd->brightness);
+	reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x13, sd->brightness);
+}
+
+static void getbrightness(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	__u16 brightness;
+
+	brightness = reg_read(gspca_dev->dev, SPCA501_REG_CCDSP, 0x11, 2);
+	sd->brightness = brightness << 1;
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	reg_write(gspca_dev->dev, 0x00, 0x00,
+				  (sd->contrast >> 8) & 0xff);
+	reg_write(gspca_dev->dev, 0x00, 0x01,
+				  sd->contrast & 0xff);
+}
+
+static void getcontrast(struct gspca_dev *gspca_dev)
+{
+/*	spca50x->contrast = 0xaa01; */
+}
+
+static void setcolors(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x0c, sd->colors);
+}
+
+static void getcolors(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->colors = reg_read(gspca_dev->dev, SPCA501_REG_CCDSP, 0x0c, 2);
+/*	sd->hue = (reg_read(gspca_dev->dev, SPCA501_REG_CCDSP, 0x13, */
+/*			2) & 0xFF) << 8; */
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+			const struct usb_device_id *id)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct cam *cam;
+	__u16 vendor;
+	__u16 product;
+
+	vendor = id->idVendor;
+	product = id->idProduct;
+	switch (vendor) {
+	case 0x0000:		/* Unknow Camera */
+/*		switch (product) { */
+/*		case 0x0000: */
+			sd->subtype = MystFromOriUnknownCamera;
+/*			break; */
+/*		} */
+		break;
+	case 0x040a:		/* Kodak cameras */
+/*		switch (product) { */
+/*		case 0x0002: */
+			sd->subtype = KodakDVC325;
+/*			break; */
+/*		} */
+		break;
+	case 0x0497:		/* Smile International */
+/*		switch (product) { */
+/*		case 0xc001: */
+			sd->subtype = SmileIntlCamera;
+/*			break; */
+/*		} */
+		break;
+	case 0x0506:		/* 3COM cameras */
+/*		switch (product) { */
+/*		case 0x00df: */
+			sd->subtype = ThreeComHomeConnectLite;
+/*			break; */
+/*		} */
+		break;
+	case 0x0733:	/* Rebadged ViewQuest (Intel) and ViewQuest cameras */
+		switch (product) {
+		case 0x0401:
+			sd->subtype = IntelCreateAndShare;
+			break;
+		case 0x0402:
+			sd->subtype = ViewQuestM318B;
+			break;
+		}
+		break;
+	case 0x1776:		/* Arowana */
+/*		switch (product) { */
+/*		case 0x501c: */
+			sd->subtype = Arowana300KCMOSCamera;
+/*			break; */
+/*		} */
+		break;
+	}
+	cam = &gspca_dev->cam;
+	cam->dev_name = (char *) id->driver_info;
+	cam->epaddr = 0x01;
+	cam->cam_mode = vga_mode;
+	cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+	sd->brightness = sd_ctrls[MY_BRIGHTNESS].qctrl.default_value;
+	sd->contrast = sd_ctrls[MY_CONTRAST].qctrl.default_value;
+	sd->colors = sd_ctrls[MY_COLOR].qctrl.default_value;
+
+	switch (sd->subtype) {
+	case Arowana300KCMOSCamera:
+	case SmileIntlCamera:
+		/* Arowana 300k CMOS Camera data */
+		if (write_vector(gspca_dev, spca501c_arowana_init_data))
+			goto error;
+		break;
+	case MystFromOriUnknownCamera:
+		/* UnKnow Ori CMOS Camera data */
+		if (write_vector(gspca_dev, spca501c_mysterious_open_data))
+			goto error;
+		break;
+	default:
+		/* generic spca501 init data */
+		if (write_vector(gspca_dev, spca501_init_data))
+			goto error;
+		break;
+	}
+	return 0;
+error:
+	return -EINVAL;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	PDEBUG(D_STREAM, "SPCA501 init");
+	switch (sd->subtype) {
+	case ThreeComHomeConnectLite:
+		/* Special handling for 3com data */
+		write_vector(gspca_dev, spca501_3com_open_data);
+		break;
+	case Arowana300KCMOSCamera:
+	case SmileIntlCamera:
+		/* Arowana 300k CMOS Camera data */
+		write_vector(gspca_dev, spca501c_arowana_open_data);
+		break;
+	case MystFromOriUnknownCamera:
+		/* UnKnow  CMOS Camera data */
+		write_vector(gspca_dev, spca501c_mysterious_init_data);
+		break;
+	default:
+		/* Generic 501 open data */
+		write_vector(gspca_dev, spca501_open_data);
+	}
+	PDEBUG(D_STREAM, "Initializing SPCA501 finished");
+	return 0;
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+	struct usb_device *dev = gspca_dev->dev;
+	int mode;
+
+	/* memorize the wanted pixel format */
+	mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].mode;
+
+	/* Enable ISO packet machine CTRL reg=2,
+	 * index=1 bitmask=0x2 (bit ordinal 1) */
+	reg_write(dev, SPCA50X_REG_USB, 0x6, 0x94);
+	switch (mode) {
+	case 0: /* 640x480 */
+		reg_write(dev, SPCA50X_REG_USB, 0x07, 0x004a);
+		break;
+	case 1: /* 320x240 */
+		reg_write(dev, SPCA50X_REG_USB, 0x07, 0x104a);
+		break;
+	default:
+/*	case 2:  * 160x120 */
+		reg_write(dev, SPCA50X_REG_USB, 0x07, 0x204a);
+		break;
+	}
+	reg_write(dev, SPCA501_REG_CTLRL, 0x01, 0x02);
+
+	/* HDG atleast the Intel CreateAndShare needs to have one of its
+	 * brightness / contrast / color set otherwise it assumes wath seems
+	 * max contrast. Note that strange enough setting any of these is
+	 * enough to fix the max contrast problem, to be sure we set all 3 */
+	setbrightness(gspca_dev);
+	setcontrast(gspca_dev);
+	setcolors(gspca_dev);
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+	/* Disable ISO packet
+	 * machine CTRL reg=2, index=1 bitmask=0x0 (bit ordinal 1) */
+	reg_write(gspca_dev->dev, SPCA501_REG_CTLRL, 0x01, 0x00);
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+/* this function is called at close time */
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+	reg_write(gspca_dev->dev, SPCA501_REG_CTLRL, 0x05, 0x00);
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+			struct gspca_frame *frame,	/* target */
+			__u8 *data,			/* isoc packet */
+			int len)			/* iso packet length */
+{
+	switch (data[0]) {
+	case 0:				/* start of frame */
+		frame = gspca_frame_add(gspca_dev,
+					LAST_PACKET,
+					frame,
+					data, 0);
+		data += SPCA501_OFFSET_DATA;
+		len -= SPCA501_OFFSET_DATA;
+		gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+				data, len);
+		return;
+	case 0xff:			/* drop */
+/*		gspca_dev->last_packet_type = DISCARD_PACKET; */
+		return;
+	}
+	data++;
+	len--;
+	gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+			data, len);
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->brightness = val;
+	if (gspca_dev->streaming)
+		setbrightness(gspca_dev);
+	return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	getbrightness(gspca_dev);
+	*val = sd->brightness;
+	return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->contrast = val;
+	if (gspca_dev->streaming)
+		setcontrast(gspca_dev);
+	return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	getcontrast(gspca_dev);
+	*val = sd->contrast;
+	return 0;
+}
+
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->colors = val;
+	if (gspca_dev->streaming)
+		setcolors(gspca_dev);
+	return 0;
+}
+
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	getcolors(gspca_dev);
+	*val = sd->colors;
+	return 0;
+}
+
+/* sub-driver description */
+static struct sd_desc sd_desc = {
+	.name = MODULE_NAME,
+	.ctrls = sd_ctrls,
+	.nctrls = ARRAY_SIZE(sd_ctrls),
+	.config = sd_config,
+	.open = sd_open,
+	.start = sd_start,
+	.stopN = sd_stopN,
+	.stop0 = sd_stop0,
+	.close = sd_close,
+	.pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static __devinitdata struct usb_device_id device_table[] = {
+	{USB_DEVICE(0x040a, 0x0002), DVNM("Kodak DVC-325")},
+	{USB_DEVICE(0x0497, 0xc001), DVNM("Smile International")},
+	{USB_DEVICE(0x0506, 0x00df), DVNM("3Com HomeConnect Lite")},
+	{USB_DEVICE(0x0733, 0x0401), DVNM("Intel Create and Share")},
+	{USB_DEVICE(0x0733, 0x0402), DVNM("ViewQuest M318B")},
+	{USB_DEVICE(0x1776, 0x501c), DVNM("Arowana 300K CMOS Camera")},
+	{USB_DEVICE(0x0000, 0x0000), DVNM("MystFromOri Unknow Camera")},
+	{}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+			const struct usb_device_id *id)
+{
+	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+				THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+	.name = MODULE_NAME,
+	.id_table = device_table,
+	.probe = sd_probe,
+	.disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+	if (usb_register(&sd_driver) < 0)
+		return -1;
+	PDEBUG(D_PROBE, "v%s registered", version);
+	return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+	usb_deregister(&sd_driver);
+	PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/spca505.c b/drivers/media/video/gspca/spca505.c
new file mode 100644
index 0000000..5b23518
--- /dev/null
+++ b/drivers/media/video/gspca/spca505.c
@@ -0,0 +1,933 @@
+/*
+ * SPCA505 chip based cameras initialization data
+ *
+ * V4L2 by Jean-Francis Moine <http://moinejf.free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#define MODULE_NAME "spca505"
+
+#include "gspca.h"
+
+#define DRIVER_VERSION_NUMBER	KERNEL_VERSION(2, 1, 0)
+static const char version[] = "2.1.0";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("GSPCA/SPCA505 USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+	struct gspca_dev gspca_dev;		/* !! must be the first item */
+
+	int buflen;
+	unsigned char tmpbuf[640 * 480 * 3 / 2]; /* YYUV per line */
+	unsigned char tmpbuf2[640 * 480 * 2];	/* YUYV */
+
+	unsigned char brightness;
+
+	char subtype;
+#define IntelPCCameraPro 0
+#define Nxultra 1
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+#define SD_BRIGHTNESS 0
+	{
+	    {
+		.id      = V4L2_CID_BRIGHTNESS,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Brightness",
+		.minimum = 0,
+		.maximum = 255,
+		.step    = 1,
+		.default_value = 127,
+	    },
+	    .set = sd_setbrightness,
+	    .get = sd_getbrightness,
+	},
+};
+
+static struct cam_mode vga_mode[] = {
+	{V4L2_PIX_FMT_YUYV, 160, 120, 5},
+	{V4L2_PIX_FMT_YUYV, 176, 144, 4},
+	{V4L2_PIX_FMT_YUYV, 320, 240, 2},
+	{V4L2_PIX_FMT_YUYV, 352, 288, 1},
+	{V4L2_PIX_FMT_YUYV, 640, 480, 0},
+};
+
+#define SPCA50X_OFFSET_DATA 10
+
+#define SPCA50X_REG_USB 0x02	/* spca505 501 */
+
+#define SPCA50X_USB_CTRL 0x00	/* spca505 */
+#define SPCA50X_CUSB_ENABLE 0x01 /* spca505 */
+#define SPCA50X_REG_GLOBAL 0x03	/* spca505 */
+#define SPCA50X_GMISC0_IDSEL 0x01 /* Global control device ID select spca505 */
+#define SPCA50X_GLOBAL_MISC0 0x00 /* Global control miscellaneous 0 spca505 */
+
+#define SPCA50X_GLOBAL_MISC1 0x01 /* 505 */
+#define SPCA50X_GLOBAL_MISC3 0x03 /* 505 */
+#define SPCA50X_GMISC3_SAA7113RST 0x20	/* Not sure about this one spca505 */
+
+/*
+ * Data to initialize a SPCA505. Common to the CCD and external modes
+ */
+static __u16 spca505_init_data[][3] = {
+	/* line	   bmRequest,value,index */
+	/* 1819 */
+	{SPCA50X_REG_GLOBAL, SPCA50X_GMISC3_SAA7113RST, SPCA50X_GLOBAL_MISC3},
+	/* Sensor reset */
+	/* 1822 */ {SPCA50X_REG_GLOBAL, 0x00, SPCA50X_GLOBAL_MISC3},
+	/* 1825 */ {SPCA50X_REG_GLOBAL, 0x00, SPCA50X_GLOBAL_MISC1},
+	/* Block USB reset */
+	/* 1828 */ {SPCA50X_REG_GLOBAL, SPCA50X_GMISC0_IDSEL,
+		SPCA50X_GLOBAL_MISC0},
+
+	/* 1831 */ {0x5, 0x01, 0x10},
+					/* Maybe power down some stuff */
+	/* 1834 */ {0x5, 0x0f, 0x11},
+
+	/* Setup internal CCD  ? */
+	/* 1837 */ {0x6, 0x10, 0x08},
+	/* 1840 */ {0x6, 0x00, 0x09},
+	/* 1843 */ {0x6, 0x00, 0x0a},
+	/* 1846 */ {0x6, 0x00, 0x0b},
+	/* 1849 */ {0x6, 0x10, 0x0c},
+	/* 1852 */ {0x6, 0x00, 0x0d},
+	/* 1855 */ {0x6, 0x00, 0x0e},
+	/* 1858 */ {0x6, 0x00, 0x0f},
+	/* 1861 */ {0x6, 0x10, 0x10},
+	/* 1864 */ {0x6, 0x02, 0x11},
+	/* 1867 */ {0x6, 0x00, 0x12},
+	/* 1870 */ {0x6, 0x04, 0x13},
+	/* 1873 */ {0x6, 0x02, 0x14},
+	/* 1876 */ {0x6, 0x8a, 0x51},
+	/* 1879 */ {0x6, 0x40, 0x52},
+	/* 1882 */ {0x6, 0xb6, 0x53},
+	/* 1885 */ {0x6, 0x3d, 0x54},
+	{}
+};
+
+/*
+ * Data to initialize the camera using the internal CCD
+ */
+static __u16 spca505_open_data_ccd[][3] = {
+	/* line	   bmRequest,value,index */
+	/* Internal CCD data set */
+	/* 1891 */ {0x3, 0x04, 0x01},
+	/* This could be a reset */
+	/* 1894 */ {0x3, 0x00, 0x01},
+
+	/* Setup compression and image registers. 0x6 and 0x7 seem to be
+	   related to H&V hold, and are resolution mode specific */
+		/* 1897 */ {0x4, 0x10, 0x01},
+		/* DIFF(0x50), was (0x10) */
+	/* 1900 */ {0x4, 0x00, 0x04},
+	/* 1903 */ {0x4, 0x00, 0x05},
+	/* 1906 */ {0x4, 0x20, 0x06},
+	/* 1909 */ {0x4, 0x20, 0x07},
+
+	/* 1912 */ {0x8, 0x0a, 0x00},
+	/* DIFF (0x4a), was (0xa) */
+
+	/* 1915 */ {0x5, 0x00, 0x10},
+	/* 1918 */ {0x5, 0x00, 0x11},
+	/* 1921 */ {0x5, 0x00, 0x00},
+	/* DIFF not written */
+	/* 1924 */ {0x5, 0x00, 0x01},
+	/* DIFF not written */
+	/* 1927 */ {0x5, 0x00, 0x02},
+	/* DIFF not written */
+	/* 1930 */ {0x5, 0x00, 0x03},
+	/* DIFF not written */
+	/* 1933 */ {0x5, 0x00, 0x04},
+	/* DIFF not written */
+		/* 1936 */ {0x5, 0x80, 0x05},
+		/* DIFF not written */
+		/* 1939 */ {0x5, 0xe0, 0x06},
+		/* DIFF not written */
+		/* 1942 */ {0x5, 0x20, 0x07},
+		/* DIFF not written */
+		/* 1945 */ {0x5, 0xa0, 0x08},
+		/* DIFF not written */
+		/* 1948 */ {0x5, 0x0, 0x12},
+		/* DIFF not written */
+	/* 1951 */ {0x5, 0x02, 0x0f},
+	/* DIFF not written */
+		/* 1954 */ {0x5, 0x10, 0x46},
+		/* DIFF not written */
+		/* 1957 */ {0x5, 0x8, 0x4a},
+		/* DIFF not written */
+
+	/* 1960 */ {0x3, 0x08, 0x03},
+	/* DIFF (0x3,0x28,0x3) */
+	/* 1963 */ {0x3, 0x08, 0x01},
+	/* 1966 */ {0x3, 0x0c, 0x03},
+	/* DIFF not written */
+		/* 1969 */ {0x3, 0x21, 0x00},
+		/* DIFF (0x39) */
+
+/* Extra block copied from init to hopefully ensure CCD is in a sane state */
+	/* 1837 */ {0x6, 0x10, 0x08},
+	/* 1840 */ {0x6, 0x00, 0x09},
+	/* 1843 */ {0x6, 0x00, 0x0a},
+	/* 1846 */ {0x6, 0x00, 0x0b},
+	/* 1849 */ {0x6, 0x10, 0x0c},
+	/* 1852 */ {0x6, 0x00, 0x0d},
+	/* 1855 */ {0x6, 0x00, 0x0e},
+	/* 1858 */ {0x6, 0x00, 0x0f},
+	/* 1861 */ {0x6, 0x10, 0x10},
+	/* 1864 */ {0x6, 0x02, 0x11},
+	/* 1867 */ {0x6, 0x00, 0x12},
+	/* 1870 */ {0x6, 0x04, 0x13},
+	/* 1873 */ {0x6, 0x02, 0x14},
+	/* 1876 */ {0x6, 0x8a, 0x51},
+	/* 1879 */ {0x6, 0x40, 0x52},
+	/* 1882 */ {0x6, 0xb6, 0x53},
+	/* 1885 */ {0x6, 0x3d, 0x54},
+	/* End of extra block */
+
+		/* 1972 */ {0x6, 0x3f, 0x1},
+		/* Block skipped */
+	/* 1975 */ {0x6, 0x10, 0x02},
+	/* 1978 */ {0x6, 0x64, 0x07},
+	/* 1981 */ {0x6, 0x10, 0x08},
+	/* 1984 */ {0x6, 0x00, 0x09},
+	/* 1987 */ {0x6, 0x00, 0x0a},
+	/* 1990 */ {0x6, 0x00, 0x0b},
+	/* 1993 */ {0x6, 0x10, 0x0c},
+	/* 1996 */ {0x6, 0x00, 0x0d},
+	/* 1999 */ {0x6, 0x00, 0x0e},
+	/* 2002 */ {0x6, 0x00, 0x0f},
+	/* 2005 */ {0x6, 0x10, 0x10},
+	/* 2008 */ {0x6, 0x02, 0x11},
+	/* 2011 */ {0x6, 0x00, 0x12},
+	/* 2014 */ {0x6, 0x04, 0x13},
+	/* 2017 */ {0x6, 0x02, 0x14},
+	/* 2020 */ {0x6, 0x8a, 0x51},
+	/* 2023 */ {0x6, 0x40, 0x52},
+	/* 2026 */ {0x6, 0xb6, 0x53},
+	/* 2029 */ {0x6, 0x3d, 0x54},
+	/* 2032 */ {0x6, 0x60, 0x57},
+	/* 2035 */ {0x6, 0x20, 0x58},
+	/* 2038 */ {0x6, 0x15, 0x59},
+	/* 2041 */ {0x6, 0x05, 0x5a},
+
+	/* 2044 */ {0x5, 0x01, 0xc0},
+	/* 2047 */ {0x5, 0x10, 0xcb},
+		/* 2050 */ {0x5, 0x80, 0xc1},
+		/* */
+		/* 2053 */ {0x5, 0x0, 0xc2},
+		/* 4 was 0 */
+	/* 2056 */ {0x5, 0x00, 0xca},
+		/* 2059 */ {0x5, 0x80, 0xc1},
+		/*  */
+	/* 2062 */ {0x5, 0x04, 0xc2},
+	/* 2065 */ {0x5, 0x00, 0xca},
+		/* 2068 */ {0x5, 0x0, 0xc1},
+		/*  */
+	/* 2071 */ {0x5, 0x00, 0xc2},
+	/* 2074 */ {0x5, 0x00, 0xca},
+		/* 2077 */ {0x5, 0x40, 0xc1},
+		/* */
+	/* 2080 */ {0x5, 0x17, 0xc2},
+	/* 2083 */ {0x5, 0x00, 0xca},
+		/* 2086 */ {0x5, 0x80, 0xc1},
+		/* */
+	/* 2089 */ {0x5, 0x06, 0xc2},
+	/* 2092 */ {0x5, 0x00, 0xca},
+		/* 2095 */ {0x5, 0x80, 0xc1},
+		/* */
+	/* 2098 */ {0x5, 0x04, 0xc2},
+	/* 2101 */ {0x5, 0x00, 0xca},
+
+	/* 2104 */ {0x3, 0x4c, 0x3},
+	/* 2107 */ {0x3, 0x18, 0x1},
+
+	/* 2110 */ {0x6, 0x70, 0x51},
+	/* 2113 */ {0x6, 0xbe, 0x53},
+	/* 2116 */ {0x6, 0x71, 0x57},
+	/* 2119 */ {0x6, 0x20, 0x58},
+	/* 2122 */ {0x6, 0x05, 0x59},
+	/* 2125 */ {0x6, 0x15, 0x5a},
+
+	/* 2128 */ {0x4, 0x00, 0x08},
+	/* Compress = OFF (0x1 to turn on) */
+	/* 2131 */ {0x4, 0x12, 0x09},
+	/* 2134 */ {0x4, 0x21, 0x0a},
+	/* 2137 */ {0x4, 0x10, 0x0b},
+	/* 2140 */ {0x4, 0x21, 0x0c},
+	/* 2143 */ {0x4, 0x05, 0x00},
+	/* was 5 (Image Type ? ) */
+	/* 2146 */ {0x4, 0x00, 0x01},
+
+	/* 2149 */ {0x6, 0x3f, 0x01},
+
+	/* 2152 */ {0x4, 0x00, 0x04},
+	/* 2155 */ {0x4, 0x00, 0x05},
+	/* 2158 */ {0x4, 0x40, 0x06},
+	/* 2161 */ {0x4, 0x40, 0x07},
+
+	/* 2164 */ {0x6, 0x1c, 0x17},
+	/* 2167 */ {0x6, 0xe2, 0x19},
+	/* 2170 */ {0x6, 0x1c, 0x1b},
+	/* 2173 */ {0x6, 0xe2, 0x1d},
+	/* 2176 */ {0x6, 0xaa, 0x1f},
+	/* 2179 */ {0x6, 0x70, 0x20},
+
+	/* 2182 */ {0x5, 0x01, 0x10},
+	/* 2185 */ {0x5, 0x00, 0x11},
+	/* 2188 */ {0x5, 0x01, 0x00},
+	/* 2191 */ {0x5, 0x05, 0x01},
+		/* 2194 */ {0x5, 0x00, 0xc1},
+		/* */
+	/* 2197 */ {0x5, 0x00, 0xc2},
+	/* 2200 */ {0x5, 0x00, 0xca},
+
+	/* 2203 */ {0x6, 0x70, 0x51},
+	/* 2206 */ {0x6, 0xbe, 0x53},
+	{}
+};
+
+/*
+   Made by Tomasz Zablocki (skalamandra@poczta.onet.pl)
+ * SPCA505b chip based cameras initialization data
+ *
+ */
+/* jfm */
+#define initial_brightness 0x7f	/* 0x0(white)-0xff(black) */
+/* #define initial_brightness 0x0	//0x0(white)-0xff(black) */
+/*
+ * Data to initialize a SPCA505. Common to the CCD and external modes
+ */
+static __u16 spca505b_init_data[][3] = {
+/* start */
+	{0x02, 0x00, 0x00},		/* init */
+	{0x02, 0x00, 0x01},
+	{0x02, 0x00, 0x02},
+	{0x02, 0x00, 0x03},
+	{0x02, 0x00, 0x04},
+	{0x02, 0x00, 0x05},
+	{0x02, 0x00, 0x06},
+	{0x02, 0x00, 0x07},
+	{0x02, 0x00, 0x08},
+	{0x02, 0x00, 0x09},
+	{0x03, 0x00, 0x00},
+	{0x03, 0x00, 0x01},
+	{0x03, 0x00, 0x02},
+	{0x03, 0x00, 0x03},
+	{0x03, 0x00, 0x04},
+	{0x03, 0x00, 0x05},
+	{0x03, 0x00, 0x06},
+	{0x04, 0x00, 0x00},
+	{0x04, 0x00, 0x02},
+	{0x04, 0x00, 0x04},
+	{0x04, 0x00, 0x05},
+	{0x04, 0x00, 0x06},
+	{0x04, 0x00, 0x07},
+	{0x04, 0x00, 0x08},
+	{0x04, 0x00, 0x09},
+	{0x04, 0x00, 0x0a},
+	{0x04, 0x00, 0x0b},
+	{0x04, 0x00, 0x0c},
+	{0x07, 0x00, 0x00},
+	{0x07, 0x00, 0x03},
+	{0x08, 0x00, 0x00},
+	{0x08, 0x00, 0x01},
+	{0x08, 0x00, 0x02},
+	{0x00, 0x01, 0x00},
+	{0x00, 0x01, 0x01},
+	{0x00, 0x01, 0x34},
+	{0x00, 0x01, 0x35},
+	{0x06, 0x18, 0x08},
+	{0x06, 0xfc, 0x09},
+	{0x06, 0xfc, 0x0a},
+	{0x06, 0xfc, 0x0b},
+	{0x06, 0x18, 0x0c},
+	{0x06, 0xfc, 0x0d},
+	{0x06, 0xfc, 0x0e},
+	{0x06, 0xfc, 0x0f},
+	{0x06, 0x18, 0x10},
+	{0x06, 0xfe, 0x12},
+	{0x06, 0x00, 0x11},
+	{0x06, 0x00, 0x14},
+	{0x06, 0x00, 0x13},
+	{0x06, 0x28, 0x51},
+	{0x06, 0xff, 0x53},
+	{0x02, 0x00, 0x08},
+
+	{0x03, 0x00, 0x03},
+	{0x03, 0x10, 0x03},
+	{}
+};
+
+/*
+ * Data to initialize the camera using the internal CCD
+ */
+static __u16 spca505b_open_data_ccd[][3] = {
+
+/* {0x02,0x00,0x00}, */
+	{0x03, 0x04, 0x01},		/* rst */
+	{0x03, 0x00, 0x01},
+	{0x03, 0x00, 0x00},
+	{0x03, 0x21, 0x00},
+	{0x03, 0x00, 0x04},
+	{0x03, 0x00, 0x03},
+	{0x03, 0x18, 0x03},
+	{0x03, 0x08, 0x01},
+	{0x03, 0x1c, 0x03},
+	{0x03, 0x5c, 0x03},
+	{0x03, 0x5c, 0x03},
+	{0x03, 0x18, 0x01},
+
+/* same as 505 */
+	{0x04, 0x10, 0x01},
+	{0x04, 0x00, 0x04},
+	{0x04, 0x00, 0x05},
+	{0x04, 0x20, 0x06},
+	{0x04, 0x20, 0x07},
+
+	{0x08, 0x0a, 0x00},
+
+	{0x05, 0x00, 0x10},
+	{0x05, 0x00, 0x11},
+	{0x05, 0x00, 0x12},
+	{0x05, 0x6f, 0x00},
+	{0x05, initial_brightness >> 6, 0x00},
+	{0x05, initial_brightness << 2, 0x01},
+	{0x05, 0x00, 0x02},
+	{0x05, 0x01, 0x03},
+	{0x05, 0x00, 0x04},
+	{0x05, 0x03, 0x05},
+	{0x05, 0xe0, 0x06},
+	{0x05, 0x20, 0x07},
+	{0x05, 0xa0, 0x08},
+	{0x05, 0x00, 0x12},
+	{0x05, 0x02, 0x0f},
+	{0x05, 128, 0x14},		/* max exposure off (0=on) */
+	{0x05, 0x01, 0xb0},
+	{0x05, 0x01, 0xbf},
+	{0x03, 0x02, 0x06},
+	{0x05, 0x10, 0x46},
+	{0x05, 0x08, 0x4a},
+
+	{0x06, 0x00, 0x01},
+	{0x06, 0x10, 0x02},
+	{0x06, 0x64, 0x07},
+	{0x06, 0x18, 0x08},
+	{0x06, 0xfc, 0x09},
+	{0x06, 0xfc, 0x0a},
+	{0x06, 0xfc, 0x0b},
+	{0x04, 0x00, 0x01},
+	{0x06, 0x18, 0x0c},
+	{0x06, 0xfc, 0x0d},
+	{0x06, 0xfc, 0x0e},
+	{0x06, 0xfc, 0x0f},
+	{0x06, 0x11, 0x10},		/* contrast */
+	{0x06, 0x00, 0x11},
+	{0x06, 0xfe, 0x12},
+	{0x06, 0x00, 0x13},
+	{0x06, 0x00, 0x14},
+	{0x06, 0x9d, 0x51},
+	{0x06, 0x40, 0x52},
+	{0x06, 0x7c, 0x53},
+	{0x06, 0x40, 0x54},
+	{0x06, 0x02, 0x57},
+	{0x06, 0x03, 0x58},
+	{0x06, 0x15, 0x59},
+	{0x06, 0x05, 0x5a},
+	{0x06, 0x03, 0x56},
+	{0x06, 0x02, 0x3f},
+	{0x06, 0x00, 0x40},
+	{0x06, 0x39, 0x41},
+	{0x06, 0x69, 0x42},
+	{0x06, 0x87, 0x43},
+	{0x06, 0x9e, 0x44},
+	{0x06, 0xb1, 0x45},
+	{0x06, 0xbf, 0x46},
+	{0x06, 0xcc, 0x47},
+	{0x06, 0xd5, 0x48},
+	{0x06, 0xdd, 0x49},
+	{0x06, 0xe3, 0x4a},
+	{0x06, 0xe8, 0x4b},
+	{0x06, 0xed, 0x4c},
+	{0x06, 0xf2, 0x4d},
+	{0x06, 0xf7, 0x4e},
+	{0x06, 0xfc, 0x4f},
+	{0x06, 0xff, 0x50},
+
+	{0x05, 0x01, 0xc0},
+	{0x05, 0x10, 0xcb},
+	{0x05, 0x40, 0xc1},
+	{0x05, 0x04, 0xc2},
+	{0x05, 0x00, 0xca},
+	{0x05, 0x40, 0xc1},
+	{0x05, 0x09, 0xc2},
+	{0x05, 0x00, 0xca},
+	{0x05, 0xc0, 0xc1},
+	{0x05, 0x09, 0xc2},
+	{0x05, 0x00, 0xca},
+	{0x05, 0x40, 0xc1},
+	{0x05, 0x59, 0xc2},
+	{0x05, 0x00, 0xca},
+	{0x04, 0x00, 0x01},
+	{0x05, 0x80, 0xc1},
+	{0x05, 0xec, 0xc2},
+	{0x05, 0x0, 0xca},
+
+	{0x06, 0x02, 0x57},
+	{0x06, 0x01, 0x58},
+	{0x06, 0x15, 0x59},
+	{0x06, 0x0a, 0x5a},
+	{0x06, 0x01, 0x57},
+	{0x06, 0x8a, 0x03},
+	{0x06, 0x0a, 0x6c},
+	{0x06, 0x30, 0x01},
+	{0x06, 0x20, 0x02},
+	{0x06, 0x00, 0x03},
+
+	{0x05, 0x8c, 0x25},
+
+	{0x06, 0x4d, 0x51},		/* maybe saturation (4d) */
+	{0x06, 0x84, 0x53},		/* making green (84) */
+	{0x06, 0x00, 0x57},		/* sharpness (1) */
+	{0x06, 0x18, 0x08},
+	{0x06, 0xfc, 0x09},
+	{0x06, 0xfc, 0x0a},
+	{0x06, 0xfc, 0x0b},
+	{0x06, 0x18, 0x0c},		/* maybe hue (18) */
+	{0x06, 0xfc, 0x0d},
+	{0x06, 0xfc, 0x0e},
+	{0x06, 0xfc, 0x0f},
+	{0x06, 0x18, 0x10},		/* maybe contrast (18) */
+
+	{0x05, 0x01, 0x02},
+
+	{0x04, 0x00, 0x08},		/* compression */
+	{0x04, 0x12, 0x09},
+	{0x04, 0x21, 0x0a},
+	{0x04, 0x10, 0x0b},
+	{0x04, 0x21, 0x0c},
+	{0x04, 0x1d, 0x00},		/* imagetype (1d) */
+	{0x04, 0x41, 0x01},		/* hardware snapcontrol */
+
+	{0x04, 0x00, 0x04},
+	{0x04, 0x00, 0x05},
+	{0x04, 0x10, 0x06},
+	{0x04, 0x10, 0x07},
+	{0x04, 0x40, 0x06},
+	{0x04, 0x40, 0x07},
+	{0x04, 0x00, 0x04},
+	{0x04, 0x00, 0x05},
+
+	{0x06, 0x1c, 0x17},
+	{0x06, 0xe2, 0x19},
+	{0x06, 0x1c, 0x1b},
+	{0x06, 0xe2, 0x1d},
+	{0x06, 0x5f, 0x1f},
+	{0x06, 0x32, 0x20},
+
+	{0x05, initial_brightness >> 6, 0x00},
+	{0x05, initial_brightness << 2, 0x01},
+	{0x05, 0x06, 0xc1},
+	{0x05, 0x58, 0xc2},
+	{0x05, 0x0, 0xca},
+	{0x05, 0x0, 0x11},
+	{}
+};
+
+static int reg_write(struct usb_device *dev,
+		     __u16 reg, __u16 index, __u16 value)
+{
+	int ret;
+
+	ret = usb_control_msg(dev,
+			usb_sndctrlpipe(dev, 0),
+			reg,
+			USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			value, index, NULL, 0, 500);
+	PDEBUG(D_PACK, "reg write: 0x%02x,0x%02x:0x%02x, 0x%x",
+		reg, index, value, ret);
+	if (ret < 0)
+		PDEBUG(D_ERR, "reg write: error %d", ret);
+	return ret;
+}
+
+/* returns: negative is error, pos or zero is data */
+static int reg_read(struct usb_device *dev,
+			__u16 reg,	/* bRequest */
+			__u16 index,	/* wIndex */
+			__u16 length)	/* wLength (1 or 2 only) */
+{
+	int ret;
+	unsigned char buf[4];
+
+	buf[1] = 0;
+	ret = usb_control_msg(dev,
+			usb_rcvctrlpipe(dev, 0),
+			reg,
+			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			(__u16) 0,		/* value */
+			(__u16) index,
+			buf,
+			length,
+			500);			/* timeout */
+	if (ret < 0) {
+		PDEBUG(D_ERR, "reg_read err %d", ret);
+		return -1;
+	}
+	return (buf[1] << 8) + buf[0];
+}
+
+static int write_vector(struct gspca_dev *gspca_dev,
+				__u16 data[][3])
+{
+	struct usb_device *dev = gspca_dev->dev;
+	int ret, i = 0;
+
+	while (data[i][0] != 0 || data[i][1] != 0 || data[i][2] != 0) {
+		ret = reg_write(dev, data[i][0], data[i][2], data[i][1]);
+		if (ret < 0) {
+			PDEBUG(D_ERR,
+				"Register write failed for 0x%x,0x%x,0x%x",
+				data[i][0], data[i][1], data[i][2]);
+			return ret;
+		}
+		i++;
+	}
+	return 0;
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+			const struct usb_device_id *id)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct cam *cam;
+	__u16 vendor;
+	__u16 product;
+
+	vendor = id->idVendor;
+	product = id->idProduct;
+	switch (vendor) {
+	case 0x041e:		/* Creative cameras */
+/*		switch (product) { */
+/*		case 0x401d:	 * here505b */
+			sd->subtype = Nxultra;
+/*			break; */
+/*		} */
+		break;
+	case 0x0733:	/* Rebadged ViewQuest (Intel) and ViewQuest cameras */
+/*		switch (product) { */
+/*		case 0x0430: */
+/*		fixme: may be UsbGrabberPV321 BRIDGE_SPCA506 SENSOR_SAA7113 */
+			sd->subtype = IntelPCCameraPro;
+/*			break; */
+/*		} */
+		break;
+	}
+
+	cam = &gspca_dev->cam;
+	cam->dev_name = (char *) id->driver_info;
+	cam->epaddr = 0x01;
+	cam->cam_mode = vga_mode;
+	if (sd->subtype != IntelPCCameraPro)
+		cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+	else			/* no 640x480 for IntelPCCameraPro */
+		cam->nmodes = sizeof vga_mode / sizeof vga_mode[0] - 1;
+	sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
+
+	if (sd->subtype == Nxultra) {
+		if (write_vector(gspca_dev, spca505b_init_data))
+			return -EIO;
+	} else {
+		if (write_vector(gspca_dev, spca505_init_data))
+			return -EIO;
+	}
+	return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int ret;
+
+	PDEBUG(D_STREAM, "Initializing SPCA505");
+	if (sd->subtype == Nxultra)
+		write_vector(gspca_dev, spca505b_open_data_ccd);
+	else
+		write_vector(gspca_dev, spca505_open_data_ccd);
+	ret = reg_read(gspca_dev->dev, 6, 0x16, 2);
+
+	if (ret < 0) {
+		PDEBUG(D_ERR|D_STREAM,
+		       "register read failed for after vector read err = %d",
+		       ret);
+		return -EIO;
+	}
+	PDEBUG(D_STREAM,
+		"After vector read returns : 0x%x should be 0x0101",
+		ret & 0xffff);
+
+	ret = reg_write(gspca_dev->dev, 6, 0x16, 0x0a);
+	if (ret < 0) {
+		PDEBUG(D_ERR, "register write failed for (6,0xa,0x16) err=%d",
+		       ret);
+		return -EIO;
+	}
+	reg_write(gspca_dev->dev, 5, 0xc2, 18);
+	return 0;
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+	struct usb_device *dev = gspca_dev->dev;
+	int ret;
+
+	/* necessary because without it we can see stream
+	 * only once after loading module */
+	/* stopping usb registers Tomasz change */
+	reg_write(dev, 0x02, 0x0, 0x0);
+	switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].mode) {
+	case 0:
+		reg_write(dev, 0x04, 0x00, 0x00);
+		reg_write(dev, 0x04, 0x06, 0x10);
+		reg_write(dev, 0x04, 0x07, 0x10);
+		break;
+	case 1:
+		reg_write(dev, 0x04, 0x00, 0x01);
+		reg_write(dev, 0x04, 0x06, 0x1a);
+		reg_write(dev, 0x04, 0x07, 0x1a);
+		break;
+	case 2:
+		reg_write(dev, 0x04, 0x00, 0x02);
+		reg_write(dev, 0x04, 0x06, 0x1c);
+		reg_write(dev, 0x04, 0x07, 0x1d);
+		break;
+	case 4:
+		reg_write(dev, 0x04, 0x00, 0x04);
+		reg_write(dev, 0x04, 0x06, 0x34);
+		reg_write(dev, 0x04, 0x07, 0x34);
+		break;
+	default:
+/*	case 5: */
+		reg_write(dev, 0x04, 0x00, 0x05);
+		reg_write(dev, 0x04, 0x06, 0x40);
+		reg_write(dev, 0x04, 0x07, 0x40);
+		break;
+	}
+/* Enable ISO packet machine - should we do this here or in ISOC init ? */
+	ret = reg_write(dev, SPCA50X_REG_USB,
+			 SPCA50X_USB_CTRL,
+			 SPCA50X_CUSB_ENABLE);
+
+/*	reg_write(dev, 0x5, 0x0, 0x0); */
+/*	reg_write(dev, 0x5, 0x0, 0x1); */
+/*	reg_write(dev, 0x5, 0x11, 0x2); */
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+	/* Disable ISO packet machine */
+	reg_write(gspca_dev->dev, 0x02, 0x00, 0x00);
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+/* this function is called at close time */
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+	/* This maybe reset or power control */
+	reg_write(gspca_dev->dev, 0x03, 0x03, 0x20);
+	reg_write(gspca_dev->dev, 0x03, 0x01, 0x0);
+	reg_write(gspca_dev->dev, 0x03, 0x00, 0x1);
+	reg_write(gspca_dev->dev, 0x05, 0x10, 0x1);
+	reg_write(gspca_dev->dev, 0x05, 0x11, 0xf);
+}
+
+/* convert YYUV per line to YUYV (YUV 4:2:2) */
+static void yyuv_decode(unsigned char *out,
+			unsigned char *in,
+			int width,
+			int height)
+{
+	unsigned char *Ui, *Vi, *yi, *yi1;
+	unsigned char *out1;
+	int i, j;
+
+	yi = in;
+	for (i = height / 2; --i >= 0; ) {
+		out1 = out + width * 2;		/* next line */
+		yi1 = yi + width;
+		Ui = yi1 + width;
+		Vi = Ui + width / 2;
+		for (j = width / 2; --j >= 0; ) {
+			*out++ = 128 + *yi++;
+			*out++ = 128 + *Ui;
+			*out++ = 128 + *yi++;
+			*out++ = 128 + *Vi;
+
+			*out1++ = 128 + *yi1++;
+			*out1++ = 128 + *Ui++;
+			*out1++ = 128 + *yi1++;
+			*out1++ = 128 + *Vi++;
+		}
+		yi += width * 2;
+		out = out1;
+	}
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+			struct gspca_frame *frame,	/* target */
+			unsigned char *data,		/* isoc packet */
+			int len)			/* iso packet length */
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	switch (data[0]) {
+	case 0:				/* start of frame */
+		if (gspca_dev->last_packet_type == FIRST_PACKET) {
+			yyuv_decode(sd->tmpbuf2, sd->tmpbuf,
+					gspca_dev->width,
+					gspca_dev->height);
+			frame = gspca_frame_add(gspca_dev,
+						LAST_PACKET,
+						frame,
+						sd->tmpbuf2,
+						gspca_dev->width
+							* gspca_dev->height
+							* 2);
+		}
+		gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+				data, 0);
+		data += SPCA50X_OFFSET_DATA;
+		len -= SPCA50X_OFFSET_DATA;
+		if (len > 0)
+			memcpy(sd->tmpbuf, data, len);
+		else
+			len = 0;
+		sd->buflen = len;
+		return;
+	case 0xff:			/* drop */
+/*		gspca_dev->last_packet_type = DISCARD_PACKET; */
+		return;
+	}
+	data += 1;
+	len -= 1;
+	memcpy(&sd->tmpbuf[sd->buflen], data, len);
+	sd->buflen += len;
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	__u8 brightness = sd->brightness;
+	reg_write(gspca_dev->dev, 5, 0x00, (255 - brightness) >> 6);
+	reg_write(gspca_dev->dev, 5, 0x01, (255 - brightness) << 2);
+
+}
+static void getbrightness(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->brightness = 255
+		- ((reg_read(gspca_dev->dev, 5, 0x01, 1) >> 2)
+			+ (reg_read(gspca_dev->dev, 5, 0x0, 1) << 6));
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->brightness = val;
+	if (gspca_dev->streaming)
+		setbrightness(gspca_dev);
+	return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	getbrightness(gspca_dev);
+	*val = sd->brightness;
+	return 0;
+}
+
+/* sub-driver description */
+static struct sd_desc sd_desc = {
+	.name = MODULE_NAME,
+	.ctrls = sd_ctrls,
+	.nctrls = ARRAY_SIZE(sd_ctrls),
+	.config = sd_config,
+	.open = sd_open,
+	.start = sd_start,
+	.stopN = sd_stopN,
+	.stop0 = sd_stop0,
+	.close = sd_close,
+	.pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static __devinitdata struct usb_device_id device_table[] = {
+	{USB_DEVICE(0x041e, 0x401d), DVNM("Creative Webcam NX ULTRA")},
+	{USB_DEVICE(0x0733, 0x0430), DVNM("Intel PC Camera Pro")},
+	{}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+			const struct usb_device_id *id)
+{
+	return gspca_dev_probe(intf, id, &sd_desc, sizeof (struct sd),
+				THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+	.name = MODULE_NAME,
+	.id_table = device_table,
+	.probe = sd_probe,
+	.disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+	if (usb_register(&sd_driver) < 0)
+		return -1;
+	PDEBUG(D_PROBE, "v%s registered", version);
+	return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+	usb_deregister(&sd_driver);
+	PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/spca506.c b/drivers/media/video/gspca/spca506.c
new file mode 100644
index 0000000..614fb3a
--- /dev/null
+++ b/drivers/media/video/gspca/spca506.c
@@ -0,0 +1,830 @@
+/*
+ * SPCA506 chip based cameras function
+ * M Xhaard 15/04/2004 based on different work Mark Taylor and others
+ * and my own snoopy file on a pv-321c donate by a german compagny
+ *                "Firma Frank Gmbh" from  Saarbruecken
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define MODULE_NAME "spca506"
+
+#include "gspca.h"
+
+#define DRIVER_VERSION_NUMBER	KERNEL_VERSION(2, 1, 0)
+static const char version[] = "2.1.0";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("GSPCA/SPCA506 USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+	struct gspca_dev gspca_dev;		/* !! must be the first item */
+
+	int buflen;
+	unsigned char tmpbuf[640 * 480 * 3];	/* YYUV per line */
+	unsigned char tmpbuf2[640 * 480 * 2];	/* YUYV */
+
+	unsigned char brightness;
+	unsigned char contrast;
+	unsigned char colors;
+	unsigned char hue;
+	char norme;
+	char channel;
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+#define SD_BRIGHTNESS 0
+	{
+	    {
+		.id      = V4L2_CID_BRIGHTNESS,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Brightness",
+		.minimum = 0,
+		.maximum = 0xff,
+		.step    = 1,
+		.default_value = 0x80,
+	    },
+	    .set = sd_setbrightness,
+	    .get = sd_getbrightness,
+	},
+#define SD_CONTRAST 1
+	{
+	    {
+		.id      = V4L2_CID_CONTRAST,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Contrast",
+		.minimum = 0,
+		.maximum = 0xff,
+		.step    = 1,
+		.default_value = 0x47,
+	    },
+	    .set = sd_setcontrast,
+	    .get = sd_getcontrast,
+	},
+#define SD_COLOR 2
+	{
+	    {
+		.id      = V4L2_CID_SATURATION,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Saturation",
+		.minimum = 0,
+		.maximum = 0xff,
+		.step    = 1,
+		.default_value = 0x40,
+	    },
+	    .set = sd_setcolors,
+	    .get = sd_getcolors,
+	},
+#define SD_HUE 3
+	{
+	    {
+		.id      = V4L2_CID_HUE,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Hue",
+		.minimum = 0,
+		.maximum = 0xff,
+		.step    = 1,
+		.default_value = 0,
+	    },
+	    .set = sd_sethue,
+	    .get = sd_gethue,
+	},
+};
+
+static struct cam_mode vga_mode[] = {
+	{V4L2_PIX_FMT_YUYV, 160, 120, 5},
+	{V4L2_PIX_FMT_YUYV, 176, 144, 4},
+	{V4L2_PIX_FMT_YUYV, 320, 240, 2},
+	{V4L2_PIX_FMT_YUYV, 352, 288, 1},
+	{V4L2_PIX_FMT_YUYV, 640, 480, 0},
+};
+
+#define SPCA50X_OFFSET_DATA 10
+
+#define SAA7113_bright 0x0a	/* defaults 0x80 */
+#define SAA7113_contrast 0x0b	/* defaults 0x47 */
+#define SAA7113_saturation 0x0c	/* defaults 0x40 */
+#define SAA7113_hue 0x0d	/* defaults 0x00 */
+#define SAA7113_I2C_BASE_WRITE 0x4a
+
+static void reg_r(struct usb_device *dev,
+		  __u16 req,
+		  __u16 index,
+		  __u8 *buffer, __u16 length)
+{
+	usb_control_msg(dev,
+			usb_rcvctrlpipe(dev, 0),
+			req,
+			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			0,		/* value */
+			index, buffer, length,
+			500);
+}
+
+static void reg_w(struct usb_device *dev,
+		  __u16 req,
+		  __u16 value,
+		  __u16 index)
+{
+	usb_control_msg(dev,
+			usb_sndctrlpipe(dev, 0),
+			req,
+			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			value, index,
+			NULL, 0, 500);
+}
+
+static void spca506_Initi2c(struct gspca_dev *gspca_dev)
+{
+	reg_w(gspca_dev->dev, 0x07, SAA7113_I2C_BASE_WRITE, 0x0004);
+}
+
+static void spca506_WriteI2c(struct gspca_dev *gspca_dev, __u16 valeur,
+			     __u16 reg)
+{
+	int retry = 60;
+	unsigned char Data[2];
+
+	reg_w(gspca_dev->dev, 0x07, reg, 0x0001);
+	reg_w(gspca_dev->dev, 0x07, valeur, 0x0000);
+	while (retry--) {
+		reg_r(gspca_dev->dev, 0x07, 0x0003, Data, 2);
+		if ((Data[0] | Data[1]) == 0x00)
+			break;
+	}
+}
+
+static int spca506_ReadI2c(struct gspca_dev *gspca_dev, __u16 reg)
+{
+	int retry = 60;
+	unsigned char Data[2];
+	unsigned char value;
+
+	reg_w(gspca_dev->dev, 0x07, SAA7113_I2C_BASE_WRITE, 0x0004);
+	reg_w(gspca_dev->dev, 0x07, reg, 0x0001);
+	reg_w(gspca_dev->dev, 0x07, 0x01, 0x0002);
+	while (--retry) {
+		reg_r(gspca_dev->dev, 0x07, 0x0003, Data, 2);
+		if ((Data[0] | Data[1]) == 0x00)
+			break;
+	}
+	if (retry == 0)
+		return -1;
+	reg_r(gspca_dev->dev, 0x07, 0x0000, &value, 1);
+	return value;
+}
+
+static void spca506_SetNormeInput(struct gspca_dev *gspca_dev,
+				 __u16 norme,
+				 __u16 channel)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+/* fixme: check if channel == 0..3 and 6..9 (8 values) */
+	__u8 setbit0 = 0x00;
+	__u8 setbit1 = 0x00;
+	__u8 videomask = 0x00;
+
+	PDEBUG(D_STREAM, "** Open Set Norme **");
+	spca506_Initi2c(gspca_dev);
+	/* NTSC bit0 -> 1(525 l) PAL SECAM bit0 -> 0 (625 l) */
+	/* Composite channel bit1 -> 1 S-video bit 1 -> 0 */
+	/* and exclude SAA7113 reserved channel set default 0 otherwise */
+	if (norme & V4L2_STD_NTSC)
+		setbit0 = 0x01;
+	if (channel == 4 || channel == 5 || channel > 9)
+		channel = 0;
+	if (channel < 4)
+		setbit1 = 0x02;
+	videomask = (0x48 | setbit0 | setbit1);
+	reg_w(gspca_dev->dev, 0x08, videomask, 0x0000);
+	spca506_WriteI2c(gspca_dev, (0xc0 | (channel & 0x0F)), 0x02);
+
+	if (norme & V4L2_STD_NTSC)
+		spca506_WriteI2c(gspca_dev, 0x33, 0x0e);
+					/* Chrominance Control NTSC N */
+	else if (norme & V4L2_STD_SECAM)
+		spca506_WriteI2c(gspca_dev, 0x53, 0x0e);
+					/* Chrominance Control SECAM */
+	else
+		spca506_WriteI2c(gspca_dev, 0x03, 0x0e);
+					/* Chrominance Control PAL BGHIV */
+
+	sd->norme = norme;
+	sd->channel = channel;
+	PDEBUG(D_STREAM, "Set Video Byte to 0x%2x", videomask);
+	PDEBUG(D_STREAM, "Set Norme: %08x Channel %d", norme, channel);
+}
+
+static void spca506_GetNormeInput(struct gspca_dev *gspca_dev,
+				  __u16 *norme, __u16 *channel)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	/* Read the register is not so good value change so
+	   we use your own copy in spca50x struct */
+	*norme = sd->norme;
+	*channel = sd->channel;
+	PDEBUG(D_STREAM, "Get Norme: %d Channel %d", *norme, *channel);
+}
+
+static void spca506_Setsize(struct gspca_dev *gspca_dev, __u16 code,
+			    __u16 xmult, __u16 ymult)
+{
+	struct usb_device *dev = gspca_dev->dev;
+
+	PDEBUG(D_STREAM, "** SetSize **");
+	reg_w(dev, 0x04, (0x18 | (code & 0x07)), 0x0000);
+	/* Soft snap 0x40 Hard 0x41 */
+	reg_w(dev, 0x04, 0x41, 0x0001);
+	reg_w(dev, 0x04, 0x00, 0x0002);
+	/* reserved */
+	reg_w(dev, 0x04, 0x00, 0x0003);
+
+	/* reserved */
+	reg_w(dev, 0x04, 0x00, 0x0004);
+	/* reserved */
+	reg_w(dev, 0x04, 0x01, 0x0005);
+	/* reserced */
+	reg_w(dev, 0x04, xmult, 0x0006);
+	/* reserved */
+	reg_w(dev, 0x04, ymult, 0x0007);
+	/* compression 1 */
+	reg_w(dev, 0x04, 0x00, 0x0008);
+	/* T=64 -> 2 */
+	reg_w(dev, 0x04, 0x00, 0x0009);
+	/* threshold2D */
+	reg_w(dev, 0x04, 0x21, 0x000a);
+	/* quantization */
+	reg_w(dev, 0x04, 0x00, 0x000b);
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+			const struct usb_device_id *id)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct cam *cam;
+
+	cam = &gspca_dev->cam;
+	cam->dev_name = (char *) id->driver_info;
+	cam->epaddr = 0x01;
+	cam->cam_mode = vga_mode;
+	cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+	sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
+	sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
+	sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value;
+	sd->hue = sd_ctrls[SD_HUE].qctrl.default_value;
+	return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+	struct usb_device *dev = gspca_dev->dev;
+
+	reg_w(dev, 0x03, 0x00, 0x0004);
+	reg_w(dev, 0x03, 0xFF, 0x0003);
+	reg_w(dev, 0x03, 0x00, 0x0000);
+	reg_w(dev, 0x03, 0x1c, 0x0001);
+	reg_w(dev, 0x03, 0x18, 0x0001);
+	/* Init on PAL and composite input0 */
+	spca506_SetNormeInput(gspca_dev, 0, 0);
+	reg_w(dev, 0x03, 0x1c, 0x0001);
+	reg_w(dev, 0x03, 0x18, 0x0001);
+	reg_w(dev, 0x05, 0x00, 0x0000);
+	reg_w(dev, 0x05, 0xef, 0x0001);
+	reg_w(dev, 0x05, 0x00, 0x00c1);
+	reg_w(dev, 0x05, 0x00, 0x00c2);
+	reg_w(dev, 0x06, 0x18, 0x0002);
+	reg_w(dev, 0x06, 0xf5, 0x0011);
+	reg_w(dev, 0x06, 0x02, 0x0012);
+	reg_w(dev, 0x06, 0xfb, 0x0013);
+	reg_w(dev, 0x06, 0x00, 0x0014);
+	reg_w(dev, 0x06, 0xa4, 0x0051);
+	reg_w(dev, 0x06, 0x40, 0x0052);
+	reg_w(dev, 0x06, 0x71, 0x0053);
+	reg_w(dev, 0x06, 0x40, 0x0054);
+	/************************************************/
+	reg_w(dev, 0x03, 0x00, 0x0004);
+	reg_w(dev, 0x03, 0x00, 0x0003);
+	reg_w(dev, 0x03, 0x00, 0x0004);
+	reg_w(dev, 0x03, 0xFF, 0x0003);
+	reg_w(dev, 0x02, 0x00, 0x0000);
+	reg_w(dev, 0x03, 0x60, 0x0000);
+	reg_w(dev, 0x03, 0x18, 0x0001);
+	/* for a better reading mx :)	  */
+	/*sdca506_WriteI2c(value,register) */
+	spca506_Initi2c(gspca_dev);
+	spca506_WriteI2c(gspca_dev, 0x08, 0x01);
+	spca506_WriteI2c(gspca_dev, 0xc0, 0x02);
+						/* input composite video */
+	spca506_WriteI2c(gspca_dev, 0x33, 0x03);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x04);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x05);
+	spca506_WriteI2c(gspca_dev, 0x0d, 0x06);
+	spca506_WriteI2c(gspca_dev, 0xf0, 0x07);
+	spca506_WriteI2c(gspca_dev, 0x98, 0x08);
+	spca506_WriteI2c(gspca_dev, 0x03, 0x09);
+	spca506_WriteI2c(gspca_dev, 0x80, 0x0a);
+	spca506_WriteI2c(gspca_dev, 0x47, 0x0b);
+	spca506_WriteI2c(gspca_dev, 0x48, 0x0c);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x0d);
+	spca506_WriteI2c(gspca_dev, 0x03, 0x0e);	/* Chroma Pal adjust */
+	spca506_WriteI2c(gspca_dev, 0x2a, 0x0f);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x10);
+	spca506_WriteI2c(gspca_dev, 0x0c, 0x11);
+	spca506_WriteI2c(gspca_dev, 0xb8, 0x12);
+	spca506_WriteI2c(gspca_dev, 0x01, 0x13);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x14);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x15);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x16);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x17);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x18);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x19);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x1a);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x1b);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x1c);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x1d);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x1e);
+	spca506_WriteI2c(gspca_dev, 0xa1, 0x1f);
+	spca506_WriteI2c(gspca_dev, 0x02, 0x40);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x41);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x42);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x43);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x44);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x45);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x46);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x47);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x48);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x49);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x4a);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x4b);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x4c);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x4d);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x4e);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x4f);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x50);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x51);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x52);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x53);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x54);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x55);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x56);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x57);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x58);
+	spca506_WriteI2c(gspca_dev, 0x54, 0x59);
+	spca506_WriteI2c(gspca_dev, 0x07, 0x5a);
+	spca506_WriteI2c(gspca_dev, 0x83, 0x5b);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x5c);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x5d);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x5e);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x5f);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x60);
+	spca506_WriteI2c(gspca_dev, 0x05, 0x61);
+	spca506_WriteI2c(gspca_dev, 0x9f, 0x62);
+	PDEBUG(D_STREAM, "** Close Init *");
+	return 0;
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+	struct usb_device *dev = gspca_dev->dev;
+	__u16 norme;
+	__u16 channel;
+	__u8 Data[2];
+
+	/**************************************/
+	reg_w(dev, 0x03, 0x00, 0x0004);
+	reg_w(dev, 0x03, 0x00, 0x0003);
+	reg_w(dev, 0x03, 0x00, 0x0004);
+	reg_w(dev, 0x03, 0xFF, 0x0003);
+	reg_w(dev, 0x02, 0x00, 0x0000);
+	reg_w(dev, 0x03, 0x60, 0x0000);
+	reg_w(dev, 0x03, 0x18, 0x0001);
+
+	/*sdca506_WriteI2c(value,register) */
+	spca506_Initi2c(gspca_dev);
+	spca506_WriteI2c(gspca_dev, 0x08, 0x01);	/* Increment Delay */
+/*	spca506_WriteI2c(gspca_dev, 0xc0, 0x02); * Analog Input Control 1 */
+	spca506_WriteI2c(gspca_dev, 0x33, 0x03);
+						/* Analog Input Control 2 */
+	spca506_WriteI2c(gspca_dev, 0x00, 0x04);
+						/* Analog Input Control 3 */
+	spca506_WriteI2c(gspca_dev, 0x00, 0x05);
+						/* Analog Input Control 4 */
+	spca506_WriteI2c(gspca_dev, 0x0d, 0x06);
+					/* Horizontal Sync Start 0xe9-0x0d */
+	spca506_WriteI2c(gspca_dev, 0xf0, 0x07);
+					/* Horizontal Sync Stop  0x0d-0xf0 */
+
+	spca506_WriteI2c(gspca_dev, 0x98, 0x08);	/* Sync Control */
+/*		Defaults value			*/
+	spca506_WriteI2c(gspca_dev, 0x03, 0x09);	/* Luminance Control */
+	spca506_WriteI2c(gspca_dev, 0x80, 0x0a);
+						/* Luminance Brightness */
+	spca506_WriteI2c(gspca_dev, 0x47, 0x0b);	/* Luminance Contrast */
+	spca506_WriteI2c(gspca_dev, 0x48, 0x0c);
+						/* Chrominance Saturation */
+	spca506_WriteI2c(gspca_dev, 0x00, 0x0d);
+						/* Chrominance Hue Control */
+	spca506_WriteI2c(gspca_dev, 0x2a, 0x0f);
+						/* Chrominance Gain Control */
+	/**************************************/
+	spca506_WriteI2c(gspca_dev, 0x00, 0x10);
+						/* Format/Delay Control */
+	spca506_WriteI2c(gspca_dev, 0x0c, 0x11);	/* Output Control 1 */
+	spca506_WriteI2c(gspca_dev, 0xb8, 0x12);	/* Output Control 2 */
+	spca506_WriteI2c(gspca_dev, 0x01, 0x13);	/* Output Control 3 */
+	spca506_WriteI2c(gspca_dev, 0x00, 0x14);	/* reserved */
+	spca506_WriteI2c(gspca_dev, 0x00, 0x15);	/* VGATE START */
+	spca506_WriteI2c(gspca_dev, 0x00, 0x16);	/* VGATE STOP */
+	spca506_WriteI2c(gspca_dev, 0x00, 0x17);    /* VGATE Control (MSB) */
+	spca506_WriteI2c(gspca_dev, 0x00, 0x18);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x19);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x1a);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x1b);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x1c);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x1d);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x1e);
+	spca506_WriteI2c(gspca_dev, 0xa1, 0x1f);
+	spca506_WriteI2c(gspca_dev, 0x02, 0x40);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x41);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x42);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x43);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x44);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x45);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x46);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x47);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x48);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x49);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x4a);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x4b);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x4c);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x4d);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x4e);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x4f);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x50);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x51);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x52);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x53);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x54);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x55);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x56);
+	spca506_WriteI2c(gspca_dev, 0xff, 0x57);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x58);
+	spca506_WriteI2c(gspca_dev, 0x54, 0x59);
+	spca506_WriteI2c(gspca_dev, 0x07, 0x5a);
+	spca506_WriteI2c(gspca_dev, 0x83, 0x5b);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x5c);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x5d);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x5e);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x5f);
+	spca506_WriteI2c(gspca_dev, 0x00, 0x60);
+	spca506_WriteI2c(gspca_dev, 0x05, 0x61);
+	spca506_WriteI2c(gspca_dev, 0x9f, 0x62);
+	/**************************************/
+	reg_w(dev, 0x05, 0x00, 0x0003);
+	reg_w(dev, 0x05, 0x00, 0x0004);
+	reg_w(dev, 0x03, 0x10, 0x0001);
+	reg_w(dev, 0x03, 0x78, 0x0000);
+	switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].mode) {
+	case 0:
+		spca506_Setsize(gspca_dev, 0, 0x10, 0x10);
+		break;
+	case 1:
+		spca506_Setsize(gspca_dev, 1, 0x1a, 0x1a);
+		break;
+	case 2:
+		spca506_Setsize(gspca_dev, 2, 0x1c, 0x1c);
+		break;
+	case 4:
+		spca506_Setsize(gspca_dev, 4, 0x34, 0x34);
+		break;
+	default:
+/*	case 5: */
+		spca506_Setsize(gspca_dev, 5, 0x40, 0x40);
+		break;
+	}
+
+	/* compress setting and size */
+	/* set i2c luma */
+	reg_w(dev, 0x02, 0x01, 0x0000);
+	reg_w(dev, 0x03, 0x12, 0x000);
+	reg_r(dev, 0x04, 0x0001, Data, 2);
+	PDEBUG(D_STREAM, "webcam started");
+	spca506_GetNormeInput(gspca_dev, &norme, &channel);
+	spca506_SetNormeInput(gspca_dev, norme, channel);
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+	struct usb_device *dev = gspca_dev->dev;
+
+	reg_w(dev, 0x02, 0x00, 0x0000);
+	reg_w(dev, 0x03, 0x00, 0x0004);
+	reg_w(dev, 0x03, 0x00, 0x0003);
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+/* convert YYUV per line to YUYV (YUV 4:2:2) */
+static void yyuv_decode(unsigned char *out,
+			unsigned char *in,
+			int width,
+			int height)
+{
+	unsigned char *Ui, *Vi, *yi, *yi1;
+	unsigned char *out1;
+	int i, j;
+
+	yi = in;
+	for (i = height / 2; --i >= 0; ) {
+		out1 = out + width * 2;		/* next line */
+		yi1 = yi + width;
+		Ui = yi1 + width;
+		Vi = Ui + width / 2;
+		for (j = width / 2; --j >= 0; ) {
+			*out++ = 128 + *yi++;
+			*out++ = 128 + *Ui;
+			*out++ = 128 + *yi++;
+			*out++ = 128 + *Vi;
+
+			*out1++ = 128 + *yi1++;
+			*out1++ = 128 + *Ui++;
+			*out1++ = 128 + *yi1++;
+			*out1++ = 128 + *Vi++;
+		}
+		yi += width * 2;
+		out = out1;
+	}
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+			struct gspca_frame *frame,	/* target */
+			unsigned char *data,		/* isoc packet */
+			int len)			/* iso packet length */
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	switch (data[0]) {
+	case 0:				/* start of frame */
+		if (gspca_dev->last_packet_type == FIRST_PACKET) {
+			yyuv_decode(sd->tmpbuf2, sd->tmpbuf,
+					gspca_dev->width,
+					gspca_dev->height);
+			frame = gspca_frame_add(gspca_dev,
+						LAST_PACKET,
+						frame,
+						sd->tmpbuf2,
+						gspca_dev->width
+							* gspca_dev->height
+							* 2);
+		}
+		gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+				data, 0);
+		data += SPCA50X_OFFSET_DATA;
+		len -= SPCA50X_OFFSET_DATA;
+		if (len > 0)
+			memcpy(sd->tmpbuf, data, len);
+		else
+			len = 0;
+		sd->buflen = len;
+		return;
+	case 0xff:			/* drop */
+/*		gspca_dev->last_packet_type = DISCARD_PACKET; */
+		return;
+	}
+	data += 1;
+	len -= 1;
+	memcpy(&sd->tmpbuf[sd->buflen], data, len);
+	sd->buflen += len;
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	spca506_Initi2c(gspca_dev);
+	spca506_WriteI2c(gspca_dev, sd->brightness, SAA7113_bright);
+	spca506_WriteI2c(gspca_dev, 0x01, 0x09);
+}
+
+static void getbrightness(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->brightness = spca506_ReadI2c(gspca_dev, SAA7113_bright);
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	spca506_Initi2c(gspca_dev);
+	spca506_WriteI2c(gspca_dev, sd->contrast, SAA7113_contrast);
+	spca506_WriteI2c(gspca_dev, 0x01, 0x09);
+}
+
+static void getcontrast(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->contrast = spca506_ReadI2c(gspca_dev, SAA7113_contrast);
+}
+
+static void setcolors(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	spca506_Initi2c(gspca_dev);
+	spca506_WriteI2c(gspca_dev, sd->colors, SAA7113_saturation);
+	spca506_WriteI2c(gspca_dev, 0x01, 0x09);
+}
+
+static void getcolors(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->colors = spca506_ReadI2c(gspca_dev, SAA7113_saturation);
+}
+
+static void sethue(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	spca506_Initi2c(gspca_dev);
+	spca506_WriteI2c(gspca_dev, sd->hue, SAA7113_hue);
+	spca506_WriteI2c(gspca_dev, 0x01, 0x09);
+}
+
+static void gethue(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->hue = spca506_ReadI2c(gspca_dev, SAA7113_hue);
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->brightness = val;
+	if (gspca_dev->streaming)
+		setbrightness(gspca_dev);
+	return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	getbrightness(gspca_dev);
+	*val = sd->brightness;
+	return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->contrast = val;
+	if (gspca_dev->streaming)
+		setcontrast(gspca_dev);
+	return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	getcontrast(gspca_dev);
+	*val = sd->contrast;
+	return 0;
+}
+
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->colors = val;
+	if (gspca_dev->streaming)
+		setcolors(gspca_dev);
+	return 0;
+}
+
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	getcolors(gspca_dev);
+	*val = sd->colors;
+	return 0;
+}
+
+static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->hue = val;
+	if (gspca_dev->streaming)
+		sethue(gspca_dev);
+	return 0;
+}
+
+static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	gethue(gspca_dev);
+	*val = sd->hue;
+	return 0;
+}
+
+/* sub-driver description */
+static struct sd_desc sd_desc = {
+	.name = MODULE_NAME,
+	.ctrls = sd_ctrls,
+	.nctrls = ARRAY_SIZE(sd_ctrls),
+	.config = sd_config,
+	.open = sd_open,
+	.start = sd_start,
+	.stopN = sd_stopN,
+	.stop0 = sd_stop0,
+	.close = sd_close,
+	.pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static __devinitdata struct usb_device_id device_table[] = {
+	{USB_DEVICE(0x06e1, 0xa190), DVNM("ADS Instant VCD")},
+/*	{USB_DEVICE(0x0733, 0x0430), DVNM("UsbGrabber PV321c")}, */
+	{USB_DEVICE(0x0734, 0x043b), DVNM("3DeMon USB Capture aka")},
+	{USB_DEVICE(0x99fa, 0x8988), DVNM("Grandtec V.cap")},
+	{}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+			const struct usb_device_id *id)
+{
+	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+				THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+	.name = MODULE_NAME,
+	.id_table = device_table,
+	.probe = sd_probe,
+	.disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+	if (usb_register(&sd_driver) < 0)
+		return -1;
+	PDEBUG(D_PROBE, "v%s registered", version);
+	return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+	usb_deregister(&sd_driver);
+	PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/spca508.c b/drivers/media/video/gspca/spca508.c
new file mode 100644
index 0000000..566adf4
--- /dev/null
+++ b/drivers/media/video/gspca/spca508.c
@@ -0,0 +1,1774 @@
+/*
+ * SPCA508 chip based cameras subdriver
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define MODULE_NAME "spca508"
+
+#include "gspca.h"
+
+#define DRIVER_VERSION_NUMBER	KERNEL_VERSION(2, 1, 0)
+static const char version[] = "2.1.0";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("GSPCA/SPCA508 USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+	struct gspca_dev gspca_dev;		/* !! must be the first item */
+
+	int buflen;
+	unsigned char tmpbuf[352 * 288 * 3 / 2]; /* YUVY per line */
+	unsigned char tmpbuf2[352 * 288 * 2];	/* YUYV */
+
+	unsigned char brightness;
+
+	char subtype;
+#define CreativeVista 0
+#define HamaUSBSightcam 1
+#define HamaUSBSightcam2 2
+#define IntelEasyPCCamera 3
+#define MicroInnovationIC200 4
+#define ViewQuestVQ110 5
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+#define SD_BRIGHTNESS 0
+	{
+	    {
+		.id      = V4L2_CID_BRIGHTNESS,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Brightness",
+		.minimum = 0,
+		.maximum = 0xff,
+		.step    = 1,
+		.default_value = 0x80,
+	    },
+	    .set = sd_setbrightness,
+	    .get = sd_getbrightness,
+	},
+};
+
+static struct cam_mode sif_mode[] = {
+	{V4L2_PIX_FMT_YUYV, 160, 120, 3},
+	{V4L2_PIX_FMT_YUYV, 176, 144, 2},
+	{V4L2_PIX_FMT_YUYV, 320, 240, 1},
+	{V4L2_PIX_FMT_YUYV, 352, 288, 0},
+};
+
+/* Frame packet header offsets for the spca508 */
+#define SPCA508_OFFSET_TYPE 1
+#define SPCA508_OFFSET_COMPRESS 2
+#define SPCA508_OFFSET_FRAMSEQ 8
+#define SPCA508_OFFSET_WIN1LUM 11
+#define SPCA508_OFFSET_DATA 37
+
+#define SPCA508_SNAPBIT 0x20
+#define SPCA508_SNAPCTRL 0x40
+/*************** I2c ****************/
+#define SPCA508_INDEX_I2C_BASE 0x8800
+
+/*
+ * Initialization data: this is the first set-up data written to the
+ * device (before the open data).
+ */
+static __u16 spca508_init_data[][3] =
+#define IGN(x)			/* nothing */
+{
+	/*  line   URB      value, index */
+	/* 44274  1804 */ {0x0000, 0x870b},
+
+	/* 44299  1805 */ {0x0020, 0x8112},
+	/* Video drop enable, ISO streaming disable */
+	/* 44324  1806 */ {0x0003, 0x8111},
+	/* Reset compression & memory */
+	/* 44349  1807 */ {0x0000, 0x8110},
+	/* Disable all outputs */
+	/* 44372  1808 */ /* READ {0x0000, 0x8114} -> 0000: 00  */
+	/* 44398  1809 */ {0x0000, 0x8114},
+	/* SW GPIO data */
+	/* 44423  1810 */ {0x0008, 0x8110},
+	/* Enable charge pump output */
+	/* 44527  1811 */ {0x0002, 0x8116},
+	/* 200 kHz pump clock */
+	/* 44555  1812 */
+		/* UNKNOWN DIRECTION (URB_FUNCTION_SELECT_INTERFACE:) */
+	/* 44590  1813 */ {0x0003, 0x8111},
+	/* Reset compression & memory */
+	/* 44615  1814 */ {0x0000, 0x8111},
+	/* Normal mode (not reset) */
+	/* 44640  1815 */ {0x0098, 0x8110},
+	/* Enable charge pump output, sync.serial,external 2x clock */
+	/* 44665  1816 */ {0x000d, 0x8114},
+	/* SW GPIO data */
+	/* 44690  1817 */ {0x0002, 0x8116},
+	/* 200 kHz pump clock */
+	/* 44715  1818 */ {0x0020, 0x8112},
+	/* Video drop enable, ISO streaming disable */
+/* --------------------------------------- */
+	/* 44740  1819 */ {0x000f, 0x8402},
+	/* memory bank */
+	/* 44765  1820 */ {0x0000, 0x8403},
+	/* ... address */
+/* --------------------------------------- */
+/* 0x88__ is Synchronous Serial Interface. */
+/* TBD: This table could be expressed more compactly */
+/* using spca508_write_i2c_vector(). */
+/* TBD: Should see if the values in spca50x_i2c_data */
+/* would work with the VQ110 instead of the values */
+/* below. */
+	/* 44790  1821 */ {0x00c0, 0x8804},
+	/* SSI slave addr */
+	/* 44815  1822 */ {0x0008, 0x8802},
+	/* 375 Khz SSI clock */
+	/* 44838  1823 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 44862  1824 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 44888  1825 */ {0x0008, 0x8802},
+	/* 375 Khz SSI clock */
+	/* 44913  1826 */ {0x0012, 0x8801},
+	/* SSI reg addr */
+	/* 44938  1827 */ {0x0080, 0x8800},
+	/* SSI data to write */
+	/* 44961  1828 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 44985  1829 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 45009  1830 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 45035  1831 */ {0x0008, 0x8802},
+	/* 375 Khz SSI clock */
+	/* 45060  1832 */ {0x0012, 0x8801},
+	/* SSI reg addr */
+	/* 45085  1833 */ {0x0000, 0x8800},
+	/* SSI data to write */
+	/* 45108  1834 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 45132  1835 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 45156  1836 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 45182  1837 */ {0x0008, 0x8802},
+	/* 375 Khz SSI clock */
+	/* 45207  1838 */ {0x0011, 0x8801},
+	/* SSI reg addr */
+	/* 45232  1839 */ {0x0040, 0x8800},
+	/* SSI data to write */
+	/* 45255  1840 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 45279  1841 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 45303  1842 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 45329  1843 */ {0x0008, 0x8802},
+	/* 45354  1844 */ {0x0013, 0x8801},
+	/* 45379  1845 */ {0x0000, 0x8800},
+	/* 45402  1846 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 45426  1847 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 45450  1848 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 45476  1849 */ {0x0008, 0x8802},
+	/* 45501  1850 */ {0x0014, 0x8801},
+	/* 45526  1851 */ {0x0000, 0x8800},
+	/* 45549  1852 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 45573  1853 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 45597  1854 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 45623  1855 */ {0x0008, 0x8802},
+	/* 45648  1856 */ {0x0015, 0x8801},
+	/* 45673  1857 */ {0x0001, 0x8800},
+	/* 45696  1858 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 45720  1859 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 45744  1860 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 45770  1861 */ {0x0008, 0x8802},
+	/* 45795  1862 */ {0x0016, 0x8801},
+	/* 45820  1863 */ {0x0003, 0x8800},
+	/* 45843  1864 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 45867  1865 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 45891  1866 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 45917  1867 */ {0x0008, 0x8802},
+	/* 45942  1868 */ {0x0017, 0x8801},
+	/* 45967  1869 */ {0x0036, 0x8800},
+	/* 45990  1870 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 46014  1871 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 46038  1872 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 46064  1873 */ {0x0008, 0x8802},
+	/* 46089  1874 */ {0x0018, 0x8801},
+	/* 46114  1875 */ {0x00ec, 0x8800},
+	/* 46137  1876 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 46161  1877 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 46185  1878 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 46211  1879 */ {0x0008, 0x8802},
+	/* 46236  1880 */ {0x001a, 0x8801},
+	/* 46261  1881 */ {0x0094, 0x8800},
+	/* 46284  1882 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 46308  1883 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 46332  1884 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 46358  1885 */ {0x0008, 0x8802},
+	/* 46383  1886 */ {0x001b, 0x8801},
+	/* 46408  1887 */ {0x0000, 0x8800},
+	/* 46431  1888 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 46455  1889 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 46479  1890 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 46505  1891 */ {0x0008, 0x8802},
+	/* 46530  1892 */ {0x0027, 0x8801},
+	/* 46555  1893 */ {0x00a2, 0x8800},
+	/* 46578  1894 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 46602  1895 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 46626  1896 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 46652  1897 */ {0x0008, 0x8802},
+	/* 46677  1898 */ {0x0028, 0x8801},
+	/* 46702  1899 */ {0x0040, 0x8800},
+	/* 46725  1900 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 46749  1901 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 46773  1902 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 46799  1903 */ {0x0008, 0x8802},
+	/* 46824  1904 */ {0x002a, 0x8801},
+	/* 46849  1905 */ {0x0084, 0x8800},
+	/* 46872  1906 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 46896  1907 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+	/* 46920  1908 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 46946  1909 */ {0x0008, 0x8802},
+	/* 46971  1910 */ {0x002b, 0x8801},
+	/* 46996  1911 */ {0x00a8, 0x8800},
+	/* 47019  1912 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 47043  1913 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 47067  1914 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 47093  1915 */ {0x0008, 0x8802},
+	/* 47118  1916 */ {0x002c, 0x8801},
+	/* 47143  1917 */ {0x00fe, 0x8800},
+	/* 47166  1918 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 47190  1919 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 47214  1920 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 47240  1921 */ {0x0008, 0x8802},
+	/* 47265  1922 */ {0x002d, 0x8801},
+	/* 47290  1923 */ {0x0003, 0x8800},
+	/* 47313  1924 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 47337  1925 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 47361  1926 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 47387  1927 */ {0x0008, 0x8802},
+	/* 47412  1928 */ {0x0038, 0x8801},
+	/* 47437  1929 */ {0x0083, 0x8800},
+	/* 47460  1930 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 47484  1931 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 47508  1932 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 47534  1933 */ {0x0008, 0x8802},
+	/* 47559  1934 */ {0x0033, 0x8801},
+	/* 47584  1935 */ {0x0081, 0x8800},
+	/* 47607  1936 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 47631  1937 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 47655  1938 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 47681  1939 */ {0x0008, 0x8802},
+	/* 47706  1940 */ {0x0034, 0x8801},
+	/* 47731  1941 */ {0x004a, 0x8800},
+	/* 47754  1942 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 47778  1943 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 47802  1944 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 47828  1945 */ {0x0008, 0x8802},
+	/* 47853  1946 */ {0x0039, 0x8801},
+	/* 47878  1947 */ {0x0000, 0x8800},
+	/* 47901  1948 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 47925  1949 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 47949  1950 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 47975  1951 */ {0x0008, 0x8802},
+	/* 48000  1952 */ {0x0010, 0x8801},
+	/* 48025  1953 */ {0x00a8, 0x8800},
+	/* 48048  1954 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 48072  1955 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 48096  1956 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 48122  1957 */ {0x0008, 0x8802},
+	/* 48147  1958 */ {0x0006, 0x8801},
+	/* 48172  1959 */ {0x0058, 0x8800},
+	/* 48195  1960 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 48219  1961 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+	/* 48243  1962 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 48269  1963 */ {0x0008, 0x8802},
+	/* 48294  1964 */ {0x0000, 0x8801},
+	/* 48319  1965 */ {0x0004, 0x8800},
+	/* 48342  1966 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 48366  1967 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 48390  1968 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 48416  1969 */ {0x0008, 0x8802},
+	/* 48441  1970 */ {0x0040, 0x8801},
+	/* 48466  1971 */ {0x0080, 0x8800},
+	/* 48489  1972 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 48513  1973 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 48537  1974 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 48563  1975 */ {0x0008, 0x8802},
+	/* 48588  1976 */ {0x0041, 0x8801},
+	/* 48613  1977 */ {0x000c, 0x8800},
+	/* 48636  1978 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 48660  1979 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 48684  1980 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 48710  1981 */ {0x0008, 0x8802},
+	/* 48735  1982 */ {0x0042, 0x8801},
+	/* 48760  1983 */ {0x000c, 0x8800},
+	/* 48783  1984 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 48807  1985 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 48831  1986 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 48857  1987 */ {0x0008, 0x8802},
+	/* 48882  1988 */ {0x0043, 0x8801},
+	/* 48907  1989 */ {0x0028, 0x8800},
+	/* 48930  1990 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 48954  1991 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 48978  1992 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 49004  1993 */ {0x0008, 0x8802},
+	/* 49029  1994 */ {0x0044, 0x8801},
+	/* 49054  1995 */ {0x0080, 0x8800},
+	/* 49077  1996 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 49101  1997 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 49125  1998 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 49151  1999 */ {0x0008, 0x8802},
+	/* 49176  2000 */ {0x0045, 0x8801},
+	/* 49201  2001 */ {0x0020, 0x8800},
+	/* 49224  2002 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 49248  2003 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 49272  2004 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 49298  2005 */ {0x0008, 0x8802},
+	/* 49323  2006 */ {0x0046, 0x8801},
+	/* 49348  2007 */ {0x0020, 0x8800},
+	/* 49371  2008 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 49395  2009 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 49419  2010 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 49445  2011 */ {0x0008, 0x8802},
+	/* 49470  2012 */ {0x0047, 0x8801},
+	/* 49495  2013 */ {0x0080, 0x8800},
+	/* 49518  2014 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 49542  2015 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 49566  2016 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 49592  2017 */ {0x0008, 0x8802},
+	/* 49617  2018 */ {0x0048, 0x8801},
+	/* 49642  2019 */ {0x004c, 0x8800},
+	/* 49665  2020 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 49689  2021 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 49713  2022 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 49739  2023 */ {0x0008, 0x8802},
+	/* 49764  2024 */ {0x0049, 0x8801},
+	/* 49789  2025 */ {0x0084, 0x8800},
+	/* 49812  2026 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 49836  2027 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 49860  2028 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 49886  2029 */ {0x0008, 0x8802},
+	/* 49911  2030 */ {0x004a, 0x8801},
+	/* 49936  2031 */ {0x0084, 0x8800},
+	/* 49959  2032 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 49983  2033 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 50007  2034 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 50033  2035 */ {0x0008, 0x8802},
+	/* 50058  2036 */ {0x004b, 0x8801},
+	/* 50083  2037 */ {0x0084, 0x8800},
+	/* 50106  2038 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* --------------------------------------- */
+	/* 50132  2039 */ {0x0012, 0x8700},
+	/* Clock speed 48Mhz/(2+2)/2= 6 Mhz */
+	/* 50157  2040 */ {0x0000, 0x8701},
+	/* CKx1 clock delay adj */
+	/* 50182  2041 */ {0x0000, 0x8701},
+	/* CKx1 clock delay adj */
+	/* 50207  2042 */ {0x0001, 0x870c},
+	/* CKOx2 output */
+	/* --------------------------------------- */
+	/* 50232  2043 */ {0x0080, 0x8600},
+	/* Line memory read counter (L) */
+	/* 50257  2044 */ {0x0001, 0x8606},
+	/* reserved */
+	/* 50282  2045 */ {0x0064, 0x8607},
+	/* Line memory read counter (H) 0x6480=25,728 */
+	/* 50307  2046 */ {0x002a, 0x8601},
+	/* CDSP sharp interpolation mode,
+	 *			line sel for color sep, edge enhance enab */
+	/* 50332  2047 */ {0x0000, 0x8602},
+	/* optical black level for user settng = 0 */
+	/* 50357  2048 */ {0x0080, 0x8600},
+	/* Line memory read counter (L) */
+	/* 50382  2049 */ {0x000a, 0x8603},
+	/* optical black level calc mode: auto; optical black offset = 10 */
+	/* 50407  2050 */ {0x00df, 0x865b},
+	/* Horiz offset for valid pixels (L)=0xdf */
+	/* 50432  2051 */ {0x0012, 0x865c},
+	/* Vert offset for valid lines (L)=0x12 */
+
+/* The following two lines seem to be the "wrong" resolution. */
+/* But perhaps these indicate the actual size of the sensor */
+/* rather than the size of the current video mode. */
+	/* 50457  2052 */ {0x0058, 0x865d},
+	/* Horiz valid pixels (*4) (L) = 352 */
+	/* 50482  2053 */ {0x0048, 0x865e},
+	/* Vert valid lines (*4) (L) = 288 */
+
+	/* 50507  2054 */ {0x0015, 0x8608},
+	/* A11 Coef ... */
+	/* 50532  2055 */ {0x0030, 0x8609},
+	/* 50557  2056 */ {0x00fb, 0x860a},
+	/* 50582  2057 */ {0x003e, 0x860b},
+	/* 50607  2058 */ {0x00ce, 0x860c},
+	/* 50632  2059 */ {0x00f4, 0x860d},
+	/* 50657  2060 */ {0x00eb, 0x860e},
+	/* 50682  2061 */ {0x00dc, 0x860f},
+	/* 50707  2062 */ {0x0039, 0x8610},
+	/* 50732  2063 */ {0x0001, 0x8611},
+	/* R offset for white balance ... */
+	/* 50757  2064 */ {0x0000, 0x8612},
+	/* 50782  2065 */ {0x0001, 0x8613},
+	/* 50807  2066 */ {0x0000, 0x8614},
+	/* 50832  2067 */ {0x005b, 0x8651},
+	/* R gain for white balance ... */
+	/* 50857  2068 */ {0x0040, 0x8652},
+	/* 50882  2069 */ {0x0060, 0x8653},
+	/* 50907  2070 */ {0x0040, 0x8654},
+	/* 50932  2071 */ {0x0000, 0x8655},
+	/* 50957  2072 */ {0x0001, 0x863f},
+	/* Fixed gamma correction enable, USB control,
+	 *			 lum filter disable, lum noise clip disable */
+	/* 50982  2073 */ {0x00a1, 0x8656},
+	/* Window1 size 256x256, Windows2 size 64x64,
+	 *		 gamma look-up disable, new edge enhancement enable */
+	/* 51007  2074 */ {0x0018, 0x8657},
+	/* Edge gain high thresh */
+	/* 51032  2075 */ {0x0020, 0x8658},
+	/* Edge gain low thresh */
+	/* 51057  2076 */ {0x000a, 0x8659},
+	/* Edge bandwidth high threshold */
+	/* 51082  2077 */ {0x0005, 0x865a},
+	/* Edge bandwidth low threshold */
+	/* -------------------------------- */
+	/* 51107  2078 */ {0x0030, 0x8112},
+	/* Video drop enable, ISO streaming enable */
+	/* 51130  2079 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 51154  2080 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 51180  2081 */ {0xa908, 0x8802},
+	/* 51205  2082 */ {0x0034, 0x8801},
+	/* SSI reg addr */
+	/* 51230  2083 */ {0x00ca, 0x8800},
+	/* SSI data to write */
+	/* 51253  2084 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 51277  2085 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 51301  2086 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 51327  2087 */ {0x1f08, 0x8802},
+	/* 51352  2088 */ {0x0006, 0x8801},
+	/* 51377  2089 */ {0x0080, 0x8800},
+	/* 51400  2090 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+
+/* ----- Read back coefs we wrote earlier. */
+	/* 51424  2091 */ /* READ { 0, 0x0000, 0x8608 } -> 0000: 15  */
+	/* 51448  2092 */ /* READ { 0, 0x0000, 0x8609 } -> 0000: 30  */
+	/* 51472  2093 */ /* READ { 0, 0x0000, 0x860a } -> 0000: fb  */
+	/* 51496  2094 */ /* READ { 0, 0x0000, 0x860b } -> 0000: 3e  */
+	/* 51520  2095 */ /* READ { 0, 0x0000, 0x860c } -> 0000: ce  */
+	/* 51544  2096 */ /* READ { 0, 0x0000, 0x860d } -> 0000: f4  */
+	/* 51568  2097 */ /* READ { 0, 0x0000, 0x860e } -> 0000: eb  */
+	/* 51592  2098 */ /* READ { 0, 0x0000, 0x860f } -> 0000: dc  */
+	/* 51616  2099 */ /* READ { 0, 0x0000, 0x8610 } -> 0000: 39  */
+	/* 51640  2100 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 51664  2101 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
+	/* 51690  2102 */ {0xb008, 0x8802},
+	/* 51715  2103 */ {0x0006, 0x8801},
+	/* 51740  2104 */ {0x007d, 0x8800},
+	/* 51763  2105 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+
+
+	/* This chunk is seemingly redundant with */
+	/* earlier commands (A11 Coef...), but if I disable it, */
+	/* the image appears too dark.  Maybe there was some kind of */
+	/* reset since the earlier commands, so this is necessary again. */
+	/* 51789  2106 */ {0x0015, 0x8608},
+	/* 51814  2107 */ {0x0030, 0x8609},
+	/* 51839  2108 */ {0xfffb, 0x860a},
+	/* 51864  2109 */ {0x003e, 0x860b},
+	/* 51889  2110 */ {0xffce, 0x860c},
+	/* 51914  2111 */ {0xfff4, 0x860d},
+	/* 51939  2112 */ {0xffeb, 0x860e},
+	/* 51964  2113 */ {0xffdc, 0x860f},
+	/* 51989  2114 */ {0x0039, 0x8610},
+	/* 52014  2115 */ {0x0018, 0x8657},
+
+	/* 52039  2116 */ {0x0000, 0x8508},
+	/* Disable compression. */
+	/* Previous line was:
+	 * 52039  2116 *  { 0, 0x0021, 0x8508 },  * Enable compression. */
+	/* 52064  2117 */ {0x0032, 0x850b},
+	/* compression stuff */
+	/* 52089  2118 */ {0x0003, 0x8509},
+	/* compression stuff */
+	/* 52114  2119 */ {0x0011, 0x850a},
+	/* compression stuff */
+	/* 52139  2120 */ {0x0021, 0x850d},
+	/* compression stuff */
+	/* 52164  2121 */ {0x0010, 0x850c},
+	/* compression stuff */
+	/* 52189  2122 */ {0x0003, 0x8500},
+	/* *** Video mode: 160x120 */
+	/* 52214  2123 */ {0x0001, 0x8501},
+	/* Hardware-dominated snap control */
+	/* 52239  2124 */ {0x0061, 0x8656},
+	/* Window1 size 128x128, Windows2 size 128x128,
+	 *		gamma look-up disable, new edge enhancement enable */
+	/* 52264  2125 */ {0x0018, 0x8617},
+	/* Window1 start X (*2) */
+	/* 52289  2126 */ {0x0008, 0x8618},
+	/* Window1 start Y (*2) */
+	/* 52314  2127 */ {0x0061, 0x8656},
+	/* Window1 size 128x128, Windows2 size 128x128,
+	 *		gamma look-up disable, new edge enhancement enable */
+	/* 52339  2128 */ {0x0058, 0x8619},
+	/* Window2 start X (*2) */
+	/* 52364  2129 */ {0x0008, 0x861a},
+	/* Window2 start Y (*2) */
+	/* 52389  2130 */ {0x00ff, 0x8615},
+	/* High lum thresh for white balance */
+	/* 52414  2131 */ {0x0000, 0x8616},
+	/* Low lum thresh for white balance */
+	/* 52439  2132 */ {0x0012, 0x8700},
+	/* Clock speed 48Mhz/(2+2)/2= 6 Mhz */
+	/* 52464  2133 */ {0x0012, 0x8700},
+	/* Clock speed 48Mhz/(2+2)/2= 6 Mhz */
+	/* 52487  2134 */ /* READ { 0, 0x0000, 0x8656 } -> 0000: 61  */
+	/* 52513  2135 */ {0x0028, 0x8802},
+	/* 375 Khz SSI clock, SSI r/w sync with VSYNC */
+	/* 52536  2136 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 52560  2137 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 28  */
+	/* 52586  2138 */ {0x1f28, 0x8802},
+	/* 375 Khz SSI clock, SSI r/w sync with VSYNC */
+	/* 52611  2139 */ {0x0010, 0x8801},
+	/* SSI reg addr */
+	/* 52636  2140 */ {0x003e, 0x8800},
+	/* SSI data to write */
+	/* 52659  2141 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 52685  2142 */ {0x0028, 0x8802},
+	/* 52708  2143 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 52732  2144 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 28  */
+	/* 52758  2145 */ {0x1f28, 0x8802},
+	/* 52783  2146 */ {0x0000, 0x8801},
+	/* 52808  2147 */ {0x001f, 0x8800},
+	/* 52831  2148 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 52857  2149 */ {0x0001, 0x8602},
+	/* optical black level for user settning = 1 */
+
+	/* Original: */
+	/* 52882  2150 */ {0x0023, 0x8700},
+	/* Clock speed 48Mhz/(3+2)/4= 2.4 Mhz */
+	/* 52907  2151 */ {0x000f, 0x8602},
+	/* optical black level for user settning = 15 */
+
+	/* 52932  2152 */ {0x0028, 0x8802},
+	/* 52955  2153 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 52979  2154 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 28  */
+	/* 53005  2155 */ {0x1f28, 0x8802},
+	/* 53030  2156 */ {0x0010, 0x8801},
+	/* 53055  2157 */ {0x007b, 0x8800},
+	/* 53078  2158 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+	/* 53104  2159 */ {0x002f, 0x8651},
+	/* R gain for white balance ... */
+	/* 53129  2160 */ {0x0080, 0x8653},
+	/* 53152  2161 */ /* READ { 0, 0x0000, 0x8655 } -> 0000: 00  */
+	/* 53178  2162 */ {0x0000, 0x8655},
+
+	/* 53203  2163 */ {0x0030, 0x8112},
+	/* Video drop enable, ISO streaming enable */
+	/* 53228  2164 */ {0x0020, 0x8112},
+	/* Video drop enable, ISO streaming disable */
+	/* 53252  2165 */
+	     /* UNKNOWN DIRECTION (URB_FUNCTION_SELECT_INTERFACE: (ALT=0) ) */
+	{0, 0}
+};
+
+
+/*
+ * Initialization data for Intel EasyPC Camera CS110
+ */
+static __u16 spca508cs110_init_data[][3] = {
+	{0x0000, 0x870b}, /* Reset CTL3 */
+	{0x0003, 0x8111}, /* Soft Reset compression, memory, TG & CDSP */
+	{0x0000, 0x8111}, /* Normal operation on reset */
+	{0x0090, 0x8110},
+		 /* External Clock 2x & Synchronous Serial Interface Output */
+	{0x0020, 0x8112}, /* Video Drop packet enable */
+	{0x0000, 0x8114}, /* Software GPIO output data */
+	{0x0001, 0x8114},
+	{0x0001, 0x8114},
+	{0x0001, 0x8114},
+	{0x0003, 0x8114},
+
+	/* Initial sequence Synchronous Serial Interface */
+	{0x000f, 0x8402}, /* Memory bank Address */
+	{0x0000, 0x8403}, /* Memory bank Address */
+	{0x00ba, 0x8804}, /* SSI Slave address */
+	{0x0010, 0x8802}, /* 93.75kHz SSI Clock Two DataByte */
+	{0x0010, 0x8802}, /* 93.75kHz SSI Clock two DataByte */
+
+	{0x0001, 0x8801},
+	{0x000a, 0x8805},/* a - NWG: Dunno what this is about */
+	{0x0000, 0x8800},
+	{0x0010, 0x8802},
+
+	{0x0002, 0x8801},
+	{0x0000, 0x8805},
+	{0x0000, 0x8800},
+	{0x0010, 0x8802},
+
+	{0x0003, 0x8801},
+	{0x0027, 0x8805},
+	{0x0001, 0x8800},
+	{0x0010, 0x8802},
+
+	{0x0004, 0x8801},
+	{0x0065, 0x8805},
+	{0x0001, 0x8800},
+	{0x0010, 0x8802},
+
+	{0x0005, 0x8801},
+	{0x0003, 0x8805},
+	{0x0000, 0x8800},
+	{0x0010, 0x8802},
+
+	{0x0006, 0x8801},
+	{0x001c, 0x8805},
+	{0x0000, 0x8800},
+	{0x0010, 0x8802},
+
+	{0x0007, 0x8801},
+	{0x002a, 0x8805},
+	{0x0000, 0x8800},
+	{0x0010, 0x8802},
+
+	{0x0002, 0x8704}, /* External input CKIx1 */
+	{0x0001, 0x8606}, /* 1 Line memory Read Counter (H) Result: (d)410 */
+	{0x009a, 0x8600}, /* Line memory Read Counter (L) */
+	{0x0001, 0x865b}, /* 1 Horizontal Offset for Valid Pixel(L) */
+	{0x0003, 0x865c}, /* 3 Vertical Offset for Valid Lines(L) */
+	{0x0058, 0x865d}, /* 58 Horizontal Valid Pixel Window(L) */
+
+	{0x0006, 0x8660}, /* Nibble data + input order */
+
+	{0x000a, 0x8602}, /* Optical black level set to 0x0a */
+/* 1945 */ {0x0000, 0x8603}, /* Optical black level Offset */
+
+/* 1962 *  {0, 0x0000, 0x8611},  * 0 R  Offset for white Balance */
+/* 1963 *  {0, 0x0000, 0x8612},  * 1 Gr Offset for white Balance */
+/* 1964 *  {0, 0x0000, 0x8613},  * 1f B  Offset for white Balance */
+/* 1965 *  {0, 0x0000, 0x8614},  * f0 Gb Offset for white Balance */
+
+	{0x0040, 0x8651}, /* 2b BLUE gain for white balance  good at all 60 */
+	{0x0030, 0x8652}, /* 41 Gr Gain for white Balance (L) */
+	{0x0035, 0x8653}, /* 26 RED gain for white balance */
+	{0x0035, 0x8654}, /* 40Gb Gain for white Balance (L) */
+	{0x0041, 0x863f},
+	      /* Fixed Gamma correction enabled (makes colours look better) */
+
+/* 2422 */ {0x0000, 0x8655},
+	/* High bits for white balance*****brightness control*** */
+	{}
+};
+
+static __u16 spca508_sightcam_init_data[][3] = {
+/* This line seems to setup the frame/canvas */
+	/*368  */ {0x000f, 0x8402},
+
+/* Theese 6 lines are needed to startup the webcam */
+	/*398  */ {0x0090, 0x8110},
+	/*399  */ {0x0001, 0x8114},
+	/*400  */ {0x0001, 0x8114},
+	/*401  */ {0x0001, 0x8114},
+	/*402  */ {0x0003, 0x8114},
+	/*403  */ {0x0080, 0x8804},
+
+/* This part seems to make the pictures darker? (autobrightness?) */
+	/*436  */ {0x0001, 0x8801},
+	/*437  */ {0x0004, 0x8800},
+	/*439  */ {0x0003, 0x8801},
+	/*440  */ {0x00e0, 0x8800},
+	/*442  */ {0x0004, 0x8801},
+	/*443  */ {0x00b4, 0x8800},
+	/*445  */ {0x0005, 0x8801},
+	/*446  */ {0x0000, 0x8800},
+
+	/*448  */ {0x0006, 0x8801},
+	/*449  */ {0x00e0, 0x8800},
+	/*451  */ {0x0007, 0x8801},
+	/*452  */ {0x000c, 0x8800},
+
+/* This section is just needed, it probably
+ * does something like the previous section,
+ * but the cam won't start if it's not included.
+ */
+	/*484  */ {0x0014, 0x8801},
+	/*485  */ {0x0008, 0x8800},
+	/*487  */ {0x0015, 0x8801},
+	/*488  */ {0x0067, 0x8800},
+	/*490  */ {0x0016, 0x8801},
+	/*491  */ {0x0000, 0x8800},
+	/*493  */ {0x0017, 0x8801},
+	/*494  */ {0x0020, 0x8800},
+	/*496  */ {0x0018, 0x8801},
+	/*497  */ {0x0044, 0x8800},
+
+/* Makes the picture darker - and the
+ * cam won't start if not included
+ */
+	/*505  */ {0x001e, 0x8801},
+	/*506  */ {0x00ea, 0x8800},
+	/*508  */ {0x001f, 0x8801},
+	/*509  */ {0x0001, 0x8800},
+	/*511  */ {0x0003, 0x8801},
+	/*512  */ {0x00e0, 0x8800},
+
+/* seems to place the colors ontop of each other #1 */
+	/*517  */ {0x0006, 0x8704},
+	/*518  */ {0x0001, 0x870c},
+	/*519  */ {0x0016, 0x8600},
+	/*520  */ {0x0002, 0x8606},
+
+/* if not included the pictures becomes _very_ dark */
+	/*521  */ {0x0064, 0x8607},
+	/*522  */ {0x003a, 0x8601},
+	/*523  */ {0x0000, 0x8602},
+
+/* seems to place the colors ontop of each other #2 */
+	/*524  */ {0x0016, 0x8600},
+	/*525  */ {0x0018, 0x8617},
+	/*526  */ {0x0008, 0x8618},
+	/*527  */ {0x00a1, 0x8656},
+
+/* webcam won't start if not included */
+	/*528  */ {0x0007, 0x865b},
+	/*529  */ {0x0001, 0x865c},
+	/*530  */ {0x0058, 0x865d},
+	/*531  */ {0x0048, 0x865e},
+
+/* adjusts the colors */
+	/*541  */ {0x0049, 0x8651},
+	/*542  */ {0x0040, 0x8652},
+	/*543  */ {0x004c, 0x8653},
+	/*544  */ {0x0040, 0x8654},
+
+	{0, 0}
+};
+
+static __u16 spca508_sightcam2_init_data[][3] = {
+/* 35 */ {0x0020, 0x8112},
+
+/* 36 */ {0x000f, 0x8402},
+/* 37 */ {0x0000, 0x8403},
+
+/* 38 */ {0x0008, 0x8201},
+/* 39 */ {0x0008, 0x8200},
+/* 40 */ {0x0001, 0x8200},
+/* 43 */ {0x0009, 0x8201},
+/* 44 */ {0x0008, 0x8200},
+/* 45 */ {0x0001, 0x8200},
+/* 48 */ {0x000a, 0x8201},
+/* 49 */ {0x0008, 0x8200},
+/* 50 */ {0x0001, 0x8200},
+/* 53 */ {0x000b, 0x8201},
+/* 54 */ {0x0008, 0x8200},
+/* 55 */ {0x0001, 0x8200},
+/* 58 */ {0x000c, 0x8201},
+/* 59 */ {0x0008, 0x8200},
+/* 60 */ {0x0001, 0x8200},
+/* 63 */ {0x000d, 0x8201},
+/* 64 */ {0x0008, 0x8200},
+/* 65 */ {0x0001, 0x8200},
+/* 68 */ {0x000e, 0x8201},
+/* 69 */ {0x0008, 0x8200},
+/* 70 */ {0x0001, 0x8200},
+/* 73 */ {0x0007, 0x8201},
+/* 74 */ {0x0008, 0x8200},
+/* 75 */ {0x0001, 0x8200},
+/* 78 */ {0x000f, 0x8201},
+/* 79 */ {0x0008, 0x8200},
+/* 80 */ {0x0001, 0x8200},
+
+/* 84 */ {0x0018, 0x8660},
+/* 85 */ {0x0010, 0x8201},
+
+/* 86 */ {0x0008, 0x8200},
+/* 87 */ {0x0001, 0x8200},
+/* 90 */ {0x0011, 0x8201},
+/* 91 */ {0x0008, 0x8200},
+/* 92 */ {0x0001, 0x8200},
+
+/* 95 */ {0x0000, 0x86b0},
+/* 96 */ {0x0034, 0x86b1},
+/* 97 */ {0x0000, 0x86b2},
+/* 98 */ {0x0049, 0x86b3},
+/* 99 */ {0x0000, 0x86b4},
+/* 100 */ {0x0000, 0x86b4},
+
+/* 101 */ {0x0012, 0x8201},
+/* 102 */ {0x0008, 0x8200},
+/* 103 */ {0x0001, 0x8200},
+/* 106 */ {0x0013, 0x8201},
+/* 107 */ {0x0008, 0x8200},
+/* 108 */ {0x0001, 0x8200},
+
+/* 111 */ {0x0001, 0x86b0},
+/* 112 */ {0x00aa, 0x86b1},
+/* 113 */ {0x0000, 0x86b2},
+/* 114 */ {0x00e4, 0x86b3},
+/* 115 */ {0x0000, 0x86b4},
+/* 116 */ {0x0000, 0x86b4},
+
+/* 118 */ {0x0018, 0x8660},
+
+/* 119 */ {0x0090, 0x8110},
+/* 120 */ {0x0001, 0x8114},
+/* 121 */ {0x0001, 0x8114},
+/* 122 */ {0x0001, 0x8114},
+/* 123 */ {0x0003, 0x8114},
+
+/* 124 */ {0x0080, 0x8804},
+/* 157 */ {0x0003, 0x8801},
+/* 158 */ {0x0012, 0x8800},
+/* 160 */ {0x0004, 0x8801},
+/* 161 */ {0x0005, 0x8800},
+/* 163 */ {0x0005, 0x8801},
+/* 164 */ {0x0000, 0x8800},
+/* 166 */ {0x0006, 0x8801},
+/* 167 */ {0x0000, 0x8800},
+/* 169 */ {0x0007, 0x8801},
+/* 170 */ {0x0000, 0x8800},
+/* 172 */ {0x0008, 0x8801},
+/* 173 */ {0x0005, 0x8800},
+/* 175 */ {0x000a, 0x8700},
+/* 176 */ {0x000e, 0x8801},
+/* 177 */ {0x0004, 0x8800},
+/* 179 */ {0x0005, 0x8801},
+/* 180 */ {0x0047, 0x8800},
+/* 182 */ {0x0006, 0x8801},
+/* 183 */ {0x0000, 0x8800},
+/* 185 */ {0x0007, 0x8801},
+/* 186 */ {0x00c0, 0x8800},
+/* 188 */ {0x0008, 0x8801},
+/* 189 */ {0x0003, 0x8800},
+/* 191 */ {0x0013, 0x8801},
+/* 192 */ {0x0001, 0x8800},
+/* 194 */ {0x0009, 0x8801},
+/* 195 */ {0x0000, 0x8800},
+/* 197 */ {0x000a, 0x8801},
+/* 198 */ {0x0000, 0x8800},
+/* 200 */ {0x000b, 0x8801},
+/* 201 */ {0x0000, 0x8800},
+/* 203 */ {0x000c, 0x8801},
+/* 204 */ {0x0000, 0x8800},
+/* 206 */ {0x000e, 0x8801},
+/* 207 */ {0x0004, 0x8800},
+/* 209 */ {0x000f, 0x8801},
+/* 210 */ {0x0000, 0x8800},
+/* 212 */ {0x0010, 0x8801},
+/* 213 */ {0x0006, 0x8800},
+/* 215 */ {0x0011, 0x8801},
+/* 216 */ {0x0006, 0x8800},
+/* 218 */ {0x0012, 0x8801},
+/* 219 */ {0x0000, 0x8800},
+/* 221 */ {0x0013, 0x8801},
+/* 222 */ {0x0001, 0x8800},
+
+/* 224 */ {0x000a, 0x8700},
+/* 225 */ {0x0000, 0x8702},
+/* 226 */ {0x0000, 0x8703},
+/* 227 */ {0x00c2, 0x8704},
+/* 228 */ {0x0001, 0x870c},
+
+/* 229 */ {0x0044, 0x8600},
+/* 230 */ {0x0002, 0x8606},
+/* 231 */ {0x0064, 0x8607},
+/* 232 */ {0x003a, 0x8601},
+/* 233 */ {0x0008, 0x8602},
+/* 234 */ {0x0044, 0x8600},
+/* 235 */ {0x0018, 0x8617},
+/* 236 */ {0x0008, 0x8618},
+/* 237 */ {0x00a1, 0x8656},
+/* 238 */ {0x0004, 0x865b},
+/* 239 */ {0x0002, 0x865c},
+/* 240 */ {0x0058, 0x865d},
+/* 241 */ {0x0048, 0x865e},
+/* 242 */ {0x0012, 0x8608},
+/* 243 */ {0x002c, 0x8609},
+/* 244 */ {0x0002, 0x860a},
+/* 245 */ {0x002c, 0x860b},
+/* 246 */ {0x00db, 0x860c},
+/* 247 */ {0x00f9, 0x860d},
+/* 248 */ {0x00f1, 0x860e},
+/* 249 */ {0x00e3, 0x860f},
+/* 250 */ {0x002c, 0x8610},
+/* 251 */ {0x006c, 0x8651},
+/* 252 */ {0x0041, 0x8652},
+/* 253 */ {0x0059, 0x8653},
+/* 254 */ {0x0040, 0x8654},
+/* 255 */ {0x00fa, 0x8611},
+/* 256 */ {0x00ff, 0x8612},
+/* 257 */ {0x00f8, 0x8613},
+/* 258 */ {0x0000, 0x8614},
+/* 259 */ {0x0001, 0x863f},
+/* 260 */ {0x0000, 0x8640},
+/* 261 */ {0x0026, 0x8641},
+/* 262 */ {0x0045, 0x8642},
+/* 263 */ {0x0060, 0x8643},
+/* 264 */ {0x0075, 0x8644},
+/* 265 */ {0x0088, 0x8645},
+/* 266 */ {0x009b, 0x8646},
+/* 267 */ {0x00b0, 0x8647},
+/* 268 */ {0x00c5, 0x8648},
+/* 269 */ {0x00d2, 0x8649},
+/* 270 */ {0x00dc, 0x864a},
+/* 271 */ {0x00e5, 0x864b},
+/* 272 */ {0x00eb, 0x864c},
+/* 273 */ {0x00f0, 0x864d},
+/* 274 */ {0x00f6, 0x864e},
+/* 275 */ {0x00fa, 0x864f},
+/* 276 */ {0x00ff, 0x8650},
+/* 277 */ {0x0060, 0x8657},
+/* 278 */ {0x0010, 0x8658},
+/* 279 */ {0x0018, 0x8659},
+/* 280 */ {0x0005, 0x865a},
+/* 281 */ {0x0018, 0x8660},
+/* 282 */ {0x0003, 0x8509},
+/* 283 */ {0x0011, 0x850a},
+/* 284 */ {0x0032, 0x850b},
+/* 285 */ {0x0010, 0x850c},
+/* 286 */ {0x0021, 0x850d},
+/* 287 */ {0x0001, 0x8500},
+/* 288 */ {0x0000, 0x8508},
+/* 289 */ {0x0012, 0x8608},
+/* 290 */ {0x002c, 0x8609},
+/* 291 */ {0x0002, 0x860a},
+/* 292 */ {0x0039, 0x860b},
+/* 293 */ {0x00d0, 0x860c},
+/* 294 */ {0x00f7, 0x860d},
+/* 295 */ {0x00ed, 0x860e},
+/* 296 */ {0x00db, 0x860f},
+/* 297 */ {0x0039, 0x8610},
+/* 298 */ {0x0012, 0x8657},
+/* 299 */ {0x000c, 0x8619},
+/* 300 */ {0x0004, 0x861a},
+/* 301 */ {0x00a1, 0x8656},
+/* 302 */ {0x00c8, 0x8615},
+/* 303 */ {0x0032, 0x8616},
+
+/* 306 */ {0x0030, 0x8112},
+/* 313 */ {0x0020, 0x8112},
+/* 314 */ {0x0020, 0x8112},
+/* 315 */ {0x000f, 0x8402},
+/* 316 */ {0x0000, 0x8403},
+
+/* 317 */ {0x0090, 0x8110},
+/* 318 */ {0x0001, 0x8114},
+/* 319 */ {0x0001, 0x8114},
+/* 320 */ {0x0001, 0x8114},
+/* 321 */ {0x0003, 0x8114},
+/* 322 */ {0x0080, 0x8804},
+
+/* 355 */ {0x0003, 0x8801},
+/* 356 */ {0x0012, 0x8800},
+/* 358 */ {0x0004, 0x8801},
+/* 359 */ {0x0005, 0x8800},
+/* 361 */ {0x0005, 0x8801},
+/* 362 */ {0x0047, 0x8800},
+/* 364 */ {0x0006, 0x8801},
+/* 365 */ {0x0000, 0x8800},
+/* 367 */ {0x0007, 0x8801},
+/* 368 */ {0x00c0, 0x8800},
+/* 370 */ {0x0008, 0x8801},
+/* 371 */ {0x0003, 0x8800},
+/* 373 */ {0x000a, 0x8700},
+/* 374 */ {0x000e, 0x8801},
+/* 375 */ {0x0004, 0x8800},
+/* 377 */ {0x0005, 0x8801},
+/* 378 */ {0x0047, 0x8800},
+/* 380 */ {0x0006, 0x8801},
+/* 381 */ {0x0000, 0x8800},
+/* 383 */ {0x0007, 0x8801},
+/* 384 */ {0x00c0, 0x8800},
+/* 386 */ {0x0008, 0x8801},
+/* 387 */ {0x0003, 0x8800},
+/* 389 */ {0x0013, 0x8801},
+/* 390 */ {0x0001, 0x8800},
+/* 392 */ {0x0009, 0x8801},
+/* 393 */ {0x0000, 0x8800},
+/* 395 */ {0x000a, 0x8801},
+/* 396 */ {0x0000, 0x8800},
+/* 398 */ {0x000b, 0x8801},
+/* 399 */ {0x0000, 0x8800},
+/* 401 */ {0x000c, 0x8801},
+/* 402 */ {0x0000, 0x8800},
+/* 404 */ {0x000e, 0x8801},
+/* 405 */ {0x0004, 0x8800},
+/* 407 */ {0x000f, 0x8801},
+/* 408 */ {0x0000, 0x8800},
+/* 410 */ {0x0010, 0x8801},
+/* 411 */ {0x0006, 0x8800},
+/* 413 */ {0x0011, 0x8801},
+/* 414 */ {0x0006, 0x8800},
+/* 416 */ {0x0012, 0x8801},
+/* 417 */ {0x0000, 0x8800},
+/* 419 */ {0x0013, 0x8801},
+/* 420 */ {0x0001, 0x8800},
+/* 422 */ {0x000a, 0x8700},
+/* 423 */ {0x0000, 0x8702},
+/* 424 */ {0x0000, 0x8703},
+/* 425 */ {0x00c2, 0x8704},
+/* 426 */ {0x0001, 0x870c},
+/* 427 */ {0x0044, 0x8600},
+/* 428 */ {0x0002, 0x8606},
+/* 429 */ {0x0064, 0x8607},
+/* 430 */ {0x003a, 0x8601},
+/* 431 */ {0x0008, 0x8602},
+/* 432 */ {0x0044, 0x8600},
+/* 433 */ {0x0018, 0x8617},
+/* 434 */ {0x0008, 0x8618},
+/* 435 */ {0x00a1, 0x8656},
+/* 436 */ {0x0004, 0x865b},
+/* 437 */ {0x0002, 0x865c},
+/* 438 */ {0x0058, 0x865d},
+/* 439 */ {0x0048, 0x865e},
+/* 440 */ {0x0012, 0x8608},
+/* 441 */ {0x002c, 0x8609},
+/* 442 */ {0x0002, 0x860a},
+/* 443 */ {0x002c, 0x860b},
+/* 444 */ {0x00db, 0x860c},
+/* 445 */ {0x00f9, 0x860d},
+/* 446 */ {0x00f1, 0x860e},
+/* 447 */ {0x00e3, 0x860f},
+/* 448 */ {0x002c, 0x8610},
+/* 449 */ {0x006c, 0x8651},
+/* 450 */ {0x0041, 0x8652},
+/* 451 */ {0x0059, 0x8653},
+/* 452 */ {0x0040, 0x8654},
+/* 453 */ {0x00fa, 0x8611},
+/* 454 */ {0x00ff, 0x8612},
+/* 455 */ {0x00f8, 0x8613},
+/* 456 */ {0x0000, 0x8614},
+/* 457 */ {0x0001, 0x863f},
+/* 458 */ {0x0000, 0x8640},
+/* 459 */ {0x0026, 0x8641},
+/* 460 */ {0x0045, 0x8642},
+/* 461 */ {0x0060, 0x8643},
+/* 462 */ {0x0075, 0x8644},
+/* 463 */ {0x0088, 0x8645},
+/* 464 */ {0x009b, 0x8646},
+/* 465 */ {0x00b0, 0x8647},
+/* 466 */ {0x00c5, 0x8648},
+/* 467 */ {0x00d2, 0x8649},
+/* 468 */ {0x00dc, 0x864a},
+/* 469 */ {0x00e5, 0x864b},
+/* 470 */ {0x00eb, 0x864c},
+/* 471 */ {0x00f0, 0x864d},
+/* 472 */ {0x00f6, 0x864e},
+/* 473 */ {0x00fa, 0x864f},
+/* 474 */ {0x00ff, 0x8650},
+/* 475 */ {0x0060, 0x8657},
+/* 476 */ {0x0010, 0x8658},
+/* 477 */ {0x0018, 0x8659},
+/* 478 */ {0x0005, 0x865a},
+/* 479 */ {0x0018, 0x8660},
+/* 480 */ {0x0003, 0x8509},
+/* 481 */ {0x0011, 0x850a},
+/* 482 */ {0x0032, 0x850b},
+/* 483 */ {0x0010, 0x850c},
+/* 484 */ {0x0021, 0x850d},
+/* 485 */ {0x0001, 0x8500},
+/* 486 */ {0x0000, 0x8508},
+
+/* 487 */ {0x0012, 0x8608},
+/* 488 */ {0x002c, 0x8609},
+/* 489 */ {0x0002, 0x860a},
+/* 490 */ {0x0039, 0x860b},
+/* 491 */ {0x00d0, 0x860c},
+/* 492 */ {0x00f7, 0x860d},
+/* 493 */ {0x00ed, 0x860e},
+/* 494 */ {0x00db, 0x860f},
+/* 495 */ {0x0039, 0x8610},
+/* 496 */ {0x0012, 0x8657},
+/* 497 */ {0x0064, 0x8619},
+
+/* This line starts it all, it is not needed here */
+/* since it has been build into the driver */
+/* jfm: don't start now */
+/* 590  *  {0x0030, 0x8112}, */
+	{}
+};
+
+/*
+ * Initialization data for Creative Webcam Vista
+ */
+static __u16 spca508_vista_init_data[][3] = {
+	{0x0008, 0x8200},	/* Clear register */
+	{0x0000, 0x870b},	/* Reset CTL3 */
+	{0x0020, 0x8112},	/* Video Drop packet enable */
+	{0x0003, 0x8111},  /* Soft Reset compression, memory, TG & CDSP */
+	{0x0000, 0x8110},	/* Disable everything */
+	{0x0000, 0x8114},	/* Software GPIO output data */
+	{0x0000, 0x8114},
+
+	{0x0003, 0x8111},
+	{0x0000, 0x8111},
+	{0x0090, 0x8110},  /* Enable: SSI output, External 2X clock output */
+	{0x0020, 0x8112},
+	{0x0000, 0x8114},
+	{0x0001, 0x8114},
+	{0x0001, 0x8114},
+	{0x0001, 0x8114},
+	{0x0003, 0x8114},
+
+	{0x000f, 0x8402},	/* Memory bank Address */
+	{0x0000, 0x8403},	/* Memory bank Address */
+	{0x00ba, 0x8804},	/* SSI Slave address */
+	{0x0010, 0x8802},	/* 93.75kHz SSI Clock Two DataByte */
+
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+	/* READ { 0, 0x0001, 0x8802 } ->
+		0000: 10  */
+	{0x0010, 0x8802},	/* Will write 2 bytes (DATA1+DATA2) */
+	{0x0020, 0x8801},	/* Register address for SSI read/write */
+	{0x0044, 0x8805},	/* DATA2 */
+	{0x0004, 0x8800},	/* DATA1 -> write triggered */
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+	/* READ { 0, 0x0001, 0x8802 } ->
+		0000: 10  */
+	{0x0010, 0x8802},
+	{0x0009, 0x8801},
+	{0x0042, 0x8805},
+	{0x0001, 0x8800},
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+	/* READ { 0, 0x0001, 0x8802 } ->
+		0000: 10  */
+	{0x0010, 0x8802},
+	{0x003c, 0x8801},
+	{0x0001, 0x8805},
+	{0x0000, 0x8800},
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+	/* READ { 0, 0x0001, 0x8802 } ->
+		0000: 10  */
+	{0x0010, 0x8802},
+	{0x0001, 0x8801},
+	{0x000a, 0x8805},
+	{0x0000, 0x8800},
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+	/* READ { 0, 0x0001, 0x8802 } ->
+		0000: 10  */
+	{0x0010, 0x8802},
+	{0x0002, 0x8801},
+	{0x0000, 0x8805},
+	{0x0000, 0x8800},
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+	/* READ { 0, 0x0001, 0x8802 } ->
+		0000: 10  */
+	{0x0010, 0x8802},
+	{0x0003, 0x8801},
+	{0x0027, 0x8805},
+	{0x0001, 0x8800},
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+	/* READ { 0, 0x0001, 0x8802 } ->
+		0000: 10  */
+	{0x0010, 0x8802},
+	{0x0004, 0x8801},
+	{0x0065, 0x8805},
+	{0x0001, 0x8800},
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+	/* READ { 0, 0x0001, 0x8802 } ->
+		0000: 10  */
+	{0x0010, 0x8802},
+	{0x0005, 0x8801},
+	{0x0003, 0x8805},
+	{0x0000, 0x8800},
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+	/* READ { 0, 0x0001, 0x8802 } ->
+		0000: 10  */
+	{0x0010, 0x8802},
+	{0x0006, 0x8801},
+	{0x001c, 0x8805},
+	{0x0000, 0x8800},
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+	/* READ { 0, 0x0001, 0x8802 } ->
+		0000: 10  */
+	{0x0010, 0x8802},
+	{0x0007, 0x8801},
+	{0x002a, 0x8805},
+	{0x0000, 0x8800},
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+	/* READ { 0, 0x0001, 0x8802 } ->
+		0000: 10  */
+	{0x0010, 0x8802},
+	{0x000e, 0x8801},
+	{0x0000, 0x8805},
+	{0x0000, 0x8800},
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+	/* READ { 0, 0x0001, 0x8802 } ->
+		0000: 10  */
+	{0x0010, 0x8802},
+	{0x0028, 0x8801},
+	{0x002e, 0x8805},
+	{0x0000, 0x8800},
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+	/* READ { 0, 0x0001, 0x8802 } ->
+		0000: 10  */
+	{0x0010, 0x8802},
+	{0x0039, 0x8801},
+	{0x0013, 0x8805},
+	{0x0000, 0x8800},
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+	/* READ { 0, 0x0001, 0x8802 } ->
+		0000: 10  */
+	{0x0010, 0x8802},
+	{0x003b, 0x8801},
+	{0x000c, 0x8805},
+	{0x0000, 0x8800},
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+	/* READ { 0, 0x0001, 0x8802 } ->
+		0000: 10  */
+	{0x0010, 0x8802},
+	{0x0035, 0x8801},
+	{0x0028, 0x8805},
+	{0x0000, 0x8800},
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+	/* READ { 0, 0x0001, 0x8802 } ->
+		0000: 10  */
+	{0x0010, 0x8802},
+	{0x0009, 0x8801},
+	{0x0042, 0x8805},
+	{0x0001, 0x8800},
+	/* READ { 0, 0x0001, 0x8803 } ->
+		0000: 00  */
+
+	{0x0050, 0x8703},
+	{0x0002, 0x8704},	/* External input CKIx1 */
+	{0x0001, 0x870C},	/* Select CKOx2 output */
+	{0x009A, 0x8600},	/* Line memory Read Counter (L) */
+	{0x0001, 0x8606},  /* 1 Line memory Read Counter (H) Result: (d)410 */
+	{0x0023, 0x8601},
+	{0x0010, 0x8602},
+	{0x000A, 0x8603},
+	{0x009A, 0x8600},
+	{0x0001, 0x865B},	/* 1 Horizontal Offset for Valid Pixel(L) */
+	{0x0003, 0x865C},	/* Vertical offset for valid lines (L) */
+	{0x0058, 0x865D},	/* Horizontal valid pixels window (L) */
+	{0x0048, 0x865E},	/* Vertical valid lines window (L) */
+	{0x0000, 0x865F},
+
+	{0x0006, 0x8660},
+		    /* Enable nibble data input, select nibble input order */
+
+	{0x0013, 0x8608},	/* A11 Coeficients for color correction */
+	{0x0028, 0x8609},
+		    /* Note: these values are confirmed at the end of array */
+	{0x0005, 0x860A},	/* ... */
+	{0x0025, 0x860B},
+	{0x00E1, 0x860C},
+	{0x00FA, 0x860D},
+	{0x00F4, 0x860E},
+	{0x00E8, 0x860F},
+	{0x0025, 0x8610},	/* A33 Coef. */
+	{0x00FC, 0x8611},	/* White balance offset: R */
+	{0x0001, 0x8612},	/* White balance offset: Gr */
+	{0x00FE, 0x8613},	/* White balance offset: B */
+	{0x0000, 0x8614},	/* White balance offset: Gb */
+
+	{0x0064, 0x8651},	/* R gain for white balance (L) */
+	{0x0040, 0x8652},	/* Gr gain for white balance (L) */
+	{0x0066, 0x8653},	/* B gain for white balance (L) */
+	{0x0040, 0x8654},	/* Gb gain for white balance (L) */
+	{0x0001, 0x863F},	/* Enable fixed gamma correction */
+
+	{0x00A1, 0x8656},	/* Size - Window1: 256x256, Window2: 128x128 */
+	/* UV division: UV no change, Enable New edge enhancement */
+	{0x0018, 0x8657},	/* Edge gain high threshold */
+	{0x0020, 0x8658},	/* Edge gain low threshold */
+	{0x000A, 0x8659},	/* Edge bandwidth high threshold */
+	{0x0005, 0x865A},	/* Edge bandwidth low threshold */
+	{0x0064, 0x8607},	/* UV filter enable */
+
+	{0x0016, 0x8660},
+	{0x0000, 0x86B0},	/* Bad pixels compensation address */
+	{0x00DC, 0x86B1},	/* X coord for bad pixels compensation (L) */
+	{0x0000, 0x86B2},
+	{0x0009, 0x86B3},	/* Y coord for bad pixels compensation (L) */
+	{0x0000, 0x86B4},
+
+	{0x0001, 0x86B0},
+	{0x00F5, 0x86B1},
+	{0x0000, 0x86B2},
+	{0x00C6, 0x86B3},
+	{0x0000, 0x86B4},
+
+	{0x0002, 0x86B0},
+	{0x001C, 0x86B1},
+	{0x0001, 0x86B2},
+	{0x00D7, 0x86B3},
+	{0x0000, 0x86B4},
+
+	{0x0003, 0x86B0},
+	{0x001C, 0x86B1},
+	{0x0001, 0x86B2},
+	{0x00D8, 0x86B3},
+	{0x0000, 0x86B4},
+
+	{0x0004, 0x86B0},
+	{0x001D, 0x86B1},
+	{0x0001, 0x86B2},
+	{0x00D8, 0x86B3},
+	{0x0000, 0x86B4},
+	{0x001E, 0x8660},
+
+	/* READ { 0, 0x0000, 0x8608 } ->
+		0000: 13  */
+	/* READ { 0, 0x0000, 0x8609 } ->
+		0000: 28  */
+	/* READ { 0, 0x0000, 0x8610 } ->
+		0000: 05  */
+	/* READ { 0, 0x0000, 0x8611 } ->
+		0000: 25  */
+	/* READ { 0, 0x0000, 0x8612 } ->
+		0000: e1  */
+	/* READ { 0, 0x0000, 0x8613 } ->
+		0000: fa  */
+	/* READ { 0, 0x0000, 0x8614 } ->
+		0000: f4  */
+	/* READ { 0, 0x0000, 0x8615 } ->
+		0000: e8  */
+	/* READ { 0, 0x0000, 0x8616 } ->
+		0000: 25  */
+	{}
+};
+
+static int reg_write(struct usb_device *dev,
+			__u16 index, __u16 value)
+{
+	int ret;
+
+	ret = usb_control_msg(dev,
+			usb_sndctrlpipe(dev, 0),
+			0,		/* request */
+			USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			value, index, NULL, 0, 500);
+	PDEBUG(D_USBO, "reg write i:0x%04x = 0x%02x",
+		index, value);
+	if (ret < 0)
+		PDEBUG(D_ERR|D_USBO, "reg write: error %d", ret);
+	return ret;
+}
+
+/* read 1 byte */
+/* returns: negative is error, pos or zero is data */
+static int reg_read(struct usb_device *dev,
+			__u16 index)	/* wIndex */
+{
+	int ret;
+	__u8 data;
+
+	ret = usb_control_msg(dev,
+			usb_rcvctrlpipe(dev, 0),
+			0,			/* register */
+			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			(__u16) 0,		/* value */
+			index,
+			&data, 1,
+			500);			/* timeout */
+	PDEBUG(D_USBI, "reg read i:%04x --> %02x", index, data);
+	if (ret < 0) {
+		PDEBUG(D_ERR|D_USBI, "reg_read err %d", ret);
+		return ret;
+	}
+	return data;
+}
+
+static int write_vector(struct gspca_dev *gspca_dev,
+				__u16 data[][3])
+{
+	struct usb_device *dev = gspca_dev->dev;
+	int ret, i = 0;
+
+	while (data[i][1] != 0) {
+		ret = reg_write(dev, data[i][1], data[i][0]);
+		if (ret < 0)
+			return ret;
+		i++;
+	}
+	return 0;
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+			const struct usb_device_id *id)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct usb_device *dev = gspca_dev->dev;
+	struct cam *cam;
+	__u16 vendor;
+	__u16 product;
+	int data1, data2;
+
+	vendor = id->idVendor;
+	product = id->idProduct;
+	switch (vendor) {
+	case 0x041e:		/* Creative cameras */
+/*		switch (product) { */
+/*		case 0x4018: */
+			sd->subtype = CreativeVista;
+/*			break; */
+/*		} */
+		break;
+	case 0x0461:		/* MicroInnovation */
+/*		switch (product) { */
+/*		case 0x0815: */
+			sd->subtype = MicroInnovationIC200;
+/*			break; */
+/*		} */
+		break;
+	case 0x0733:	/* Rebadged ViewQuest (Intel) and ViewQuest cameras */
+/*		switch (product) { */
+/*		case 0x110: */
+			sd->subtype = ViewQuestVQ110;
+/*			break; */
+/*		} */
+		break;
+	case 0x0af9:		/* Hama cameras */
+		switch (product) {
+		case 0x0010:
+			sd->subtype = HamaUSBSightcam;
+			break;
+		case 0x0011:
+			sd->subtype = HamaUSBSightcam2;
+			break;
+		}
+		break;
+	case 0x8086:		/* Intel */
+/*		switch (product) { */
+/*		case 0x0110: */
+			sd->subtype = IntelEasyPCCamera;
+/*			break; */
+/*		} */
+		break;
+	}
+
+	/* Read from global register the USB product and vendor IDs, just to */
+	/* prove that we can communicate with the device.  This works, which */
+	/* confirms at we are communicating properly and that the device */
+	/* is a 508. */
+	data1 = reg_read(dev, 0x8104);
+	data2 = reg_read(dev, 0x8105);
+	PDEBUG(D_PROBE,
+		"Read from GLOBAL: USB Vendor ID 0x%02x%02x", data2, data1);
+
+	data1 = reg_read(dev, 0x8106);
+	data2 = reg_read(dev, 0x8107);
+	PDEBUG(D_PROBE,
+		"Read from GLOBAL: USB Product ID 0x%02x%02x", data2, data1);
+
+	data1 = reg_read(dev, 0x8621);
+	PDEBUG(D_PROBE,
+		"Read from GLOBAL: Window 1 average luminance %d", data1);
+
+	cam = &gspca_dev->cam;
+	cam->dev_name = (char *) id->driver_info;
+	cam->epaddr = 0x01;
+	cam->cam_mode = sif_mode;
+	cam->nmodes = sizeof sif_mode / sizeof sif_mode[0];
+	sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
+
+	switch (sd->subtype) {
+	case ViewQuestVQ110:
+		if (write_vector(gspca_dev, spca508_init_data))
+			return -1;
+		break;
+	default:
+/*	case MicroInnovationIC200: */
+/*	case IntelEasyPCCamera: */
+		if (write_vector(gspca_dev, spca508cs110_init_data))
+			return -1;
+		break;
+	case HamaUSBSightcam:
+		if (write_vector(gspca_dev, spca508_sightcam_init_data))
+			return -1;
+		break;
+	case HamaUSBSightcam2:
+		if (write_vector(gspca_dev, spca508_sightcam2_init_data))
+			return -1;
+		break;
+	case CreativeVista:
+		if (write_vector(gspca_dev, spca508_vista_init_data))
+			return -1;
+		break;
+	}
+	return 0;			/* success */
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+/*	write_vector(gspca_dev, spca508_open_data); */
+	return 0;
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+	int mode;
+
+	mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].mode;
+	reg_write(gspca_dev->dev, 0x8500, mode);
+	switch (mode) {
+	case 0:
+	case 1:
+		reg_write(gspca_dev->dev, 0x8700, 0x28);	/* clock */
+		break;
+	default:
+/*	case 2: */
+/*	case 3: */
+		reg_write(gspca_dev->dev, 0x8700, 0x23);	/* clock */
+		break;
+	}
+	reg_write(gspca_dev->dev, 0x8112, 0x10 | 0x20);
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+	/* Video ISO disable, Video Drop Packet enable: */
+	reg_write(gspca_dev->dev, 0x8112, 0x20);
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+/* this function is called at close time */
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+/* convert YUVY per line to YUYV (YUV 4:2:2) */
+static void yuvy_decode(unsigned char *out,
+			unsigned char *in,
+			int width,
+			int height)
+{
+	unsigned char *Ui, *Vi, *yi, *yi1;
+	unsigned char *out1;
+	int i, j;
+
+	yi = in;
+	for (i = height / 2; --i >= 0; ) {
+		out1 = out + width * 2;		/* next line */
+		Ui = yi + width;
+		Vi = Ui + width / 2;
+		yi1 = Vi + width / 2;
+		for (j = width / 2; --j >= 0; ) {
+			*out++ = 128 + *yi++;
+			*out++ = 128 + *Ui;
+			*out++ = 128 + *yi++;
+			*out++ = 128 + *Vi;
+
+			*out1++ = 128 + *yi1++;
+			*out1++ = 128 + *Ui++;
+			*out1++ = 128 + *yi1++;
+			*out1++ = 128 + *Vi++;
+		}
+		yi += width * 2;
+		out = out1;
+	}
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+			struct gspca_frame *frame,	/* target */
+			unsigned char *data,		/* isoc packet */
+			int len)			/* iso packet length */
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	switch (data[0]) {
+	case 0:				/* start of frame */
+		if (gspca_dev->last_packet_type == FIRST_PACKET) {
+			yuvy_decode(sd->tmpbuf2, sd->tmpbuf,
+					gspca_dev->width,
+					gspca_dev->height);
+			frame = gspca_frame_add(gspca_dev,
+						LAST_PACKET,
+						frame,
+						sd->tmpbuf2,
+						gspca_dev->width
+							* gspca_dev->height
+							* 2);
+		}
+		gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+				data, 0);
+		data += SPCA508_OFFSET_DATA;
+		len -= SPCA508_OFFSET_DATA;
+		if (len > 0)
+			memcpy(sd->tmpbuf, data, len);
+		else
+			len = 0;
+		sd->buflen = len;
+		return;
+	case 0xff:			/* drop */
+/*		gspca_dev->last_packet_type = DISCARD_PACKET; */
+		return;
+	}
+	data += 1;
+	len -= 1;
+	memcpy(&sd->tmpbuf[sd->buflen], data, len);
+	sd->buflen += len;
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	__u8 brightness = sd->brightness;
+
+/* MX seem contrast */
+	reg_write(gspca_dev->dev, 0x8651, brightness);
+	reg_write(gspca_dev->dev, 0x8652, brightness);
+	reg_write(gspca_dev->dev, 0x8653, brightness);
+	reg_write(gspca_dev->dev, 0x8654, brightness);
+}
+
+static void getbrightness(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->brightness = reg_read(gspca_dev->dev, 0x8651);
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->brightness = val;
+	if (gspca_dev->streaming)
+		setbrightness(gspca_dev);
+	return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	getbrightness(gspca_dev);
+	*val = sd->brightness;
+	return 0;
+}
+
+/* sub-driver description */
+static struct sd_desc sd_desc = {
+	.name = MODULE_NAME,
+	.ctrls = sd_ctrls,
+	.nctrls = ARRAY_SIZE(sd_ctrls),
+	.config = sd_config,
+	.open = sd_open,
+	.start = sd_start,
+	.stopN = sd_stopN,
+	.stop0 = sd_stop0,
+	.close = sd_close,
+	.pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static __devinitdata struct usb_device_id device_table[] = {
+	{USB_DEVICE(0x041e, 0x4018), DVNM("Creative Webcam Vista (PD1100)")},
+	{USB_DEVICE(0x0461, 0x0815), DVNM("Micro Innovation IC200")},
+	{USB_DEVICE(0x0733, 0x0110), DVNM("ViewQuest VQ110")},
+	{USB_DEVICE(0x0af9, 0x0010), DVNM("Hama USB Sightcam 100")},
+	{USB_DEVICE(0x0af9, 0x0011), DVNM("Hama USB Sightcam 100")},
+	{USB_DEVICE(0x8086, 0x0110), DVNM("Intel Easy PC Camera")},
+	{}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+			const struct usb_device_id *id)
+{
+	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+				THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+	.name = MODULE_NAME,
+	.id_table = device_table,
+	.probe = sd_probe,
+	.disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+	if (usb_register(&sd_driver) < 0)
+		return -1;
+	PDEBUG(D_PROBE, "v%s registered", version);
+	return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+	usb_deregister(&sd_driver);
+	PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/spca561.c b/drivers/media/video/gspca/spca561.c
new file mode 100644
index 0000000..a94e627
--- /dev/null
+++ b/drivers/media/video/gspca/spca561.c
@@ -0,0 +1,1025 @@
+/*
+ * Sunplus spca561 subdriver
+ *
+ * Copyright (C) 2004 Michel Xhaard mxhaard@magic.fr
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define MODULE_NAME "spca561"
+
+#include "gspca.h"
+
+#define DRIVER_VERSION_NUMBER	KERNEL_VERSION(2, 1, 0)
+static const char version[] = "2.1.0";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("GSPCA/SPCA561 USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+	struct gspca_dev gspca_dev;	/* !! must be the first item */
+
+	unsigned short contrast;
+	__u8 brightness;
+	__u8 autogain;
+
+	__u8 chip_revision;
+	signed char ag_cnt;
+#define AG_CNT_START 13
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+#define SD_BRIGHTNESS 0
+	{
+	 {
+	  .id = V4L2_CID_BRIGHTNESS,
+	  .type = V4L2_CTRL_TYPE_INTEGER,
+	  .name = "Brightness",
+	  .minimum = 0,
+	  .maximum = 63,
+	  .step = 1,
+	  .default_value = 32,
+	  },
+	 .set = sd_setbrightness,
+	 .get = sd_getbrightness,
+	 },
+#define SD_CONTRAST 1
+	{
+	 {
+	  .id = V4L2_CID_CONTRAST,
+	  .type = V4L2_CTRL_TYPE_INTEGER,
+	  .name = "Contrast",
+	  .minimum = 0,
+	  .maximum = 0x3fff,
+	  .step = 1,
+	  .default_value = 0x2000,
+	  },
+	 .set = sd_setcontrast,
+	 .get = sd_getcontrast,
+	 },
+#define SD_AUTOGAIN 2
+	{
+	 {
+	  .id = V4L2_CID_AUTOGAIN,
+	  .type = V4L2_CTRL_TYPE_BOOLEAN,
+	  .name = "Auto Gain",
+	  .minimum = 0,
+	  .maximum = 1,
+	  .step = 1,
+	  .default_value = 1,
+	  },
+	 .set = sd_setautogain,
+	 .get = sd_getautogain,
+	 },
+};
+
+static struct cam_mode sif_mode[] = {
+	{V4L2_PIX_FMT_SPCA561, 160, 120, 3},
+	{V4L2_PIX_FMT_SPCA561, 176, 144, 2},
+	{V4L2_PIX_FMT_SPCA561, 320, 240, 1},
+	{V4L2_PIX_FMT_SPCA561, 352, 288, 0},
+};
+
+/*
+ * Initialization data
+ * I'm not very sure how to split initialization from open data
+ * chunks. For now, we'll consider everything as initialization
+ */
+/* Frame packet header offsets for the spca561 */
+#define SPCA561_OFFSET_SNAP 1
+#define SPCA561_OFFSET_TYPE 2
+#define SPCA561_OFFSET_COMPRESS 3
+#define SPCA561_OFFSET_FRAMSEQ   4
+#define SPCA561_OFFSET_GPIO 5
+#define SPCA561_OFFSET_USBBUFF 6
+#define SPCA561_OFFSET_WIN2GRAVE 7
+#define SPCA561_OFFSET_WIN2RAVE 8
+#define SPCA561_OFFSET_WIN2BAVE 9
+#define SPCA561_OFFSET_WIN2GBAVE 10
+#define SPCA561_OFFSET_WIN1GRAVE 11
+#define SPCA561_OFFSET_WIN1RAVE 12
+#define SPCA561_OFFSET_WIN1BAVE 13
+#define SPCA561_OFFSET_WIN1GBAVE 14
+#define SPCA561_OFFSET_FREQ 15
+#define SPCA561_OFFSET_VSYNC 16
+#define SPCA561_OFFSET_DATA 1
+#define SPCA561_INDEX_I2C_BASE 0x8800
+#define SPCA561_SNAPBIT 0x20
+#define SPCA561_SNAPCTRL 0x40
+enum {
+	Rev072A = 0,
+	Rev012A,
+};
+
+static void reg_w_val(struct usb_device *dev, __u16 index, __u16 value)
+{
+	int ret;
+
+	ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+			      0,		/* request */
+			      USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			      value, index, NULL, 0, 500);
+	PDEBUG(D_USBO, "reg write: 0x%02x:0x%02x", index, value);
+	if (ret < 0)
+		PDEBUG(D_ERR, "reg write: error %d", ret);
+}
+
+static void write_vector(struct gspca_dev *gspca_dev, __u16 data[][2])
+{
+	struct usb_device *dev = gspca_dev->dev;
+	int i;
+
+	i = 0;
+	while (data[i][1] != 0) {
+		reg_w_val(dev, data[i][1], data[i][0]);
+		i++;
+	}
+}
+
+static void reg_r(struct usb_device *dev,
+		  __u16 index, __u8 *buffer, __u16 length)
+{
+	usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+			0,			/* request */
+			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			0,			/* value */
+			index, buffer, length, 500);
+}
+
+static void reg_w_buf(struct usb_device *dev,
+		      __u16 index, __u8 *buffer, __u16 length)
+{
+	usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+			0,			/* request */
+			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			0,			/* value */
+			index, buffer, length, 500);
+}
+
+static void i2c_init(struct gspca_dev *gspca_dev, __u8 mode)
+{
+	reg_w_val(gspca_dev->dev, 0x92, 0x8804);
+	reg_w_val(gspca_dev->dev, mode, 0x8802);
+}
+
+static void i2c_write(struct gspca_dev *gspca_dev, __u16 valeur, __u16 reg)
+{
+	int retry = 60;
+	__u8 DataLow;
+	__u8 DataHight;
+	__u8 Data;
+
+	DataLow = valeur;
+	DataHight = valeur >> 8;
+	reg_w_val(gspca_dev->dev, reg, 0x8801);
+	reg_w_val(gspca_dev->dev, DataLow, 0x8805);
+	reg_w_val(gspca_dev->dev, DataHight, 0x8800);
+	while (retry--) {
+		reg_r(gspca_dev->dev, 0x8803, &Data, 1);
+		if (!Data)
+			break;
+	}
+}
+
+static int i2c_read(struct gspca_dev *gspca_dev, __u16 reg, __u8 mode)
+{
+	int retry = 60;
+	__u8 value;
+	__u8 vallsb;
+	__u8 Data;
+
+	reg_w_val(gspca_dev->dev, 0x92, 0x8804);
+	reg_w_val(gspca_dev->dev, reg, 0x8801);
+	reg_w_val(gspca_dev->dev, (mode | 0x01), 0x8802);
+	while (retry--) {
+		reg_r(gspca_dev->dev, 0x8803, &Data, 1);
+		if (!Data)
+			break;
+	}
+	if (retry == 0)
+		return -1;
+	reg_r(gspca_dev->dev, 0x8800, &value, 1);
+	reg_r(gspca_dev->dev, 0x8805, &vallsb, 1);
+	return ((int) value << 8) | vallsb;
+}
+
+static __u16 spca561_init_data[][2] = {
+	{0x0000, 0x8114},	/* Software GPIO output data */
+	{0x0001, 0x8114},	/* Software GPIO output data */
+	{0x0000, 0x8112},	/* Some kind of reset */
+	{0x0003, 0x8701},	/* PCLK clock delay adjustment */
+	{0x0001, 0x8703},	/* HSYNC from cmos inverted */
+	{0x0011, 0x8118},	/* Enable and conf sensor */
+	{0x0001, 0x8118},	/* Conf sensor */
+	{0x0092, 0x8804},	/* I know nothing about these */
+	{0x0010, 0x8802},	/* 0x88xx registers, so I won't */
+	/***************/
+	{0x000d, 0x8805},	/* sensor default setting */
+	{0x0001, 0x8801},	/* 1 <- 0x0d */
+	{0x0000, 0x8800},
+	{0x0018, 0x8805},
+	{0x0002, 0x8801},	/* 2 <- 0x18 */
+	{0x0000, 0x8800},
+	{0x0065, 0x8805},
+	{0x0004, 0x8801},	/* 4 <- 0x01 0x65 */
+	{0x0001, 0x8800},
+	{0x0021, 0x8805},
+	{0x0005, 0x8801},	/* 5 <- 0x21 */
+	{0x0000, 0x8800},
+	{0x00aa, 0x8805},
+	{0x0007, 0x8801},	/* 7 <- 0xaa */
+	{0x0000, 0x8800},
+	{0x0004, 0x8805},
+	{0x0020, 0x8801},	/* 0x20 <- 0x15 0x04 */
+	{0x0015, 0x8800},
+	{0x0002, 0x8805},
+	{0x0039, 0x8801},	/* 0x39 <- 0x02 */
+	{0x0000, 0x8800},
+	{0x0010, 0x8805},
+	{0x0035, 0x8801},	/* 0x35 <- 0x10 */
+	{0x0000, 0x8800},
+	{0x0049, 0x8805},
+	{0x0009, 0x8801},	/* 0x09 <- 0x10 0x49 */
+	{0x0010, 0x8800},
+	{0x000b, 0x8805},
+	{0x0028, 0x8801},	/* 0x28 <- 0x0b */
+	{0x0000, 0x8800},
+	{0x000f, 0x8805},
+	{0x003b, 0x8801},	/* 0x3b <- 0x0f */
+	{0x0000, 0x8800},
+	{0x0000, 0x8805},
+	{0x003c, 0x8801},	/* 0x3c <- 0x00 */
+	{0x0000, 0x8800},
+	/***************/
+	{0x0018, 0x8601},	/* Pixel/line selection for color separation */
+	{0x0000, 0x8602},	/* Optical black level for user setting */
+	{0x0060, 0x8604},	/* Optical black horizontal offset */
+	{0x0002, 0x8605},	/* Optical black vertical offset */
+	{0x0000, 0x8603},	/* Non-automatic optical black level */
+	{0x0002, 0x865b},	/* Horizontal offset for valid pixels */
+	{0x0000, 0x865f},	/* Vertical valid pixels window (x2) */
+	{0x00b0, 0x865d},	/* Horizontal valid pixels window (x2) */
+	{0x0090, 0x865e},	/* Vertical valid lines window (x2) */
+	{0x00e0, 0x8406},	/* Memory buffer threshold */
+	{0x0000, 0x8660},	/* Compensation memory stuff */
+	{0x0002, 0x8201},	/* Output address for r/w serial EEPROM */
+	{0x0008, 0x8200},	/* Clear valid bit for serial EEPROM */
+	{0x0001, 0x8200},	/* OprMode to be executed by hardware */
+	{0x0007, 0x8201},	/* Output address for r/w serial EEPROM */
+	{0x0008, 0x8200},	/* Clear valid bit for serial EEPROM */
+	{0x0001, 0x8200},	/* OprMode to be executed by hardware */
+	{0x0010, 0x8660},	/* Compensation memory stuff */
+	{0x0018, 0x8660},	/* Compensation memory stuff */
+
+	{0x0004, 0x8611},	/* R offset for white balance */
+	{0x0004, 0x8612},	/* Gr offset for white balance */
+	{0x0007, 0x8613},	/* B offset for white balance */
+	{0x0000, 0x8614},	/* Gb offset for white balance */
+	{0x008c, 0x8651},	/* R gain for white balance */
+	{0x008c, 0x8652},	/* Gr gain for white balance */
+	{0x00b5, 0x8653},	/* B gain for white balance */
+	{0x008c, 0x8654},	/* Gb gain for white balance */
+	{0x0002, 0x8502},	/* Maximum average bit rate stuff */
+
+	{0x0011, 0x8802},
+	{0x0087, 0x8700},	/* Set master clock (96Mhz????) */
+	{0x0081, 0x8702},	/* Master clock output enable */
+
+	{0x0000, 0x8500},	/* Set image type (352x288 no compression) */
+	/* Originally was 0x0010 (352x288 compression) */
+
+	{0x0002, 0x865b},	/* Horizontal offset for valid pixels */
+	{0x0003, 0x865c},	/* Vertical offset for valid lines */
+	/***************//* sensor active */
+	{0x0003, 0x8801},	/* 0x03 <- 0x01 0x21 //289 */
+	{0x0021, 0x8805},
+	{0x0001, 0x8800},
+	{0x0004, 0x8801},	/* 0x04 <- 0x01 0x65 //357 */
+	{0x0065, 0x8805},
+	{0x0001, 0x8800},
+	{0x0005, 0x8801},	/* 0x05 <- 0x2f */
+	{0x002f, 0x8805},
+	{0x0000, 0x8800},
+	{0x0006, 0x8801},	/* 0x06 <- 0 */
+	{0x0000, 0x8805},
+	{0x0000, 0x8800},
+	{0x000a, 0x8801},	/* 0x0a <- 2 */
+	{0x0002, 0x8805},
+	{0x0000, 0x8800},
+	{0x0009, 0x8801},	/* 0x09 <- 0x1061 */
+	{0x0061, 0x8805},
+	{0x0010, 0x8800},
+	{0x0035, 0x8801},	/* 0x35 <-0x14 */
+	{0x0014, 0x8805},
+	{0x0000, 0x8800},
+	{0x0030, 0x8112},	/* ISO and drop packet enable */
+	{0x0000, 0x8112},	/* Some kind of reset ???? */
+	{0x0009, 0x8118},	/* Enable sensor and set standby */
+	{0x0000, 0x8114},	/* Software GPIO output data */
+	{0x0000, 0x8114},	/* Software GPIO output data */
+	{0x0001, 0x8114},	/* Software GPIO output data */
+	{0x0000, 0x8112},	/* Some kind of reset ??? */
+	{0x0003, 0x8701},
+	{0x0001, 0x8703},
+	{0x0011, 0x8118},
+	{0x0001, 0x8118},
+	/***************/
+	{0x0092, 0x8804},
+	{0x0010, 0x8802},
+	{0x000d, 0x8805},
+	{0x0001, 0x8801},
+	{0x0000, 0x8800},
+	{0x0018, 0x8805},
+	{0x0002, 0x8801},
+	{0x0000, 0x8800},
+	{0x0065, 0x8805},
+	{0x0004, 0x8801},
+	{0x0001, 0x8800},
+	{0x0021, 0x8805},
+	{0x0005, 0x8801},
+	{0x0000, 0x8800},
+	{0x00aa, 0x8805},
+	{0x0007, 0x8801},	/* mode 0xaa */
+	{0x0000, 0x8800},
+	{0x0004, 0x8805},
+	{0x0020, 0x8801},
+	{0x0015, 0x8800},	/* mode 0x0415 */
+	{0x0002, 0x8805},
+	{0x0039, 0x8801},
+	{0x0000, 0x8800},
+	{0x0010, 0x8805},
+	{0x0035, 0x8801},
+	{0x0000, 0x8800},
+	{0x0049, 0x8805},
+	{0x0009, 0x8801},
+	{0x0010, 0x8800},
+	{0x000b, 0x8805},
+	{0x0028, 0x8801},
+	{0x0000, 0x8800},
+	{0x000f, 0x8805},
+	{0x003b, 0x8801},
+	{0x0000, 0x8800},
+	{0x0000, 0x8805},
+	{0x003c, 0x8801},
+	{0x0000, 0x8800},
+	{0x0002, 0x8502},
+	{0x0039, 0x8801},
+	{0x0000, 0x8805},
+	{0x0000, 0x8800},
+
+	{0x0087, 0x8700},	/* overwrite by start */
+	{0x0081, 0x8702},
+	{0x0000, 0x8500},
+/*	{0x0010, 0x8500},  -- Previous line was this */
+	{0x0002, 0x865b},
+	{0x0003, 0x865c},
+	/***************/
+	{0x0003, 0x8801},	/* 0x121-> 289 */
+	{0x0021, 0x8805},
+	{0x0001, 0x8800},
+	{0x0004, 0x8801},	/* 0x165 -> 357 */
+	{0x0065, 0x8805},
+	{0x0001, 0x8800},
+	{0x0005, 0x8801},	/* 0x2f //blanking control colonne */
+	{0x002f, 0x8805},
+	{0x0000, 0x8800},
+	{0x0006, 0x8801},	/* 0x00 //blanking mode row */
+	{0x0000, 0x8805},
+	{0x0000, 0x8800},
+	{0x000a, 0x8801},	/* 0x01 //0x02 */
+	{0x0001, 0x8805},
+	{0x0000, 0x8800},
+	{0x0009, 0x8801},	/* 0x1061 - setexposure times && pixel clock
+				 * 0001 0 | 000 0110 0001 */
+	{0x0061, 0x8805},	/* 61 31 */
+	{0x0008, 0x8800},	/* 08 */
+	{0x0035, 0x8801},	/* 0x14 - set gain general */
+	{0x001f, 0x8805},	/* 0x14 */
+	{0x0000, 0x8800},
+	{0x0030, 0x8112},
+	{}
+};
+
+static void sensor_reset(struct gspca_dev *gspca_dev)
+{
+	reg_w_val(gspca_dev->dev, 0x8631, 0xc8);
+	reg_w_val(gspca_dev->dev, 0x8634, 0xc8);
+	reg_w_val(gspca_dev->dev, 0x8112, 0x00);
+	reg_w_val(gspca_dev->dev, 0x8114, 0x00);
+	reg_w_val(gspca_dev->dev, 0x8118, 0x21);
+	i2c_init(gspca_dev, 0x14);
+	i2c_write(gspca_dev, 1, 0x0d);
+	i2c_write(gspca_dev, 0, 0x0d);
+}
+
+/******************** QC Express etch2 stuff ********************/
+static __u16 Pb100_1map8300[][2] = {
+	/* reg, value */
+	{0x8320, 0x3304},
+
+	{0x8303, 0x0125},	/* image area */
+	{0x8304, 0x0169},
+	{0x8328, 0x000b},
+	{0x833c, 0x0001},
+
+	{0x832f, 0x0419},
+	{0x8307, 0x00aa},
+	{0x8301, 0x0003},
+	{0x8302, 0x000e},
+	{}
+};
+static __u16 Pb100_2map8300[][2] = {
+	/* reg, value */
+	{0x8339, 0x0000},
+	{0x8307, 0x00aa},
+	{}
+};
+
+static __u16 spca561_161rev12A_data1[][2] = {
+	{0x21, 0x8118},
+	{0x01, 0x8114},
+	{0x00, 0x8112},
+	{0x92, 0x8804},
+	{0x04, 0x8802},		/* windows uses 08 */
+	{}
+};
+static __u16 spca561_161rev12A_data2[][2] = {
+	{0x21, 0x8118},
+	{0x10, 0x8500},
+	{0x07, 0x8601},
+	{0x07, 0x8602},
+	{0x04, 0x8501},
+	{0x21, 0x8118},
+
+	{0x07, 0x8201},		/* windows uses 02 */
+	{0x08, 0x8200},
+	{0x01, 0x8200},
+
+	{0x00, 0x8114},
+	{0x01, 0x8114},		/* windows uses 00 */
+
+	{0x90, 0x8604},
+	{0x00, 0x8605},
+	{0xb0, 0x8603},
+
+	/* sensor gains */
+	{0x00, 0x8610},		/* *red */
+	{0x00, 0x8611},		/* 3f   *green */
+	{0x00, 0x8612},		/* green *blue */
+	{0x00, 0x8613},		/* blue *green */
+	{0x35, 0x8614},		/* green *red */
+	{0x35, 0x8615},		/* 40   *green */
+	{0x35, 0x8616},		/* 7a   *blue */
+	{0x35, 0x8617},		/* 40   *green */
+
+	{0x0c, 0x8620},		/* 0c */
+	{0xc8, 0x8631},		/* c8 */
+	{0xc8, 0x8634},		/* c8 */
+	{0x23, 0x8635},		/* 23 */
+	{0x1f, 0x8636},		/* 1f */
+	{0xdd, 0x8637},		/* dd */
+	{0xe1, 0x8638},		/* e1 */
+	{0x1d, 0x8639},		/* 1d */
+	{0x21, 0x863a},		/* 21 */
+	{0xe3, 0x863b},		/* e3 */
+	{0xdf, 0x863c},		/* df */
+	{0xf0, 0x8505},
+	{0x32, 0x850a},
+	{}
+};
+
+static void sensor_mapwrite(struct gspca_dev *gspca_dev,
+			    __u16 sensormap[][2])
+{
+	int i = 0;
+	__u8 usbval[2];
+
+	while (sensormap[i][0]) {
+		usbval[0] = sensormap[i][1];
+		usbval[1] = sensormap[i][1] >> 8;
+		reg_w_buf(gspca_dev->dev, sensormap[i][0], usbval, 2);
+		i++;
+	}
+}
+static void init_161rev12A(struct gspca_dev *gspca_dev)
+{
+	sensor_reset(gspca_dev);
+	write_vector(gspca_dev, spca561_161rev12A_data1);
+	sensor_mapwrite(gspca_dev, Pb100_1map8300);
+	write_vector(gspca_dev, spca561_161rev12A_data2);
+	sensor_mapwrite(gspca_dev, Pb100_2map8300);
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+		     const struct usb_device_id *id)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct usb_device *dev = gspca_dev->dev;
+	struct cam *cam;
+	__u16 vendor, product;
+	__u8 data1, data2;
+
+	/* Read frm global register the USB product and vendor IDs, just to
+	 * prove that we can communicate with the device.  This works, which
+	 * confirms at we are communicating properly and that the device
+	 * is a 561. */
+	reg_r(dev, 0x8104, &data1, 1);
+	reg_r(dev, 0x8105, &data2, 1);
+	vendor = (data2 << 8) | data1;
+	reg_r(dev, 0x8106, &data1, 1);
+	reg_r(dev, 0x8107, &data2, 1);
+	product = (data2 << 8) | data1;
+	if (vendor != id->idVendor || product != id->idProduct) {
+		PDEBUG(D_PROBE, "Bad vendor / product from device");
+		return -EINVAL;
+	}
+	switch (product) {
+	case 0x0928:
+	case 0x0929:
+	case 0x092a:
+	case 0x092b:
+	case 0x092c:
+	case 0x092d:
+	case 0x092e:
+	case 0x092f:
+	case 0x403b:
+		sd->chip_revision = Rev012A;
+		break;
+	default:
+/*	case 0x0561:
+	case 0x0815:			* ?? in spca508.c
+	case 0x401a:
+	case 0x7004:
+	case 0x7e50:
+	case 0xa001:
+	case 0xcdee: */
+		sd->chip_revision = Rev072A;
+		break;
+	}
+	cam = &gspca_dev->cam;
+	cam->dev_name = (char *) id->driver_info;
+	cam->epaddr = 0x01;
+	gspca_dev->nbalt = 7 + 1;	/* choose alternate 7 first */
+	cam->cam_mode = sif_mode;
+	cam->nmodes = sizeof sif_mode / sizeof sif_mode[0];
+	sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
+	sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
+	sd->autogain = sd_ctrls[SD_AUTOGAIN].qctrl.default_value;
+	return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	switch (sd->chip_revision) {
+	case Rev072A:
+		PDEBUG(D_STREAM, "Chip revision id: 072a");
+		write_vector(gspca_dev, spca561_init_data);
+		break;
+	default:
+/*	case Rev012A: */
+		PDEBUG(D_STREAM, "Chip revision id: 012a");
+		init_161rev12A(gspca_dev);
+		break;
+	}
+	return 0;
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct usb_device *dev = gspca_dev->dev;
+	__u8 lowb;
+	int expotimes;
+
+	switch (sd->chip_revision) {
+	case Rev072A:
+		lowb = sd->contrast >> 8;
+		reg_w_val(dev, lowb, 0x8651);
+		reg_w_val(dev, lowb, 0x8652);
+		reg_w_val(dev, lowb, 0x8653);
+		reg_w_val(dev, lowb, 0x8654);
+		break;
+	case Rev012A: {
+		__u8 Reg8391[] =
+			{ 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00 };
+
+		/* Write camera sensor settings */
+		expotimes = (sd->contrast >> 5) & 0x07ff;
+		Reg8391[0] = expotimes & 0xff;	/* exposure */
+		Reg8391[1] = 0x18 | (expotimes >> 8);
+		Reg8391[2] = sd->brightness;	/* gain */
+		reg_w_buf(dev, 0x8391, Reg8391, 8);
+		reg_w_buf(dev, 0x8390, Reg8391, 8);
+		break;
+	    }
+	}
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct usb_device *dev = gspca_dev->dev;
+	int Clck;
+	__u8 Reg8307[] = { 0xaa, 0x00 };
+	int mode;
+
+	mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].mode;
+	switch (sd->chip_revision) {
+	case Rev072A:
+		switch (mode) {
+		default:
+/*		case 0:
+		case 1: */
+			Clck = 0x25;
+			break;
+		case 2:
+			Clck = 0x22;
+			break;
+		case 3:
+			Clck = 0x21;
+			break;
+		}
+		reg_w_val(dev, 0x8500, mode);	/* mode */
+		reg_w_val(dev, 0x8700, Clck);	/* 0x27 clock */
+		reg_w_val(dev, 0x8112, 0x10 | 0x20);
+		break;
+	default:
+/*	case Rev012A: */
+		switch (mode) {
+		case 0:
+		case 1:
+			Clck = 0x8a;
+			break;
+		case 2:
+			Clck = 0x85;
+			break;
+		default:
+			Clck = 0x83;
+			break;
+		}
+		if (mode <= 1) {
+			/* Use compression on 320x240 and above */
+			reg_w_val(dev, 0x8500, 0x10 | mode);
+		} else {
+			/* I couldn't get the compression to work below 320x240
+			 * Fortunately at these resolutions the bandwidth
+			 * is sufficient to push raw frames at ~20fps */
+			reg_w_val(dev, 0x8500, mode);
+		}		/* -- qq@kuku.eu.org */
+		reg_w_buf(dev, 0x8307, Reg8307, 2);
+		reg_w_val(dev, 0x8700, Clck);	/* 0x8f 0x85 0x27 clock */
+		reg_w_val(dev, 0x8112, 0x1e | 0x20);
+		reg_w_val(dev, 0x850b, 0x03);
+		setcontrast(gspca_dev);
+		break;
+	}
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+	reg_w_val(gspca_dev->dev, 0x8112, 0x20);
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+/* this function is called at close time */
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+	reg_w_val(gspca_dev->dev, 0x8114, 0);
+}
+
+static void setautogain(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int expotimes = 0;
+	int pixelclk = 0;
+	int gainG = 0;
+	__u8 R, Gr, Gb, B;
+	int y;
+	__u8 luma_mean = 110;
+	__u8 luma_delta = 20;
+	__u8 spring = 4;
+
+	switch (sd->chip_revision) {
+	case Rev072A:
+		reg_r(gspca_dev->dev, 0x8621, &Gr, 1);
+		reg_r(gspca_dev->dev, 0x8622, &R, 1);
+		reg_r(gspca_dev->dev, 0x8623, &B, 1);
+		reg_r(gspca_dev->dev, 0x8624, &Gb, 1);
+		y = (77 * R + 75 * (Gr + Gb) + 29 * B) >> 8;
+		/* u= (128*B-(43*(Gr+Gb+R))) >> 8; */
+		/* v= (128*R-(53*(Gr+Gb))-21*B) >> 8; */
+		/* PDEBUG(D_CONF,"reading Y %d U %d V %d ",y,u,v); */
+
+		if (y < luma_mean - luma_delta ||
+		    y > luma_mean + luma_delta) {
+			expotimes = i2c_read(gspca_dev, 0x09, 0x10);
+			pixelclk = 0x0800;
+			expotimes = expotimes & 0x07ff;
+			/* PDEBUG(D_PACK,
+				"Exposition Times 0x%03X Clock 0x%04X ",
+				expotimes,pixelclk); */
+			gainG = i2c_read(gspca_dev, 0x35, 0x10);
+			/* PDEBUG(D_PACK,
+				"reading Gain register %d", gainG); */
+
+			expotimes += (luma_mean - y) >> spring;
+			gainG += (luma_mean - y) / 50;
+			/* PDEBUG(D_PACK,
+				"compute expotimes %d gain %d",
+				expotimes,gainG); */
+
+			if (gainG > 0x3f)
+				gainG = 0x3f;
+			else if (gainG < 4)
+				gainG = 3;
+			i2c_write(gspca_dev, gainG, 0x35);
+
+			if (expotimes >= 0x0256)
+				expotimes = 0x0256;
+			else if (expotimes < 4)
+				expotimes = 3;
+			i2c_write(gspca_dev, expotimes | pixelclk, 0x09);
+		}
+		break;
+	case Rev012A:
+		/* sensor registers is access and memory mapped to 0x8300 */
+		/* readind all 0x83xx block the sensor */
+		/*
+		 * The data from the header seem wrong where is the luma
+		 * and chroma mean value
+		 * at the moment set exposure in contrast set
+		 */
+		break;
+	}
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+			struct gspca_frame *frame, /* target */
+			__u8 *data,		/* isoc packet */
+			int len)		/* iso packet length */
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	switch (data[0]) {
+	case 0:		/* start of frame */
+		frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+					data, 0);
+		if (sd->ag_cnt >= 0) {
+			if (--sd->ag_cnt < 0) {
+				sd->ag_cnt = AG_CNT_START;
+				setautogain(gspca_dev);
+			}
+		}
+		data += SPCA561_OFFSET_DATA;
+		len -= SPCA561_OFFSET_DATA;
+		if (data[1] & 0x10) {
+			/* compressed bayer */
+			gspca_frame_add(gspca_dev, FIRST_PACKET,
+					frame, data, len);
+		} else {
+			/*fixme: which format?*/
+			data += 20;
+			len -= 20;
+			gspca_frame_add(gspca_dev, FIRST_PACKET,
+						frame, data, len);
+		}
+		return;
+	case 0xff:		/* drop */
+/*		gspca_dev->last_packet_type = DISCARD_PACKET; */
+		return;
+	}
+	data++;
+	len--;
+	gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	__u8 value;
+
+	switch (sd->chip_revision) {
+	case Rev072A:
+		value = sd->brightness;
+		reg_w_val(gspca_dev->dev, value, 0x8611);
+		reg_w_val(gspca_dev->dev, value, 0x8612);
+		reg_w_val(gspca_dev->dev, value, 0x8613);
+		reg_w_val(gspca_dev->dev, value, 0x8614);
+		break;
+	default:
+/*	case Rev012A: */
+		setcontrast(gspca_dev);
+		break;
+	}
+}
+
+static void getbrightness(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	__u8 value;
+	__u16 tot;
+
+	switch (sd->chip_revision) {
+	case Rev072A:
+		tot = 0;
+		reg_r(gspca_dev->dev, 0x8611, &value, 1);
+		tot += value;
+		reg_r(gspca_dev->dev, 0x8612, &value, 1);
+		tot += value;
+		reg_r(gspca_dev->dev, 0x8613, &value, 1);
+		tot += value;
+		reg_r(gspca_dev->dev, 0x8614, &value, 1);
+		tot += value;
+		sd->brightness = tot >> 2;
+		break;
+	default:
+/*	case Rev012A: */
+		/* no way to read sensor settings */
+		break;
+	}
+}
+
+static void getcontrast(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	__u8 value;
+	__u16 tot;
+
+	switch (sd->chip_revision) {
+	case Rev072A:
+		tot = 0;
+		reg_r(gspca_dev->dev, 0x8651, &value, 1);
+		tot += value;
+		reg_r(gspca_dev->dev, 0x8652, &value, 1);
+		tot += value;
+		reg_r(gspca_dev->dev, 0x8653, &value, 1);
+		tot += value;
+		reg_r(gspca_dev->dev, 0x8654, &value, 1);
+		tot += value;
+		sd->contrast = tot << 6;
+		break;
+	default:
+/*	case Rev012A: */
+		/* no way to read sensor settings */
+		break;
+	}
+	PDEBUG(D_CONF, "get contrast %d", sd->contrast);
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->brightness = val;
+	if (gspca_dev->streaming)
+		setbrightness(gspca_dev);
+	return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	getbrightness(gspca_dev);
+	*val = sd->brightness;
+	return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->contrast = val;
+	if (gspca_dev->streaming)
+		setcontrast(gspca_dev);
+	return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	getcontrast(gspca_dev);
+	*val = sd->contrast;
+	return 0;
+}
+
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->autogain = val;
+	if (val)
+		sd->ag_cnt = AG_CNT_START;
+	else
+		sd->ag_cnt = -1;
+	return 0;
+}
+
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->autogain;
+	return 0;
+}
+
+/* sub-driver description */
+static struct sd_desc sd_desc = {
+	.name = MODULE_NAME,
+	.ctrls = sd_ctrls,
+	.nctrls = ARRAY_SIZE(sd_ctrls),
+	.config = sd_config,
+	.open = sd_open,
+	.start = sd_start,
+	.stopN = sd_stopN,
+	.stop0 = sd_stop0,
+	.close = sd_close,
+	.pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static __devinitdata struct usb_device_id device_table[] = {
+	{USB_DEVICE(0x041e, 0x401a), DVNM("Creative Webcam Vista (PD1100)")},
+	{USB_DEVICE(0x041e, 0x403b),  DVNM("Creative Webcam Vista (VF0010)")},
+	{USB_DEVICE(0x0458, 0x7004), DVNM("Genius VideoCAM Express V2")},
+	{USB_DEVICE(0x046d, 0x0928), DVNM("Logitech QC Express Etch2")},
+	{USB_DEVICE(0x046d, 0x0929), DVNM("Labtec Webcam Elch2")},
+	{USB_DEVICE(0x046d, 0x092a), DVNM("Logitech QC for Notebook")},
+	{USB_DEVICE(0x046d, 0x092b), DVNM("Labtec Webcam Plus")},
+	{USB_DEVICE(0x046d, 0x092c), DVNM("Logitech QC chat Elch2")},
+	{USB_DEVICE(0x046d, 0x092d), DVNM("Logitech QC Elch2")},
+	{USB_DEVICE(0x046d, 0x092e), DVNM("Logitech QC Elch2")},
+	{USB_DEVICE(0x046d, 0x092f), DVNM("Logitech QC Elch2")},
+	{USB_DEVICE(0x04fc, 0x0561), DVNM("Flexcam 100")},
+	{USB_DEVICE(0x060b, 0xa001), DVNM("Maxell Compact Pc PM3")},
+	{USB_DEVICE(0x10fd, 0x7e50), DVNM("FlyCam Usb 100")},
+	{USB_DEVICE(0xabcd, 0xcdee), DVNM("Petcam")},
+	{}
+};
+
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+		    const struct usb_device_id *id)
+{
+	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+			       THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+	.name = MODULE_NAME,
+	.id_table = device_table,
+	.probe = sd_probe,
+	.disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+	if (usb_register(&sd_driver) < 0)
+		return -1;
+	PDEBUG(D_PROBE, "v%s registered", version);
+	return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+	usb_deregister(&sd_driver);
+	PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/stk014.c b/drivers/media/video/gspca/stk014.c
index d8c203e..6832fe0 100644
--- a/drivers/media/video/gspca/stk014.c
+++ b/drivers/media/video/gspca/stk014.c
@@ -23,8 +23,8 @@
 #include "gspca.h"
 #include "jpeg.h"
 
-#define DRIVER_VERSION_NUMBER	KERNEL_VERSION(0, 2, 7)
-static const char version[] = "0.2.7";
+#define DRIVER_VERSION_NUMBER	KERNEL_VERSION(2, 1, 0)
+static const char version[] = "2.1.0";
 
 MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>");
 MODULE_DESCRIPTION("Syntek DV4000 (STK014) USB Camera Driver");
@@ -37,10 +37,10 @@
 	unsigned char brightness;
 	unsigned char contrast;
 	unsigned char colors;
+	unsigned char lightfreq;
 };
 
 /* global parameters */
-static int lightfreq = 50;
 static int sd_quant = 7;		/* <= 4 KO - 7: good (enough!) */
 
 /* V4L2 controls supported by the driver */
@@ -50,6 +50,8 @@
 static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
 static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
 
 static struct ctrl sd_ctrls[] = {
 #define SD_BRIGHTNESS 0
@@ -94,6 +96,20 @@
 	    .set = sd_setcolors,
 	    .get = sd_getcolors,
 	},
+#define SD_FREQ 3
+	{
+	    {
+		.id	 = V4L2_CID_POWER_LINE_FREQUENCY,
+		.type    = V4L2_CTRL_TYPE_MENU,
+		.name    = "Light frequency filter",
+		.minimum = 1,
+		.maximum = 2,	/* 0: 0, 1: 50Hz, 2:60Hz */
+		.step    = 1,
+		.default_value = 1,
+	    },
+	    .set = sd_setfreq,
+	    .get = sd_getfreq,
+	},
 };
 
 static struct cam_mode vga_mode[] = {
@@ -102,11 +118,11 @@
 };
 
 /* -- read a register -- */
-static int reg_read(struct gspca_dev *gspca_dev,
+static int reg_r(struct gspca_dev *gspca_dev,
 			__u16 index, __u8 *buf)
 {
-	int ret;
 	struct usb_device *dev = gspca_dev->dev;
+	int ret;
 
 	ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
 			0x00,
@@ -116,12 +132,12 @@
 			buf, 1,
 			500);
 	if (ret < 0)
-		PDEBUG(D_ERR, "reg_read err %d", ret);
+		PDEBUG(D_ERR, "reg_r err %d", ret);
 	return ret;
 }
 
 /* -- write a register -- */
-static int reg_write(struct gspca_dev *gspca_dev,
+static int reg_w(struct gspca_dev *gspca_dev,
 			__u16 index, __u16 value)
 {
 	struct usb_device *dev = gspca_dev->dev;
@@ -136,7 +152,7 @@
 			0,
 			500);
 	if (ret < 0)
-		PDEBUG(D_ERR, "reg_write err %d", ret);
+		PDEBUG(D_ERR, "reg_w err %d", ret);
 	return ret;
 }
 
@@ -149,15 +165,15 @@
 	int alen, ret;
 	unsigned char bulk_buf[4];
 
-	reg_write(gspca_dev, 0x634, (ads >> 16) & 0xff);
-	reg_write(gspca_dev, 0x635, (ads >> 8) & 0xff);
-	reg_write(gspca_dev, 0x636, ads & 0xff);
-	reg_write(gspca_dev, 0x637, 0);
-	reg_write(gspca_dev, 0x638, len & 0xff);
-	reg_write(gspca_dev, 0x639, len >> 8);
-	reg_write(gspca_dev, 0x63a, 0);
-	reg_write(gspca_dev, 0x63b, 0);
-	reg_write(gspca_dev, 0x630, 5);
+	reg_w(gspca_dev, 0x634, (ads >> 16) & 0xff);
+	reg_w(gspca_dev, 0x635, (ads >> 8) & 0xff);
+	reg_w(gspca_dev, 0x636, ads & 0xff);
+	reg_w(gspca_dev, 0x637, 0);
+	reg_w(gspca_dev, 0x638, len & 0xff);
+	reg_w(gspca_dev, 0x639, len >> 8);
+	reg_w(gspca_dev, 0x63a, 0);
+	reg_w(gspca_dev, 0x63b, 0);
+	reg_w(gspca_dev, 0x630, 5);
 	if (len > sizeof bulk_buf)
 		return -1;
 	ret = usb_bulk_msg(dev,
@@ -180,26 +196,26 @@
 	unsigned char bulk_buf[4];
 
 	if (ads == 0x003f08) {
-		ret = reg_read(gspca_dev, 0x0704, &value);
+		ret = reg_r(gspca_dev, 0x0704, &value);
 		if (ret < 0)
 			goto ko;
-		ret = reg_read(gspca_dev, 0x0705, &seq);
+		ret = reg_r(gspca_dev, 0x0705, &seq);
 		if (ret < 0)
 			goto ko;
-		ret = reg_read(gspca_dev, 0x0650, &value);
+		ret = reg_r(gspca_dev, 0x0650, &value);
 		if (ret < 0)
 			goto ko;
-		reg_write(gspca_dev, 0x654, seq);
+		reg_w(gspca_dev, 0x654, seq);
 	} else
-		reg_write(gspca_dev, 0x654, (ads >> 16) & 0xff);
-	reg_write(gspca_dev, 0x655, (ads >> 8) & 0xff);
-	reg_write(gspca_dev, 0x656, ads & 0xff);
-	reg_write(gspca_dev, 0x657, 0);
-	reg_write(gspca_dev, 0x658, 0x04);	/* size */
-	reg_write(gspca_dev, 0x659, 0);
-	reg_write(gspca_dev, 0x65a, 0);
-	reg_write(gspca_dev, 0x65b, 0);
-	reg_write(gspca_dev, 0x650, 5);
+		reg_w(gspca_dev, 0x654, (ads >> 16) & 0xff);
+	reg_w(gspca_dev, 0x655, (ads >> 8) & 0xff);
+	reg_w(gspca_dev, 0x656, ads & 0xff);
+	reg_w(gspca_dev, 0x657, 0);
+	reg_w(gspca_dev, 0x658, 0x04);	/* size */
+	reg_w(gspca_dev, 0x659, 0);
+	reg_w(gspca_dev, 0x65a, 0);
+	reg_w(gspca_dev, 0x65b, 0);
+	reg_w(gspca_dev, 0x650, 5);
 	bulk_buf[0] = (val >> 24) & 0xff;
 	bulk_buf[1] = (val >> 16) & 0xff;
 	bulk_buf[2] = (val >> 8) & 0xff;
@@ -215,7 +231,7 @@
 	if (ads == 0x003f08) {
 		seq += 4;
 		seq &= 0x3f;
-		reg_write(gspca_dev, 0x705, seq);
+		reg_w(gspca_dev, 0x705, seq);
 	}
 	return ret;
 ko:
@@ -235,7 +251,6 @@
 	struct sd *sd = (struct sd *) gspca_dev;
 	int parval;
 
-	PDEBUG(D_CONF, "brightness: %d", sd->brightness);
 	parval = 0x06000000		/* whiteness */
 		+ (sd->brightness << 16);
 	set_par(gspca_dev, parval);
@@ -246,7 +261,6 @@
 	struct sd *sd = (struct sd *) gspca_dev;
 	int parval;
 
-	PDEBUG(D_CONF, "contrast: %d", sd->contrast);
 	parval = 0x07000000		/* contrast */
 		+ (sd->contrast << 16);
 	set_par(gspca_dev, parval);
@@ -257,13 +271,20 @@
 	struct sd *sd = (struct sd *) gspca_dev;
 	int parval;
 
-	PDEBUG(D_CONF, "saturation: %d",
-		sd->colors);
 	parval = 0x08000000		/* saturation */
 		+ (sd->colors << 16);
 	set_par(gspca_dev, parval);
 }
 
+static void setfreq(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	set_par(gspca_dev, sd->lightfreq == 1
+			? 0x33640000		/* 50 Hz */
+			: 0x33780000);		/* 60 Hz */
+}
+
 /* this function is called at probe time */
 static int sd_config(struct gspca_dev *gspca_dev,
 			const struct usb_device_id *id)
@@ -278,6 +299,7 @@
 	sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
 	sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
 	sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value;
+	sd->lightfreq = sd_ctrls[SD_FREQ].qctrl.default_value;
 	return 0;
 }
 
@@ -289,7 +311,7 @@
 
 	/* check if the device responds */
 	usb_set_interface(gspca_dev->dev, gspca_dev->iface, 1);
-	ret = reg_read(gspca_dev, 0x0740, &value);
+	ret = reg_r(gspca_dev, 0x0740, &value);
 	if (ret < 0)
 		return ret;
 	if (value != 0xff) {
@@ -320,21 +342,24 @@
 	ret = usb_set_interface(gspca_dev->dev,
 					gspca_dev->iface,
 					gspca_dev->alt);
-	if (ret < 0)
+	if (ret < 0) {
+		PDEBUG(D_ERR|D_STREAM, "set intf %d %d failed",
+			gspca_dev->iface, gspca_dev->alt);
 		goto out;
-	ret = reg_read(gspca_dev, 0x0630, &dum);
+	}
+	ret = reg_r(gspca_dev, 0x0630, &dum);
 	if (ret < 0)
 		goto out;
 	rcv_val(gspca_dev, 0x000020, 4);	/* << (value ff ff ff ff) */
-	ret = reg_read(gspca_dev, 0x0650, &dum);
+	ret = reg_r(gspca_dev, 0x0650, &dum);
 	if (ret < 0)
 		goto out;
 	snd_val(gspca_dev, 0x000020, 0xffffffff);
-	reg_write(gspca_dev, 0x0620, 0);
-	reg_write(gspca_dev, 0x0630, 0);
-	reg_write(gspca_dev, 0x0640, 0);
-	reg_write(gspca_dev, 0x0650, 0);
-	reg_write(gspca_dev, 0x0660, 0);
+	reg_w(gspca_dev, 0x0620, 0);
+	reg_w(gspca_dev, 0x0630, 0);
+	reg_w(gspca_dev, 0x0640, 0);
+	reg_w(gspca_dev, 0x0650, 0);
+	reg_w(gspca_dev, 0x0660, 0);
 	setbrightness(gspca_dev);		/* whiteness */
 	setcontrast(gspca_dev);			/* contrast */
 	setcolors(gspca_dev);			/* saturation */
@@ -342,9 +367,7 @@
 	set_par(gspca_dev, 0x0a800000);		/* Green ? */
 	set_par(gspca_dev, 0x0b800000);		/* Blue ? */
 	set_par(gspca_dev, 0x0d030000);		/* Gamma ? */
-	set_par(gspca_dev, lightfreq == 60
-			? 0x33780000		/* 60 Hz */
-			: 0x33640000);		/* 50 Hz */
+	setfreq(gspca_dev);			/* light frequency */
 
 	/* start the video flow */
 	set_par(gspca_dev, 0x01000000);
@@ -363,15 +386,15 @@
 	set_par(gspca_dev, 0x02000000);
 	set_par(gspca_dev, 0x02000000);
 	usb_set_interface(dev, gspca_dev->iface, 1);
-	reg_read(gspca_dev, 0x0630, &value);
+	reg_r(gspca_dev, 0x0630, &value);
 	rcv_val(gspca_dev, 0x000020, 4);	/* << (value ff ff ff ff) */
-	reg_read(gspca_dev, 0x0650, &value);
+	reg_r(gspca_dev, 0x0650, &value);
 	snd_val(gspca_dev, 0x000020, 0xffffffff);
-	reg_write(gspca_dev, 0x0620, 0);
-	reg_write(gspca_dev, 0x0630, 0);
-	reg_write(gspca_dev, 0x0640, 0);
-	reg_write(gspca_dev, 0x0650, 0);
-	reg_write(gspca_dev, 0x0660, 0);
+	reg_w(gspca_dev, 0x0620, 0);
+	reg_w(gspca_dev, 0x0630, 0);
+	reg_w(gspca_dev, 0x0640, 0);
+	reg_w(gspca_dev, 0x0650, 0);
+	reg_w(gspca_dev, 0x0660, 0);
 	PDEBUG(D_STREAM, "camera stopped");
 }
 
@@ -470,6 +493,42 @@
 	return 0;
 }
 
+static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->lightfreq = val;
+	if (gspca_dev->streaming)
+		setfreq(gspca_dev);
+	return 0;
+}
+
+static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->lightfreq;
+	return 0;
+}
+
+static int sd_querymenu(struct gspca_dev *gspca_dev,
+			struct v4l2_querymenu *menu)
+{
+	switch (menu->id) {
+	case V4L2_CID_POWER_LINE_FREQUENCY:
+		switch (menu->index) {
+		case 1:		/* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
+			strcpy(menu->name, "50 Hz");
+			return 0;
+		case 2:		/* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
+			strcpy(menu->name, "60 Hz");
+			return 0;
+		}
+		break;
+	}
+	return -EINVAL;
+}
+
 /* sub-driver description */
 static struct sd_desc sd_desc = {
 	.name = MODULE_NAME,
@@ -482,6 +541,7 @@
 	.stop0 = sd_stop0,
 	.close = sd_close,
 	.pkt_scan = sd_pkt_scan,
+	.querymenu = sd_querymenu,
 };
 
 /* -- module initialisation -- */
@@ -524,7 +584,5 @@
 module_init(sd_mod_init);
 module_exit(sd_mod_exit);
 
-module_param(lightfreq, int, 0644);
-MODULE_PARM_DESC(lightfreq, "Light frequency 50 or 60 Hz");
 module_param_named(quant, sd_quant, int, 0644);
 MODULE_PARM_DESC(quant, "Quantization index (0..8)");
diff --git a/drivers/media/video/gspca/sunplus.c b/drivers/media/video/gspca/sunplus.c
new file mode 100644
index 0000000..52d1b32
--- /dev/null
+++ b/drivers/media/video/gspca/sunplus.c
@@ -0,0 +1,1638 @@
+/*
+ *		Sunplus spca504(abc) spca533 spca536 library
+ *		Copyright (C) 2005 Michel Xhaard mxhaard@magic.fr
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define MODULE_NAME "sunplus"
+
+#include "gspca.h"
+#include "jpeg.h"
+
+#define DRIVER_VERSION_NUMBER	KERNEL_VERSION(2, 1, 0)
+static const char version[] = "2.1.0";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("GSPCA/SPCA5xx USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+	struct gspca_dev gspca_dev;	/* !! must be the first item */
+
+	unsigned char packet[ISO_MAX_SIZE + 128];
+				/* !! no more than 128 ff in an ISO packet */
+
+	unsigned char brightness;
+	unsigned char contrast;
+	unsigned char colors;
+	unsigned char autogain;
+
+	char qindex;
+	char bridge;
+#define BRIDGE_SPCA504 0
+#define BRIDGE_SPCA504B 1
+#define BRIDGE_SPCA504C 2
+#define BRIDGE_SPCA533 3
+#define BRIDGE_SPCA536 4
+	char subtype;
+#define AiptekMiniPenCam13 1
+#define LogitechClickSmart420 2
+#define LogitechClickSmart820 3
+#define MegapixV4 4
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+#define SD_BRIGHTNESS 0
+	{
+	    {
+		.id      = V4L2_CID_BRIGHTNESS,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Brightness",
+		.minimum = 0,
+		.maximum = 0xff,
+		.step    = 1,
+		.default_value = 0,
+	    },
+	    .set = sd_setbrightness,
+	    .get = sd_getbrightness,
+	},
+#define SD_CONTRAST 1
+	{
+	    {
+		.id      = V4L2_CID_CONTRAST,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Contrast",
+		.minimum = 0,
+		.maximum = 0xff,
+		.step    = 1,
+		.default_value = 0x20,
+	    },
+	    .set = sd_setcontrast,
+	    .get = sd_getcontrast,
+	},
+#define SD_COLOR 2
+	{
+	    {
+		.id      = V4L2_CID_SATURATION,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Color",
+		.minimum = 0,
+		.maximum = 0xff,
+		.step    = 1,
+		.default_value = 0x1a,
+	    },
+	    .set = sd_setcolors,
+	    .get = sd_getcolors,
+	},
+#define SD_AUTOGAIN 3
+	{
+	    {
+		.id      = V4L2_CID_AUTOGAIN,
+		.type    = V4L2_CTRL_TYPE_BOOLEAN,
+		.name    = "Auto Gain",
+		.minimum = 0,
+		.maximum = 1,
+		.step    = 1,
+		.default_value = 1,
+	    },
+	    .set = sd_setautogain,
+	    .get = sd_getautogain,
+	},
+};
+
+static struct cam_mode vga_mode[] = {
+	{V4L2_PIX_FMT_JPEG, 320, 240, 2},
+	{V4L2_PIX_FMT_JPEG, 640, 480, 1},
+};
+
+static struct cam_mode custom_mode[] = {
+	{V4L2_PIX_FMT_JPEG, 320, 240, 2},
+	{V4L2_PIX_FMT_JPEG, 464, 480, 1},
+};
+
+static struct cam_mode vga_mode2[] = {
+	{V4L2_PIX_FMT_JPEG, 176, 144, 4},
+	{V4L2_PIX_FMT_JPEG, 320, 240, 3},
+	{V4L2_PIX_FMT_JPEG, 352, 288, 2},
+	{V4L2_PIX_FMT_JPEG, 640, 480, 1},
+};
+
+#define SPCA50X_OFFSET_DATA 10
+#define SPCA504_PCCAM600_OFFSET_SNAPSHOT 3
+#define SPCA504_PCCAM600_OFFSET_COMPRESS 4
+#define SPCA504_PCCAM600_OFFSET_MODE	 5
+#define SPCA504_PCCAM600_OFFSET_DATA	 14
+ /* Frame packet header offsets for the spca533 */
+#define SPCA533_OFFSET_DATA      16
+#define SPCA533_OFFSET_FRAMSEQ	15
+/* Frame packet header offsets for the spca536 */
+#define SPCA536_OFFSET_DATA      4
+#define SPCA536_OFFSET_FRAMSEQ	 1
+
+/* Initialisation data for the Creative PC-CAM 600 */
+static __u16 spca504_pccam600_init_data[][3] = {
+/*	{0xa0, 0x0000, 0x0503},  * capture mode */
+	{0x00, 0x0000, 0x2000},
+	{0x00, 0x0013, 0x2301},
+	{0x00, 0x0003, 0x2000},
+	{0x00, 0x0001, 0x21ac},
+	{0x00, 0x0001, 0x21a6},
+	{0x00, 0x0000, 0x21a7},	/* brightness */
+	{0x00, 0x0020, 0x21a8},	/* contrast */
+	{0x00, 0x0001, 0x21ac},	/* sat/hue */
+	{0x00, 0x0000, 0x21ad},	/* hue */
+	{0x00, 0x001a, 0x21ae},	/* saturation */
+	{0x00, 0x0002, 0x21a3},	/* gamma */
+	{0x30, 0x0154, 0x0008},
+	{0x30, 0x0004, 0x0006},
+	{0x30, 0x0258, 0x0009},
+	{0x30, 0x0004, 0x0000},
+	{0x30, 0x0093, 0x0004},
+	{0x30, 0x0066, 0x0005},
+	{0x00, 0x0000, 0x2000},
+	{0x00, 0x0013, 0x2301},
+	{0x00, 0x0003, 0x2000},
+	{0x00, 0x0013, 0x2301},
+	{0x00, 0x0003, 0x2000},
+	{}
+};
+
+/* Creative PC-CAM 600 specific open data, sent before using the
+ * generic initialisation data from spca504_open_data.
+ */
+static __u16 spca504_pccam600_open_data[][3] = {
+	{0x00, 0x0001, 0x2501},
+	{0x20, 0x0500, 0x0001},	/* snapshot mode */
+	{0x00, 0x0003, 0x2880},
+	{0x00, 0x0001, 0x2881},
+	{}
+};
+
+/* Initialisation data for the logitech clicksmart 420 */
+static __u16 spca504A_clicksmart420_init_data[][3] = {
+/*	{0xa0, 0x0000, 0x0503},  * capture mode */
+	{0x00, 0x0000, 0x2000},
+	{0x00, 0x0013, 0x2301},
+	{0x00, 0x0003, 0x2000},
+	{0x00, 0x0001, 0x21ac},
+	{0x00, 0x0001, 0x21a6},
+	{0x00, 0x0000, 0x21a7},	/* brightness */
+	{0x00, 0x0020, 0x21a8},	/* contrast */
+	{0x00, 0x0001, 0x21ac},	/* sat/hue */
+	{0x00, 0x0000, 0x21ad},	/* hue */
+	{0x00, 0x001a, 0x21ae},	/* saturation */
+	{0x00, 0x0002, 0x21a3},	/* gamma */
+	{0x30, 0x0004, 0x000a},
+	{0xb0, 0x0001, 0x0000},
+
+
+	{0x0a1, 0x0080, 0x0001},
+	{0x30, 0x0049, 0x0000},
+	{0x30, 0x0060, 0x0005},
+	{0x0c, 0x0004, 0x0000},
+	{0x00, 0x0000, 0x0000},
+	{0x00, 0x0000, 0x2000},
+	{0x00, 0x0013, 0x2301},
+	{0x00, 0x0003, 0x2000},
+	{0x00, 0x0000, 0x2000},
+
+	{}
+};
+
+/* clicksmart 420 open data ? */
+static __u16 spca504A_clicksmart420_open_data[][3] = {
+	{0x00, 0x0001, 0x2501},
+	{0x20, 0x0502, 0x0000},
+	{0x06, 0x0000, 0x0000},
+	{0x00, 0x0004, 0x2880},
+	{0x00, 0x0001, 0x2881},
+/* look like setting a qTable */
+	{0x00, 0x0006, 0x2800},
+	{0x00, 0x0004, 0x2801},
+	{0x00, 0x0004, 0x2802},
+	{0x00, 0x0006, 0x2803},
+	{0x00, 0x000a, 0x2804},
+	{0x00, 0x0010, 0x2805},
+	{0x00, 0x0014, 0x2806},
+	{0x00, 0x0018, 0x2807},
+	{0x00, 0x0005, 0x2808},
+	{0x00, 0x0005, 0x2809},
+	{0x00, 0x0006, 0x280a},
+	{0x00, 0x0008, 0x280b},
+	{0x00, 0x000a, 0x280c},
+	{0x00, 0x0017, 0x280d},
+	{0x00, 0x0018, 0x280e},
+	{0x00, 0x0016, 0x280f},
+
+	{0x00, 0x0006, 0x2810},
+	{0x00, 0x0005, 0x2811},
+	{0x00, 0x0006, 0x2812},
+	{0x00, 0x000a, 0x2813},
+	{0x00, 0x0010, 0x2814},
+	{0x00, 0x0017, 0x2815},
+	{0x00, 0x001c, 0x2816},
+	{0x00, 0x0016, 0x2817},
+	{0x00, 0x0006, 0x2818},
+	{0x00, 0x0007, 0x2819},
+	{0x00, 0x0009, 0x281a},
+	{0x00, 0x000c, 0x281b},
+	{0x00, 0x0014, 0x281c},
+	{0x00, 0x0023, 0x281d},
+	{0x00, 0x0020, 0x281e},
+	{0x00, 0x0019, 0x281f},
+
+	{0x00, 0x0007, 0x2820},
+	{0x00, 0x0009, 0x2821},
+	{0x00, 0x000f, 0x2822},
+	{0x00, 0x0016, 0x2823},
+	{0x00, 0x001b, 0x2824},
+	{0x00, 0x002c, 0x2825},
+	{0x00, 0x0029, 0x2826},
+	{0x00, 0x001f, 0x2827},
+	{0x00, 0x000a, 0x2828},
+	{0x00, 0x000e, 0x2829},
+	{0x00, 0x0016, 0x282a},
+	{0x00, 0x001a, 0x282b},
+	{0x00, 0x0020, 0x282c},
+	{0x00, 0x002a, 0x282d},
+	{0x00, 0x002d, 0x282e},
+	{0x00, 0x0025, 0x282f},
+
+	{0x00, 0x0014, 0x2830},
+	{0x00, 0x001a, 0x2831},
+	{0x00, 0x001f, 0x2832},
+	{0x00, 0x0023, 0x2833},
+	{0x00, 0x0029, 0x2834},
+	{0x00, 0x0030, 0x2835},
+	{0x00, 0x0030, 0x2836},
+	{0x00, 0x0028, 0x2837},
+	{0x00, 0x001d, 0x2838},
+	{0x00, 0x0025, 0x2839},
+	{0x00, 0x0026, 0x283a},
+	{0x00, 0x0027, 0x283b},
+	{0x00, 0x002d, 0x283c},
+	{0x00, 0x0028, 0x283d},
+	{0x00, 0x0029, 0x283e},
+	{0x00, 0x0028, 0x283f},
+
+	{0x00, 0x0007, 0x2840},
+	{0x00, 0x0007, 0x2841},
+	{0x00, 0x000a, 0x2842},
+	{0x00, 0x0013, 0x2843},
+	{0x00, 0x0028, 0x2844},
+	{0x00, 0x0028, 0x2845},
+	{0x00, 0x0028, 0x2846},
+	{0x00, 0x0028, 0x2847},
+	{0x00, 0x0007, 0x2848},
+	{0x00, 0x0008, 0x2849},
+	{0x00, 0x000a, 0x284a},
+	{0x00, 0x001a, 0x284b},
+	{0x00, 0x0028, 0x284c},
+	{0x00, 0x0028, 0x284d},
+	{0x00, 0x0028, 0x284e},
+	{0x00, 0x0028, 0x284f},
+
+	{0x00, 0x000a, 0x2850},
+	{0x00, 0x000a, 0x2851},
+	{0x00, 0x0016, 0x2852},
+	{0x00, 0x0028, 0x2853},
+	{0x00, 0x0028, 0x2854},
+	{0x00, 0x0028, 0x2855},
+	{0x00, 0x0028, 0x2856},
+	{0x00, 0x0028, 0x2857},
+	{0x00, 0x0013, 0x2858},
+	{0x00, 0x001a, 0x2859},
+	{0x00, 0x0028, 0x285a},
+	{0x00, 0x0028, 0x285b},
+	{0x00, 0x0028, 0x285c},
+	{0x00, 0x0028, 0x285d},
+	{0x00, 0x0028, 0x285e},
+	{0x00, 0x0028, 0x285f},
+
+	{0x00, 0x0028, 0x2860},
+	{0x00, 0x0028, 0x2861},
+	{0x00, 0x0028, 0x2862},
+	{0x00, 0x0028, 0x2863},
+	{0x00, 0x0028, 0x2864},
+	{0x00, 0x0028, 0x2865},
+	{0x00, 0x0028, 0x2866},
+	{0x00, 0x0028, 0x2867},
+	{0x00, 0x0028, 0x2868},
+	{0x00, 0x0028, 0x2869},
+	{0x00, 0x0028, 0x286a},
+	{0x00, 0x0028, 0x286b},
+	{0x00, 0x0028, 0x286c},
+	{0x00, 0x0028, 0x286d},
+	{0x00, 0x0028, 0x286e},
+	{0x00, 0x0028, 0x286f},
+
+	{0x00, 0x0028, 0x2870},
+	{0x00, 0x0028, 0x2871},
+	{0x00, 0x0028, 0x2872},
+	{0x00, 0x0028, 0x2873},
+	{0x00, 0x0028, 0x2874},
+	{0x00, 0x0028, 0x2875},
+	{0x00, 0x0028, 0x2876},
+	{0x00, 0x0028, 0x2877},
+	{0x00, 0x0028, 0x2878},
+	{0x00, 0x0028, 0x2879},
+	{0x00, 0x0028, 0x287a},
+	{0x00, 0x0028, 0x287b},
+	{0x00, 0x0028, 0x287c},
+	{0x00, 0x0028, 0x287d},
+	{0x00, 0x0028, 0x287e},
+	{0x00, 0x0028, 0x287f},
+
+	{0xa0, 0x0000, 0x0503},
+	{}
+};
+
+static unsigned char qtable_creative_pccam[2][64] = {
+	{				/* Q-table Y-components */
+	 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
+	 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
+	 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11,
+	 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13,
+	 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17,
+	 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c,
+	 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e,
+	 0x16, 0x1c, 0x1d, 0x1d, 0x22, 0x1e, 0x1f, 0x1e},
+	{				/* Q-table C-components */
+	 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e,
+	 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e,
+	 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+	 0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+	 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+	 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+	 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+	 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
+};
+
+/* FIXME: This Q-table is identical to the Creative PC-CAM one,
+ *		except for one byte. Possibly a typo?
+ *		NWG: 18/05/2003.
+ */
+static unsigned char qtable_spca504_default[2][64] = {
+	{				/* Q-table Y-components */
+	 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
+	 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
+	 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11,
+	 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13,
+	 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17,
+	 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c,
+	 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e,
+	 0x16, 0x1c, 0x1d, 0x1d, 0x1d /* 0x22 */ , 0x1e, 0x1f, 0x1e,
+	 },
+	{				/* Q-table C-components */
+	 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e,
+	 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e,
+	 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+	 0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+	 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+	 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+	 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+	 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
+};
+
+static void spca5xxRegRead(struct usb_device *dev,
+			   __u16 req,
+			   __u16 index,
+			   __u8 *buffer, __u16 length)
+{
+	usb_control_msg(dev,
+			usb_rcvctrlpipe(dev, 0),
+			req,
+			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			0,		/* value */
+			index, buffer, length,
+			500);
+}
+
+static void spca5xxRegWrite(struct usb_device *dev,
+			    __u16 req,
+			    __u16 value,
+			    __u16 index,
+			    __u8 *buffer, __u16 length)
+{
+	usb_control_msg(dev,
+			usb_sndctrlpipe(dev, 0),
+			req,
+			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			value, index, buffer, length,
+			500);
+}
+
+static int reg_write(struct usb_device *dev,
+		     __u16 req, __u16 index, __u16 value)
+{
+	int ret;
+
+	ret = usb_control_msg(dev,
+			usb_sndctrlpipe(dev, 0),
+			req,
+			USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			value, index, NULL, 0, 500);
+	PDEBUG(D_PACK, "reg write: 0x%02x,0x%02x:0x%02x, 0x%x",
+		reg, index, value, ret);
+	if (ret < 0)
+		PDEBUG(D_ERR, "reg write: error %d", ret);
+	return ret;
+}
+
+static int reg_read_info(struct usb_device *dev,
+			__u16 value)	/* wValue */
+{
+	int ret;
+	__u8 data;
+
+	ret = usb_control_msg(dev,
+			usb_rcvctrlpipe(dev, 0),
+			0x20,			/* request */
+			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			value,
+			0,			/* index */
+			&data, 1,
+			500);			/* timeout */
+	if (ret < 0) {
+		PDEBUG(D_ERR, "reg_read_info err %d", ret);
+		return 0;
+	}
+	return data;
+}
+
+/* returns: negative is error, pos or zero is data */
+static int reg_read(struct usb_device *dev,
+			__u16 req,	/* bRequest */
+			__u16 index,	/* wIndex */
+			__u16 length)	/* wLength (1 or 2 only) */
+{
+	int ret;
+	__u8 buf[2];
+
+	buf[1] = 0;
+	ret = usb_control_msg(dev,
+			usb_rcvctrlpipe(dev, 0),
+			req,
+			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			0,		/* value */
+			index,
+			buf, length,
+			500);
+	if (ret < 0) {
+		PDEBUG(D_ERR, "reg_read err %d", ret);
+		return -1;
+	}
+	return (buf[1] << 8) + buf[0];
+}
+
+static int write_vector(struct gspca_dev *gspca_dev,
+				__u16 data[][3])
+{
+	struct usb_device *dev = gspca_dev->dev;
+	int ret, i = 0;
+
+	while (data[i][0] != 0 || data[i][1] != 0 || data[i][2] != 0) {
+		ret = reg_write(dev, data[i][0], data[i][2], data[i][1]);
+		if (ret < 0) {
+			PDEBUG(D_ERR,
+				"Register write failed for 0x%x,0x%x,0x%x",
+				data[i][0], data[i][1], data[i][2]);
+			return ret;
+		}
+		i++;
+	}
+	return 0;
+}
+
+static int spca50x_setup_qtable(struct gspca_dev *gspca_dev,
+				unsigned int request,
+				unsigned int ybase,
+				unsigned int cbase,
+				unsigned char qtable[2][64])
+{
+	struct usb_device *dev = gspca_dev->dev;
+	int i, err;
+
+	/* loop over y components */
+	for (i = 0; i < 64; i++) {
+		err = reg_write(dev, request, ybase + i, qtable[0][i]);
+		if (err < 0)
+			return err;
+	}
+
+	/* loop over c components */
+	for (i = 0; i < 64; i++) {
+		err = reg_write(dev, request, cbase + i, qtable[1][i]);
+		if (err < 0)
+			return err;
+	}
+	return 0;
+}
+
+static void spca504_acknowledged_command(struct gspca_dev *gspca_dev,
+			     __u16 req, __u16 idx, __u16 val)
+{
+	struct usb_device *dev = gspca_dev->dev;
+	__u8 notdone;
+
+	reg_write(dev, req, idx, val);
+	notdone = reg_read(dev, 0x01, 0x0001, 1);
+	reg_write(dev, req, idx, val);
+
+	PDEBUG(D_FRAM, "before wait 0x%x", notdone);
+
+	msleep(200);
+	notdone = reg_read(dev, 0x01, 0x0001, 1);
+	PDEBUG(D_FRAM, "after wait 0x%x", notdone);
+}
+
+static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev,
+			__u16 req,
+			__u16 idx, __u16 val, __u8 stat, __u8 count)
+{
+	struct usb_device *dev = gspca_dev->dev;
+	__u8 status;
+	__u8 endcode;
+
+	reg_write(dev, req, idx, val);
+	status = reg_read(dev, 0x01, 0x0001, 1);
+	endcode = stat;
+	PDEBUG(D_FRAM, "Status 0x%x Need 0x%x", status, stat);
+	if (!count)
+		return;
+	count = 200;
+	while (--count > 0) {
+		msleep(10);
+		/* gsmart mini2 write a each wait setting 1 ms is enought */
+/*		reg_write(dev, req, idx, val); */
+		status = reg_read(dev, 0x01, 0x0001, 1);
+		if (status == endcode) {
+			PDEBUG(D_FRAM, "status 0x%x after wait 0x%x",
+				status, 200 - count);
+				break;
+		}
+	}
+}
+
+static int spca504B_PollingDataReady(struct usb_device *dev)
+{
+	__u8 DataReady;
+	int count = 10;
+
+	while (--count > 0) {
+		spca5xxRegRead(dev, 0x21, 0, &DataReady, 1);
+		if ((DataReady & 0x01) == 0)
+			break;
+		msleep(10);
+	}
+	return DataReady;
+}
+
+static void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev)
+{
+	struct usb_device *dev = gspca_dev->dev;
+	__u8 DataReady;
+	int count = 50;
+
+	while (--count > 0) {
+		spca5xxRegRead(dev, 0x21, 1, &DataReady, 1);
+
+		if (DataReady) {
+			DataReady = 0;
+			spca5xxRegWrite(dev, 0x21, 0, 1, &DataReady, 1);
+			spca5xxRegRead(dev, 0x21, 1, &DataReady, 1);
+			spca504B_PollingDataReady(dev);
+			break;
+		}
+		msleep(10);
+	}
+}
+
+static void spca50x_GetFirmware(struct gspca_dev *gspca_dev)
+{
+	struct usb_device *dev = gspca_dev->dev;
+	__u8 FW[5];
+	__u8 ProductInfo[64];
+
+	spca5xxRegRead(dev, 0x20, 0, FW, 5);
+	PDEBUG(D_STREAM, "FirmWare : %d %d %d %d %d ",
+		FW[0], FW[1], FW[2], FW[3], FW[4]);
+	spca5xxRegRead(dev, 0x23, 0, ProductInfo, 64);
+	spca5xxRegRead(dev, 0x23, 1, ProductInfo, 64);
+}
+
+static void spca504B_SetSizeType(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct usb_device *dev = gspca_dev->dev;
+	__u8 Size;
+	__u8 Type;
+	int rc;
+
+	Size = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].mode;
+	Type = 0;
+	switch (sd->bridge) {
+	case BRIDGE_SPCA533:
+		spca5xxRegWrite(dev, 0x31, 0, 0, NULL, 0);
+		spca504B_WaitCmdStatus(gspca_dev);
+		rc = spca504B_PollingDataReady(dev);
+		spca50x_GetFirmware(gspca_dev);
+		Type = 2;
+		spca5xxRegWrite(dev, 0x24, 0, 8, &Type, 1);
+		spca5xxRegRead(dev, 0x24, 8, &Type, 1);
+
+		spca5xxRegWrite(dev, 0x25, 0, 4, &Size, 1);
+		spca5xxRegRead(dev, 0x25, 4, &Size, 1);
+		rc = spca504B_PollingDataReady(dev);
+
+		/* Init the cam width height with some values get on init ? */
+		spca5xxRegWrite(dev, 0x31, 0, 4, NULL, 0);
+		spca504B_WaitCmdStatus(gspca_dev);
+		rc = spca504B_PollingDataReady(dev);
+		break;
+	default:
+/* case BRIDGE_SPCA504B: */
+/* case BRIDGE_SPCA536: */
+		Type = 6;
+		spca5xxRegWrite(dev, 0x25, 0, 4, &Size, 1);
+		spca5xxRegRead(dev, 0x25, 4, &Size, 1);
+		spca5xxRegWrite(dev, 0x27, 0, 0, &Type, 1);
+		spca5xxRegRead(dev, 0x27, 0, &Type, 1);
+		rc = spca504B_PollingDataReady(dev);
+		break;
+	case BRIDGE_SPCA504:
+		Size += 3;
+		if (sd->subtype == AiptekMiniPenCam13) {
+			/* spca504a aiptek */
+			spca504A_acknowledged_command(gspca_dev,
+						0x08, Size, 0,
+						0x80 | (Size & 0x0f), 1);
+			spca504A_acknowledged_command(gspca_dev,
+							1, 3, 0, 0x9f, 0);
+		} else {
+			spca504_acknowledged_command(gspca_dev, 0x08, Size, 0);
+		}
+		break;
+	case BRIDGE_SPCA504C:
+		/* capture mode */
+		reg_write(dev, 0xa0, (0x0500 | (Size & 0x0f)), 0x0);
+		reg_write(dev, 0x20, 0x01, 0x0500 | (Size & 0x0f));
+		break;
+	}
+}
+
+static void spca504_wait_status(struct gspca_dev *gspca_dev)
+{
+	struct usb_device *dev = gspca_dev->dev;
+	int cnt;
+
+	cnt = 256;
+	while (--cnt > 0) {
+		/* With this we get the status, when return 0 it's all ok */
+		if (reg_read(dev, 0x06, 0x00, 1) == 0)
+			return;
+		msleep(10);
+	}
+}
+
+static void spca504B_setQtable(struct gspca_dev *gspca_dev)
+{
+	struct usb_device *dev = gspca_dev->dev;
+	__u8 Data = 3;
+
+	spca5xxRegWrite(dev, 0x26, 0, 0, &Data, 1);
+	spca5xxRegRead(dev, 0x26, 0, &Data, 1);
+	spca504B_PollingDataReady(dev);
+}
+
+static void sp5xx_initContBrigHueRegisters(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct usb_device *dev = gspca_dev->dev;
+	int pollreg = 1;
+
+	switch (sd->bridge) {
+	case BRIDGE_SPCA504:
+	case BRIDGE_SPCA504C:
+		pollreg = 0;
+		/* fall thru */
+	default:
+/*	case BRIDGE_SPCA533: */
+/*	case BRIDGE_SPCA504B: */
+		spca5xxRegWrite(dev, 0, 0, 0x21a7, NULL, 0);	/* brightness */
+		spca5xxRegWrite(dev, 0, 0x20, 0x21a8, NULL, 0);	/* contrast */
+		spca5xxRegWrite(dev, 0, 0, 0x21ad, NULL, 0);	/* hue */
+		spca5xxRegWrite(dev, 0, 1, 0x21ac, NULL, 0);	/* sat/hue */
+		spca5xxRegWrite(dev, 0, 0x20, 0x21ae, NULL, 0);	/* saturation */
+		spca5xxRegWrite(dev, 0, 0, 0x21a3, NULL, 0);	/* gamma */
+		break;
+	case BRIDGE_SPCA536:
+		spca5xxRegWrite(dev, 0, 0, 0x20f0, NULL, 0);
+		spca5xxRegWrite(dev, 0, 0x21, 0x20f1, NULL, 0);
+		spca5xxRegWrite(dev, 0, 0x40, 0x20f5, NULL, 0);
+		spca5xxRegWrite(dev, 0, 1, 0x20f4, NULL, 0);
+		spca5xxRegWrite(dev, 0, 0x40, 0x20f6, NULL, 0);
+		spca5xxRegWrite(dev, 0, 0, 0x2089, NULL, 0);
+		break;
+	}
+	if (pollreg)
+		spca504B_PollingDataReady(dev);
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+			const struct usb_device_id *id)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct usb_device *dev = gspca_dev->dev;
+	struct cam *cam;
+	__u16 vendor;
+	__u16 product;
+	__u8 fw;
+
+	vendor = id->idVendor;
+	product = id->idProduct;
+	switch (vendor) {
+	case 0x041e:		/* Creative cameras */
+/*		switch (product) { */
+/*		case 0x400b: */
+/*		case 0x4012: */
+/*		case 0x4013: */
+/*			sd->bridge = BRIDGE_SPCA504C; */
+/*			break; */
+/*		} */
+		break;
+	case 0x0458:		/* Genius KYE cameras */
+/*		switch (product) { */
+/*		case 0x7006: */
+			sd->bridge = BRIDGE_SPCA504B;
+/*			break; */
+/*		} */
+		break;
+	case 0x046d:		/* Logitech Labtec */
+		switch (product) {
+		case 0x0905:
+			sd->subtype = LogitechClickSmart820;
+			sd->bridge = BRIDGE_SPCA533;
+			break;
+		case 0x0960:
+			sd->subtype = LogitechClickSmart420;
+			sd->bridge = BRIDGE_SPCA504C;
+			break;
+		}
+		break;
+	case 0x0471:				/* Philips */
+/*		switch (product) { */
+/*		case 0x0322: */
+			sd->bridge = BRIDGE_SPCA504B;
+/*			break; */
+/*		} */
+		break;
+	case 0x04a5:		/* Benq */
+		switch (product) {
+		case 0x3003:
+			sd->bridge = BRIDGE_SPCA504B;
+			break;
+		case 0x3008:
+		case 0x300a:
+			sd->bridge = BRIDGE_SPCA533;
+			break;
+		}
+		break;
+	case 0x04f1:		/* JVC */
+/*		switch (product) { */
+/*		case 0x1001: */
+			sd->bridge = BRIDGE_SPCA504B;
+/*			break; */
+/*		} */
+		break;
+	case 0x04fc:		/* SunPlus */
+		switch (product) {
+		case 0x500c:
+			sd->bridge = BRIDGE_SPCA504B;
+			break;
+		case 0x504a:
+/* try to get the firmware as some cam answer 2.0.1.2.2
+ * and should be a spca504b then overwrite that setting */
+			spca5xxRegRead(dev, 0x20, 0, &fw, 1);
+			if (fw == 1) {
+				sd->subtype = AiptekMiniPenCam13;
+				sd->bridge = BRIDGE_SPCA504;
+			} else if (fw == 2) {
+				sd->bridge = BRIDGE_SPCA504B;
+			} else
+				return -ENODEV;
+			break;
+		case 0x504b:
+			sd->bridge = BRIDGE_SPCA504B;
+			break;
+		case 0x5330:
+			sd->bridge = BRIDGE_SPCA533;
+			break;
+		case 0x5360:
+			sd->bridge = BRIDGE_SPCA536;
+			break;
+		case 0xffff:
+			sd->bridge = BRIDGE_SPCA504B;
+			break;
+		}
+		break;
+	case 0x052b:		/* ?? Megapix */
+/*		switch (product) { */
+/*		case 0x1513: */
+			sd->subtype = MegapixV4;
+			sd->bridge = BRIDGE_SPCA533;
+/*			break; */
+/*		} */
+		break;
+	case 0x0546:		/* Polaroid */
+		switch (product) {
+		case 0x3155:
+			sd->bridge = BRIDGE_SPCA533;
+			break;
+		case 0x3191:
+		case 0x3273:
+			sd->bridge = BRIDGE_SPCA504B;
+			break;
+		}
+		break;
+	case 0x055f:		/* Mustek cameras */
+		switch (product) {
+		case 0xc211:
+			sd->bridge = BRIDGE_SPCA536;
+			break;
+		case 0xc230:
+		case 0xc232:
+			sd->bridge = BRIDGE_SPCA533;
+			break;
+		case 0xc360:
+			sd->bridge = BRIDGE_SPCA536;
+			break;
+		case 0xc420:
+			sd->bridge = BRIDGE_SPCA504;
+			break;
+		case 0xc430:
+		case 0xc440:
+			sd->bridge = BRIDGE_SPCA533;
+			break;
+		case 0xc520:
+			sd->bridge = BRIDGE_SPCA504;
+			break;
+		case 0xc530:
+		case 0xc540:
+		case 0xc630:
+		case 0xc650:
+			sd->bridge = BRIDGE_SPCA533;
+			break;
+		}
+		break;
+	case 0x05da:		/* Digital Dream cameras */
+/*		switch (product) { */
+/*		case 0x1018: */
+			sd->bridge = BRIDGE_SPCA504B;
+/*			break; */
+/*		} */
+		break;
+	case 0x06d6:		/* Trust */
+/*		switch (product) { */
+/*		case 0x0031: */
+			sd->bridge = BRIDGE_SPCA533;	/* SPCA533A */
+/*			break; */
+/*		} */
+		break;
+	case 0x0733:	/* Rebadged ViewQuest (Intel) and ViewQuest cameras */
+		switch (product) {
+		case 0x1311:
+		case 0x1314:
+		case 0x2211:
+		case 0x2221:
+			sd->bridge = BRIDGE_SPCA533;
+			break;
+		case 0x3261:
+		case 0x3281:
+			sd->bridge = BRIDGE_SPCA536;
+			break;
+		}
+		break;
+	case 0x08ca:		/* Aiptek */
+		switch (product) {
+		case 0x0104:
+		case 0x0106:
+			sd->bridge = BRIDGE_SPCA533;
+			break;
+		case 0x2008:
+			sd->bridge = BRIDGE_SPCA504B;
+			break;
+		case 0x2010:
+			sd->bridge = BRIDGE_SPCA533;
+			break;
+		case 0x2016:
+		case 0x2018:
+			sd->bridge = BRIDGE_SPCA504B;
+			break;
+		case 0x2020:
+		case 0x2022:
+			sd->bridge = BRIDGE_SPCA533;
+			break;
+		case 0x2024:
+			sd->bridge = BRIDGE_SPCA536;
+			break;
+		case 0x2028:
+			sd->bridge = BRIDGE_SPCA533;
+			break;
+		case 0x2040:
+		case 0x2042:
+		case 0x2060:
+			sd->bridge = BRIDGE_SPCA536;
+			break;
+		}
+		break;
+	case 0x0d64:		/* SunPlus */
+/*		switch (product) { */
+/*		case 0x0303: */
+			sd->bridge = BRIDGE_SPCA536;
+/*			break; */
+/*		} */
+		break;
+	}
+
+	cam = &gspca_dev->cam;
+	cam->dev_name = (char *) id->driver_info;
+	cam->epaddr = 0x01;
+
+	switch (sd->bridge) {
+	default:
+/*	case BRIDGE_SPCA504B: */
+/*	case BRIDGE_SPCA504: */
+/*	case BRIDGE_SPCA536: */
+		cam->cam_mode = vga_mode;
+		cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+		break;
+	case BRIDGE_SPCA533:
+		cam->cam_mode = custom_mode;
+		cam->nmodes = sizeof custom_mode / sizeof custom_mode[0];
+		break;
+	case BRIDGE_SPCA504C:
+		cam->cam_mode = vga_mode2;
+		cam->nmodes = sizeof vga_mode2 / sizeof vga_mode2[0];
+		break;
+	}
+	sd->qindex = 5;			/* set the quantization table */
+	sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
+	sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
+	sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value;
+	return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct usb_device *dev = gspca_dev->dev;
+	int rc;
+	__u8 Data;
+	__u8 i;
+	__u8 info[6];
+	int err_code;
+
+	switch (sd->bridge) {
+	case BRIDGE_SPCA504B:
+		spca5xxRegWrite(dev, 0x1d, 0, 0, NULL, 0);
+		spca5xxRegWrite(dev, 0, 1, 0x2306, NULL, 0);
+		spca5xxRegWrite(dev, 0, 0, 0x0d04, NULL, 0);
+		spca5xxRegWrite(dev, 0, 0, 0x2000, NULL, 0);
+		spca5xxRegWrite(dev, 0, 0x13, 0x2301, NULL, 0);
+		spca5xxRegWrite(dev, 0, 0, 0x2306, NULL, 0);
+		/* fall thru */
+	case BRIDGE_SPCA533:
+		rc = spca504B_PollingDataReady(dev);
+		spca50x_GetFirmware(gspca_dev);
+		break;
+	case BRIDGE_SPCA536:
+		spca50x_GetFirmware(gspca_dev);
+		spca5xxRegRead(dev, 0x00, 0x5002, &Data, 1);
+		Data = 0;
+		spca5xxRegWrite(dev, 0x24, 0, 0, &Data, 1);
+		spca5xxRegRead(dev, 0x24, 0, &Data, 1);
+		rc = spca504B_PollingDataReady(dev);
+		spca5xxRegWrite(dev, 0x34, 0, 0, NULL, 0);
+		spca504B_WaitCmdStatus(gspca_dev);
+		break;
+	case BRIDGE_SPCA504C:	/* pccam600 */
+		PDEBUG(D_STREAM, "Opening SPCA504 (PC-CAM 600)");
+		reg_write(dev, 0xe0, 0x0000, 0x0000);
+		reg_write(dev, 0xe0, 0x0000, 0x0001);	/* reset */
+		spca504_wait_status(gspca_dev);
+		if (sd->subtype == LogitechClickSmart420)
+			write_vector(gspca_dev,
+					spca504A_clicksmart420_open_data);
+		else
+			write_vector(gspca_dev, spca504_pccam600_open_data);
+		err_code = spca50x_setup_qtable(gspca_dev,
+						0x00, 0x2800,
+						0x2840, qtable_creative_pccam);
+		if (err_code < 0) {
+			PDEBUG(D_ERR|D_STREAM, "spca50x_setup_qtable failed");
+			return err_code;
+		}
+		break;
+	default:
+/*	case BRIDGE_SPCA504: */
+		PDEBUG(D_STREAM, "Opening SPCA504");
+		if (sd->subtype == AiptekMiniPenCam13) {
+			/*****************************/
+			for (i = 0; i < 6; i++)
+				info[i] = reg_read_info(dev, i);
+			PDEBUG(D_STREAM,
+				"Read info: %d %d %d %d %d %d."
+				" Should be 1,0,2,2,0,0",
+				info[0], info[1], info[2],
+				info[3], info[4], info[5]);
+			/* spca504a aiptek */
+			/* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
+			spca504A_acknowledged_command(gspca_dev, 0x24,
+							8, 3, 0x9e, 1);
+			/* Twice sequencial need status 0xff->0x9e->0x9d */
+			spca504A_acknowledged_command(gspca_dev, 0x24,
+							8, 3, 0x9e, 0);
+
+			spca504A_acknowledged_command(gspca_dev, 0x24,
+							0, 0, 0x9d, 1);
+			/******************************/
+			/* spca504a aiptek */
+			spca504A_acknowledged_command(gspca_dev, 0x08,
+							6, 0, 0x86, 1);
+/*			reg_write (dev, 0, 0x2000, 0); */
+/*			reg_write (dev, 0, 0x2883, 1); */
+/*			spca504A_acknowledged_command (gspca_dev, 0x08,
+							6, 0, 0x86, 1); */
+/*			spca504A_acknowledged_command (gspca_dev, 0x24,
+							0, 0, 0x9D, 1); */
+			reg_write(dev, 0x0, 0x270c, 0x5); /* L92 sno1t.txt */
+			reg_write(dev, 0x0, 0x2310, 0x5);
+			spca504A_acknowledged_command(gspca_dev, 0x01,
+							0x0f, 0, 0xff, 0);
+		}
+		/* setup qtable */
+		reg_write(dev, 0, 0x2000, 0);
+		reg_write(dev, 0, 0x2883, 1);
+		err_code = spca50x_setup_qtable(gspca_dev,
+						0x00, 0x2800,
+						0x2840,
+						qtable_spca504_default);
+		if (err_code < 0) {
+			PDEBUG(D_ERR, "spca50x_setup_qtable failed");
+			return err_code;
+		}
+		break;
+	}
+	return 0;
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct usb_device *dev = gspca_dev->dev;
+	int rc;
+	int enable;
+	__u8 i;
+	__u8 info[6];
+
+	if (sd->bridge == BRIDGE_SPCA504B)
+		spca504B_setQtable(gspca_dev);
+	spca504B_SetSizeType(gspca_dev);
+	switch (sd->bridge) {
+	default:
+/*	case BRIDGE_SPCA504B: */
+/*	case BRIDGE_SPCA533: */
+/*	case BRIDGE_SPCA536: */
+		if (sd->subtype == MegapixV4 ||
+		    sd->subtype == LogitechClickSmart820) {
+			spca5xxRegWrite(dev, 0xf0, 0, 0, NULL, 0);
+			spca504B_WaitCmdStatus(gspca_dev);
+			spca5xxRegRead(dev, 0xf0, 4, NULL, 0);
+			spca504B_WaitCmdStatus(gspca_dev);
+		} else {
+			spca5xxRegWrite(dev, 0x31, 0, 4, NULL, 0);
+			spca504B_WaitCmdStatus(gspca_dev);
+			rc = spca504B_PollingDataReady(dev);
+		}
+		break;
+	case BRIDGE_SPCA504:
+		if (sd->subtype == AiptekMiniPenCam13) {
+			for (i = 0; i < 6; i++)
+				info[i] = reg_read_info(dev, i);
+			PDEBUG(D_STREAM,
+				"Read info: %d %d %d %d %d %d."
+				" Should be 1,0,2,2,0,0",
+				info[0], info[1], info[2],
+				info[3], info[4], info[5]);
+			/* spca504a aiptek */
+			/* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
+			spca504A_acknowledged_command(gspca_dev, 0x24,
+							8, 3, 0x9e, 1);
+			/* Twice sequencial need status 0xff->0x9e->0x9d */
+			spca504A_acknowledged_command(gspca_dev, 0x24,
+							8, 3, 0x9e, 0);
+			spca504A_acknowledged_command(gspca_dev, 0x24,
+							0, 0, 0x9d, 1);
+		} else {
+			spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
+			for (i = 0; i < 6; i++)
+				info[i] = reg_read_info(dev, i);
+			PDEBUG(D_STREAM,
+				"Read info: %d %d %d %d %d %d."
+				" Should be 1,0,2,2,0,0",
+				info[0], info[1], info[2],
+				info[3], info[4], info[5]);
+			spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
+			spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
+		}
+		spca504B_SetSizeType(gspca_dev);
+		reg_write(dev, 0x0, 0x270c, 0x5);	/* L92 sno1t.txt */
+		reg_write(dev, 0x0, 0x2310, 0x5);
+		break;
+	case BRIDGE_SPCA504C:
+		if (sd->subtype == LogitechClickSmart420) {
+			write_vector(gspca_dev,
+					spca504A_clicksmart420_init_data);
+		} else {
+			write_vector(gspca_dev, spca504_pccam600_init_data);
+		}
+		enable = (sd->autogain ? 0x4 : 0x1);
+		reg_write(dev, 0x0c, 0x0000, enable);	/* auto exposure */
+		reg_write(dev, 0xb0, 0x0000, enable);	/* auto whiteness */
+
+		/* set default exposure compensation and whiteness balance */
+		reg_write(dev, 0x30, 0x0001, 800);	/* ~ 20 fps */
+		reg_write(dev, 0x30, 0x0002, 1600);
+		spca504B_SetSizeType(gspca_dev);
+		break;
+	}
+	sp5xx_initContBrigHueRegisters(gspca_dev);
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct usb_device *dev = gspca_dev->dev;
+
+	switch (sd->bridge) {
+	default:
+/*	case BRIDGE_SPCA533: */
+/*	case BRIDGE_SPCA536: */
+/*	case BRIDGE_SPCA504B: */
+		spca5xxRegWrite(dev, 0x31, 0, 0, NULL, 0);
+		spca504B_WaitCmdStatus(gspca_dev);
+		spca504B_PollingDataReady(dev);
+		break;
+	case BRIDGE_SPCA504:
+	case BRIDGE_SPCA504C:
+		reg_write(dev, 0x00, 0x2000, 0x0000);
+
+		if (sd->subtype == AiptekMiniPenCam13) {
+			/* spca504a aiptek */
+/*			spca504A_acknowledged_command(gspca_dev, 0x08,
+							 6, 0, 0x86, 1); */
+			spca504A_acknowledged_command(gspca_dev, 0x24,
+							0x00, 0x00, 0x9d, 1);
+			spca504A_acknowledged_command(gspca_dev, 0x01,
+							0x0f, 0x00, 0xff, 1);
+		} else {
+			spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
+			reg_write(dev, 0x01, 0x000f, 0x0);
+		}
+		break;
+	}
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+			struct gspca_frame *frame,	/* target */
+			unsigned char *data,		/* isoc packet */
+			int len)			/* iso packet length */
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int i, sof = 0;
+	unsigned char *s, *d;
+	static unsigned char ffd9[] = {0xff, 0xd9};
+
+/* frames are jpeg 4.1.1 without 0xff escape */
+	switch (sd->bridge) {
+	case BRIDGE_SPCA533:
+		if (data[0] == 0xff) {
+			if (data[1] != 0x01) {	/* drop packet */
+/*				gspca_dev->last_packet_type = DISCARD_PACKET; */
+				return;
+			}
+			sof = 1;
+			data += SPCA533_OFFSET_DATA;
+			len -= SPCA533_OFFSET_DATA;
+		} else {
+			data += 1;
+			len -= 1;
+		}
+		break;
+	case BRIDGE_SPCA536:
+		if (data[0] == 0xff) {
+			sof = 1;
+			data += SPCA536_OFFSET_DATA;
+			len -= SPCA536_OFFSET_DATA;
+		} else {
+			data += 2;
+			len -= 2;
+		}
+		break;
+	default:
+/*	case BRIDGE_SPCA504: */
+/*	case BRIDGE_SPCA504B: */
+		switch (data[0]) {
+		case 0xfe:			/* start of frame */
+			sof = 1;
+			data += SPCA50X_OFFSET_DATA;
+			len -= SPCA50X_OFFSET_DATA;
+			break;
+		case 0xff:			/* drop packet */
+/*			gspca_dev->last_packet_type = DISCARD_PACKET; */
+			return;
+		default:
+			data += 1;
+			len -= 1;
+			break;
+		}
+		break;
+	case BRIDGE_SPCA504C:
+		switch (data[0]) {
+		case 0xfe:			/* start of frame */
+			sof = 1;
+			data += SPCA504_PCCAM600_OFFSET_DATA;
+			len -= SPCA504_PCCAM600_OFFSET_DATA;
+			break;
+		case 0xff:			/* drop packet */
+/*			gspca_dev->last_packet_type = DISCARD_PACKET; */
+			return;
+		default:
+			data += 1;
+			len -= 1;
+			break;
+		}
+		break;
+	}
+	if (sof) {		/* start of frame */
+		frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+					ffd9, 2);
+
+		/* put the JPEG header in the new frame */
+		jpeg_put_header(gspca_dev, frame,
+				((struct sd *) gspca_dev)->qindex,
+				0x22);
+	}
+
+	/* add 0x00 after 0xff */
+	for (i = len; --i >= 0; )
+		if (data[i] == 0xff)
+			break;
+	if (i < 0) {			/* no 0xff */
+		gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+		return;
+	}
+	s = data;
+	d = sd->packet;
+	for (i = 0; i < len; i++) {
+		*d++ = *s++;
+		if (s[-1] == 0xff)
+			*d++ = 0x00;
+	}
+	gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+			sd->packet, d - sd->packet);
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct usb_device *dev = gspca_dev->dev;
+
+	switch (sd->bridge) {
+	default:
+/*	case BRIDGE_SPCA533: */
+/*	case BRIDGE_SPCA504B: */
+/*	case BRIDGE_SPCA504: */
+/*	case BRIDGE_SPCA504C: */
+		reg_write(dev, 0x0, 0x21a7, sd->brightness);
+		break;
+	case BRIDGE_SPCA536:
+		reg_write(dev, 0x0, 0x20f0, sd->brightness);
+		break;
+	}
+}
+
+static void getbrightness(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct usb_device *dev = gspca_dev->dev;
+	__u16 brightness = 0;
+
+	switch (sd->bridge) {
+	default:
+/*	case BRIDGE_SPCA533: */
+/*	case BRIDGE_SPCA504B: */
+/*	case BRIDGE_SPCA504: */
+/*	case BRIDGE_SPCA504C: */
+		brightness = reg_read(dev, 0x0, 0x21a7, 2);
+		break;
+	case BRIDGE_SPCA536:
+		brightness = reg_read(dev, 0x0, 0x20f0, 2);
+		break;
+	}
+	sd->brightness = ((brightness & 0xff) - 128) % 255;
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct usb_device *dev = gspca_dev->dev;
+
+	switch (sd->bridge) {
+	default:
+/*	case BRIDGE_SPCA533: */
+/*	case BRIDGE_SPCA504B: */
+/*	case BRIDGE_SPCA504: */
+/*	case BRIDGE_SPCA504C: */
+		reg_write(dev, 0x0, 0x21a8, sd->contrast);
+		break;
+	case BRIDGE_SPCA536:
+		reg_write(dev, 0x0, 0x20f1, sd->contrast);
+		break;
+	}
+}
+
+static void getcontrast(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct usb_device *dev = gspca_dev->dev;
+
+	switch (sd->bridge) {
+	default:
+/*	case BRIDGE_SPCA533: */
+/*	case BRIDGE_SPCA504B: */
+/*	case BRIDGE_SPCA504: */
+/*	case BRIDGE_SPCA504C: */
+		sd->contrast = reg_read(dev, 0x0, 0x21a8, 2);
+		break;
+	case BRIDGE_SPCA536:
+		sd->contrast = reg_read(dev, 0x0, 0x20f1, 2);
+		break;
+	}
+}
+
+static void setcolors(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct usb_device *dev = gspca_dev->dev;
+
+	switch (sd->bridge) {
+	default:
+/*	case BRIDGE_SPCA533: */
+/*	case BRIDGE_SPCA504B: */
+/*	case BRIDGE_SPCA504: */
+/*	case BRIDGE_SPCA504C: */
+		reg_write(dev, 0x0, 0x21ae, sd->colors);
+		break;
+	case BRIDGE_SPCA536:
+		reg_write(dev, 0x0, 0x20f6, sd->colors);
+		break;
+	}
+}
+
+static void getcolors(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct usb_device *dev = gspca_dev->dev;
+
+	switch (sd->bridge) {
+	default:
+/*	case BRIDGE_SPCA533: */
+/*	case BRIDGE_SPCA504B: */
+/*	case BRIDGE_SPCA504: */
+/*	case BRIDGE_SPCA504C: */
+		sd->colors = reg_read(dev, 0x0, 0x21ae, 2) >> 1;
+		break;
+	case BRIDGE_SPCA536:
+		sd->colors = reg_read(dev, 0x0, 0x20f6, 2) >> 1;
+		break;
+	}
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->brightness = val;
+	if (gspca_dev->streaming)
+		setbrightness(gspca_dev);
+	return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	getbrightness(gspca_dev);
+	*val = sd->brightness;
+	return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->contrast = val;
+	if (gspca_dev->streaming)
+		setcontrast(gspca_dev);
+	return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	getcontrast(gspca_dev);
+	*val = sd->contrast;
+	return 0;
+}
+
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->colors = val;
+	if (gspca_dev->streaming)
+		setcolors(gspca_dev);
+	return 0;
+}
+
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	getcolors(gspca_dev);
+	*val = sd->colors;
+	return 0;
+}
+
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->autogain = val;
+	return 0;
+}
+
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->autogain;
+	return 0;
+}
+
+/* sub-driver description */
+static struct sd_desc sd_desc = {
+	.name = MODULE_NAME,
+	.ctrls = sd_ctrls,
+	.nctrls = ARRAY_SIZE(sd_ctrls),
+	.config = sd_config,
+	.open = sd_open,
+	.start = sd_start,
+	.stopN = sd_stopN,
+	.stop0 = sd_stop0,
+	.close = sd_close,
+	.pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static __devinitdata struct usb_device_id device_table[] = {
+	{USB_DEVICE(0x041e, 0x400b), DVNM("Creative PC-CAM 600")},
+	{USB_DEVICE(0x041e, 0x4012), DVNM("PC-Cam350")},
+	{USB_DEVICE(0x041e, 0x4013), DVNM("Creative Pccam750")},
+	{USB_DEVICE(0x0458, 0x7006), DVNM("Genius Dsc 1.3 Smart")},
+	{USB_DEVICE(0x046d, 0x0905), DVNM("Logitech ClickSmart 820")},
+	{USB_DEVICE(0x046d, 0x0960), DVNM("Logitech ClickSmart 420")},
+	{USB_DEVICE(0x0471, 0x0322), DVNM("Philips DMVC1300K")},
+	{USB_DEVICE(0x04a5, 0x3003), DVNM("Benq DC 1300")},
+	{USB_DEVICE(0x04a5, 0x3008), DVNM("Benq DC 1500")},
+	{USB_DEVICE(0x04a5, 0x300a), DVNM("Benq DC3410")},
+	{USB_DEVICE(0x04f1, 0x1001), DVNM("JVC GC A50")},
+	{USB_DEVICE(0x04fc, 0x500c), DVNM("Sunplus CA500C")},
+	{USB_DEVICE(0x04fc, 0x504a), DVNM("Aiptek Mini PenCam 1.3")},
+	{USB_DEVICE(0x04fc, 0x504b), DVNM("Maxell MaxPocket LE 1.3")},
+	{USB_DEVICE(0x04fc, 0x5330), DVNM("Digitrex 2110")},
+	{USB_DEVICE(0x04fc, 0x5360), DVNM("Sunplus Generic")},
+	{USB_DEVICE(0x04fc, 0xffff), DVNM("Pure DigitalDakota")},
+	{USB_DEVICE(0x052b, 0x1513), DVNM("Megapix V4")},
+	{USB_DEVICE(0x0546, 0x3155), DVNM("Polaroid PDC3070")},
+	{USB_DEVICE(0x0546, 0x3191), DVNM("Polaroid Ion 80")},
+	{USB_DEVICE(0x0546, 0x3273), DVNM("Polaroid PDC2030")},
+	{USB_DEVICE(0x055f, 0xc211), DVNM("Kowa Bs888e Microcamera")},
+	{USB_DEVICE(0x055f, 0xc230), DVNM("Mustek Digicam 330K")},
+	{USB_DEVICE(0x055f, 0xc232), DVNM("Mustek MDC3500")},
+	{USB_DEVICE(0x055f, 0xc360), DVNM("Mustek DV4000 Mpeg4 ")},
+	{USB_DEVICE(0x055f, 0xc420), DVNM("Mustek gSmart Mini 2")},
+	{USB_DEVICE(0x055f, 0xc430), DVNM("Mustek Gsmart LCD 2")},
+	{USB_DEVICE(0x055f, 0xc440), DVNM("Mustek DV 3000")},
+	{USB_DEVICE(0x055f, 0xc520), DVNM("Mustek gSmart Mini 3")},
+	{USB_DEVICE(0x055f, 0xc530), DVNM("Mustek Gsmart LCD 3")},
+	{USB_DEVICE(0x055f, 0xc540), DVNM("Gsmart D30")},
+	{USB_DEVICE(0x055f, 0xc630), DVNM("Mustek MDC4000")},
+	{USB_DEVICE(0x055f, 0xc650), DVNM("Mustek MDC5500Z")},
+	{USB_DEVICE(0x05da, 0x1018), DVNM("Digital Dream Enigma 1.3")},
+	{USB_DEVICE(0x06d6, 0x0031), DVNM("Trust 610 LCD PowerC@m Zoom")},
+	{USB_DEVICE(0x0733, 0x1311), DVNM("Digital Dream Epsilon 1.3")},
+	{USB_DEVICE(0x0733, 0x1314), DVNM("Mercury 2.1MEG Deluxe Classic Cam")},
+	{USB_DEVICE(0x0733, 0x2211), DVNM("Jenoptik jdc 21 LCD")},
+	{USB_DEVICE(0x0733, 0x2221), DVNM("Mercury Digital Pro 3.1p")},
+	{USB_DEVICE(0x0733, 0x3261), DVNM("Concord 3045 spca536a")},
+	{USB_DEVICE(0x0733, 0x3281), DVNM("Cyberpix S550V")},
+	{USB_DEVICE(0x08ca, 0x0104), DVNM("Aiptek PocketDVII 1.3")},
+	{USB_DEVICE(0x08ca, 0x0106), DVNM("Aiptek Pocket DV3100+")},
+	{USB_DEVICE(0x08ca, 0x2008), DVNM("Aiptek Mini PenCam 2 M")},
+	{USB_DEVICE(0x08ca, 0x2010), DVNM("Aiptek PocketCam 3M")},
+	{USB_DEVICE(0x08ca, 0x2016), DVNM("Aiptek PocketCam 2 Mega")},
+	{USB_DEVICE(0x08ca, 0x2018), DVNM("Aiptek Pencam SD 2M")},
+	{USB_DEVICE(0x08ca, 0x2020), DVNM("Aiptek Slim 3000F")},
+	{USB_DEVICE(0x08ca, 0x2022), DVNM("Aiptek Slim 3200")},
+	{USB_DEVICE(0x08ca, 0x2024), DVNM("Aiptek DV3500 Mpeg4 ")},
+	{USB_DEVICE(0x08ca, 0x2028), DVNM("Aiptek PocketCam4M")},
+	{USB_DEVICE(0x08ca, 0x2040), DVNM("Aiptek PocketDV4100M")},
+	{USB_DEVICE(0x08ca, 0x2042), DVNM("Aiptek PocketDV5100")},
+	{USB_DEVICE(0x08ca, 0x2060), DVNM("Aiptek PocketDV5300")},
+	{USB_DEVICE(0x0d64, 0x0303), DVNM("Sunplus FashionCam DXG")},
+	{}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+			const struct usb_device_id *id)
+{
+	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+				THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+	.name = MODULE_NAME,
+	.id_table = device_table,
+	.probe = sd_probe,
+	.disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+	if (usb_register(&sd_driver) < 0)
+		return -1;
+	PDEBUG(D_PROBE, "v%s registered", version);
+	return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+	usb_deregister(&sd_driver);
+	PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/t613.c b/drivers/media/video/gspca/t613.c
new file mode 100644
index 0000000..c22b301
--- /dev/null
+++ b/drivers/media/video/gspca/t613.c
@@ -0,0 +1,1013 @@
+/*
+ *Notes: * t613  + tas5130A
+ *	* Focus to light do not balance well as in win.
+ *	  Quality in win is not good, but its kinda better.
+ *	 * Fix some "extraneous bytes", most of apps will show the image anyway
+ *	 * Gamma table, is there, but its really doing something?
+ *	 * 7~8 Fps, its ok, max on win its 10.
+ *			Costantino Leandro
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define MODULE_NAME "t613"
+#include "gspca.h"
+#define DRIVER_VERSION_NUMBER	KERNEL_VERSION(2, 1, 0)
+static const char version[] = "2.1.0";
+
+struct control_menu_info {
+	int value;
+	char name[32];
+};
+
+#define MAX_GAMMA 0x10		/* 0 to 15 */
+
+/* From LUVCVIEW */
+#define V4L2_CID_EFFECTS (V4L2_CID_PRIVATE_BASE + 3)
+
+MODULE_AUTHOR("Leandro Costantino <le_costantino@pixartargentina.com.ar>");
+MODULE_DESCRIPTION("GSPCA/T613 (JPEG Compliance) USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+struct sd {
+	struct gspca_dev gspca_dev;	/* !! must be the first item */
+
+	unsigned char brightness;
+	unsigned char contrast;
+	unsigned char colors;
+	unsigned char autogain;
+	unsigned char gamma;
+	unsigned char sharpness;
+	unsigned char freq;
+	unsigned char whitebalance;
+	unsigned char mirror;
+	unsigned char effect;
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setlowlight(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getlowlight(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setflip(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getflip(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_seteffect(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_geteffect(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_querymenu(struct gspca_dev *gspca_dev,
+			struct v4l2_querymenu *menu);
+
+static struct ctrl sd_ctrls[] = {
+#define SD_BRIGHTNESS 0
+	{
+	 {
+	  .id = V4L2_CID_BRIGHTNESS,
+	  .type = V4L2_CTRL_TYPE_INTEGER,
+	  .name = "Brightness",
+	  .minimum = 0,
+	  .maximum = 0x0f,
+	  .step = 1,
+	  .default_value = 0x09,
+	  },
+	 .set = sd_setbrightness,
+	 .get = sd_getbrightness,
+	 },
+#define SD_CONTRAST 1
+	{
+	 {
+	  .id = V4L2_CID_CONTRAST,
+	  .type = V4L2_CTRL_TYPE_INTEGER,
+	  .name = "Contrast",
+	  .minimum = 0,
+	  .maximum = 0x0d,
+	  .step = 1,
+	  .default_value = 0x07,
+	  },
+	 .set = sd_setcontrast,
+	 .get = sd_getcontrast,
+	 },
+#define SD_COLOR 2
+	{
+	 {
+	  .id = V4L2_CID_SATURATION,
+	  .type = V4L2_CTRL_TYPE_INTEGER,
+	  .name = "Color",
+	  .minimum = 0,
+	  .maximum = 0x0f,
+	  .step = 1,
+	  .default_value = 0x05,
+	  },
+	 .set = sd_setcolors,
+	 .get = sd_getcolors,
+	 },
+#define SD_GAMMA 3
+	{
+	 {
+	  .id = V4L2_CID_GAMMA,	/* (gamma on win) */
+	  .type = V4L2_CTRL_TYPE_INTEGER,
+	  .name = "Gamma (Untested)",
+	  .minimum = 0,
+	  .maximum = MAX_GAMMA,
+	  .step = 1,
+	  .default_value = 0x09,
+	  },
+	 .set = sd_setgamma,
+	 .get = sd_getgamma,
+	 },
+#define SD_AUTOGAIN 4
+	{
+	 {
+	  .id = V4L2_CID_GAIN,	/* here, i activate only the lowlight,
+				 * some apps dont bring up the
+				 * backligth_compensation control) */
+	  .type = V4L2_CTRL_TYPE_INTEGER,
+	  .name = "Low Light",
+	  .minimum = 0,
+	  .maximum = 1,
+	  .step = 1,
+	  .default_value = 0x01,
+	  },
+	 .set = sd_setlowlight,
+	 .get = sd_getlowlight,
+	 },
+#define SD_MIRROR 5
+	{
+	 {
+	  .id = V4L2_CID_HFLIP,
+	  .type = V4L2_CTRL_TYPE_BOOLEAN,
+	  .name = "Mirror Image",
+	  .minimum = 0,
+	  .maximum = 1,
+	  .step = 1,
+	  .default_value = 0,
+	  },
+	 .set = sd_setflip,
+	 .get = sd_getflip
+	},
+#define SD_LIGHTFREQ 6
+	{
+	 {
+	  .id = V4L2_CID_POWER_LINE_FREQUENCY,
+	  .type = V4L2_CTRL_TYPE_MENU,
+	  .name = "Light Frequency Filter",
+	  .minimum = 1,		/* 1 -> 0x50, 2->0x60 */
+	  .maximum = 2,
+	  .step = 1,
+	  .default_value = 1,
+	  },
+	 .set = sd_setfreq,
+	 .get = sd_getfreq},
+
+#define SD_WHITE_BALANCE 7
+	{
+	 {
+	  .id = V4L2_CID_WHITE_BALANCE_TEMPERATURE,
+	  .type = V4L2_CTRL_TYPE_INTEGER,
+	  .name = "White Balance",
+	  .minimum = 0,
+	  .maximum = 1,
+	  .step = 1,
+	  .default_value = 1,
+	  },
+	 .set = sd_setwhitebalance,
+	 .get = sd_getwhitebalance
+	},
+#define SD_SHARPNESS 8		/* (aka definition on win) */
+	{
+	 {
+	  .id = V4L2_CID_SHARPNESS,
+	  .type = V4L2_CTRL_TYPE_INTEGER,
+	  .name = "Sharpness",
+	  .minimum = 0,
+	  .maximum = MAX_GAMMA,	/* 0 to 16 */
+	  .step = 1,
+	  .default_value = 0x06,
+	  },
+	 .set = sd_setsharpness,
+	 .get = sd_getsharpness,
+	 },
+#define SD_EFFECTS 9
+	{
+	 {
+	  .id = V4L2_CID_EFFECTS,
+	  .type = V4L2_CTRL_TYPE_MENU,
+	  .name = "Webcam Effects",
+	  .minimum = 0,
+	  .maximum = 4,
+	  .step = 1,
+	  .default_value = 0,
+	  },
+	 .set = sd_seteffect,
+	 .get = sd_geteffect
+	},
+};
+
+static struct control_menu_info effects_control[] = {
+	{0, "Normal"},
+	{1, "Emboss"},		/* disabled */
+	{2, "Monochrome"},
+	{3, "Sepia"},
+	{4, "Sketch"},
+	{5, "Sun Effect"},	/* disabled */
+	{6, "Negative"},
+};
+
+#define NUM_EFFECTS_CONTROL \
+			(sizeof(effects_control)/sizeof(effects_control[0]))
+
+static struct cam_mode vga_mode_t16[] = {
+	{V4L2_PIX_FMT_JPEG, 160, 120, 4},
+	{V4L2_PIX_FMT_JPEG, 176, 144, 3},
+	{V4L2_PIX_FMT_JPEG, 320, 240, 2},
+	{V4L2_PIX_FMT_JPEG, 352, 288, 1},
+	{V4L2_PIX_FMT_JPEG, 640, 480, 0},
+};
+
+#define T16_OFFSET_DATA 631
+#define MAX_EFFECTS 7
+/* easily done by soft, this table could be removed,
+ * i keep it here just in case */
+unsigned char effects_table[MAX_EFFECTS][6] = {
+	{0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x00},	/* Normal */
+	{0xa8, 0xc8, 0xc6, 0x52, 0xc0, 0x04},	/* Repujar */
+	{0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x20},	/* Monochrome */
+	{0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x80},	/* Sepia */
+	{0xa8, 0xc8, 0xc6, 0x52, 0xc0, 0x02},	/* Croquis */
+	{0xa8, 0xc8, 0xc6, 0xd2, 0xc0, 0x10},	/* Sun Effect */
+	{0xa8, 0xc8, 0xc6, 0xd2, 0xc0, 0x40},	/* Negative */
+};
+
+unsigned char gamma_table[MAX_GAMMA][34] = {
+	{0x90, 0x00, 0x91, 0x3e, 0x92, 0x69, 0x93, 0x85,
+	 0x94, 0x95, 0x95, 0xa1, 0x96, 0xae, 0x97, 0xb9,
+	 0x98, 0xc2, 0x99, 0xcb, 0x9a, 0xd4, 0x9b, 0xdb,
+	 0x9c, 0xe3, 0x9d, 0xea, 0x9e, 0xf1, 0x9f, 0xf8,
+	 0xa0, 0xff},
+	{0x90, 0x00, 0x91, 0x33, 0x92, 0x5A, 0x93, 0x75,
+	 0x94, 0x85, 0x95, 0x93, 0x96, 0xA1, 0x97, 0xAD,
+	 0x98, 0xB7, 0x99, 0xC2, 0x9A, 0xCB, 0x9B, 0xD4,
+	 0x9C, 0xDE, 0x9D, 0xE7, 0x9E, 0xF0, 0x9F, 0xF7,
+	 0xa0, 0xff},
+	{0x90, 0x00, 0x91, 0x2F, 0x92, 0x51, 0x93, 0x6B,
+	 0x94, 0x7C, 0x95, 0x8A, 0x96, 0x99, 0x97, 0xA6,
+	 0x98, 0xB1, 0x99, 0xBC, 0x9A, 0xC6, 0x9B, 0xD0,
+	 0x9C, 0xDB, 0x9D, 0xE4, 0x9E, 0xED, 0x9F, 0xF6,
+	 0xa0, 0xff},
+	{0x90, 0x00, 0x91, 0x29, 0x92, 0x48, 0x93, 0x60,
+	 0x94, 0x72, 0x95, 0x81, 0x96, 0x90, 0x97, 0x9E,
+	 0x98, 0xAA, 0x99, 0xB5, 0x9A, 0xBF, 0x9B, 0xCB,
+	 0x9C, 0xD6, 0x9D, 0xE1, 0x9E, 0xEB, 0x9F, 0xF5,
+	 0xa0, 0xff},
+	{0x90, 0x00, 0x91, 0x23, 0x92, 0x3F, 0x93, 0x55,
+	 0x94, 0x68, 0x95, 0x77, 0x96, 0x86, 0x97, 0x95,
+	 0x98, 0xA2, 0x99, 0xAD, 0x9A, 0xB9, 0x9B, 0xC6,
+	 0x9C, 0xD2, 0x9D, 0xDE, 0x9E, 0xE9, 0x9F, 0xF4,
+	 0xa0, 0xff},
+	{0x90, 0x00, 0x91, 0x1B, 0x92, 0x33, 0x93, 0x48,
+	 0x94, 0x59, 0x95, 0x69, 0x96, 0x79, 0x97, 0x87,
+	 0x98, 0x96, 0x99, 0xA3, 0x9A, 0xB1, 0x9B, 0xBE,
+	 0x9C, 0xCC, 0x9D, 0xDA, 0x9E, 0xE7, 0x9F, 0xF3,
+	 0xa0, 0xff},
+	{0x90, 0x00, 0x91, 0x02, 0x92, 0x10, 0x93, 0x20,
+	 0x94, 0x32, 0x95, 0x40, 0x96, 0x57, 0x97, 0x67,
+	 0x98, 0x77, 0x99, 0x88, 0x9a, 0x99, 0x9b, 0xaa,
+	 0x9c, 0xbb, 0x9d, 0xcc, 0x9e, 0xdd, 0x9f, 0xee,
+	 0xa0, 0xff},
+	{0x90, 0x00, 0x91, 0x02, 0x92, 0x14, 0x93, 0x26,
+	 0x94, 0x38, 0x95, 0x4A, 0x96, 0x60, 0x97, 0x70,
+	 0x98, 0x80, 0x99, 0x90, 0x9A, 0xA0, 0x9B, 0xB0,
+	 0x9C, 0xC0, 0x9D, 0xD0, 0x9E, 0xE0, 0x9F, 0xF0,
+	 0xa0, 0xff},
+	{0x90, 0x00, 0x91, 0x10, 0x92, 0x22, 0x93, 0x35,
+	 0x94, 0x47, 0x95, 0x5A, 0x96, 0x69, 0x97, 0x79,
+	 0x98, 0x88, 0x99, 0x97, 0x9A, 0xA7, 0x9B, 0xB6,
+	 0x9C, 0xC4, 0x9D, 0xD3, 0x9E, 0xE0, 0x9F, 0xF0,
+	 0xa0, 0xff},
+	{0x90, 0x00, 0x91, 0x10, 0x92, 0x26, 0x93, 0x40,
+	 0x94, 0x54, 0x95, 0x65, 0x96, 0x75, 0x97, 0x84,
+	 0x98, 0x93, 0x99, 0xa1, 0x9a, 0xb0, 0x9b, 0xbd,
+	 0x9c, 0xca, 0x9d, 0xd6, 0x9e, 0xe0, 0x9f, 0xf0,
+	 0xa0, 0xff},
+	{0x90, 0x00, 0x91, 0x18, 0x92, 0x2B, 0x93, 0x44,
+	 0x94, 0x60, 0x95, 0x70, 0x96, 0x80, 0x97, 0x8E,
+	 0x98, 0x9C, 0x99, 0xAA, 0x9A, 0xB7, 0x9B, 0xC4,
+	 0x9C, 0xD0, 0x9D, 0xD8, 0x9E, 0xE2, 0x9F, 0xF0,
+	 0xa0, 0xff},
+	{0x90, 0x00, 0x91, 0x1A, 0x92, 0x34, 0x93, 0x52,
+	 0x94, 0x66, 0x95, 0x7E, 0x96, 0x8D, 0x97, 0x9B,
+	 0x98, 0xA8, 0x99, 0xB4, 0x9A, 0xC0, 0x9B, 0xCB,
+	 0x9C, 0xD6, 0x9D, 0xE1, 0x9E, 0xEB, 0x9F, 0xF5,
+	 0xa0, 0xff},
+	{0x90, 0x00, 0x91, 0x3F, 0x92, 0x5A, 0x93, 0x6E,
+	 0x94, 0x7F, 0x95, 0x8E, 0x96, 0x9C, 0x97, 0xA8,
+	 0x98, 0xB4, 0x99, 0xBF, 0x9A, 0xC9, 0x9B, 0xD3,
+	 0x9C, 0xDC, 0x9D, 0xE5, 0x9E, 0xEE, 0x9F, 0xF6,
+	 0xA0, 0xFF},
+	{0x90, 0x00, 0x91, 0x54, 0x92, 0x6F, 0x93, 0x83,
+	 0x94, 0x93, 0x95, 0xA0, 0x96, 0xAD, 0x97, 0xB7,
+	 0x98, 0xC2, 0x99, 0xCB, 0x9A, 0xD4, 0x9B, 0xDC,
+	 0x9C, 0xE4, 0x9D, 0xEB, 0x9E, 0xF2, 0x9F, 0xF9,
+	 0xa0, 0xff},
+	{0x90, 0x00, 0x91, 0x6E, 0x92, 0x88, 0x93, 0x9A,
+	 0x94, 0xA8, 0x95, 0xB3, 0x96, 0xBD, 0x97, 0xC6,
+	 0x98, 0xCF, 0x99, 0xD6, 0x9A, 0xDD, 0x9B, 0xE3,
+	 0x9C, 0xE9, 0x9D, 0xEF, 0x9E, 0xF4, 0x9F, 0xFA,
+	 0xa0, 0xff},
+	{0x90, 0x00, 0x91, 0x93, 0x92, 0xA8, 0x93, 0xB7,
+	 0x94, 0xC1, 0x95, 0xCA, 0x96, 0xD2, 0x97, 0xD8,
+	 0x98, 0xDE, 0x99, 0xE3, 0x9A, 0xE8, 0x9B, 0xED,
+	 0x9C, 0xF1, 0x9D, 0xF5, 0x9E, 0xF8, 0x9F, 0xFC,
+	 0xA0, 0xFF}
+};
+
+static __u8 tas5130a_sensor_init[][8] = {
+	{0x62, 0x08, 0x63, 0x70, 0x64, 0x1d, 0x60, 0x09},
+	{0x62, 0x20, 0x63, 0x01, 0x64, 0x02, 0x60, 0x09},
+	{0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09},
+	{0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09},
+	{},
+};
+
+static void t16RegRead(struct usb_device *dev,
+		       __u16 index, __u8 *buffer, __u16 length)
+{
+	usb_control_msg(dev,
+			usb_rcvctrlpipe(dev, 0),
+			0,		/* request */
+			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			0,		/* value */
+			index, buffer, length, 500);
+}
+
+static void t16RegWrite(struct usb_device *dev,
+			__u16 value,
+			__u16 index, __u8 *buffer, __u16 length)
+{
+	usb_control_msg(dev,
+			usb_sndctrlpipe(dev, 0),
+			0,		/* request */
+			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			value, index, buffer, length, 500);
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+		     const struct usb_device_id *id)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct cam *cam;
+
+	cam = &gspca_dev->cam;
+	cam->dev_name = (char *) id->driver_info;
+	cam->epaddr = 0x01;
+
+	cam->cam_mode = vga_mode_t16;
+	cam->nmodes = ARRAY_SIZE(vga_mode_t16);
+
+	sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
+	sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
+	sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value;
+	sd->gamma = sd_ctrls[SD_GAMMA].qctrl.default_value;
+	sd->mirror = sd_ctrls[SD_MIRROR].qctrl.default_value;
+	sd->freq = sd_ctrls[SD_LIGHTFREQ].qctrl.default_value;
+	sd->whitebalance = sd_ctrls[SD_WHITE_BALANCE].qctrl.default_value;
+	sd->sharpness = sd_ctrls[SD_SHARPNESS].qctrl.default_value;
+	sd->effect = sd_ctrls[SD_EFFECTS].qctrl.default_value;
+	return 0;
+}
+
+static int init_default_parameters(struct gspca_dev *gspca_dev)
+{
+	struct usb_device *dev = gspca_dev->dev;
+
+	/* some of this registers are not really neded, because
+	 * they are overriden by setbrigthness, setcontrast, etc,
+	 * but wont hurt anyway, and can help someone with similar webcam
+	 * to see the initial parameters.*/
+	int i = 0;
+	__u8 test_byte;
+
+	static unsigned char read_indexs[] =
+		{ 0x06, 0x07, 0x0a, 0x0b, 0x66, 0x80, 0x81, 0x8e, 0x8f, 0xa5,
+		  0xa6, 0xa8, 0xbb, 0xbc, 0xc6, 0x00, 0x00 };
+	static unsigned char n1[6] =
+			{0x08, 0x03, 0x09, 0x03, 0x12, 0x04};
+	static unsigned char n2[2] =
+			{0x08, 0x00};
+	static unsigned char nset[6] =
+		{ 0x61, 0x68, 0x62, 0xff, 0x60, 0x07 };
+	static unsigned char n3[6] =
+			{0x61, 0x68, 0x65, 0x0a, 0x60, 0x04};
+	static unsigned char n4[0x46] =
+		{0x09, 0x01, 0x12, 0x04, 0x66, 0x8a, 0x80, 0x3c,
+		 0x81, 0x22, 0x84, 0x50, 0x8a, 0x78, 0x8b, 0x68,
+		 0x8c, 0x88, 0x8e, 0x33, 0x8f, 0x24, 0xaa, 0xb1,
+		 0xa2, 0x60, 0xa5, 0x30, 0xa6, 0x3a, 0xa8, 0xe8,
+		 0xae, 0x05, 0xb1, 0x00, 0xbb, 0x04, 0xbc, 0x48,
+		 0xbe, 0x36, 0xc6, 0x88, 0xe9, 0x00, 0xc5, 0xc0,
+		 0x65, 0x0a, 0xbb, 0x86, 0xaf, 0x58, 0xb0, 0x68,
+		 0x87, 0x40, 0x89, 0x2b, 0x8d, 0xff, 0x83, 0x40,
+		 0xac, 0x84, 0xad, 0x86, 0xaf, 0x46};
+	static unsigned char nset4[18] = {
+		0xe0, 0x60, 0xe1, 0xa8, 0xe2, 0xe0, 0xe3, 0x60, 0xe4, 0xa8,
+		0xe5, 0xe0, 0xe6, 0x60, 0xe7, 0xa8,
+		0xe8, 0xe0
+	};
+	/* ojo puede ser 0xe6 en vez de 0xe9 */
+	static unsigned char nset2[20] = {
+		0xd0, 0xbb, 0xd1, 0x28, 0xd2, 0x10, 0xd3, 0x10, 0xd4, 0xbb,
+		0xd5, 0x28, 0xd6, 0x1e, 0xd7, 0x27,
+		0xd8, 0xc8, 0xd9, 0xfc
+	};
+	static unsigned char missing[8] =
+		{ 0x87, 0x20, 0x88, 0x20, 0x89, 0x20, 0x80, 0x38 };
+	static unsigned char nset3[18] = {
+		0xc7, 0x60, 0xc8, 0xa8, 0xc9, 0xe0, 0xca, 0x60, 0xcb, 0xa8,
+		0xcc, 0xe0, 0xcd, 0x60, 0xce, 0xa8,
+		0xcf, 0xe0
+	};
+	static unsigned char nset5[4] =
+		{ 0x8f, 0x24, 0xc3, 0x00 };	/* bright */
+	static unsigned char nset6[34] = {
+		0x90, 0x00, 0x91, 0x1c, 0x92, 0x30, 0x93, 0x43, 0x94, 0x54,
+		0x95, 0x65, 0x96, 0x75, 0x97, 0x84,
+		0x98, 0x93, 0x99, 0xa1, 0x9a, 0xb0, 0x9b, 0xbd, 0x9c, 0xca,
+		0x9d, 0xd8, 0x9e, 0xe5, 0x9f, 0xf2,
+		0xa0, 0xff
+	};			/* Gamma */
+	static unsigned char nset7[4] =
+			{ 0x66, 0xca, 0xa8, 0xf8 };	/* 50/60 Hz */
+	static unsigned char nset9[4] =
+			{ 0x0b, 0x04, 0x0a, 0x78 };
+	static unsigned char nset8[6] =
+			{ 0xa8, 0xf0, 0xc6, 0x88, 0xc0, 0x00 };
+	static unsigned char nset10[6] =
+			{ 0x0c, 0x03, 0xab, 0x10, 0x81, 0x20 };
+
+	t16RegWrite(dev, 0x01, 0x0000, n1, 0x06);
+	t16RegWrite(dev, 0x01, 0x0000, nset, 0x06);
+	t16RegRead(dev, 0x0063, &test_byte, 1);
+	t16RegWrite(dev, 0x01, 0x0000, n2, 0x02);
+
+	while (read_indexs[i] != 0x00) {
+		t16RegRead(dev, read_indexs[i], &test_byte, 1);
+		PDEBUG(D_CONF, "Reg 0x%x => 0x%x", read_indexs[i],
+		       test_byte);
+		i++;
+	}
+
+	t16RegWrite(dev, 0x01, 0x0000, n3, 0x06);
+	t16RegWrite(dev, 0x01, 0x0000, n4, 0x46);
+	t16RegRead(dev, 0x0080, &test_byte, 1);
+	t16RegWrite(dev, 0x00, 0x2c80, 0x00, 0x0);
+	t16RegWrite(dev, 0x01, 0x0000, nset2, 0x14);
+	t16RegWrite(dev, 0x01, 0x0000, nset3, 0x12);
+	t16RegWrite(dev, 0x01, 0x0000, nset4, 0x12);
+	t16RegWrite(dev, 0x00, 0x3880, 0x00, 0x0);
+	t16RegWrite(dev, 0x00, 0x3880, 0x00, 0x0);
+	t16RegWrite(dev, 0x00, 0x338e, 0x00, 0x0);
+	t16RegWrite(dev, 0x01, 00, nset5, 0x04);
+	t16RegWrite(dev, 0x00, 0x00a9, 0x00, 0x0);
+	t16RegWrite(dev, 0x01, 00, nset6, 0x22);
+	t16RegWrite(dev, 0x00, 0x86bb, 0x00, 0x0);
+	t16RegWrite(dev, 0x00, 0x4aa6, 0x00, 0x0);
+
+	t16RegWrite(dev, 0x01, 00, missing, 0x08);
+
+	t16RegWrite(dev, 0x00, 0x2087, 0x00, 0x0);
+	t16RegWrite(dev, 0x00, 0x2088, 0x00, 0x0);
+	t16RegWrite(dev, 0x00, 0x2089, 0x00, 0x0);
+
+	t16RegWrite(dev, 0x01, 00, nset7, 0x4);
+	t16RegWrite(dev, 0x01, 00, nset10, 0x06);
+	t16RegWrite(dev, 0x01, 00, nset8, 0x06);
+	t16RegWrite(dev, 0x01, 00, nset9, 0x04);
+
+	t16RegWrite(dev, 0x00, 0x2880, 0x00, 0x0);
+	t16RegWrite(dev, 0x01, 0x0000, nset2, 0x14);
+	t16RegWrite(dev, 0x01, 0x0000, nset3, 0x12);
+	t16RegWrite(dev, 0x01, 0x0000, nset4, 0x12);
+
+	return 0;
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct usb_device *dev = gspca_dev->dev;
+	unsigned int brightness;
+	unsigned char set6[4] = { 0x8f, 0x26, 0xc3, 0x80 };
+	brightness = sd->brightness;
+
+	if (brightness < 7) {
+		set6[3] = 0x70 - (brightness * 0xa);
+	} else {
+		set6[1] = 0x24;
+		set6[3] = 0x00 + ((brightness - 7) * 0xa);
+	}
+
+	t16RegWrite(dev, 0x01, 0x0000, set6, 4);
+}
+
+static void setflip(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct usb_device *dev = gspca_dev->dev;
+
+	unsigned char flipcmd[8] =
+	    { 0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09 };
+
+	if (sd->mirror == 1)
+		flipcmd[3] = 0x01;
+
+	t16RegWrite(dev, 0x01, 0x0000, flipcmd, 8);
+}
+
+static void seteffect(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct usb_device *dev = gspca_dev->dev;
+
+	t16RegWrite(dev, 0x01, 0x0000, effects_table[sd->effect], 0x06);
+	if (sd->effect == 1 || sd->effect == 5) {
+		PDEBUG(D_CONF,
+		       "This effect have been disabled for webcam \"safety\"");
+		return;
+	}
+
+	if (sd->effect == 1 || sd->effect == 4)
+		t16RegWrite(dev, 0x00, 0x4aa6, 0x00, 0x00);
+	else
+		t16RegWrite(dev, 0x00, 0xfaa6, 0x00, 0x00);
+}
+
+static void setwhitebalance(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct usb_device *dev = gspca_dev->dev;
+
+	unsigned char white_balance[8] =
+	    { 0x87, 0x20, 0x88, 0x20, 0x89, 0x20, 0x80, 0x38 };
+
+	if (sd->whitebalance == 1)
+		white_balance[7] = 0x3c;
+
+	t16RegWrite(dev, 0x01, 0x0000, white_balance, 8);
+}
+
+static void setlightfreq(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct usb_device *dev = gspca_dev->dev;
+	__u8 freq[4] = { 0x66, 0x40, 0xa8, 0xe8 };
+
+	if (sd->freq == 2)	/* 60hz */
+		freq[1] = 0x00;
+
+	t16RegWrite(dev, 0x1, 0x0000, freq, 0x4);
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct usb_device *dev = gspca_dev->dev;
+	unsigned int contrast = sd->contrast;
+	__u16 reg_to_write = 0x00;
+
+	if (contrast < 7)
+		reg_to_write = 0x8ea9 - (0x200 * contrast);
+	else
+		reg_to_write = (0x00a9 + ((contrast - 7) * 0x200));
+
+	t16RegWrite(dev, 0x00, reg_to_write, 0x00, 0);
+
+}
+
+static void setcolors(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct usb_device *dev = gspca_dev->dev;
+	__u16 reg_to_write = 0x00;
+
+	reg_to_write = 0xc0bb + sd->colors * 0x100;
+	t16RegWrite(dev, 0x00, reg_to_write, 0x00, 0);
+}
+
+static void setgamma(struct gspca_dev *gspca_dev)
+{
+}
+
+static void setsharpness(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct usb_device *dev = gspca_dev->dev;
+	__u16 reg_to_write = 0x00;
+
+	reg_to_write = 0x0aa6 + 0x1000 * sd->sharpness;
+
+	t16RegWrite(dev, 0x00, reg_to_write, 0x00, 0x00);
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->brightness = val;
+	if (gspca_dev->streaming)
+		setbrightness(gspca_dev);
+	return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	*val = sd->brightness;
+	return *val;
+}
+
+static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->whitebalance = val;
+	if (gspca_dev->streaming)
+		setwhitebalance(gspca_dev);
+	return 0;
+}
+
+static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->whitebalance;
+	return *val;
+}
+
+
+static int sd_setflip(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->mirror = val;
+	if (gspca_dev->streaming)
+		setflip(gspca_dev);
+	return 0;
+}
+
+static int sd_getflip(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->mirror;
+	return *val;
+}
+
+static int sd_seteffect(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->effect = val;
+	if (gspca_dev->streaming)
+		seteffect(gspca_dev);
+	return 0;
+}
+
+static int sd_geteffect(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->effect;
+	return *val;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->contrast = val;
+	if (gspca_dev->streaming)
+		setcontrast(gspca_dev);
+	return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->contrast;
+	return *val;
+}
+
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->colors = val;
+	if (gspca_dev->streaming)
+		setcolors(gspca_dev);
+	return 0;
+}
+
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->colors;
+	return 0;
+}
+
+static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->gamma = val;
+	if (gspca_dev->streaming)
+		setgamma(gspca_dev);
+	return 0;
+}
+
+static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	*val = sd->gamma;
+	return 0;
+}
+
+static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->freq = val;
+	if (gspca_dev->streaming)
+		setlightfreq(gspca_dev);
+	return 0;
+}
+
+static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->freq;
+	return 0;
+}
+
+static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->sharpness = val;
+	if (gspca_dev->streaming)
+		setsharpness(gspca_dev);
+	return 0;
+}
+
+static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->sharpness;
+	return 0;
+}
+
+/* Low Light set  here......*/
+static int sd_setlowlight(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct usb_device *dev = gspca_dev->dev;
+
+	sd->autogain = val;
+	if (val != 0)
+		t16RegWrite(dev, 0x00, 0xf48e, 0x00, 0);
+	else
+		t16RegWrite(dev, 0x00, 0xb48e, 0x00, 0);
+	return 0;
+}
+
+static int sd_getlowlight(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->autogain;
+	return 0;
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+	struct usb_device *dev = gspca_dev->dev;
+	int mode;
+	__u8 test_byte;
+
+	static __u8 t1[] = { 0x66, 0x00, 0xa8, 0xe8 };
+	__u8 t2[] = { 0x07, 0x00, 0x0d, 0x60, 0x0e, 0x80 };
+	static __u8 t3[] =
+		{ 0xb3, 0x07, 0xb4, 0x00, 0xb5, 0x88, 0xb6, 0x02, 0xb7, 0x06,
+		  0xb8, 0x00, 0xb9, 0xe7, 0xba, 0x01 };
+	static __u8 t4[] = { 0x0b, 0x04, 0x0a, 0x40 };
+
+	mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode]. mode;
+	switch (mode) {
+	case 1:		/* 352x288 */
+		t2[1] = 0x40;
+		break;
+	case 2:		/* 320x240 */
+		t2[1] = 0x10;
+		break;
+	case 3:		/* 176x144 */
+		t2[1] = 0x50;
+		break;
+	case 4:		/* 160x120 */
+		t2[1] = 0x20;
+		break;
+	default:	/* 640x480 (0x00) */
+		break;
+	}
+
+	t16RegWrite(dev, 0x01, 0x0000, tas5130a_sensor_init[0], 0x8);
+	t16RegWrite(dev, 0x01, 0x0000, tas5130a_sensor_init[1], 0x8);
+	t16RegWrite(dev, 0x01, 0x0000, tas5130a_sensor_init[2], 0x8);
+	t16RegWrite(dev, 0x01, 0x0000, tas5130a_sensor_init[3], 0x8);
+	t16RegWrite(dev, 0x00, 0x3c80, 0x00, 0x00);
+		/* just in case and to keep sync with logs  (for mine) */
+	t16RegWrite(dev, 0x01, 0x0000, tas5130a_sensor_init[3], 0x8);
+	t16RegWrite(dev, 0x00, 0x3c80, 0x00, 0x00);
+		/* just in case and to keep sync with logs  (for mine) */
+	t16RegWrite(dev, 0x01, 0x0000, t1, 4);
+	t16RegWrite(dev, 0x01, 0x0000, t2, 6);
+	t16RegRead(dev, 0x0012, &test_byte, 0x1);
+	t16RegWrite(dev, 0x01, 0x0000, t3, 0x10);
+	t16RegWrite(dev, 0x00, 0x0013, 0x00, 0x00);
+	t16RegWrite(dev, 0x01, 0x0000, t4, 0x4);
+	/* restart on each start, just in case, sometimes regs goes wrong
+	 * when using controls from app */
+	setbrightness(gspca_dev);
+	setcontrast(gspca_dev);
+	setcolors(gspca_dev);
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+			struct gspca_frame *frame,	/* target */
+			unsigned char *data,		/* isoc packet */
+			int len)			/* iso packet length */
+{
+	int sof = 0;
+	static unsigned char ffd9[] = { 0xff, 0xd9 };
+
+	if (data[0] == 0x5a) {
+		/* Control Packet, after this came the header again,
+		 * but extra bytes came in the packet before this,
+		 * sometimes an EOF arrives, sometimes not... */
+		return;
+	}
+
+	if (data[len - 1] == 0xff && data[len] == 0xd9) {
+		/* Just in case, i have seen packets with the marker,
+		 * other's do not include it... */
+		data += 2;
+		len -= 4;
+	} else if (data[2] == 0xff && data[3] == 0xd8) {
+		sof = 1;
+		data += 2;
+		len -= 2;
+	} else {
+		data += 2;
+		len -= 2;
+	}
+
+	if (sof) {
+		/* extra bytes....., could be processed too but would be
+		 * a waste of time, right now leave the application and
+		 * libjpeg do it for ourserlves.. */
+		frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+					ffd9, 2);
+		gspca_frame_add(gspca_dev, FIRST_PACKET, frame, data, len);
+		return;
+	}
+
+	gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+}
+
+static int sd_querymenu(struct gspca_dev *gspca_dev,
+			struct v4l2_querymenu *menu)
+{
+	memset(menu->name, 0, sizeof menu->name);
+
+	switch (menu->id) {
+	case V4L2_CID_POWER_LINE_FREQUENCY:
+		switch (menu->index) {
+		case 1:		/* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
+			strcpy(menu->name, "50 Hz");
+			return 0;
+		case 2:		/* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
+			strcpy(menu->name, "60 Hz");
+			return 0;
+		}
+		break;
+	case V4L2_CID_EFFECTS:
+		if (menu->index < 0 || menu->index >= NUM_EFFECTS_CONTROL)
+			return -EINVAL;
+		strncpy((char *) menu->name,
+			effects_control[menu->index].name, 32);
+		break;
+	}
+	return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+	init_default_parameters(gspca_dev);
+	return 0;
+}
+
+/* sub-driver description */
+static struct sd_desc sd_desc = {
+	.name = MODULE_NAME,
+	.ctrls = sd_ctrls,
+	.nctrls = ARRAY_SIZE(sd_ctrls),
+	.config = sd_config,
+	.open = sd_open,
+	.start = sd_start,
+	.stopN = sd_stopN,
+	.stop0 = sd_stop0,
+	.close = sd_close,
+	.pkt_scan = sd_pkt_scan,
+	.querymenu = sd_querymenu,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static __devinitdata struct usb_device_id device_table[] = {
+	{USB_DEVICE(0x17a1, 0x0128), DVNM("XPX Webcam")},
+	{}
+};
+
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+		    const struct usb_device_id *id)
+{
+	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+			       THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+	.name = MODULE_NAME,
+	.id_table = device_table,
+	.probe = sd_probe,
+	.disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+	if (usb_register(&sd_driver) < 0)
+		return -1;
+	PDEBUG(D_PROBE, "v%s registered", version);
+	return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+	usb_deregister(&sd_driver);
+	PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/tv8532.c b/drivers/media/video/gspca/tv8532.c
new file mode 100644
index 0000000..6218441
--- /dev/null
+++ b/drivers/media/video/gspca/tv8532.c
@@ -0,0 +1,709 @@
+/*
+ * Quickcam cameras initialization data
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#define MODULE_NAME "tv8532"
+
+#include "gspca.h"
+
+#define DRIVER_VERSION_NUMBER	KERNEL_VERSION(2, 1, 0)
+static const char version[] = "2.1.0";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("TV8532 USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+	struct gspca_dev gspca_dev;	/* !! must be the first item */
+
+	int buflen;			/* current length of tmpbuf */
+	__u8 tmpbuf[352 * 288 + 10 * 288];	/* no protection... */
+	__u8 tmpbuf2[352 * 288];		/* no protection... */
+
+	unsigned short brightness;
+	unsigned short contrast;
+
+	char packet;
+	char synchro;
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+#define SD_BRIGHTNESS 0
+	{
+	 {
+	  .id = V4L2_CID_BRIGHTNESS,
+	  .type = V4L2_CTRL_TYPE_INTEGER,
+	  .name = "Brightness",
+	  .minimum = 1,
+	  .maximum = 0x2ff,
+	  .step = 1,
+	  .default_value = 0x18f,
+	  },
+	 .set = sd_setbrightness,
+	 .get = sd_getbrightness,
+	 },
+#define SD_CONTRAST 1
+	{
+	 {
+	  .id = V4L2_CID_CONTRAST,
+	  .type = V4L2_CTRL_TYPE_INTEGER,
+	  .name = "Contrast",
+	  .minimum = 0,
+	  .maximum = 0xffff,
+	  .step = 1,
+	  .default_value = 0x7fff,
+	  },
+	 .set = sd_setcontrast,
+	 .get = sd_getcontrast,
+	 },
+};
+
+static struct cam_mode sif_mode[] = {
+	{V4L2_PIX_FMT_SBGGR8, 176, 144, 1},
+	{V4L2_PIX_FMT_SBGGR8, 352, 288, 0},
+};
+
+/*
+ * Initialization data: this is the first set-up data written to the
+ * device (before the open data).
+ */
+#define TESTCLK 0x10		/* reg 0x2c -> 0x12 //10 */
+#define TESTCOMP 0x90		/* reg 0x28 -> 0x80 */
+#define TESTLINE 0x81		/* reg 0x29 -> 0x81 */
+#define QCIFLINE 0x41		/* reg 0x29 -> 0x81 */
+#define TESTPTL 0x14		/* reg 0x2D -> 0x14 */
+#define TESTPTH 0x01		/* reg 0x2E -> 0x01 */
+#define TESTPTBL 0x12		/* reg 0x2F -> 0x0a */
+#define TESTPTBH 0x01		/* reg 0x30 -> 0x01 */
+#define ADWIDTHL 0xe8		/* reg 0x0c -> 0xe8 */
+#define ADWIDTHH 0x03		/* reg 0x0d -> 0x03 */
+#define ADHEIGHL 0x90		/* reg 0x0e -> 0x91 //93 */
+#define ADHEIGHH 0x01		/* reg 0x0f -> 0x01 */
+#define EXPOL 0x8f		/* reg 0x1c -> 0x8f */
+#define EXPOH 0x01		/* reg 0x1d -> 0x01 */
+#define ADCBEGINL 0x44		/* reg 0x10 -> 0x46 //47 */
+#define ADCBEGINH 0x00		/* reg 0x11 -> 0x00 */
+#define ADRBEGINL 0x0a		/* reg 0x14 -> 0x0b //0x0c */
+#define ADRBEGINH 0x00		/* reg 0x15 -> 0x00 */
+#define TV8532_CMD_UPDATE 0x84
+
+#define TV8532_EEprom_Add 0x03
+#define TV8532_EEprom_DataL 0x04
+#define TV8532_EEprom_DataM 0x05
+#define TV8532_EEprom_DataH 0x06
+#define TV8532_EEprom_TableLength 0x07
+#define TV8532_EEprom_Write 0x08
+#define TV8532_PART_CTRL 0x00
+#define TV8532_CTRL 0x01
+#define TV8532_CMD_EEprom_Open 0x30
+#define TV8532_CMD_EEprom_Close 0x29
+#define TV8532_UDP_UPDATE 0x31
+#define TV8532_GPIO 0x39
+#define TV8532_GPIO_OE 0x3B
+#define TV8532_REQ_RegWrite 0x02
+#define TV8532_REQ_RegRead 0x03
+
+#define TV8532_ADWIDTH_L 0x0C
+#define TV8532_ADWIDTH_H 0x0D
+#define TV8532_ADHEIGHT_L 0x0E
+#define TV8532_ADHEIGHT_H 0x0F
+#define TV8532_EXPOSURE 0x1C
+#define TV8532_QUANT_COMP 0x28
+#define TV8532_MODE_PACKET 0x29
+#define TV8532_SETCLK 0x2C
+#define TV8532_POINT_L 0x2D
+#define TV8532_POINT_H 0x2E
+#define TV8532_POINTB_L 0x2F
+#define TV8532_POINTB_H 0x30
+#define TV8532_BUDGET_L 0x2A
+#define TV8532_BUDGET_H 0x2B
+#define TV8532_VID_L 0x34
+#define TV8532_VID_H 0x35
+#define TV8532_PID_L 0x36
+#define TV8532_PID_H 0x37
+#define TV8532_DeviceID 0x83
+#define TV8532_AD_SLOPE 0x91
+#define TV8532_AD_BITCTRL 0x94
+#define TV8532_AD_COLBEGIN_L 0x10
+#define TV8532_AD_COLBEGIN_H 0x11
+#define TV8532_AD_ROWBEGIN_L 0x14
+#define TV8532_AD_ROWBEGIN_H 0x15
+
+static __u32 tv_8532_eeprom_data[] = {
+/*	add		dataL	   dataM	dataH */
+	0x00010001, 0x01018011, 0x02050014, 0x0305001c,
+	0x040d001e, 0x0505001f, 0x06050519, 0x0705011b,
+	0x0805091e, 0x090d892e, 0x0a05892f, 0x0b050dd9,
+	0x0c0509f1, 0
+};
+
+static void reg_r(struct usb_device *dev,
+		  __u16 index, __u8 *buffer)
+{
+	usb_control_msg(dev,
+			usb_rcvctrlpipe(dev, 0),
+			TV8532_REQ_RegRead,
+			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			0,	/* value */
+			index, buffer, sizeof(__u8),
+			500);
+}
+
+static void reg_w(struct usb_device *dev,
+		  __u16 index, __u8 *buffer, __u16 length)
+{
+	usb_control_msg(dev,
+			usb_sndctrlpipe(dev, 0),
+			TV8532_REQ_RegWrite,
+			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			0,	/* value */
+			index, buffer, length, 500);
+}
+
+static void tv_8532WriteEEprom(struct gspca_dev *gspca_dev)
+{
+	int i = 0;
+	__u8 reg, data0, data1, data2, datacmd;
+	struct usb_device *dev = gspca_dev->dev;
+
+	datacmd = 0xb0;;
+	reg_w(dev, TV8532_GPIO, &datacmd, 1);
+	datacmd = TV8532_CMD_EEprom_Open;
+	reg_w(dev, TV8532_CTRL, &datacmd,
+			1);
+/*	msleep(1); */
+	while (tv_8532_eeprom_data[i]) {
+		reg = (tv_8532_eeprom_data[i] & 0xff000000) >> 24;
+		reg_w(dev, TV8532_EEprom_Add, &reg, 1);
+		/* msleep(1); */
+		data0 = (tv_8532_eeprom_data[i] & 0x000000ff);
+		reg_w(dev, TV8532_EEprom_DataL, &data0, 1);
+		/* msleep(1); */
+		data1 = (tv_8532_eeprom_data[i] & 0x0000FF00) >> 8;
+		reg_w(dev, TV8532_EEprom_DataM, &data1, 1);
+		/* msleep(1); */
+		data2 = (tv_8532_eeprom_data[i] & 0x00FF0000) >> 16;
+		reg_w(dev, TV8532_EEprom_DataH, &data2, 1);
+		/* msleep(1); */
+		datacmd = 0;
+		reg_w(dev, TV8532_EEprom_Write, &datacmd, 1);
+		/* msleep(10); */
+		i++;
+	}
+	datacmd = i;
+	reg_w(dev, TV8532_EEprom_TableLength, &datacmd, 1);
+/*	msleep(1); */
+	datacmd = TV8532_CMD_EEprom_Close;
+	reg_w(dev, TV8532_CTRL, &datacmd, 1);
+	msleep(10);
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+		     const struct usb_device_id *id)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct cam *cam;
+
+	tv_8532WriteEEprom(gspca_dev);
+
+	cam = &gspca_dev->cam;
+	cam->dev_name = (char *) id->driver_info;
+	cam->epaddr = 1;
+	cam->cam_mode = sif_mode;
+	cam->nmodes = sizeof sif_mode / sizeof sif_mode[0];
+
+	sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
+	sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
+	return 0;
+}
+
+static void tv_8532ReadRegisters(struct gspca_dev *gspca_dev)
+{
+	struct usb_device *dev = gspca_dev->dev;
+	__u8 data = 0;
+/*	__u16 vid, pid; */
+
+	reg_r(dev, 0x0001, &data);
+	PDEBUG(D_USBI, "register 0x01-> %x", data);
+	reg_r(dev, 0x0002, &data);
+	PDEBUG(D_USBI, "register 0x02-> %x", data);
+	reg_r(dev, TV8532_ADWIDTH_L, &data);
+	reg_r(dev, TV8532_ADWIDTH_H, &data);
+	reg_r(dev, TV8532_QUANT_COMP, &data);
+	reg_r(dev, TV8532_MODE_PACKET, &data);
+	reg_r(dev, TV8532_SETCLK, &data);
+	reg_r(dev, TV8532_POINT_L, &data);
+	reg_r(dev, TV8532_POINT_H, &data);
+	reg_r(dev, TV8532_POINTB_L, &data);
+	reg_r(dev, TV8532_POINTB_H, &data);
+	reg_r(dev, TV8532_BUDGET_L, &data);
+	reg_r(dev, TV8532_BUDGET_H, &data);
+	reg_r(dev, TV8532_VID_L, &data);
+	reg_r(dev, TV8532_VID_H, &data);
+	reg_r(dev, TV8532_PID_L, &data);
+	reg_r(dev, TV8532_PID_H, &data);
+	reg_r(dev, TV8532_DeviceID, &data);
+	reg_r(dev, TV8532_AD_COLBEGIN_L, &data);
+	reg_r(dev, TV8532_AD_COLBEGIN_H, &data);
+	reg_r(dev, TV8532_AD_ROWBEGIN_L, &data);
+	reg_r(dev, TV8532_AD_ROWBEGIN_H, &data);
+}
+
+static void tv_8532_setReg(struct gspca_dev *gspca_dev)
+{
+	struct usb_device *dev = gspca_dev->dev;
+	__u8 data = 0;
+	__u8 value[2] = { 0, 0 };
+
+	data = ADCBEGINL;
+	reg_w(dev, TV8532_AD_COLBEGIN_L, &data, 1);	/* 0x10 */
+	data = ADCBEGINH;	/* also digital gain */
+	reg_w(dev, TV8532_AD_COLBEGIN_H, &data, 1);
+	data = TV8532_CMD_UPDATE;
+	reg_w(dev, TV8532_PART_CTRL, &data, 1);	/* 0x00<-0x84 */
+
+	data = 0x0a;
+	reg_w(dev, TV8532_GPIO_OE, &data, 1);
+	/******************************************************/
+	data = ADHEIGHL;
+	reg_w(dev, TV8532_ADHEIGHT_L, &data, 1);	/* 0e */
+	data = ADHEIGHH;
+	reg_w(dev, TV8532_ADHEIGHT_H, &data, 1);	/* 0f */
+	value[0] = EXPOL;
+	value[1] = EXPOH;	/* 350d 0x014c; */
+	reg_w(dev, TV8532_EXPOSURE, value, 2);	/* 1c */
+	data = ADCBEGINL;
+	reg_w(dev, TV8532_AD_COLBEGIN_L, &data, 1);	/* 0x10 */
+	data = ADCBEGINH;	/* also digital gain */
+	reg_w(dev, TV8532_AD_COLBEGIN_H, &data, 1);
+	data = ADRBEGINL;
+	reg_w(dev, TV8532_AD_ROWBEGIN_L, &data, 1);	/* 0x14 */
+
+	data = 0x00;
+	reg_w(dev, TV8532_AD_SLOPE, &data, 1);	/* 0x91 */
+	data = 0x02;
+	reg_w(dev, TV8532_AD_BITCTRL, &data, 1);	/* 0x94 */
+
+
+	data = TV8532_CMD_EEprom_Close;
+	reg_w(dev, TV8532_CTRL, &data, 1);	/* 0x01 */
+
+	data = 0x00;
+	reg_w(dev, TV8532_AD_SLOPE, &data, 1);	/* 0x91 */
+	data = TV8532_CMD_UPDATE;
+	reg_w(dev, TV8532_PART_CTRL, &data, 1);	/* 0x00<-0x84 */
+}
+
+static void tv_8532_PollReg(struct gspca_dev *gspca_dev)
+{
+	struct usb_device *dev = gspca_dev->dev;
+	__u8 data = 0;
+	int i;
+
+	/* strange polling from tgc */
+	for (i = 0; i < 10; i++) {
+		data = TESTCLK;	/* 0x48; //0x08; */
+		reg_w(dev, TV8532_SETCLK, &data, 1);	/* 0x2c */
+		data = TV8532_CMD_UPDATE;
+		reg_w(dev, TV8532_PART_CTRL, &data, 1);
+		data = 0x01;
+		reg_w(dev, TV8532_UDP_UPDATE, &data, 1);	/* 0x31 */
+	}
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+	struct usb_device *dev = gspca_dev->dev;
+	__u8 data = 0;
+	__u8 dataStart = 0;
+	__u8 value[2] = { 0, 0 };
+
+	data = 0x32;
+	reg_w(dev, TV8532_AD_SLOPE, &data, 1);
+	data = 0;
+	reg_w(dev, TV8532_AD_BITCTRL, &data, 1);
+	tv_8532ReadRegisters(gspca_dev);
+	data = 0x0b;
+	reg_w(dev, TV8532_GPIO_OE, &data, 1);
+	value[0] = ADHEIGHL;
+	value[1] = ADHEIGHH;	/* 401d 0x0169; */
+	reg_w(dev, TV8532_ADHEIGHT_L, value, 2);	/* 0e */
+	value[0] = EXPOL;
+	value[1] = EXPOH;	/* 350d 0x014c; */
+	reg_w(dev, TV8532_EXPOSURE, value, 2);	/* 1c */
+	data = ADWIDTHL;	/* 0x20; */
+	reg_w(dev, TV8532_ADWIDTH_L, &data, 1);	/* 0x0c */
+	data = ADWIDTHH;
+	reg_w(dev, TV8532_ADWIDTH_H, &data, 1);	/* 0x0d */
+
+	/*******************************************************************/
+	data = TESTCOMP;	/* 0x72 compressed mode */
+	reg_w(dev, TV8532_QUANT_COMP, &data, 1);	/* 0x28 */
+	data = TESTLINE;	/* 0x84; // CIF | 4 packet */
+	reg_w(dev, TV8532_MODE_PACKET, &data, 1);	/* 0x29 */
+
+	/************************************************/
+	data = TESTCLK;		/* 0x48; //0x08; */
+	reg_w(dev, TV8532_SETCLK, &data, 1);	/* 0x2c */
+	data = TESTPTL;		/* 0x38; */
+	reg_w(dev, TV8532_POINT_L, &data, 1);	/* 0x2d */
+	data = TESTPTH;		/* 0x04; */
+	reg_w(dev, TV8532_POINT_H, &data, 1);	/* 0x2e */
+	dataStart = TESTPTBL;	/* 0x04; */
+	reg_w(dev, TV8532_POINTB_L, &dataStart, 1);	/* 0x2f */
+	data = TESTPTBH;	/* 0x04; */
+	reg_w(dev, TV8532_POINTB_H, &data, 1);	/* 0x30 */
+	data = TV8532_CMD_UPDATE;
+	reg_w(dev, TV8532_PART_CTRL, &data, 1);	/* 0x00<-0x84 */
+	/*************************************************/
+	data = 0x01;
+	reg_w(dev, TV8532_UDP_UPDATE, &data, 1);	/* 0x31 */
+	msleep(200);
+	data = 0x00;
+	reg_w(dev, TV8532_UDP_UPDATE, &data, 1);	/* 0x31 */
+	/*************************************************/
+	tv_8532_setReg(gspca_dev);
+	/*************************************************/
+	data = 0x0b;
+	reg_w(dev, TV8532_GPIO_OE, &data,
+			1);
+	/*************************************************/
+	tv_8532_setReg(gspca_dev);
+	/*************************************************/
+	tv_8532_PollReg(gspca_dev);
+	return 0;
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	__u8 value[2];
+	__u8 data;
+	int brightness = sd->brightness;
+
+	value[1] = (brightness >> 8) & 0xff;
+	value[0] = (brightness) & 0xff;
+	reg_w(gspca_dev->dev, TV8532_EXPOSURE, value, 2);	/* 1c */
+	data = TV8532_CMD_UPDATE;
+	reg_w(gspca_dev->dev, TV8532_PART_CTRL, &data, 1);
+}
+
+/* -- start the camera -- */
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+	struct usb_device *dev = gspca_dev->dev;
+	__u8 data = 0;
+	__u8 dataStart = 0;
+	__u8 value[2];
+
+	data = 0x32;
+	reg_w(dev, TV8532_AD_SLOPE, &data, 1);
+	data = 0;
+	reg_w(dev, TV8532_AD_BITCTRL, &data, 1);
+	tv_8532ReadRegisters(gspca_dev);
+	data = 0x0b;
+	reg_w(dev, TV8532_GPIO_OE, &data, 1);
+	value[0] = ADHEIGHL;
+	value[1] = ADHEIGHH;	/* 401d 0x0169; */
+	reg_w(dev, TV8532_ADHEIGHT_L, value, 2);	/* 0e */
+/*	value[0] = EXPOL; value[1] =EXPOH; 		 * 350d 0x014c; */
+/*	reg_w(dev,TV8532_REQ_RegWrite,0,TV8532_EXPOSURE,value,2);  * 1c */
+	setbrightness(gspca_dev);
+
+	data = ADWIDTHL;	/* 0x20; */
+	reg_w(dev, TV8532_ADWIDTH_L, &data, 1);	/* 0x0c */
+	data = ADWIDTHH;
+	reg_w(dev, TV8532_ADWIDTH_H, &data, 1);	/* 0x0d */
+
+	/************************************************/
+	data = TESTCOMP;	/* 0x72 compressed mode */
+	reg_w(dev, TV8532_QUANT_COMP, &data, 1);	/* 0x28 */
+	if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].mode) {
+		/* 176x144 */
+		data = QCIFLINE;	/* 0x84; // CIF | 4 packet */
+		reg_w(dev, TV8532_MODE_PACKET, &data, 1);	/* 0x29 */
+	} else {
+		/* 352x288 */
+		data = TESTLINE;	/* 0x84; // CIF | 4 packet */
+		reg_w(dev, TV8532_MODE_PACKET, &data, 1);	/* 0x29 */
+	}
+	/************************************************/
+	data = TESTCLK;		/* 0x48; //0x08; */
+	reg_w(dev, TV8532_SETCLK, &data, 1);	/* 0x2c */
+	data = TESTPTL;		/* 0x38; */
+	reg_w(dev, TV8532_POINT_L, &data, 1);	/* 0x2d */
+	data = TESTPTH;		/* 0x04; */
+	reg_w(dev, TV8532_POINT_H, &data, 1);	/* 0x2e */
+	dataStart = TESTPTBL;	/* 0x04; */
+	reg_w(dev, TV8532_POINTB_L, &dataStart, 1);	/* 0x2f */
+	data = TESTPTBH;	/* 0x04; */
+	reg_w(dev, TV8532_POINTB_H, &data, 1);	/* 0x30 */
+	data = TV8532_CMD_UPDATE;
+	reg_w(dev, TV8532_PART_CTRL, &data, 1);	/* 0x00<-0x84 */
+	/************************************************/
+	data = 0x01;
+	reg_w(dev, TV8532_UDP_UPDATE, &data, 1);	/* 0x31 */
+	msleep(200);
+	data = 0x00;
+	reg_w(dev, TV8532_UDP_UPDATE, &data, 1);	/* 0x31 */
+	/************************************************/
+	tv_8532_setReg(gspca_dev);
+	/************************************************/
+	data = 0x0b;
+	reg_w(dev, TV8532_GPIO_OE, &data, 1);
+	/************************************************/
+	tv_8532_setReg(gspca_dev);
+	/************************************************/
+	tv_8532_PollReg(gspca_dev);
+	data = 0x00;
+	reg_w(dev, TV8532_UDP_UPDATE, &data, 1);	/* 0x31 */
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+	struct usb_device *dev = gspca_dev->dev;
+	__u8 data;
+
+	data = 0x0b;
+	reg_w(dev, TV8532_GPIO_OE, &data, 1);
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+}
+
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+}
+
+static void tv8532_preprocess(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+/* we should received a whole frame with header and EOL marker
+ * in gspca_dev->tmpbuf and return a GBRG pattern in gspca_dev->tmpbuf2
+ * sequence 2bytes header the Alternate pixels bayer GB 4 bytes
+ * Alternate pixels bayer RG 4 bytes EOL */
+	int width = gspca_dev->width;
+	int height = gspca_dev->height;
+	unsigned char *dst = sd->tmpbuf2;
+	unsigned char *data = sd->tmpbuf;
+	int i;
+
+	/* precompute where is the good bayer line */
+	if (((data[3] + data[width + 7]) >> 1)
+	    + (data[4] >> 2)
+	    + (data[width + 6] >> 1) >= ((data[2] + data[width + 6]) >> 1)
+	    + (data[3] >> 2)
+	    + (data[width + 5] >> 1))
+		data += 3;
+	else
+		data += 2;
+	for (i = 0; i < height / 2; i++) {
+		memcpy(dst, data, width);
+		data += width + 3;
+		dst += width;
+		memcpy(dst, data, width);
+		data += width + 7;
+		dst += width;
+	}
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+			struct gspca_frame *frame,	/* target */
+			__u8 *data,			/* isoc packet */
+			int len)			/* iso packet length */
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	if (data[0] != 0x80) {
+		sd->packet++;
+		if (sd->buflen + len > sizeof sd->tmpbuf) {
+			if (gspca_dev->last_packet_type != DISCARD_PACKET) {
+				PDEBUG(D_PACK, "buffer overflow");
+				gspca_dev->last_packet_type = DISCARD_PACKET;
+			}
+			return;
+		}
+		memcpy(&sd->tmpbuf[sd->buflen], data, len);
+		sd->buflen += len;
+		return;
+	}
+
+	/* here we detect 0x80 */
+	/* counter is limited so we need few header for a frame :) */
+
+	/* header 0x80 0x80 0x80 0x80 0x80 */
+	/* packet  00   63  127  145  00   */
+	/* sof     0     1   1    0    0   */
+
+	/* update sequence */
+	if (sd->packet == 63 || sd->packet == 127)
+		sd->synchro = 1;
+
+	/* is there a frame start ? */
+	if (sd->packet >= (gspca_dev->height >> 1) - 1) {
+		PDEBUG(D_PACK, "SOF > %d packet %d", sd->synchro,
+		       sd->packet);
+		if (!sd->synchro) {	/* start of frame */
+			if (gspca_dev->last_packet_type == FIRST_PACKET) {
+				tv8532_preprocess(gspca_dev);
+				frame = gspca_frame_add(gspca_dev,
+							LAST_PACKET,
+							frame, sd->tmpbuf2,
+							gspca_dev->width *
+							    gspca_dev->width);
+			}
+			gspca_frame_add(gspca_dev, FIRST_PACKET,
+					frame, data, 0);
+			memcpy(sd->tmpbuf, data, len);
+			sd->buflen = len;
+			sd->packet = 0;
+			return;
+		}
+		if (gspca_dev->last_packet_type != DISCARD_PACKET) {
+			PDEBUG(D_PACK,
+			       "Warning wrong TV8532 frame detection %d",
+			       sd->packet);
+			gspca_dev->last_packet_type = DISCARD_PACKET;
+		}
+		return;
+	}
+
+	if (!sd->synchro) {
+		/* Drop packet frame corrupt */
+		PDEBUG(D_PACK, "DROP SOF %d packet %d",
+		       sd->synchro, sd->packet);
+		sd->packet = 0;
+		gspca_dev->last_packet_type = DISCARD_PACKET;
+		return;
+	}
+	sd->synchro = 1;
+	sd->packet++;
+	memcpy(&sd->tmpbuf[sd->buflen], data, len);
+	sd->buflen += len;
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->brightness = val;
+	if (gspca_dev->streaming)
+		setbrightness(gspca_dev);
+	return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->brightness;
+	return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->contrast = val;
+	if (gspca_dev->streaming)
+		setcontrast(gspca_dev);
+	return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->contrast;
+	return 0;
+}
+
+/* sub-driver description */
+static struct sd_desc sd_desc = {
+	.name = MODULE_NAME,
+	.ctrls = sd_ctrls,
+	.nctrls = ARRAY_SIZE(sd_ctrls),
+	.config = sd_config,
+	.open = sd_open,
+	.start = sd_start,
+	.stopN = sd_stopN,
+	.stop0 = sd_stop0,
+	.close = sd_close,
+	.pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static __devinitdata struct usb_device_id device_table[] = {
+	{USB_DEVICE(0x046d, 0x0920), DVNM("QC Express")},
+	{USB_DEVICE(0x046d, 0x0921), DVNM("Labtec Webcam")},
+	{USB_DEVICE(0x0545, 0x808b), DVNM("Veo Stingray")},
+	{USB_DEVICE(0x0545, 0x8333), DVNM("Veo Stingray")},
+	{USB_DEVICE(0x0923, 0x010f), DVNM("ICM532 cams")},
+	{}
+};
+
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+		    const struct usb_device_id *id)
+{
+	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+			       THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+	.name = MODULE_NAME,
+	.id_table = device_table,
+	.probe = sd_probe,
+	.disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+	if (usb_register(&sd_driver) < 0)
+		return -1;
+	PDEBUG(D_PROBE, "v%s registered", version);
+	return 0;
+}
+
+static void __exit sd_mod_exit(void)
+{
+	usb_deregister(&sd_driver);
+	PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/vc032x.c b/drivers/media/video/gspca/vc032x.c
new file mode 100644
index 0000000..8b5f6d1
--- /dev/null
+++ b/drivers/media/video/gspca/vc032x.c
@@ -0,0 +1,1816 @@
+/*
+ *		Z-star vc0321 library
+ *		Copyright (C) 2006 Koninski Artur takeshi87@o2.pl
+ *		Copyright (C) 2006 Michel Xhaard
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define MODULE_NAME "vc032x"
+
+#include "gspca.h"
+
+#define DRIVER_VERSION_NUMBER	KERNEL_VERSION(2, 1, 0)
+static const char version[] = "2.1.0";
+
+MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_DESCRIPTION("GSPCA/VC032X USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+	struct gspca_dev gspca_dev;	/* !! must be the first item */
+
+	unsigned char autogain;
+	unsigned char lightfreq;
+
+	char qindex;
+	char bridge;
+#define BRIDGE_VC0321 0
+#define BRIDGE_VC0323 1
+	char sensor;
+#define SENSOR_HV7131R 0
+#define SENSOR_MI1320 1
+#define SENSOR_MI1310_SOC 2
+#define SENSOR_OV7660 3
+#define SENSOR_OV7670 4
+#define SENSOR_PO3130NC 5
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
+
+static struct ctrl sd_ctrls[] = {
+#define SD_AUTOGAIN 0
+	{
+	    {
+		.id      = V4L2_CID_AUTOGAIN,
+		.type    = V4L2_CTRL_TYPE_BOOLEAN,
+		.name    = "Auto Gain",
+		.minimum = 0,
+		.maximum = 1,
+		.step    = 1,
+		.default_value = 1,
+	    },
+	    .set = sd_setautogain,
+	    .get = sd_getautogain,
+	},
+#define SD_FREQ 1
+	{
+	    {
+		.id	 = V4L2_CID_POWER_LINE_FREQUENCY,
+		.type    = V4L2_CTRL_TYPE_MENU,
+		.name    = "Light frequency filter",
+		.minimum = 0,
+		.maximum = 2,	/* 0: 0, 1: 50Hz, 2:60Hz */
+		.step    = 1,
+		.default_value = 1,
+	    },
+	    .set = sd_setfreq,
+	    .get = sd_getfreq,
+	},
+};
+
+static struct cam_mode vc0321_mode[] = {
+	{V4L2_PIX_FMT_YUYV, 320, 240, 1},
+	{V4L2_PIX_FMT_YUYV, 640, 480, 0},
+};
+static struct cam_mode vc0323_mode[] = {
+	{V4L2_PIX_FMT_JPEG, 320, 240, 1},
+	{V4L2_PIX_FMT_JPEG, 640, 480, 0},
+};
+
+static __u8 mi1310_socinitVGA_JPG[][4] = {
+	{0xb0, 0x03, 0x19, 0xcc},
+	{0xb0, 0x04, 0x02, 0xcc},
+	{0xb3, 0x00, 0x64, 0xcc},
+	{0xb3, 0x00, 0x65, 0xcc},
+	{0xb3, 0x05, 0x00, 0xcc},
+	{0xb3, 0x06, 0x00, 0xcc},
+	{0xb3, 0x08, 0x01, 0xcc},
+	{0xb3, 0x09, 0x0c, 0xcc},
+	{0xb3, 0x34, 0x02, 0xcc},
+	{0xb3, 0x35, 0xdd, 0xcc},
+	{0xb3, 0x02, 0x00, 0xcc},
+	{0xb3, 0x03, 0x0a, 0xcc},
+	{0xb3, 0x04, 0x05, 0xcc},
+	{0xb3, 0x20, 0x00, 0xcc},
+	{0xb3, 0x21, 0x00, 0xcc},
+	{0xb3, 0x22, 0x03, 0xcc},
+	{0xb3, 0x23, 0xc0, 0xcc},
+	{0xb3, 0x14, 0x00, 0xcc},
+	{0xb3, 0x15, 0x00, 0xcc},
+	{0xb3, 0x16, 0x04, 0xcc},
+	{0xb3, 0x17, 0xff, 0xcc},
+	{0xb3, 0x00, 0x65, 0xcc},
+	{0xb8, 0x00, 0x00, 0xcc},
+	{0xbc, 0x00, 0xd0, 0xcc},
+	{0xbc, 0x01, 0x01, 0xcc},
+	{0xf0, 0x00, 0x02, 0xbb},
+	{0xc8, 0x9f, 0x0b, 0xbb},
+	{0x5b, 0x00, 0x01, 0xbb},
+	{0x2f, 0xde, 0x20, 0xbb},
+	{0xf0, 0x00, 0x00, 0xbb},
+	{0x20, 0x03, 0x02, 0xbb},
+	{0xf0, 0x00, 0x01, 0xbb},
+	{0x05, 0x00, 0x07, 0xbb},
+	{0x34, 0x00, 0x00, 0xbb},
+	{0x35, 0xff, 0x00, 0xbb},
+	{0xdc, 0x07, 0x02, 0xbb},
+	{0xdd, 0x3c, 0x18, 0xbb},
+	{0xde, 0x92, 0x6d, 0xbb},
+	{0xdf, 0xcd, 0xb1, 0xbb},
+	{0xe0, 0xff, 0xe7, 0xbb},
+	{0x06, 0xf0, 0x0d, 0xbb},
+	{0x06, 0x70, 0x0e, 0xbb},
+	{0x4c, 0x00, 0x01, 0xbb},
+	{0x4d, 0x00, 0x01, 0xbb},
+	{0xf0, 0x00, 0x02, 0xbb},
+	{0x2e, 0x0c, 0x55, 0xbb},
+	{0x21, 0xb6, 0x6e, 0xbb},
+	{0x36, 0x30, 0x10, 0xbb},
+	{0x37, 0x00, 0xc1, 0xbb},
+	{0xf0, 0x00, 0x00, 0xbb},
+	{0x07, 0x00, 0x84, 0xbb},
+	{0x08, 0x02, 0x4a, 0xbb},
+	{0x05, 0x01, 0x10, 0xbb},
+	{0x06, 0x00, 0x39, 0xbb},
+	{0xf0, 0x00, 0x02, 0xbb},
+	{0x58, 0x02, 0x67, 0xbb},
+	{0x57, 0x02, 0x00, 0xbb},
+	{0x5a, 0x02, 0x67, 0xbb},
+	{0x59, 0x02, 0x00, 0xbb},
+	{0x5c, 0x12, 0x0d, 0xbb},
+	{0x5d, 0x16, 0x11, 0xbb},
+	{0x39, 0x06, 0x18, 0xbb},
+	{0x3a, 0x06, 0x18, 0xbb},
+	{0x3b, 0x06, 0x18, 0xbb},
+	{0x3c, 0x06, 0x18, 0xbb},
+	{0x64, 0x7b, 0x5b, 0xbb},
+	{0xf0, 0x00, 0x02, 0xbb},
+	{0x36, 0x30, 0x10, 0xbb},
+	{0x37, 0x00, 0xc0, 0xbb},
+	{0xbc, 0x0e, 0x00, 0xcc},
+	{0xbc, 0x0f, 0x05, 0xcc},
+	{0xbc, 0x10, 0xc0, 0xcc},
+	{0xbc, 0x11, 0x03, 0xcc},
+	{0xb6, 0x00, 0x00, 0xcc},
+	{0xb6, 0x03, 0x02, 0xcc},
+	{0xb6, 0x02, 0x80, 0xcc},
+	{0xb6, 0x05, 0x01, 0xcc},
+	{0xb6, 0x04, 0xe0, 0xcc},
+	{0xb6, 0x12, 0xf8, 0xcc},
+	{0xb6, 0x13, 0x25, 0xcc},
+	{0xb6, 0x18, 0x02, 0xcc},
+	{0xb6, 0x17, 0x58, 0xcc},
+	{0xb6, 0x16, 0x00, 0xcc},
+	{0xb6, 0x22, 0x12, 0xcc},
+	{0xb6, 0x23, 0x0b, 0xcc},
+	{0xbf, 0xc0, 0x39, 0xcc},
+	{0xbf, 0xc1, 0x04, 0xcc},
+	{0xbf, 0xcc, 0x00, 0xcc},
+	{0xbc, 0x02, 0x18, 0xcc},
+	{0xbc, 0x03, 0x50, 0xcc},
+	{0xbc, 0x04, 0x18, 0xcc},
+	{0xbc, 0x05, 0x00, 0xcc},
+	{0xbc, 0x06, 0x00, 0xcc},
+	{0xbc, 0x08, 0x30, 0xcc},
+	{0xbc, 0x09, 0x40, 0xcc},
+	{0xbc, 0x0a, 0x10, 0xcc},
+	{0xbc, 0x0b, 0x00, 0xcc},
+	{0xbc, 0x0c, 0x00, 0xcc},
+	{0xb3, 0x5c, 0x01, 0xcc},
+	{0xf0, 0x00, 0x01, 0xbb},
+	{0x80, 0x00, 0x03, 0xbb},
+	{0x81, 0xc7, 0x14, 0xbb},
+	{0x82, 0xeb, 0xe8, 0xbb},
+	{0x83, 0xfe, 0xf4, 0xbb},
+	{0x84, 0xcd, 0x10, 0xbb},
+	{0x85, 0xf3, 0xee, 0xbb},
+	{0x86, 0xff, 0xf1, 0xbb},
+	{0x87, 0xcd, 0x10, 0xbb},
+	{0x88, 0xf3, 0xee, 0xbb},
+	{0x89, 0x01, 0xf1, 0xbb},
+	{0x8a, 0xe5, 0x17, 0xbb},
+	{0x8b, 0xe8, 0xe2, 0xbb},
+	{0x8c, 0xf7, 0xed, 0xbb},
+	{0x8d, 0x00, 0xff, 0xbb},
+	{0x8e, 0xec, 0x10, 0xbb},
+	{0x8f, 0xf0, 0xed, 0xbb},
+	{0x90, 0xf9, 0xf2, 0xbb},
+	{0x91, 0x00, 0x00, 0xbb},
+	{0x92, 0xe9, 0x0d, 0xbb},
+	{0x93, 0xf4, 0xf2, 0xbb},
+	{0x94, 0xfb, 0xf5, 0xbb},
+	{0x95, 0x00, 0xff, 0xbb},
+	{0xb6, 0x0f, 0x08, 0xbb},
+	{0xb7, 0x3d, 0x16, 0xbb},
+	{0xb8, 0x0c, 0x04, 0xbb},
+	{0xb9, 0x1c, 0x07, 0xbb},
+	{0xba, 0x0a, 0x03, 0xbb},
+	{0xbb, 0x1b, 0x09, 0xbb},
+	{0xbc, 0x17, 0x0d, 0xbb},
+	{0xbd, 0x23, 0x1d, 0xbb},
+	{0xbe, 0x00, 0x28, 0xbb},
+	{0xbf, 0x11, 0x09, 0xbb},
+	{0xc0, 0x16, 0x15, 0xbb},
+	{0xc1, 0x00, 0x1b, 0xbb},
+	{0xc2, 0x0e, 0x07, 0xbb},
+	{0xc3, 0x14, 0x10, 0xbb},
+	{0xc4, 0x00, 0x17, 0xbb},
+	{0x06, 0x74, 0x8e, 0xbb},
+	{0xf0, 0x00, 0x01, 0xbb},
+	{0x06, 0xf4, 0x8e, 0xbb},
+	{0x00, 0x00, 0x50, 0xdd},
+	{0x06, 0x74, 0x8e, 0xbb},
+	{0xf0, 0x00, 0x02, 0xbb},
+	{0x24, 0x50, 0x20, 0xbb},
+	{0xf0, 0x00, 0x02, 0xbb},
+	{0x34, 0x0c, 0x50, 0xbb},
+	{0xb3, 0x01, 0x41, 0xcc},
+	{0xf0, 0x00, 0x00, 0xbb},
+	{0x03, 0x03, 0xc0, 0xbb},
+	{},
+};
+static __u8 mi1310_socinitQVGA_JPG[][4] = {
+	{0xb0, 0x03, 0x19, 0xcc},	{0xb0, 0x04, 0x02, 0xcc},
+	{0xb3, 0x00, 0x64, 0xcc},	{0xb3, 0x00, 0x65, 0xcc},
+	{0xb3, 0x05, 0x00, 0xcc},	{0xb3, 0x06, 0x00, 0xcc},
+	{0xb3, 0x08, 0x01, 0xcc},	{0xb3, 0x09, 0x0c, 0xcc},
+	{0xb3, 0x34, 0x02, 0xcc},	{0xb3, 0x35, 0xdd, 0xcc},
+	{0xb3, 0x02, 0x00, 0xcc},	{0xb3, 0x03, 0x0a, 0xcc},
+	{0xb3, 0x04, 0x05, 0xcc},	{0xb3, 0x20, 0x00, 0xcc},
+	{0xb3, 0x21, 0x00, 0xcc},	{0xb3, 0x22, 0x03, 0xcc},
+	{0xb3, 0x23, 0xc0, 0xcc},	{0xb3, 0x14, 0x00, 0xcc},
+	{0xb3, 0x15, 0x00, 0xcc},	{0xb3, 0x16, 0x04, 0xcc},
+	{0xb3, 0x17, 0xff, 0xcc},	{0xb3, 0x00, 0x65, 0xcc},
+	{0xb8, 0x00, 0x00, 0xcc},	{0xbc, 0x00, 0xf0, 0xcc},
+	{0xbc, 0x01, 0x01, 0xcc},	{0xf0, 0x00, 0x02, 0xbb},
+	{0xc8, 0x9f, 0x0b, 0xbb},	{0x5b, 0x00, 0x01, 0xbb},
+	{0x2f, 0xde, 0x20, 0xbb},	{0xf0, 0x00, 0x00, 0xbb},
+	{0x20, 0x03, 0x02, 0xbb},	{0xf0, 0x00, 0x01, 0xbb},
+	{0x05, 0x00, 0x07, 0xbb},	{0x34, 0x00, 0x00, 0xbb},
+	{0x35, 0xff, 0x00, 0xbb},	{0xdc, 0x07, 0x02, 0xbb},
+	{0xdd, 0x3c, 0x18, 0xbb},	{0xde, 0x92, 0x6d, 0xbb},
+	{0xdf, 0xcd, 0xb1, 0xbb},	{0xe0, 0xff, 0xe7, 0xbb},
+	{0x06, 0xf0, 0x0d, 0xbb},	{0x06, 0x70, 0x0e, 0xbb},
+	{0x4c, 0x00, 0x01, 0xbb},	{0x4d, 0x00, 0x01, 0xbb},
+	{0xf0, 0x00, 0x02, 0xbb},	{0x2e, 0x0c, 0x55, 0xbb},
+	{0x21, 0xb6, 0x6e, 0xbb},	{0x36, 0x30, 0x10, 0xbb},
+	{0x37, 0x00, 0xc1, 0xbb},	{0xf0, 0x00, 0x00, 0xbb},
+	{0x07, 0x00, 0x84, 0xbb},	{0x08, 0x02, 0x4a, 0xbb},
+	{0x05, 0x01, 0x10, 0xbb},	{0x06, 0x00, 0x39, 0xbb},
+	{0xf0, 0x00, 0x02, 0xbb},	{0x58, 0x02, 0x67, 0xbb},
+	{0x57, 0x02, 0x00, 0xbb},	{0x5a, 0x02, 0x67, 0xbb},
+	{0x59, 0x02, 0x00, 0xbb},	{0x5c, 0x12, 0x0d, 0xbb},
+	{0x5d, 0x16, 0x11, 0xbb},	{0x39, 0x06, 0x18, 0xbb},
+	{0x3a, 0x06, 0x18, 0xbb},	{0x3b, 0x06, 0x18, 0xbb},
+	{0x3c, 0x06, 0x18, 0xbb},	{0x64, 0x7b, 0x5b, 0xbb},
+	{0xf0, 0x00, 0x02, 0xbb},	{0x36, 0x30, 0x10, 0xbb},
+	{0x37, 0x00, 0xc0, 0xbb},	{0xbc, 0x0e, 0x00, 0xcc},
+	{0xbc, 0x0f, 0x05, 0xcc},	{0xbc, 0x10, 0xc0, 0xcc},
+	{0xbc, 0x11, 0x03, 0xcc},	{0xb6, 0x00, 0x00, 0xcc},
+	{0xb6, 0x03, 0x01, 0xcc},	{0xb6, 0x02, 0x40, 0xcc},
+	{0xb6, 0x05, 0x00, 0xcc},	{0xb6, 0x04, 0xf0, 0xcc},
+	{0xb6, 0x12, 0xf8, 0xcc},	{0xb6, 0x13, 0x25, 0xcc},
+	{0xb6, 0x18, 0x00, 0xcc},	{0xb6, 0x17, 0x96, 0xcc},
+	{0xb6, 0x16, 0x00, 0xcc},	{0xb6, 0x22, 0x12, 0xcc},
+	{0xb6, 0x23, 0x0b, 0xcc},	{0xbf, 0xc0, 0x39, 0xcc},
+	{0xbf, 0xc1, 0x04, 0xcc},	{0xbf, 0xcc, 0x00, 0xcc},
+	{0xb3, 0x5c, 0x01, 0xcc},	{0xf0, 0x00, 0x01, 0xbb},
+	{0x80, 0x00, 0x03, 0xbb},	{0x81, 0xc7, 0x14, 0xbb},
+	{0x82, 0xeb, 0xe8, 0xbb},	{0x83, 0xfe, 0xf4, 0xbb},
+	{0x84, 0xcd, 0x10, 0xbb},	{0x85, 0xf3, 0xee, 0xbb},
+	{0x86, 0xff, 0xf1, 0xbb},	{0x87, 0xcd, 0x10, 0xbb},
+	{0x88, 0xf3, 0xee, 0xbb},	{0x89, 0x01, 0xf1, 0xbb},
+	{0x8a, 0xe5, 0x17, 0xbb},	{0x8b, 0xe8, 0xe2, 0xbb},
+	{0x8c, 0xf7, 0xed, 0xbb},	{0x8d, 0x00, 0xff, 0xbb},
+	{0x8e, 0xec, 0x10, 0xbb},	{0x8f, 0xf0, 0xed, 0xbb},
+	{0x90, 0xf9, 0xf2, 0xbb},	{0x91, 0x00, 0x00, 0xbb},
+	{0x92, 0xe9, 0x0d, 0xbb},	{0x93, 0xf4, 0xf2, 0xbb},
+	{0x94, 0xfb, 0xf5, 0xbb},	{0x95, 0x00, 0xff, 0xbb},
+	{0xb6, 0x0f, 0x08, 0xbb},	{0xb7, 0x3d, 0x16, 0xbb},
+	{0xb8, 0x0c, 0x04, 0xbb},	{0xb9, 0x1c, 0x07, 0xbb},
+	{0xba, 0x0a, 0x03, 0xbb},	{0xbb, 0x1b, 0x09, 0xbb},
+	{0xbc, 0x17, 0x0d, 0xbb},	{0xbd, 0x23, 0x1d, 0xbb},
+	{0xbe, 0x00, 0x28, 0xbb},	{0xbf, 0x11, 0x09, 0xbb},
+	{0xc0, 0x16, 0x15, 0xbb},	{0xc1, 0x00, 0x1b, 0xbb},
+	{0xc2, 0x0e, 0x07, 0xbb},	{0xc3, 0x14, 0x10, 0xbb},
+	{0xc4, 0x00, 0x17, 0xbb},	{0x06, 0x74, 0x8e, 0xbb},
+	{0xf0, 0x00, 0x01, 0xbb},	{0x06, 0xf4, 0x8e, 0xbb},
+	{0x00, 0x00, 0x50, 0xdd},	{0x06, 0x74, 0x8e, 0xbb},
+	{0xf0, 0x00, 0x02, 0xbb},	{0x24, 0x50, 0x20, 0xbb},
+	{0xf0, 0x00, 0x02, 0xbb},	{0x34, 0x0c, 0x50, 0xbb},
+	{0xb3, 0x01, 0x41, 0xcc},	{0xf0, 0x00, 0x00, 0xbb},
+	{0x03, 0x03, 0xc0, 0xbb},
+	{},
+};
+
+static __u8 mi1320_gamma[17] = {
+	0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
+	0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff
+};
+static __u8 mi1320_matrix[9] = {
+	0x54, 0xda, 0x06, 0xf1, 0x50, 0xf4, 0xf7, 0xea, 0x52
+};
+static __u8 mi1320_initVGA_data[][4] = {
+	{0xb3, 0x01, 0x01, 0xcc},	{0x00, 0x00, 0x33, 0xdd},
+	{0xb0, 0x03, 0x19, 0xcc},	{0x00, 0x00, 0x33, 0xdd},
+	{0xb0, 0x04, 0x02, 0xcc},	{0x00, 0x00, 0x33, 0xdd},
+	{0xb3, 0x00, 0x64, 0xcc},	{0xb3, 0x00, 0x65, 0xcc},
+	{0xb0, 0x16, 0x03, 0xcc},	{0xb3, 0x05, 0x00, 0xcc},
+	{0xb3, 0x06, 0x00, 0xcc},	{0xb3, 0x08, 0x01, 0xcc},
+	{0xb3, 0x09, 0x0c, 0xcc},	{0xb3, 0x34, 0x02, 0xcc},
+	{0xb3, 0x35, 0xc8, 0xcc},	{0xb3, 0x02, 0x00, 0xcc},
+	{0xb3, 0x03, 0x0a, 0xcc},	{0xb3, 0x04, 0x05, 0xcc},
+	{0xb3, 0x20, 0x00, 0xcc},	{0xb3, 0x21, 0x00, 0xcc},
+	{0xb3, 0x22, 0x03, 0xcc},	{0xb3, 0x23, 0xc0, 0xcc},
+	{0xb3, 0x14, 0x00, 0xcc},	{0xb3, 0x15, 0x00, 0xcc},
+	{0xb3, 0x16, 0x04, 0xcc},	{0xb3, 0x17, 0xff, 0xcc},
+	{0xb3, 0x00, 0x67, 0xcc},	{0xbc, 0x00, 0xd0, 0xcc},
+	{0xbc, 0x01, 0x01, 0xcc},	{0xf0, 0x00, 0x00, 0xbb},
+	{0x0d, 0x00, 0x09, 0xbb},	{0x00, 0x01, 0x00, 0xdd},
+	{0x0d, 0x00, 0x08, 0xbb},	{0xf0, 0x00, 0x01, 0xbb},
+	{0xa1, 0x05, 0x00, 0xbb},	{0xa4, 0x03, 0xc0, 0xbb},
+	{0xf0, 0x00, 0x02, 0xbb},	{0x00, 0x00, 0x10, 0xdd},
+	{0xc8, 0x9f, 0x0b, 0xbb},	{0x00, 0x00, 0x10, 0xdd},
+	{0xf0, 0x00, 0x00, 0xbb},	{0x00, 0x00, 0x10, 0xdd},
+	{0x20, 0x01, 0x00, 0xbb},	{0x00, 0x00, 0x10, 0xdd},
+	{0xf0, 0x00, 0x01, 0xbb},	{0x9d, 0x3c, 0xa0, 0xbb},
+	{0x47, 0x30, 0x30, 0xbb},	{0xf0, 0x00, 0x00, 0xbb},
+	{0x0a, 0x80, 0x11, 0xbb},	{0x35, 0x00, 0x22, 0xbb},
+	{0xf0, 0x00, 0x02, 0xbb},	{0x9d, 0xc5, 0x05, 0xbb},
+	{0xdc, 0x0f, 0xfc, 0xbb},	{0xf0, 0x00, 0x01, 0xbb},
+	{0x06, 0x74, 0x0e, 0xbb},	{0x80, 0x00, 0x06, 0xbb},
+	{0x81, 0x04, 0x00, 0xbb},	{0x82, 0x01, 0x02, 0xbb},
+	{0x83, 0x03, 0x02, 0xbb},	{0x84, 0x05, 0x00, 0xbb},
+	{0x85, 0x01, 0x00, 0xbb},	{0x86, 0x03, 0x02, 0xbb},
+	{0x87, 0x05, 0x00, 0xbb},	{0x88, 0x01, 0x00, 0xbb},
+	{0x89, 0x02, 0x02, 0xbb},	{0x8a, 0xfd, 0x04, 0xbb},
+	{0x8b, 0xfc, 0xfd, 0xbb},	{0x8c, 0xff, 0xfd, 0xbb},
+	{0x8d, 0x00, 0x00, 0xbb},	{0x8e, 0xfe, 0x05, 0xbb},
+	{0x8f, 0xfc, 0xfd, 0xbb},	{0x90, 0xfe, 0xfd, 0xbb},
+	{0x91, 0x00, 0x00, 0xbb},	{0x92, 0xfe, 0x03, 0xbb},
+	{0x93, 0xfd, 0xfe, 0xbb},	{0x94, 0xff, 0xfd, 0xbb},
+	{0x95, 0x00, 0x00, 0xbb},	{0xb6, 0x07, 0x05, 0xbb},
+	{0xb7, 0x13, 0x06, 0xbb},	{0xb8, 0x08, 0x06, 0xbb},
+	{0xb9, 0x14, 0x08, 0xbb},	{0xba, 0x06, 0x05, 0xbb},
+	{0xbb, 0x13, 0x06, 0xbb},	{0xbc, 0x03, 0x01, 0xbb},
+	{0xbd, 0x03, 0x04, 0xbb},	{0xbe, 0x00, 0x02, 0xbb},
+	{0xbf, 0x03, 0x01, 0xbb},	{0xc0, 0x02, 0x04, 0xbb},
+	{0xc1, 0x00, 0x04, 0xbb},	{0xc2, 0x02, 0x01, 0xbb},
+	{0xc3, 0x01, 0x03, 0xbb},	{0xc4, 0x00, 0x04, 0xbb},
+	{0xf0, 0x00, 0x00, 0xbb},	{0x05, 0x01, 0x13, 0xbb},
+	{0x06, 0x00, 0x11, 0xbb},	{0x07, 0x00, 0x85, 0xbb},
+	{0x08, 0x00, 0x27, 0xbb},	{0x20, 0x01, 0x03, 0xbb},
+	{0x21, 0x80, 0x00, 0xbb},	{0x22, 0x0d, 0x0f, 0xbb},
+	{0x24, 0x80, 0x00, 0xbb},	{0x59, 0x00, 0xff, 0xbb},
+	{0xf0, 0x00, 0x02, 0xbb},	{0x39, 0x03, 0x0d, 0xbb},
+	{0x3a, 0x06, 0x1b, 0xbb},	{0x3b, 0x00, 0x95, 0xbb},
+	{0x3c, 0x04, 0xdb, 0xbb},	{0x57, 0x02, 0x00, 0xbb},
+	{0x58, 0x02, 0x66, 0xbb},	{0x59, 0x00, 0xff, 0xbb},
+	{0x5a, 0x01, 0x33, 0xbb},	{0x5c, 0x12, 0x0d, 0xbb},
+	{0x5d, 0x16, 0x11, 0xbb},	{0x64, 0x5e, 0x1c, 0xbb},
+	{0xf0, 0x00, 0x02, 0xbb},	{0x2f, 0xd1, 0x00, 0xbb},
+	{0x5b, 0x00, 0x01, 0xbb},	{0xf0, 0x00, 0x02, 0xbb},
+	{0x36, 0x68, 0x10, 0xbb},	{0x00, 0x00, 0x30, 0xdd},
+	{0x37, 0x82, 0x00, 0xbb},	{0xbc, 0x0e, 0x00, 0xcc},
+	{0xbc, 0x0f, 0x05, 0xcc},	{0xbc, 0x10, 0xc0, 0xcc},
+	{0xbc, 0x11, 0x03, 0xcc},	{0xb6, 0x00, 0x00, 0xcc},
+	{0xb6, 0x03, 0x05, 0xcc},	{0xb6, 0x02, 0x00, 0xcc},
+	{0xb6, 0x05, 0x04, 0xcc},	{0xb6, 0x04, 0x00, 0xcc},
+	{0xb6, 0x12, 0xf8, 0xcc},	{0xb6, 0x13, 0x29, 0xcc},
+	{0xb6, 0x18, 0x0a, 0xcc},	{0xb6, 0x17, 0x00, 0xcc},
+	{0xb6, 0x16, 0x00, 0xcc},	{0xb6, 0x22, 0x12, 0xcc},
+	{0xb6, 0x23, 0x0b, 0xcc},	{0xbf, 0xc0, 0x26, 0xcc},
+	{0xbf, 0xc1, 0x02, 0xcc},	{0xbf, 0xcc, 0x04, 0xcc},
+	{0xbc, 0x02, 0x18, 0xcc},	{0xbc, 0x03, 0x50, 0xcc},
+	{0xbc, 0x04, 0x18, 0xcc},	{0xbc, 0x05, 0x00, 0xcc},
+	{0xbc, 0x06, 0x00, 0xcc},	{0xbc, 0x08, 0x30, 0xcc},
+	{0xbc, 0x09, 0x40, 0xcc},	{0xbc, 0x0a, 0x10, 0xcc},
+	{0xbc, 0x0b, 0x00, 0xcc},	{0xbc, 0x0c, 0x00, 0xcc},
+	{0xb3, 0x5c, 0x01, 0xcc},	{0xb3, 0x01, 0x41, 0xcc},
+	{}
+};
+static __u8 mi1320_initQVGA_data[][4] = {
+	{0xb3, 0x01, 0x01, 0xcc},	{0x00, 0x00, 0x33, 0xdd},
+	{0xb0, 0x03, 0x19, 0xcc},	{0x00, 0x00, 0x33, 0xdd},
+	{0xb0, 0x04, 0x02, 0xcc},	{0x00, 0x00, 0x33, 0xdd},
+	{0xb3, 0x00, 0x64, 0xcc},	{0xb3, 0x00, 0x65, 0xcc},
+	{0xb0, 0x16, 0x03, 0xcc},	{0xb3, 0x05, 0x01, 0xcc},
+	{0xb3, 0x06, 0x01, 0xcc},	{0xb3, 0x08, 0x01, 0xcc},
+	{0xb3, 0x09, 0x0c, 0xcc},	{0xb3, 0x34, 0x02, 0xcc},
+	{0xb3, 0x35, 0xc8, 0xcc},	{0xb3, 0x02, 0x00, 0xcc},
+	{0xb3, 0x03, 0x0a, 0xcc},	{0xb3, 0x04, 0x05, 0xcc},
+	{0xb3, 0x20, 0x00, 0xcc},	{0xb3, 0x21, 0x00, 0xcc},
+	{0xb3, 0x22, 0x01, 0xcc},	{0xb3, 0x23, 0xe0, 0xcc},
+	{0xb3, 0x14, 0x00, 0xcc},	{0xb3, 0x15, 0x00, 0xcc},
+	{0xb3, 0x16, 0x02, 0xcc},	{0xb3, 0x17, 0x7f, 0xcc},
+	{0xb3, 0x00, 0x65, 0xcc},	{0xb8, 0x00, 0x00, 0xcc},
+	{0xbc, 0x00, 0xd0, 0xcc},	{0xbc, 0x01, 0x01, 0xcc},
+	{0xf0, 0x00, 0x00, 0xbb},	{0x0d, 0x00, 0x09, 0xbb},
+	{0x00, 0x01, 0x00, 0xdd},	{0x0d, 0x00, 0x08, 0xbb},
+	{0xf0, 0x00, 0x00, 0xbb},	{0x02, 0x00, 0x64, 0xbb},
+	{0x05, 0x01, 0x78, 0xbb},	{0x06, 0x00, 0x11, 0xbb},
+	{0x07, 0x01, 0x42, 0xbb},	{0x08, 0x00, 0x11, 0xbb},
+	{0x20, 0x01, 0x00, 0xbb},	{0x21, 0x80, 0x00, 0xbb},
+	{0x22, 0x0d, 0x0f, 0xbb},	{0x24, 0x80, 0x00, 0xbb},
+	{0x59, 0x00, 0xff, 0xbb},	{0xf0, 0x00, 0x01, 0xbb},
+	{0x9d, 0x3c, 0xa0, 0xbb},	{0x47, 0x30, 0x30, 0xbb},
+	{0xf0, 0x00, 0x00, 0xbb},	{0x0a, 0x80, 0x11, 0xbb},
+	{0x35, 0x00, 0x22, 0xbb},	{0xf0, 0x00, 0x02, 0xbb},
+	{0x9d, 0xc5, 0x05, 0xbb},	{0xdc, 0x0f, 0xfc, 0xbb},
+	{0xf0, 0x00, 0x01, 0xbb},	{0x06, 0x74, 0x0e, 0xbb},
+	{0x80, 0x00, 0x06, 0xbb},	{0x81, 0x04, 0x00, 0xbb},
+	{0x82, 0x01, 0x02, 0xbb},	{0x83, 0x03, 0x02, 0xbb},
+	{0x84, 0x05, 0x00, 0xbb},	{0x85, 0x01, 0x00, 0xbb},
+	{0x86, 0x03, 0x02, 0xbb},	{0x87, 0x05, 0x00, 0xbb},
+	{0x88, 0x01, 0x00, 0xbb},	{0x89, 0x02, 0x02, 0xbb},
+	{0x8a, 0xfd, 0x04, 0xbb},	{0x8b, 0xfc, 0xfd, 0xbb},
+	{0x8c, 0xff, 0xfd, 0xbb},	{0x8d, 0x00, 0x00, 0xbb},
+	{0x8e, 0xfe, 0x05, 0xbb},	{0x8f, 0xfc, 0xfd, 0xbb},
+	{0x90, 0xfe, 0xfd, 0xbb},	{0x91, 0x00, 0x00, 0xbb},
+	{0x92, 0xfe, 0x03, 0xbb},	{0x93, 0xfd, 0xfe, 0xbb},
+	{0x94, 0xff, 0xfd, 0xbb},	{0x95, 0x00, 0x00, 0xbb},
+	{0xb6, 0x07, 0x05, 0xbb},	{0xb7, 0x13, 0x06, 0xbb},
+	{0xb8, 0x08, 0x06, 0xbb},	{0xb9, 0x14, 0x08, 0xbb},
+	{0xba, 0x06, 0x05, 0xbb},	{0xbb, 0x13, 0x06, 0xbb},
+	{0xbc, 0x03, 0x01, 0xbb},	{0xbd, 0x03, 0x04, 0xbb},
+	{0xbe, 0x00, 0x02, 0xbb},	{0xbf, 0x03, 0x01, 0xbb},
+	{0xc0, 0x02, 0x04, 0xbb},	{0xc1, 0x00, 0x04, 0xbb},
+	{0xc2, 0x02, 0x01, 0xbb},	{0xc3, 0x01, 0x03, 0xbb},
+	{0xc4, 0x00, 0x04, 0xbb},	{0xf0, 0x00, 0x02, 0xbb},
+	{0xc8, 0x00, 0x00, 0xbb},	{0x2e, 0x00, 0x00, 0xbb},
+	{0x2e, 0x0c, 0x5b, 0xbb},	{0x2f, 0xd1, 0x00, 0xbb},
+	{0x39, 0x03, 0xca, 0xbb},	{0x3a, 0x06, 0x80, 0xbb},
+	{0x3b, 0x01, 0x52, 0xbb},	{0x3c, 0x05, 0x40, 0xbb},
+	{0x57, 0x01, 0x9c, 0xbb},	{0x58, 0x01, 0xee, 0xbb},
+	{0x59, 0x00, 0xf0, 0xbb},	{0x5a, 0x01, 0x20, 0xbb},
+	{0x5c, 0x1d, 0x17, 0xbb},	{0x5d, 0x22, 0x1c, 0xbb},
+	{0x64, 0x1e, 0x1c, 0xbb},	{0x5b, 0x00, 0x01, 0xbb},
+	{0xf0, 0x00, 0x02, 0xbb},	{0x36, 0x68, 0x10, 0xbb},
+	{0x00, 0x00, 0x30, 0xdd},	{0x37, 0x81, 0x00, 0xbb},
+	{0xbc, 0x02, 0x18, 0xcc},	{0xbc, 0x03, 0x50, 0xcc},
+	{0xbc, 0x04, 0x18, 0xcc},	{0xbc, 0x05, 0x00, 0xcc},
+	{0xbc, 0x06, 0x00, 0xcc},	{0xbc, 0x08, 0x30, 0xcc},
+	{0xbc, 0x09, 0x40, 0xcc},	{0xbc, 0x0a, 0x10, 0xcc},
+	{0xbc, 0x0b, 0x00, 0xcc},	{0xbc, 0x0c, 0x00, 0xcc},
+	{0xbf, 0xc0, 0x26, 0xcc},	{0xbf, 0xc1, 0x02, 0xcc},
+	{0xbf, 0xcc, 0x04, 0xcc},	{0xb3, 0x5c, 0x01, 0xcc},
+	{0xb3, 0x01, 0x41, 0xcc},
+	{}
+};
+
+static __u8 po3130_gamma[17] = {
+	0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
+	0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff
+};
+static __u8 po3130_matrix[9] = {
+	0x5f, 0xec, 0xf5, 0xf1, 0x5a, 0xf5, 0xf1, 0xec, 0x63
+};
+
+static __u8 po3130_initVGA_data[][4] = {
+	{0xb0, 0x4d, 0x00, 0xcc},	{0xb3, 0x01, 0x01, 0xcc},
+	{0x00, 0x00, 0x50, 0xdd},	{0xb0, 0x03, 0x01, 0xcc},
+	{0xb3, 0x00, 0x04, 0xcc},	{0xb3, 0x00, 0x24, 0xcc},
+	{0xb3, 0x00, 0x25, 0xcc},	{0xb3, 0x08, 0x01, 0xcc},
+	{0xb3, 0x09, 0x0c, 0xcc},	{0xb3, 0x05, 0x00, 0xcc},
+	{0xb3, 0x06, 0x01, 0xcc},	{0xb3, 0x03, 0x1a, 0xcc},
+	{0xb3, 0x04, 0x15, 0xcc},	{0xb3, 0x20, 0x00, 0xcc},
+	{0xb3, 0x21, 0x00, 0xcc},	{0xb3, 0x22, 0x01, 0xcc},
+	{0xb3, 0x23, 0xe8, 0xcc},	{0xb8, 0x08, 0xe8, 0xcc},
+	{0xb3, 0x14, 0x00, 0xcc},	{0xb3, 0x15, 0x00, 0xcc},
+	{0xb3, 0x16, 0x02, 0xcc},	{0xb3, 0x17, 0x7f, 0xcc},
+	{0xb3, 0x34, 0x01, 0xcc},	{0xb3, 0x35, 0xf6, 0xcc},
+	{0xb3, 0x00, 0x27, 0xcc},	{0xbc, 0x00, 0x71, 0xcc},
+	{0xb8, 0x00, 0x21, 0xcc},	{0xb8, 0x27, 0x20, 0xcc},
+	{0xb8, 0x01, 0x79, 0xcc},	{0xb8, 0x81, 0x09, 0xcc},
+	{0xb8, 0x2c, 0x50, 0xcc},	{0xb8, 0x2d, 0xf8, 0xcc},
+	{0xb8, 0x2e, 0xf8, 0xcc},	{0xb8, 0x2f, 0xf8, 0xcc},
+	{0xb8, 0x30, 0x50, 0xcc},	{0xb8, 0x31, 0xf8, 0xcc},
+	{0xb8, 0x32, 0xf8, 0xcc},	{0xb8, 0x33, 0xf8, 0xcc},
+	{0xb8, 0x34, 0x50, 0xcc},	{0xb8, 0x35, 0x00, 0xcc},
+	{0xb8, 0x36, 0x00, 0xcc},	{0xb8, 0x37, 0x00, 0xcc},
+	{0x00, 0x1e, 0xc6, 0xaa},	{0x00, 0x20, 0x44, 0xaa},
+	{0x00, 0xad, 0x02, 0xaa},	{0x00, 0xae, 0x2c, 0xaa},
+	{0x00, 0x12, 0x08, 0xaa},	{0x00, 0x17, 0x41, 0xaa},
+	{0x00, 0x19, 0x41, 0xaa},	{0x00, 0x1e, 0x06, 0xaa},
+	{0x00, 0x21, 0x00, 0xaa},	{0x00, 0x36, 0xc0, 0xaa},
+	{0x00, 0x37, 0xc8, 0xaa},	{0x00, 0x3b, 0x36, 0xaa},
+	{0x00, 0x4b, 0xfe, 0xaa},	{0x00, 0x51, 0x1c, 0xaa},
+	{0x00, 0x52, 0x01, 0xaa},	{0x00, 0x55, 0x0a, 0xaa},
+	{0x00, 0x59, 0x02, 0xaa},	{0x00, 0x5a, 0x04, 0xaa},
+	{0x00, 0x5c, 0x10, 0xaa},	{0x00, 0x5d, 0x10, 0xaa},
+	{0x00, 0x5e, 0x10, 0xaa},	{0x00, 0x5f, 0x10, 0xaa},
+	{0x00, 0x61, 0x00, 0xaa},	{0x00, 0x62, 0x18, 0xaa},
+	{0x00, 0x63, 0x30, 0xaa},	{0x00, 0x70, 0x68, 0xaa},
+	{0x00, 0x80, 0x71, 0xaa},	{0x00, 0x81, 0x08, 0xaa},
+	{0x00, 0x82, 0x00, 0xaa},	{0x00, 0x83, 0x55, 0xaa},
+	{0x00, 0x84, 0x06, 0xaa},	{0x00, 0x85, 0x06, 0xaa},
+	{0x00, 0x86, 0x13, 0xaa},	{0x00, 0x87, 0x18, 0xaa},
+	{0x00, 0xaa, 0x3f, 0xaa},	{0x00, 0xab, 0x44, 0xaa},
+	{0x00, 0xb0, 0x68, 0xaa},	{0x00, 0xb5, 0x10, 0xaa},
+	{0x00, 0xb8, 0x20, 0xaa},	{0x00, 0xb9, 0xa0, 0xaa},
+	{0x00, 0xbc, 0x04, 0xaa},	{0x00, 0x8b, 0x40, 0xaa},
+	{0x00, 0x8c, 0x91, 0xaa},	{0x00, 0x8d, 0x8f, 0xaa},
+	{0x00, 0x8e, 0x91, 0xaa},	{0x00, 0x8f, 0x43, 0xaa},
+	{0x00, 0x90, 0x92, 0xaa},	{0x00, 0x91, 0x89, 0xaa},
+	{0x00, 0x92, 0x9d, 0xaa},	{0x00, 0x93, 0x46, 0xaa},
+	{0x00, 0xd6, 0x22, 0xaa},	{0x00, 0x73, 0x00, 0xaa},
+	{0x00, 0x74, 0x10, 0xaa},	{0x00, 0x75, 0x20, 0xaa},
+	{0x00, 0x76, 0x2b, 0xaa},	{0x00, 0x77, 0x36, 0xaa},
+	{0x00, 0x78, 0x49, 0xaa},	{0x00, 0x79, 0x5a, 0xaa},
+	{0x00, 0x7a, 0x7f, 0xaa},	{0x00, 0x7b, 0x9b, 0xaa},
+	{0x00, 0x7c, 0xba, 0xaa},	{0x00, 0x7d, 0xd4, 0xaa},
+	{0x00, 0x7e, 0xea, 0xaa},	{0x00, 0xd6, 0x62, 0xaa},
+	{0x00, 0x73, 0x00, 0xaa},	{0x00, 0x74, 0x10, 0xaa},
+	{0x00, 0x75, 0x20, 0xaa},	{0x00, 0x76, 0x2b, 0xaa},
+	{0x00, 0x77, 0x36, 0xaa},	{0x00, 0x78, 0x49, 0xaa},
+	{0x00, 0x79, 0x5a, 0xaa},	{0x00, 0x7a, 0x7f, 0xaa},
+	{0x00, 0x7b, 0x9b, 0xaa},	{0x00, 0x7c, 0xba, 0xaa},
+	{0x00, 0x7d, 0xd4, 0xaa},	{0x00, 0x7e, 0xea, 0xaa},
+	{0x00, 0xd6, 0xa2, 0xaa},	{0x00, 0x73, 0x00, 0xaa},
+	{0x00, 0x74, 0x10, 0xaa},	{0x00, 0x75, 0x20, 0xaa},
+	{0x00, 0x76, 0x2b, 0xaa},	{0x00, 0x77, 0x36, 0xaa},
+	{0x00, 0x78, 0x49, 0xaa},	{0x00, 0x79, 0x5a, 0xaa},
+	{0x00, 0x7a, 0x7f, 0xaa},	{0x00, 0x7b, 0x9b, 0xaa},
+	{0x00, 0x7c, 0xba, 0xaa},	{0x00, 0x7d, 0xd4, 0xaa},
+	{0x00, 0x7e, 0xea, 0xaa},
+	{0x00, 0x4c, 0x07, 0xaa},
+	{0x00, 0x4b, 0xe0, 0xaa},	{0x00, 0x4e, 0x77, 0xaa},
+	{0x00, 0x59, 0x02, 0xaa},	{0x00, 0x4d, 0x0a, 0xaa},
+/*	{0x00, 0xd1, 0x00, 0xaa},	{0x00, 0x20, 0xc4, 0xaa},
+	{0xb8, 0x8e, 0x00, 0xcc},	{0xb8, 0x8f, 0xff, 0xcc}, */
+	{0x00, 0xd1, 0x3c, 0xaa},	{0x00, 0x20, 0xc4, 0xaa},
+	{0xb8, 0x8e, 0x00, 0xcc},	{0xb8, 0x8f, 0xff, 0xcc},
+	{0xb8, 0xfe, 0x00, 0xcc},	{0xb8, 0xff, 0x28, 0xcc},
+	{0xb9, 0x00, 0x28, 0xcc},	{0xb9, 0x01, 0x28, 0xcc},
+	{0xb9, 0x02, 0x28, 0xcc},	{0xb9, 0x03, 0x00, 0xcc},
+	{0xb9, 0x04, 0x00, 0xcc},	{0xb9, 0x05, 0x3c, 0xcc},
+	{0xb9, 0x06, 0x3c, 0xcc},	{0xb9, 0x07, 0x3c, 0xcc},
+	{0xb9, 0x08, 0x3c, 0xcc},	{0x00, 0x05, 0x00, 0xaa},
+	{0xb3, 0x5c, 0x00, 0xcc},	{0xb3, 0x01, 0x41, 0xcc},
+	{}
+};
+static __u8 po3130_rundata[][4] = {
+	{0x00, 0x47, 0x45, 0xaa},	{0x00, 0x48, 0x9b, 0xaa},
+	{0x00, 0x49, 0x3a, 0xaa},	{0x00, 0x4a, 0x01, 0xaa},
+	{0x00, 0x44, 0x40, 0xaa},
+/*	{0x00, 0xd5, 0x7c, 0xaa}, */
+	{0x00, 0xad, 0x04, 0xaa},	{0x00, 0xae, 0x00, 0xaa},
+	{0x00, 0xb0, 0x78, 0xaa},	{0x00, 0x98, 0x02, 0xaa},
+	{0x00, 0x94, 0x25, 0xaa},	{0x00, 0x95, 0x25, 0xaa},
+	{0x00, 0x59, 0x68, 0xaa},	{0x00, 0x44, 0x20, 0xaa},
+	{0x00, 0x17, 0x50, 0xaa},	{0x00, 0x19, 0x50, 0xaa},
+	{0x00, 0xd1, 0x3c, 0xaa},	{0x00, 0xd1, 0x3c, 0xaa},
+	{0x00, 0x1e, 0x06, 0xaa},	{0x00, 0x1e, 0x06, 0xaa},
+	{}
+};
+
+static __u8 po3130_initQVGA_data[][4] = {
+	{0xb0, 0x4d, 0x00, 0xcc},	{0xb3, 0x01, 0x01, 0xcc},
+	{0x00, 0x00, 0x50, 0xdd},	{0xb0, 0x03, 0x09, 0xcc},
+	{0xb3, 0x00, 0x04, 0xcc},	{0xb3, 0x00, 0x24, 0xcc},
+	{0xb3, 0x00, 0x25, 0xcc},	{0xb3, 0x08, 0x01, 0xcc},
+	{0xb3, 0x09, 0x0c, 0xcc},	{0xb3, 0x05, 0x00, 0xcc},
+	{0xb3, 0x06, 0x01, 0xcc},	{0xb3, 0x03, 0x1a, 0xcc},
+	{0xb3, 0x04, 0x15, 0xcc},	{0xb3, 0x20, 0x00, 0xcc},
+	{0xb3, 0x21, 0x00, 0xcc},	{0xb3, 0x22, 0x01, 0xcc},
+	{0xb3, 0x23, 0xe0, 0xcc},	{0xb8, 0x08, 0xe0, 0xcc},
+	{0xb3, 0x14, 0x00, 0xcc},	{0xb3, 0x15, 0x00, 0xcc},
+	{0xb3, 0x16, 0x02, 0xcc},	{0xb3, 0x17, 0x7f, 0xcc},
+	{0xb3, 0x34, 0x01, 0xcc},	{0xb3, 0x35, 0xf6, 0xcc},
+	{0xb3, 0x00, 0x27, 0xcc},	{0xbc, 0x00, 0xd1, 0xcc},
+	{0xb8, 0x00, 0x21, 0xcc},	{0xb8, 0x27, 0x20, 0xcc},
+	{0xb8, 0x01, 0x79, 0xcc},	{0xb8, 0x81, 0x09, 0xcc},
+	{0xb8, 0x2c, 0x50, 0xcc},	{0xb8, 0x2d, 0xf8, 0xcc},
+	{0xb8, 0x2e, 0xf8, 0xcc},	{0xb8, 0x2f, 0xf8, 0xcc},
+	{0xb8, 0x30, 0x50, 0xcc},	{0xb8, 0x31, 0xf8, 0xcc},
+	{0xb8, 0x32, 0xf8, 0xcc},	{0xb8, 0x33, 0xf8, 0xcc},
+	{0xb8, 0x34, 0x50, 0xcc},	{0xb8, 0x35, 0x00, 0xcc},
+	{0xb8, 0x36, 0x00, 0xcc},	{0xb8, 0x37, 0x00, 0xcc},
+	{0x00, 0x1e, 0xc6, 0xaa},	{0x00, 0x20, 0x44, 0xaa},
+	{0x00, 0xad, 0x02, 0xaa},	{0x00, 0xae, 0x2c, 0xaa},
+	{0x00, 0x12, 0x08, 0xaa},	{0x00, 0x17, 0x41, 0xaa},
+	{0x00, 0x19, 0x41, 0xaa},	{0x00, 0x1e, 0x06, 0xaa},
+	{0x00, 0x21, 0x00, 0xaa},	{0x00, 0x36, 0xc0, 0xaa},
+	{0x00, 0x37, 0xc8, 0xaa},	{0x00, 0x3b, 0x36, 0xaa},
+	{0x00, 0x4b, 0xfe, 0xaa},	{0x00, 0x51, 0x1c, 0xaa},
+	{0x00, 0x52, 0x01, 0xaa},	{0x00, 0x55, 0x0a, 0xaa},
+	{0x00, 0x59, 0x6f, 0xaa},	{0x00, 0x5a, 0x04, 0xaa},
+	{0x00, 0x5c, 0x10, 0xaa},	{0x00, 0x5d, 0x10, 0xaa},
+	{0x00, 0x5e, 0x10, 0xaa},	{0x00, 0x5f, 0x10, 0xaa},
+	{0x00, 0x61, 0x00, 0xaa},	{0x00, 0x62, 0x18, 0xaa},
+	{0x00, 0x63, 0x30, 0xaa},	{0x00, 0x70, 0x68, 0xaa},
+	{0x00, 0x80, 0x71, 0xaa},	{0x00, 0x81, 0x08, 0xaa},
+	{0x00, 0x82, 0x00, 0xaa},	{0x00, 0x83, 0x55, 0xaa},
+	{0x00, 0x84, 0x06, 0xaa},	{0x00, 0x85, 0x06, 0xaa},
+	{0x00, 0x86, 0x13, 0xaa},	{0x00, 0x87, 0x18, 0xaa},
+	{0x00, 0xaa, 0x3f, 0xaa},	{0x00, 0xab, 0x44, 0xaa},
+	{0x00, 0xb0, 0x68, 0xaa},	{0x00, 0xb5, 0x10, 0xaa},
+	{0x00, 0xb8, 0x20, 0xaa},	{0x00, 0xb9, 0xa0, 0xaa},
+	{0x00, 0xbc, 0x04, 0xaa},	{0x00, 0x8b, 0x40, 0xaa},
+	{0x00, 0x8c, 0x91, 0xaa},	{0x00, 0x8d, 0x8f, 0xaa},
+	{0x00, 0x8e, 0x91, 0xaa},	{0x00, 0x8f, 0x43, 0xaa},
+	{0x00, 0x90, 0x92, 0xaa},	{0x00, 0x91, 0x89, 0xaa},
+	{0x00, 0x92, 0x9d, 0xaa},	{0x00, 0x93, 0x46, 0xaa},
+	{0x00, 0xd6, 0x22, 0xaa},	{0x00, 0x73, 0x00, 0xaa},
+	{0x00, 0x74, 0x10, 0xaa},	{0x00, 0x75, 0x20, 0xaa},
+	{0x00, 0x76, 0x2b, 0xaa},	{0x00, 0x77, 0x36, 0xaa},
+	{0x00, 0x78, 0x49, 0xaa},	{0x00, 0x79, 0x5a, 0xaa},
+	{0x00, 0x7a, 0x7f, 0xaa},	{0x00, 0x7b, 0x9b, 0xaa},
+	{0x00, 0x7c, 0xba, 0xaa},	{0x00, 0x7d, 0xd4, 0xaa},
+	{0x00, 0x7e, 0xea, 0xaa},	{0x00, 0xd6, 0x62, 0xaa},
+	{0x00, 0x73, 0x00, 0xaa},	{0x00, 0x74, 0x10, 0xaa},
+	{0x00, 0x75, 0x20, 0xaa},	{0x00, 0x76, 0x2b, 0xaa},
+	{0x00, 0x77, 0x36, 0xaa},	{0x00, 0x78, 0x49, 0xaa},
+	{0x00, 0x79, 0x5a, 0xaa},	{0x00, 0x7a, 0x7f, 0xaa},
+	{0x00, 0x7b, 0x9b, 0xaa},	{0x00, 0x7c, 0xba, 0xaa},
+	{0x00, 0x7d, 0xd4, 0xaa},	{0x00, 0x7e, 0xea, 0xaa},
+	{0x00, 0xd6, 0xa2, 0xaa},	{0x00, 0x73, 0x00, 0xaa},
+	{0x00, 0x74, 0x10, 0xaa},	{0x00, 0x75, 0x20, 0xaa},
+	{0x00, 0x76, 0x2b, 0xaa},	{0x00, 0x77, 0x36, 0xaa},
+	{0x00, 0x78, 0x49, 0xaa},	{0x00, 0x79, 0x5a, 0xaa},
+	{0x00, 0x7a, 0x7f, 0xaa},	{0x00, 0x7b, 0x9b, 0xaa},
+	{0x00, 0x7c, 0xba, 0xaa},	{0x00, 0x7d, 0xd4, 0xaa},
+	{0x00, 0x7e, 0xea, 0xaa},	{0x00, 0x4c, 0x07, 0xaa},
+	{0x00, 0x4b, 0xe0, 0xaa},	{0x00, 0x4e, 0x77, 0xaa},
+	{0x00, 0x59, 0x66, 0xaa},	{0x00, 0x4d, 0x0a, 0xaa},
+	{0x00, 0xd1, 0x00, 0xaa},	{0x00, 0x20, 0xc4, 0xaa},
+	{0xb8, 0x8e, 0x00, 0xcc},	{0xb8, 0x8f, 0xff, 0xcc},
+	{0xb8, 0xfe, 0x00, 0xcc},	{0xb8, 0xff, 0x28, 0xcc},
+	{0xb9, 0x00, 0x28, 0xcc},	{0xb9, 0x01, 0x28, 0xcc},
+	{0xb9, 0x02, 0x28, 0xcc},	{0xb9, 0x03, 0x00, 0xcc},
+	{0xb9, 0x04, 0x00, 0xcc},	{0xb9, 0x05, 0x3c, 0xcc},
+	{0xb9, 0x06, 0x3c, 0xcc},	{0xb9, 0x07, 0x3c, 0xcc},
+	{0xb9, 0x08, 0x3c, 0xcc},	{0xbc, 0x02, 0x18, 0xcc},
+	{0xbc, 0x03, 0x50, 0xcc},	{0xbc, 0x04, 0x18, 0xcc},
+	{0xbc, 0x05, 0x00, 0xcc},	{0xbc, 0x06, 0x00, 0xcc},
+	{0xbc, 0x08, 0x30, 0xcc},	{0xbc, 0x09, 0x40, 0xcc},
+	{0xbc, 0x0a, 0x10, 0xcc},	{0xbc, 0x0b, 0x00, 0xcc},
+	{0xbc, 0x0c, 0x00, 0xcc},	{0x00, 0x05, 0x00, 0xaa},
+	{0xb3, 0x5c, 0x00, 0xcc},	{0xb3, 0x01, 0x41, 0xcc},
+	{}
+};
+
+static __u8 hv7131r_gamma[17] = {
+/*	0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
+ *	0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff */
+	0x04, 0x1a, 0x36, 0x55, 0x6f, 0x87, 0x9d, 0xb0, 0xc1,
+	0xcf, 0xda, 0xe4, 0xec, 0xf3, 0xf8, 0xfd, 0xff
+};
+static __u8 hv7131r_matrix[9] = {
+	0x5f, 0xec, 0xf5, 0xf1, 0x5a, 0xf5, 0xf1, 0xec, 0x63
+};
+static __u8 hv7131r_initVGA_data[][4] = {
+	{0xb0, 0x4d, 0x00, 0xcc},	{0xb3, 0x01, 0x01, 0xcc},
+	{0x00, 0x00, 0x50, 0xdd},	{0xb0, 0x03, 0x01, 0xcc},
+	{0xb3, 0x00, 0x24, 0xcc},
+	{0xb3, 0x00, 0x25, 0xcc},	{0xb3, 0x08, 0x01, 0xcc},
+	{0xb3, 0x09, 0x0c, 0xcc},	{0xb3, 0x05, 0x00, 0xcc},
+	{0xb3, 0x06, 0x01, 0xcc},
+	{0xb3, 0x01, 0x45, 0xcc},	{0xb3, 0x03, 0x0b, 0xcc},
+	{0xb3, 0x04, 0x05, 0xcc},	{0xb3, 0x20, 0x00, 0xcc},
+	{0xb3, 0x21, 0x00, 0xcc},
+	{0xb3, 0x22, 0x01, 0xcc},	{0xb3, 0x23, 0xe0, 0xcc},
+	{0xb3, 0x14, 0x00, 0xcc},	{0xb3, 0x15, 0x00, 0xcc},
+	{0xb3, 0x16, 0x02, 0xcc},
+	{0xb3, 0x17, 0x7f, 0xcc},	{0xb3, 0x34, 0x01, 0xcc},
+	{0xb3, 0x35, 0x91, 0xcc},	{0xb3, 0x00, 0x27, 0xcc},
+	{0xbc, 0x00, 0x73, 0xcc},
+	{0xb8, 0x00, 0x23, 0xcc},	{0x00, 0x01, 0x0c, 0xaa},
+	{0x00, 0x14, 0x01, 0xaa},	{0x00, 0x15, 0xe6, 0xaa},
+	{0x00, 0x16, 0x02, 0xaa},
+	{0x00, 0x17, 0x86, 0xaa},	{0x00, 0x23, 0x00, 0xaa},
+	{0x00, 0x25, 0x09, 0xaa},	{0x00, 0x26, 0x27, 0xaa},
+	{0x00, 0x27, 0xc0, 0xaa},
+	{0xb8, 0x2c, 0x60, 0xcc},	{0xb8, 0x2d, 0xf8, 0xcc},
+	{0xb8, 0x2e, 0xf8, 0xcc},	{0xb8, 0x2f, 0xf8, 0xcc},
+	{0xb8, 0x30, 0x50, 0xcc},
+	{0xb8, 0x31, 0xf8, 0xcc},	{0xb8, 0x32, 0xf8, 0xcc},
+	{0xb8, 0x33, 0xf8, 0xcc},	{0xb8, 0x34, 0x65, 0xcc},
+	{0xb8, 0x35, 0x00, 0xcc},
+	{0xb8, 0x36, 0x00, 0xcc},	{0xb8, 0x37, 0x00, 0xcc},
+	{0xb8, 0x27, 0x20, 0xcc},	{0xb8, 0x01, 0x7d, 0xcc},
+	{0xb8, 0x81, 0x09, 0xcc},
+	{0xb3, 0x01, 0x41, 0xcc},	{0xb8, 0xfe, 0x00, 0xcc},
+	{0xb8, 0xff, 0x28, 0xcc},	{0xb9, 0x00, 0x28, 0xcc},
+	{0xb9, 0x01, 0x28, 0xcc},
+	{0xb9, 0x02, 0x28, 0xcc},	{0xb9, 0x03, 0x00, 0xcc},
+	{0xb9, 0x04, 0x00, 0xcc},	{0xb9, 0x05, 0x3c, 0xcc},
+	{0xb9, 0x06, 0x3c, 0xcc},
+	{0xb9, 0x07, 0x3c, 0xcc},	{0xb9, 0x08, 0x3c, 0xcc},
+	{0xb8, 0x8e, 0x00, 0xcc},	{0xb8, 0x8f, 0xff, 0xcc},
+	{0x00, 0x30, 0x18, 0xaa},
+	{}
+};
+
+static __u8 hv7131r_initQVGA_data[][4] = {
+	{0xb0, 0x4d, 0x00, 0xcc},	{0xb3, 0x01, 0x01, 0xcc},
+	{0x00, 0x00, 0x50, 0xdd},	{0xb0, 0x03, 0x01, 0xcc},
+	{0xb3, 0x00, 0x24, 0xcc},
+	{0xb3, 0x00, 0x25, 0xcc},	{0xb3, 0x08, 0x01, 0xcc},
+	{0xb3, 0x09, 0x0c, 0xcc},	{0xb3, 0x05, 0x00, 0xcc},
+	{0xb3, 0x06, 0x01, 0xcc},
+	{0xb3, 0x03, 0x0b, 0xcc},	{0xb3, 0x04, 0x05, 0xcc},
+	{0xb3, 0x20, 0x00, 0xcc},	{0xb3, 0x21, 0x00, 0xcc},
+	{0xb3, 0x22, 0x01, 0xcc},
+	{0xb3, 0x23, 0xe0, 0xcc},	{0xb3, 0x14, 0x00, 0xcc},
+	{0xb3, 0x15, 0x00, 0xcc},	{0xb3, 0x16, 0x02, 0xcc},
+	{0xb3, 0x17, 0x7f, 0xcc},
+	{0xb3, 0x34, 0x01, 0xcc},	{0xb3, 0x35, 0x91, 0xcc},
+	{0xb3, 0x00, 0x27, 0xcc},	{0xbc, 0x00, 0xd1, 0xcc},
+	{0xb8, 0x00, 0x21, 0xcc},
+	{0x00, 0x01, 0x0c, 0xaa},	{0x00, 0x14, 0x01, 0xaa},
+	{0x00, 0x15, 0xe6, 0xaa},	{0x00, 0x16, 0x02, 0xaa},
+	{0x00, 0x17, 0x86, 0xaa},
+	{0x00, 0x23, 0x00, 0xaa},	{0x00, 0x25, 0x01, 0xaa},
+	{0x00, 0x26, 0xd4, 0xaa},	{0x00, 0x27, 0xc0, 0xaa},
+	{0xbc, 0x02, 0x08, 0xcc},
+	{0xbc, 0x03, 0x70, 0xcc},	{0xbc, 0x04, 0x08, 0xcc},
+	{0xbc, 0x05, 0x00, 0xcc},	{0xbc, 0x06, 0x00, 0xcc},
+	{0xbc, 0x08, 0x3c, 0xcc},
+	{0xbc, 0x09, 0x40, 0xcc},	{0xbc, 0x0a, 0x04, 0xcc},
+	{0xbc, 0x0b, 0x00, 0xcc},	{0xbc, 0x0c, 0x00, 0xcc},
+	{0xb8, 0xfe, 0x02, 0xcc},
+	{0xb8, 0xff, 0x07, 0xcc},	{0xb9, 0x00, 0x14, 0xcc},
+	{0xb9, 0x01, 0x14, 0xcc},	{0xb9, 0x02, 0x14, 0xcc},
+	{0xb9, 0x03, 0x00, 0xcc},
+	{0xb9, 0x04, 0x02, 0xcc},	{0xb9, 0x05, 0x05, 0xcc},
+	{0xb9, 0x06, 0x0f, 0xcc},	{0xb9, 0x07, 0x0f, 0xcc},
+	{0xb9, 0x08, 0x0f, 0xcc},
+	{0xb8, 0x2c, 0x60, 0xcc},	{0xb8, 0x2d, 0xf8, 0xcc},
+	{0xb8, 0x2e, 0xf8, 0xcc},	{0xb8, 0x2f, 0xf8, 0xcc},
+	{0xb8, 0x30, 0x50, 0xcc},
+	{0xb8, 0x31, 0xf8, 0xcc},	{0xb8, 0x32, 0xf8, 0xcc},
+	{0xb8, 0x33, 0xf8, 0xcc},
+	{0xb8, 0x34, 0x65, 0xcc},	{0xb8, 0x35, 0x00, 0xcc},
+	{0xb8, 0x36, 0x00, 0xcc},	{0xb8, 0x37, 0x00, 0xcc},
+	{0xb8, 0x27, 0x20, 0xcc},
+	{0xb8, 0x01, 0x7d, 0xcc},	{0xb8, 0x81, 0x09, 0xcc},
+	{0xb3, 0x01, 0x41, 0xcc},	{0xb8, 0xfe, 0x00, 0xcc},
+	{0xb8, 0xff, 0x28, 0xcc},
+	{0xb9, 0x00, 0x28, 0xcc},	{0xb9, 0x01, 0x28, 0xcc},
+	{0xb9, 0x02, 0x28, 0xcc},	{0xb9, 0x03, 0x00, 0xcc},
+	{0xb9, 0x04, 0x00, 0xcc},
+	{0xb9, 0x05, 0x3c, 0xcc},	{0xb9, 0x06, 0x3c, 0xcc},
+	{0xb9, 0x07, 0x3c, 0xcc},	{0xb9, 0x08, 0x3c, 0xcc},
+	{0xb8, 0x8e, 0x00, 0xcc},
+	{0xb8, 0x8f, 0xff, 0xcc},	{0x00, 0x30, 0x18, 0xaa},
+	{}
+};
+
+static __u8 ov7660_gamma[17] = {
+	0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
+	0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff
+};
+static __u8 ov7660_matrix[9] = {
+	0x5a, 0xf0, 0xf6, 0xf3, 0x57, 0xf6, 0xf3, 0xef, 0x62
+};
+static __u8 ov7660_initVGA_data[][4] = {
+	{0xb0, 0x4d, 0x00, 0xcc},	{0xb3, 0x01, 0x01, 0xcc},
+	{0x00, 0x00, 0x50, 0xdd},
+	{0xb0, 0x03, 0x01, 0xcc},
+	{0xb3, 0x00, 0x21, 0xcc},	{0xb3, 0x00, 0x26, 0xcc},
+	{0xb3, 0x05, 0x01, 0xcc},
+	{0xb3, 0x06, 0x03, 0xcc},
+	{0xb3, 0x03, 0x1f, 0xcc},	{0xb3, 0x04, 0x05, 0xcc},
+	{0xb3, 0x05, 0x00, 0xcc},
+	{0xb3, 0x06, 0x01, 0xcc},
+	{0xb3, 0x15, 0x00, 0xcc},/* 0xb315  <-0 href startl */
+	{0xb3, 0x16, 0x02, 0xcc},	{0xb3, 0x17, 0x7f, 0xcc},
+	{0xb3, 0x21, 0x00, 0xcc},
+	{0xb3, 0x23, 0xe0, 0xcc},	{0xb3, 0x1d, 0x01, 0xcc},
+	{0xb3, 0x1f, 0x02, 0xcc},
+	{0xb3, 0x34, 0x01, 0xcc},
+	{0xb3, 0x35, 0xa1, 0xcc},	{0xb3, 0x00, 0x26, 0xcc},
+	{0xb8, 0x00, 0x33, 0xcc}, /* 13 */
+	{0xb8, 0x01, 0x7d, 0xcc},
+	{0xbc, 0x00, 0x73, 0xcc},	{0xb8, 0x81, 0x09, 0xcc},
+	{0xb8, 0x27, 0x20, 0xcc},
+	{0xb8, 0x8f, 0x50, 0xcc},
+	{0x00, 0x01, 0x80, 0xaa},	{0x00, 0x02, 0x80, 0xaa},
+	{0x00, 0x12, 0x80, 0xaa},
+	{0x00, 0x12, 0x05, 0xaa},
+	{0x00, 0x1e, 0x01, 0xaa},
+	{0x00, 0x3d, 0x40, 0xaa}, /* 0x3d <-40 gamma 01 */
+	{0x00, 0x41, 0x00, 0xaa}, /* edge 00 */
+	{0x00, 0x0d, 0x48, 0xaa},	{0x00, 0x0e, 0x04, 0xaa},
+	{0x00, 0x13, 0xa7, 0xaa},
+	{0x00, 0x40, 0xc1, 0xaa},	{0x00, 0x35, 0x00, 0xaa},
+	{0x00, 0x36, 0x00, 0xaa},
+	{0x00, 0x3c, 0x68, 0xaa},	{0x00, 0x1b, 0x05, 0xaa},
+	{0x00, 0x39, 0x43, 0xaa},
+	{0x00, 0x8d, 0xcf, 0xaa},
+	{0x00, 0x8b, 0xcc, 0xaa},	{0x00, 0x8c, 0xcc, 0xaa},
+	{0x00, 0x0f, 0x62, 0xaa},
+	{0x00, 0x35, 0x84, 0xaa},
+	{0x00, 0x3b, 0x08, 0xaa}, /* 0 * Nightframe 1/4 + 50Hz -> 0xC8 */
+	{0x00, 0x3a, 0x00, 0xaa}, /* mx change yuyv format 00, 04, 01; 08, 0c*/
+	{0x00, 0x14, 0x2a, 0xaa}, /* agc ampli */
+	{0x00, 0x9e, 0x40, 0xaa},	{0xb8, 0x8f, 0x50, 0xcc},
+	{0x00, 0x01, 0x80, 0xaa},
+	{0x00, 0x02, 0x80, 0xaa},
+	{0xb8, 0xfe, 0x00, 0xcc},	{0xb8, 0xff, 0x28, 0xcc},
+	{0xb9, 0x00, 0x28, 0xcc},
+	{0xb9, 0x01, 0x28, 0xcc},	{0xb9, 0x02, 0x28, 0xcc},
+	{0xb9, 0x03, 0x00, 0xcc},
+	{0xb9, 0x04, 0x00, 0xcc},
+	{0xb9, 0x05, 0x3c, 0xcc},	{0xb9, 0x06, 0x3c, 0xcc},
+	{0xb9, 0x07, 0x3c, 0xcc},
+	{0xb9, 0x08, 0x3c, 0xcc},
+
+	{0xb8, 0x8e, 0x00, 0xcc},	{0xb8, 0x8f, 0xff, 0xcc},
+
+	{0x00, 0x29, 0x3c, 0xaa},	{0xb3, 0x01, 0x45, 0xcc},
+	{}
+};
+static __u8 ov7660_initQVGA_data[][4] = {
+	{0xb0, 0x4d, 0x00, 0xcc},	{0xb3, 0x01, 0x01, 0xcc},
+	{0x00, 0x00, 0x50, 0xdd},	{0xb0, 0x03, 0x01, 0xcc},
+	{0xb3, 0x00, 0x21, 0xcc},	{0xb3, 0x00, 0x26, 0xcc},
+	{0xb3, 0x05, 0x01, 0xcc},	{0xb3, 0x06, 0x03, 0xcc},
+	{0xb3, 0x03, 0x1f, 0xcc},	{0xb3, 0x04, 0x05, 0xcc},
+	{0xb3, 0x05, 0x00, 0xcc},	{0xb3, 0x06, 0x01, 0xcc},
+	{0xb3, 0x15, 0x00, 0xcc},/* 0xb315  <-0 href startl */
+	{0xb3, 0x16, 0x02, 0xcc},	{0xb3, 0x17, 0x7f, 0xcc},
+	{0xb3, 0x21, 0x00, 0xcc},
+	{0xb3, 0x23, 0xe0, 0xcc},	{0xb3, 0x1d, 0x01, 0xcc},
+	{0xb3, 0x1f, 0x02, 0xcc},	{0xb3, 0x34, 0x01, 0xcc},
+	{0xb3, 0x35, 0xa1, 0xcc},	{0xb3, 0x00, 0x26, 0xcc},
+	{0xb8, 0x00, 0x33, 0xcc}, /* 13 */
+	{0xb8, 0x01, 0x7d, 0xcc},
+/* sizer */
+	{0xbc, 0x00, 0xd3, 0xcc},
+	{0xb8, 0x81, 0x09, 0xcc},	{0xb8, 0x81, 0x09, 0xcc},
+	{0xb8, 0x27, 0x20, 0xcc},	{0xb8, 0x8f, 0x50, 0xcc},
+	{0x00, 0x01, 0x80, 0xaa},	{0x00, 0x02, 0x80, 0xaa},
+	{0x00, 0x12, 0x80, 0xaa},	{0x00, 0x12, 0x05, 0xaa},
+	{0x00, 0x1e, 0x01, 0xaa},
+	{0x00, 0x3d, 0x40, 0xaa}, /* 0x3d <-40 gamma 01 */
+	{0x00, 0x41, 0x00, 0xaa}, /* edge 00 */
+	{0x00, 0x0d, 0x48, 0xaa},	{0x00, 0x0e, 0x04, 0xaa},
+	{0x00, 0x13, 0xa7, 0xaa},
+	{0x00, 0x40, 0xc1, 0xaa},	{0x00, 0x35, 0x00, 0xaa},
+	{0x00, 0x36, 0x00, 0xaa},
+	{0x00, 0x3c, 0x68, 0xaa},	{0x00, 0x1b, 0x05, 0xaa},
+	{0x00, 0x39, 0x43, 0xaa},	{0x00, 0x8d, 0xcf, 0xaa},
+	{0x00, 0x8b, 0xcc, 0xaa},	{0x00, 0x8c, 0xcc, 0xaa},
+	{0x00, 0x0f, 0x62, 0xaa},	{0x00, 0x35, 0x84, 0xaa},
+	{0x00, 0x3b, 0x08, 0xaa}, /* 0  * Nightframe 1/4 + 50Hz -> 0xC8 */
+	{0x00, 0x3a, 0x00, 0xaa}, /* mx change yuyv format 00, 04, 01; 08, 0c*/
+	{0x00, 0x14, 0x2a, 0xaa}, /* agc ampli */
+	{0x00, 0x9e, 0x40, 0xaa},	{0xb8, 0x8f, 0x50, 0xcc},
+	{0x00, 0x01, 0x80, 0xaa},
+	{0x00, 0x02, 0x80, 0xaa},
+/* sizer filters */
+	{0xbc, 0x02, 0x08, 0xcc},
+	{0xbc, 0x03, 0x70, 0xcc},
+	{0xb8, 0x35, 0x00, 0xcc},
+	{0xb8, 0x36, 0x00, 0xcc},
+	{0xb8, 0x37, 0x00, 0xcc},
+	{0xbc, 0x04, 0x08, 0xcc},
+	{0xbc, 0x05, 0x00, 0xcc},
+	{0xbc, 0x06, 0x00, 0xcc},
+	{0xbc, 0x08, 0x3c, 0xcc},
+	{0xbc, 0x09, 0x40, 0xcc},
+	{0xbc, 0x0a, 0x04, 0xcc},
+	{0xbc, 0x0b, 0x00, 0xcc},
+	{0xbc, 0x0c, 0x00, 0xcc},
+/* */
+	{0xb8, 0xfe, 0x00, 0xcc},
+	{0xb8, 0xff, 0x28, 0xcc},
+/* */
+	{0xb9, 0x00, 0x28, 0xcc},	{0xb9, 0x01, 0x28, 0xcc},
+	{0xb9, 0x02, 0x28, 0xcc},	{0xb9, 0x03, 0x00, 0xcc},
+	{0xb9, 0x04, 0x00, 0xcc},	{0xb9, 0x05, 0x3c, 0xcc},
+	{0xb9, 0x06, 0x3c, 0xcc},	{0xb9, 0x07, 0x3c, 0xcc},
+	{0xb9, 0x08, 0x3c, 0xcc},
+/* */
+	{0xb8, 0x8e, 0x00, 0xcc},
+	{0xb8, 0x8f, 0xff, 0xcc}, /* ff */
+	{0x00, 0x29, 0x3c, 0xaa},
+	{0xb3, 0x01, 0x45, 0xcc}, /* 45 */
+	{0x00, 0x00, 0x00, 0x00}
+};
+
+static __u8 ov7660_50HZ[][4] = {
+	{0x00, 0x3b, 0x08, 0xaa},
+	{0x00, 0x9d, 0x40, 0xaa},
+	{0x00, 0x13, 0xa7, 0xaa},
+	{0x00, 0x00, 0x00, 0x00}
+};
+
+static __u8 ov7660_60HZ[][4] = {
+	{0x00, 0x3b, 0x00, 0xaa},
+	{0x00, 0x9e, 0x40, 0xaa},
+	{0x00, 0x13, 0xa7, 0xaa},
+	{}
+};
+
+static __u8 ov7660_NoFliker[][4] = {
+	{0x00, 0x13, 0x87, 0xaa},
+	{}
+};
+
+static __u8 ov7670_initVGA_JPG[][4] = {
+	{0xb3, 0x01, 0x05, 0xcc},
+	{0x00, 0x00, 0x30, 0xdd},	{0xb0, 0x03, 0x19, 0xcc},
+	{0x00, 0x00, 0x10, 0xdd},
+	{0xb0, 0x04, 0x02, 0xcc},	{0x00, 0x00, 0x10, 0xdd},
+	{0xb3, 0x00, 0x66, 0xcc},	{0xb3, 0x00, 0x67, 0xcc},
+	{0xb3, 0x35, 0xa1, 0xcc},	{0xb3, 0x34, 0x01, 0xcc},
+	{0xb3, 0x05, 0x01, 0xcc},	{0xb3, 0x06, 0x01, 0xcc},
+	{0xb3, 0x08, 0x01, 0xcc},	{0xb3, 0x09, 0x0c, 0xcc},
+	{0xb3, 0x02, 0x02, 0xcc},	{0xb3, 0x03, 0x1f, 0xcc},
+	{0xb3, 0x14, 0x00, 0xcc},	{0xb3, 0x15, 0x00, 0xcc},
+	{0xb3, 0x16, 0x02, 0xcc},	{0xb3, 0x17, 0x7f, 0xcc},
+	{0xb3, 0x04, 0x05, 0xcc},	{0xb3, 0x20, 0x00, 0xcc},
+	{0xb3, 0x21, 0x00, 0xcc},	{0xb3, 0x22, 0x01, 0xcc},
+	{0xb3, 0x23, 0xe0, 0xcc},	{0xbc, 0x00, 0x41, 0xcc},
+	{0xbc, 0x01, 0x01, 0xcc},	{0x00, 0x12, 0x80, 0xaa},
+	{0x00, 0x00, 0x20, 0xdd},	{0x00, 0x12, 0x00, 0xaa},
+	{0x00, 0x11, 0x40, 0xaa},	{0x00, 0x6b, 0x0a, 0xaa},
+	{0x00, 0x3a, 0x04, 0xaa},	{0x00, 0x40, 0xc0, 0xaa},
+	{0x00, 0x8c, 0x00, 0xaa},	{0x00, 0x7a, 0x29, 0xaa},
+	{0x00, 0x7b, 0x0e, 0xaa},	{0x00, 0x7c, 0x1a, 0xaa},
+	{0x00, 0x7d, 0x31, 0xaa},	{0x00, 0x7e, 0x53, 0xaa},
+	{0x00, 0x7f, 0x60, 0xaa},	{0x00, 0x80, 0x6b, 0xaa},
+	{0x00, 0x81, 0x73, 0xaa},	{0x00, 0x82, 0x7b, 0xaa},
+	{0x00, 0x83, 0x82, 0xaa},	{0x00, 0x84, 0x89, 0xaa},
+	{0x00, 0x85, 0x96, 0xaa},	{0x00, 0x86, 0xa1, 0xaa},
+	{0x00, 0x87, 0xb7, 0xaa},	{0x00, 0x88, 0xcc, 0xaa},
+	{0x00, 0x89, 0xe1, 0xaa},	{0x00, 0x13, 0xe0, 0xaa},
+	{0x00, 0x00, 0x00, 0xaa},	{0x00, 0x10, 0x00, 0xaa},
+	{0x00, 0x0d, 0x40, 0xaa},	{0x00, 0x14, 0x28, 0xaa},
+	{0x00, 0xa5, 0x05, 0xaa},	{0x00, 0xab, 0x07, 0xaa},
+	{0x00, 0x24, 0x95, 0xaa},	{0x00, 0x25, 0x33, 0xaa},
+	{0x00, 0x26, 0xe3, 0xaa},	{0x00, 0x9f, 0x88, 0xaa},
+	{0x00, 0xa0, 0x78, 0xaa},	{0x00, 0x55, 0x90, 0xaa},
+	{0x00, 0xa1, 0x03, 0xaa},	{0x00, 0xa6, 0xe0, 0xaa},
+	{0x00, 0xa7, 0xd8, 0xaa},	{0x00, 0xa8, 0xf0, 0xaa},
+	{0x00, 0xa9, 0x90, 0xaa},	{0x00, 0xaa, 0x14, 0xaa},
+	{0x00, 0x13, 0xe5, 0xaa},	{0x00, 0x0e, 0x61, 0xaa},
+	{0x00, 0x0f, 0x4b, 0xaa},	{0x00, 0x16, 0x02, 0xaa},
+	{0x00, 0x1e, 0x07, 0xaa},	{0x00, 0x21, 0x02, 0xaa},
+	{0x00, 0x22, 0x91, 0xaa},	{0x00, 0x29, 0x07, 0xaa},
+	{0x00, 0x33, 0x0b, 0xaa},	{0x00, 0x35, 0x0b, 0xaa},
+	{0x00, 0x37, 0x1d, 0xaa},	{0x00, 0x38, 0x71, 0xaa},
+	{0x00, 0x39, 0x2a, 0xaa},	{0x00, 0x3c, 0x78, 0xaa},
+	{0x00, 0x4d, 0x40, 0xaa},	{0x00, 0x4e, 0x20, 0xaa},
+	{0x00, 0x74, 0x19, 0xaa},	{0x00, 0x8d, 0x4f, 0xaa},
+	{0x00, 0x8e, 0x00, 0xaa},	{0x00, 0x8f, 0x00, 0xaa},
+	{0x00, 0x90, 0x00, 0xaa},	{0x00, 0x91, 0x00, 0xaa},
+	{0x00, 0x96, 0x00, 0xaa},	{0x00, 0x9a, 0x80, 0xaa},
+	{0x00, 0xb0, 0x84, 0xaa},	{0x00, 0xb1, 0x0c, 0xaa},
+	{0x00, 0xb2, 0x0e, 0xaa},	{0x00, 0xb3, 0x82, 0xaa},
+	{0x00, 0xb8, 0x0a, 0xaa},	{0x00, 0x43, 0x14, 0xaa},
+	{0x00, 0x44, 0xf0, 0xaa},	{0x00, 0x45, 0x45, 0xaa},
+	{0x00, 0x46, 0x63, 0xaa},	{0x00, 0x47, 0x2d, 0xaa},
+	{0x00, 0x48, 0x46, 0xaa},	{0x00, 0x59, 0x88, 0xaa},
+	{0x00, 0x5a, 0xa0, 0xaa},	{0x00, 0x5b, 0xc6, 0xaa},
+	{0x00, 0x5c, 0x7d, 0xaa},	{0x00, 0x5d, 0x5f, 0xaa},
+	{0x00, 0x5e, 0x19, 0xaa},	{0x00, 0x6c, 0x0a, 0xaa},
+	{0x00, 0x6d, 0x55, 0xaa},	{0x00, 0x6e, 0x11, 0xaa},
+	{0x00, 0x6f, 0x9e, 0xaa},	{0x00, 0x69, 0x00, 0xaa},
+	{0x00, 0x6a, 0x40, 0xaa},	{0x00, 0x01, 0x40, 0xaa},
+	{0x00, 0x02, 0x40, 0xaa},	{0x00, 0x13, 0xe7, 0xaa},
+	{0x00, 0x5f, 0xf0, 0xaa},	{0x00, 0x60, 0xf0, 0xaa},
+	{0x00, 0x61, 0xf0, 0xaa},	{0x00, 0x27, 0xa0, 0xaa},
+	{0x00, 0x28, 0x80, 0xaa},	{0x00, 0x2c, 0x90, 0xaa},
+	{0x00, 0x4f, 0x66, 0xaa},	{0x00, 0x50, 0x66, 0xaa},
+	{0x00, 0x51, 0x00, 0xaa},	{0x00, 0x52, 0x22, 0xaa},
+	{0x00, 0x53, 0x5e, 0xaa},	{0x00, 0x54, 0x80, 0xaa},
+	{0x00, 0x58, 0x9e, 0xaa},	{0x00, 0x41, 0x08, 0xaa},
+	{0x00, 0x3f, 0x00, 0xaa},	{0x00, 0x75, 0x85, 0xaa},
+	{0x00, 0x76, 0xe1, 0xaa},	{0x00, 0x4c, 0x00, 0xaa},
+	{0x00, 0x77, 0x0a, 0xaa},	{0x00, 0x3d, 0x88, 0xaa},
+	{0x00, 0x4b, 0x09, 0xaa},	{0x00, 0xc9, 0x60, 0xaa},
+	{0x00, 0x41, 0x38, 0xaa},	{0x00, 0x62, 0x30, 0xaa},
+	{0x00, 0x63, 0x30, 0xaa},	{0x00, 0x64, 0x08, 0xaa},
+	{0x00, 0x94, 0x07, 0xaa},	{0x00, 0x95, 0x0b, 0xaa},
+	{0x00, 0x65, 0x00, 0xaa},	{0x00, 0x66, 0x05, 0xaa},
+	{0x00, 0x56, 0x50, 0xaa},	{0x00, 0x34, 0x11, 0xaa},
+	{0x00, 0xa4, 0x88, 0xaa},	{0x00, 0x96, 0x00, 0xaa},
+	{0x00, 0x97, 0x30, 0xaa},	{0x00, 0x98, 0x20, 0xaa},
+	{0x00, 0x99, 0x30, 0xaa},	{0x00, 0x9a, 0x84, 0xaa},
+	{0x00, 0x9b, 0x29, 0xaa},	{0x00, 0x9c, 0x03, 0xaa},
+	{0x00, 0x78, 0x04, 0xaa},	{0x00, 0x79, 0x01, 0xaa},
+	{0x00, 0xc8, 0xf0, 0xaa},	{0x00, 0x79, 0x0f, 0xaa},
+	{0x00, 0xc8, 0x00, 0xaa},	{0x00, 0x79, 0x10, 0xaa},
+	{0x00, 0xc8, 0x7e, 0xaa},	{0x00, 0x79, 0x0a, 0xaa},
+	{0x00, 0xc8, 0x80, 0xaa},	{0x00, 0x79, 0x0b, 0xaa},
+	{0x00, 0xc8, 0x01, 0xaa},	{0x00, 0x79, 0x0c, 0xaa},
+	{0x00, 0xc8, 0x0f, 0xaa},	{0x00, 0x79, 0x0d, 0xaa},
+	{0x00, 0xc8, 0x20, 0xaa},	{0x00, 0x79, 0x09, 0xaa},
+	{0x00, 0xc8, 0x80, 0xaa},	{0x00, 0x79, 0x02, 0xaa},
+	{0x00, 0xc8, 0xc0, 0xaa},	{0x00, 0x79, 0x03, 0xaa},
+	{0x00, 0xc8, 0x40, 0xaa},	{0x00, 0x79, 0x05, 0xaa},
+	{0x00, 0xc8, 0x30, 0xaa},	{0x00, 0x79, 0x26, 0xaa},
+	{0x00, 0x11, 0x40, 0xaa},	{0x00, 0x3a, 0x04, 0xaa},
+	{0x00, 0x12, 0x00, 0xaa},	{0x00, 0x40, 0xc0, 0xaa},
+	{0x00, 0x8c, 0x00, 0xaa},	{0x00, 0x17, 0x14, 0xaa},
+	{0x00, 0x18, 0x02, 0xaa},	{0x00, 0x32, 0x92, 0xaa},
+	{0x00, 0x19, 0x02, 0xaa},	{0x00, 0x1a, 0x7a, 0xaa},
+	{0x00, 0x03, 0x0a, 0xaa},	{0x00, 0x0c, 0x00, 0xaa},
+	{0x00, 0x3e, 0x00, 0xaa},	{0x00, 0x70, 0x3a, 0xaa},
+	{0x00, 0x71, 0x35, 0xaa},	{0x00, 0x72, 0x11, 0xaa},
+	{0x00, 0x73, 0xf0, 0xaa},	{0x00, 0xa2, 0x02, 0xaa},
+	{0x00, 0xb1, 0x00, 0xaa},	{0x00, 0xb1, 0x0c, 0xaa},
+	{0x00, 0x1e, 0x37, 0xaa},	{0x00, 0xaa, 0x14, 0xaa},
+	{0x00, 0x24, 0x80, 0xaa},	{0x00, 0x25, 0x74, 0xaa},
+	{0x00, 0x26, 0xd3, 0xaa},	{0x00, 0x0d, 0x00, 0xaa},
+	{0x00, 0x14, 0x18, 0xaa},	{0x00, 0x9d, 0x99, 0xaa},
+	{0x00, 0x9e, 0x7f, 0xaa},	{0x00, 0x64, 0x08, 0xaa},
+	{0x00, 0x94, 0x07, 0xaa},	{0x00, 0x95, 0x06, 0xaa},
+	{0x00, 0x66, 0x05, 0xaa},	{0x00, 0x41, 0x08, 0xaa},
+	{0x00, 0x3f, 0x00, 0xaa},	{0x00, 0x75, 0x07, 0xaa},
+	{0x00, 0x76, 0xe1, 0xaa},	{0x00, 0x4c, 0x00, 0xaa},
+	{0x00, 0x77, 0x00, 0xaa},	{0x00, 0x3d, 0xc2, 0xaa},
+	{0x00, 0x4b, 0x09, 0xaa},	{0x00, 0xc9, 0x60, 0xaa},
+	{0x00, 0x41, 0x38, 0xaa},	{0xb6, 0x00, 0x00, 0xcc},
+	{0xb6, 0x03, 0x02, 0xcc},	{0xb6, 0x02, 0x80, 0xcc},
+	{0xb6, 0x05, 0x01, 0xcc},	{0xb6, 0x04, 0xe0, 0xcc},
+	{0xb6, 0x12, 0xf8, 0xcc},	{0xb6, 0x13, 0x13, 0xcc},
+	{0xb6, 0x18, 0x02, 0xcc},	{0xb6, 0x17, 0x58, 0xcc},
+	{0xb6, 0x16, 0x00, 0xcc},	{0xb6, 0x22, 0x12, 0xcc},
+	{0xb6, 0x23, 0x0b, 0xcc},	{0xbf, 0xc0, 0x39, 0xcc},
+	{0xbf, 0xc1, 0x04, 0xcc},	{0xbf, 0xcc, 0x00, 0xcc},
+	{0xb3, 0x5c, 0x01, 0xcc},	{0xb3, 0x01, 0x45, 0xcc},
+	{0x00, 0x77, 0x05, 0xaa},
+	{},
+};
+
+static __u8 ov7670_initQVGA_JPG[][4] = {
+	{0xb3, 0x01, 0x05, 0xcc},	{0x00, 0x00, 0x30, 0xdd},
+	{0xb0, 0x03, 0x19, 0xcc},	{0x00, 0x00, 0x10, 0xdd},
+	{0xb0, 0x04, 0x02, 0xcc},	{0x00, 0x00, 0x10, 0xdd},
+	{0xb3, 0x00, 0x66, 0xcc},	{0xb3, 0x00, 0x67, 0xcc},
+	{0xb3, 0x35, 0xa1, 0xcc},	{0xb3, 0x34, 0x01, 0xcc},
+	{0xb3, 0x05, 0x01, 0xcc},	{0xb3, 0x06, 0x01, 0xcc},
+	{0xb3, 0x08, 0x01, 0xcc},	{0xb3, 0x09, 0x0c, 0xcc},
+	{0xb3, 0x02, 0x02, 0xcc},	{0xb3, 0x03, 0x1f, 0xcc},
+	{0xb3, 0x14, 0x00, 0xcc},	{0xb3, 0x15, 0x00, 0xcc},
+	{0xb3, 0x16, 0x02, 0xcc},	{0xb3, 0x17, 0x7f, 0xcc},
+	{0xb3, 0x04, 0x05, 0xcc},	{0xb3, 0x20, 0x00, 0xcc},
+	{0xb3, 0x21, 0x00, 0xcc},	{0xb3, 0x22, 0x01, 0xcc},
+	{0xb3, 0x23, 0xe0, 0xcc},	{0xbc, 0x00, 0xd1, 0xcc},
+	{0xbc, 0x01, 0x01, 0xcc},	{0x00, 0x12, 0x80, 0xaa},
+	{0x00, 0x00, 0x20, 0xdd},	{0x00, 0x12, 0x00, 0xaa},
+	{0x00, 0x11, 0x40, 0xaa},	{0x00, 0x6b, 0x0a, 0xaa},
+	{0x00, 0x3a, 0x04, 0xaa},	{0x00, 0x40, 0xc0, 0xaa},
+	{0x00, 0x8c, 0x00, 0xaa},	{0x00, 0x7a, 0x29, 0xaa},
+	{0x00, 0x7b, 0x0e, 0xaa},	{0x00, 0x7c, 0x1a, 0xaa},
+	{0x00, 0x7d, 0x31, 0xaa},	{0x00, 0x7e, 0x53, 0xaa},
+	{0x00, 0x7f, 0x60, 0xaa},	{0x00, 0x80, 0x6b, 0xaa},
+	{0x00, 0x81, 0x73, 0xaa},	{0x00, 0x82, 0x7b, 0xaa},
+	{0x00, 0x83, 0x82, 0xaa},	{0x00, 0x84, 0x89, 0xaa},
+	{0x00, 0x85, 0x96, 0xaa},	{0x00, 0x86, 0xa1, 0xaa},
+	{0x00, 0x87, 0xb7, 0xaa},	{0x00, 0x88, 0xcc, 0xaa},
+	{0x00, 0x89, 0xe1, 0xaa},	{0x00, 0x13, 0xe0, 0xaa},
+	{0x00, 0x00, 0x00, 0xaa},	{0x00, 0x10, 0x00, 0xaa},
+	{0x00, 0x0d, 0x40, 0xaa},	{0x00, 0x14, 0x28, 0xaa},
+	{0x00, 0xa5, 0x05, 0xaa},	{0x00, 0xab, 0x07, 0xaa},
+	{0x00, 0x24, 0x95, 0xaa},	{0x00, 0x25, 0x33, 0xaa},
+	{0x00, 0x26, 0xe3, 0xaa},	{0x00, 0x9f, 0x88, 0xaa},
+	{0x00, 0xa0, 0x78, 0xaa},	{0x00, 0x55, 0x90, 0xaa},
+	{0x00, 0xa1, 0x03, 0xaa},	{0x00, 0xa6, 0xe0, 0xaa},
+	{0x00, 0xa7, 0xd8, 0xaa},	{0x00, 0xa8, 0xf0, 0xaa},
+	{0x00, 0xa9, 0x90, 0xaa},	{0x00, 0xaa, 0x14, 0xaa},
+	{0x00, 0x13, 0xe5, 0xaa},	{0x00, 0x0e, 0x61, 0xaa},
+	{0x00, 0x0f, 0x4b, 0xaa},	{0x00, 0x16, 0x02, 0xaa},
+	{0x00, 0x1e, 0x07, 0xaa},	{0x00, 0x21, 0x02, 0xaa},
+	{0x00, 0x22, 0x91, 0xaa},	{0x00, 0x29, 0x07, 0xaa},
+	{0x00, 0x33, 0x0b, 0xaa},	{0x00, 0x35, 0x0b, 0xaa},
+	{0x00, 0x37, 0x1d, 0xaa},	{0x00, 0x38, 0x71, 0xaa},
+	{0x00, 0x39, 0x2a, 0xaa},	{0x00, 0x3c, 0x78, 0xaa},
+	{0x00, 0x4d, 0x40, 0xaa},	{0x00, 0x4e, 0x20, 0xaa},
+	{0x00, 0x74, 0x19, 0xaa},	{0x00, 0x8d, 0x4f, 0xaa},
+	{0x00, 0x8e, 0x00, 0xaa},	{0x00, 0x8f, 0x00, 0xaa},
+	{0x00, 0x90, 0x00, 0xaa},	{0x00, 0x91, 0x00, 0xaa},
+	{0x00, 0x96, 0x00, 0xaa},	{0x00, 0x9a, 0x80, 0xaa},
+	{0x00, 0xb0, 0x84, 0xaa},	{0x00, 0xb1, 0x0c, 0xaa},
+	{0x00, 0xb2, 0x0e, 0xaa},	{0x00, 0xb3, 0x82, 0xaa},
+	{0x00, 0xb8, 0x0a, 0xaa},	{0x00, 0x43, 0x14, 0xaa},
+	{0x00, 0x44, 0xf0, 0xaa},	{0x00, 0x45, 0x45, 0xaa},
+	{0x00, 0x46, 0x63, 0xaa},	{0x00, 0x47, 0x2d, 0xaa},
+	{0x00, 0x48, 0x46, 0xaa},	{0x00, 0x59, 0x88, 0xaa},
+	{0x00, 0x5a, 0xa0, 0xaa},	{0x00, 0x5b, 0xc6, 0xaa},
+	{0x00, 0x5c, 0x7d, 0xaa},	{0x00, 0x5d, 0x5f, 0xaa},
+	{0x00, 0x5e, 0x19, 0xaa},	{0x00, 0x6c, 0x0a, 0xaa},
+	{0x00, 0x6d, 0x55, 0xaa},	{0x00, 0x6e, 0x11, 0xaa},
+	{0x00, 0x6f, 0x9e, 0xaa},	{0x00, 0x69, 0x00, 0xaa},
+	{0x00, 0x6a, 0x40, 0xaa},	{0x00, 0x01, 0x40, 0xaa},
+	{0x00, 0x02, 0x40, 0xaa},	{0x00, 0x13, 0xe7, 0xaa},
+	{0x00, 0x5f, 0xf0, 0xaa},	{0x00, 0x60, 0xf0, 0xaa},
+	{0x00, 0x61, 0xf0, 0xaa},	{0x00, 0x27, 0xa0, 0xaa},
+	{0x00, 0x28, 0x80, 0xaa},	{0x00, 0x2c, 0x90, 0xaa},
+	{0x00, 0x4f, 0x66, 0xaa},	{0x00, 0x50, 0x66, 0xaa},
+	{0x00, 0x51, 0x00, 0xaa},	{0x00, 0x52, 0x22, 0xaa},
+	{0x00, 0x53, 0x5e, 0xaa},	{0x00, 0x54, 0x80, 0xaa},
+	{0x00, 0x58, 0x9e, 0xaa},	{0x00, 0x41, 0x08, 0xaa},
+	{0x00, 0x3f, 0x00, 0xaa},	{0x00, 0x75, 0x85, 0xaa},
+	{0x00, 0x76, 0xe1, 0xaa},	{0x00, 0x4c, 0x00, 0xaa},
+	{0x00, 0x77, 0x0a, 0xaa},	{0x00, 0x3d, 0x88, 0xaa},
+	{0x00, 0x4b, 0x09, 0xaa},	{0x00, 0xc9, 0x60, 0xaa},
+	{0x00, 0x41, 0x38, 0xaa},	{0x00, 0x62, 0x30, 0xaa},
+	{0x00, 0x63, 0x30, 0xaa},	{0x00, 0x64, 0x08, 0xaa},
+	{0x00, 0x94, 0x07, 0xaa},	{0x00, 0x95, 0x0b, 0xaa},
+	{0x00, 0x65, 0x00, 0xaa},	{0x00, 0x66, 0x05, 0xaa},
+	{0x00, 0x56, 0x50, 0xaa},	{0x00, 0x34, 0x11, 0xaa},
+	{0x00, 0xa4, 0x88, 0xaa},	{0x00, 0x96, 0x00, 0xaa},
+	{0x00, 0x97, 0x30, 0xaa},	{0x00, 0x98, 0x20, 0xaa},
+	{0x00, 0x99, 0x30, 0xaa},	{0x00, 0x9a, 0x84, 0xaa},
+	{0x00, 0x9b, 0x29, 0xaa},	{0x00, 0x9c, 0x03, 0xaa},
+	{0x00, 0x78, 0x04, 0xaa},	{0x00, 0x79, 0x01, 0xaa},
+	{0x00, 0xc8, 0xf0, 0xaa},	{0x00, 0x79, 0x0f, 0xaa},
+	{0x00, 0xc8, 0x00, 0xaa},	{0x00, 0x79, 0x10, 0xaa},
+	{0x00, 0xc8, 0x7e, 0xaa},	{0x00, 0x79, 0x0a, 0xaa},
+	{0x00, 0xc8, 0x80, 0xaa},	{0x00, 0x79, 0x0b, 0xaa},
+	{0x00, 0xc8, 0x01, 0xaa},	{0x00, 0x79, 0x0c, 0xaa},
+	{0x00, 0xc8, 0x0f, 0xaa},	{0x00, 0x79, 0x0d, 0xaa},
+	{0x00, 0xc8, 0x20, 0xaa},	{0x00, 0x79, 0x09, 0xaa},
+	{0x00, 0xc8, 0x80, 0xaa},	{0x00, 0x79, 0x02, 0xaa},
+	{0x00, 0xc8, 0xc0, 0xaa},	{0x00, 0x79, 0x03, 0xaa},
+	{0x00, 0xc8, 0x40, 0xaa},	{0x00, 0x79, 0x05, 0xaa},
+	{0x00, 0xc8, 0x30, 0xaa},	{0x00, 0x79, 0x26, 0xaa},
+	{0x00, 0x11, 0x40, 0xaa},	{0x00, 0x3a, 0x04, 0xaa},
+	{0x00, 0x12, 0x00, 0xaa},	{0x00, 0x40, 0xc0, 0xaa},
+	{0x00, 0x8c, 0x00, 0xaa},	{0x00, 0x17, 0x14, 0xaa},
+	{0x00, 0x18, 0x02, 0xaa},	{0x00, 0x32, 0x92, 0xaa},
+	{0x00, 0x19, 0x02, 0xaa},	{0x00, 0x1a, 0x7a, 0xaa},
+	{0x00, 0x03, 0x0a, 0xaa},	{0x00, 0x0c, 0x00, 0xaa},
+	{0x00, 0x3e, 0x00, 0xaa},	{0x00, 0x70, 0x3a, 0xaa},
+	{0x00, 0x71, 0x35, 0xaa},	{0x00, 0x72, 0x11, 0xaa},
+	{0x00, 0x73, 0xf0, 0xaa},	{0x00, 0xa2, 0x02, 0xaa},
+	{0x00, 0xb1, 0x00, 0xaa},	{0x00, 0xb1, 0x0c, 0xaa},
+	{0x00, 0x1e, 0x37, 0xaa},	{0x00, 0xaa, 0x14, 0xaa},
+	{0x00, 0x24, 0x80, 0xaa},	{0x00, 0x25, 0x74, 0xaa},
+	{0x00, 0x26, 0xd3, 0xaa},	{0x00, 0x0d, 0x00, 0xaa},
+	{0x00, 0x14, 0x18, 0xaa},	{0x00, 0x9d, 0x99, 0xaa},
+	{0x00, 0x9e, 0x7f, 0xaa},	{0x00, 0x64, 0x08, 0xaa},
+	{0x00, 0x94, 0x07, 0xaa},	{0x00, 0x95, 0x06, 0xaa},
+	{0x00, 0x66, 0x05, 0xaa},	{0x00, 0x41, 0x08, 0xaa},
+	{0x00, 0x3f, 0x00, 0xaa},	{0x00, 0x75, 0x07, 0xaa},
+	{0x00, 0x76, 0xe1, 0xaa},	{0x00, 0x4c, 0x00, 0xaa},
+	{0x00, 0x77, 0x00, 0xaa},	{0x00, 0x3d, 0xc2, 0xaa},
+	{0x00, 0x4b, 0x09, 0xaa},	{0x00, 0xc9, 0x60, 0xaa},
+	{0x00, 0x41, 0x38, 0xaa},	{0xb6, 0x00, 0x00, 0xcc},
+	{0xb6, 0x03, 0x01, 0xcc},	{0xb6, 0x02, 0x40, 0xcc},
+	{0xb6, 0x05, 0x00, 0xcc},	{0xb6, 0x04, 0xf0, 0xcc},
+	{0xb6, 0x12, 0xf8, 0xcc},	{0xb6, 0x13, 0x21, 0xcc},
+	{0xb6, 0x18, 0x00, 0xcc},	{0xb6, 0x17, 0x96, 0xcc},
+	{0xb6, 0x16, 0x00, 0xcc},	{0xb6, 0x22, 0x12, 0xcc},
+	{0xb6, 0x23, 0x0b, 0xcc},	{0xbf, 0xc0, 0x39, 0xcc},
+	{0xbf, 0xc1, 0x04, 0xcc},	{0xbf, 0xcc, 0x00, 0xcc},
+	{0xbc, 0x02, 0x18, 0xcc},	{0xbc, 0x03, 0x50, 0xcc},
+	{0xbc, 0x04, 0x18, 0xcc},	{0xbc, 0x05, 0x00, 0xcc},
+	{0xbc, 0x06, 0x00, 0xcc},	{0xbc, 0x08, 0x30, 0xcc},
+	{0xbc, 0x09, 0x40, 0xcc},	{0xbc, 0x0a, 0x10, 0xcc},
+	{0xbc, 0x0b, 0x00, 0xcc},	{0xbc, 0x0c, 0x00, 0xcc},
+	{0xb3, 0x5c, 0x01, 0xcc},	{0xb3, 0x01, 0x45, 0xcc},
+	{0x00, 0x77, 0x05, 0xaa },
+	{},
+};
+
+struct sensor_info {
+	int sensorId;
+	__u8 I2cAdd;
+	__u8 IdAdd;
+	__u16 VpId;
+	__u8 m1;
+	__u8 m2;
+	__u8 op;
+	};
+
+static struct sensor_info sensor_info_data[] = {
+/*      sensorId,         I2cAdd,	IdAdd,  VpId,  m1,    m2,  op */
+	{SENSOR_HV7131R,    0x80 | 0x11, 0x00, 0x0209, 0x24, 0x25, 0x01},
+	{SENSOR_OV7660,     0x80 | 0x21, 0x0a, 0x7660, 0x26, 0x26, 0x05},
+	{SENSOR_PO3130NC,   0x80 | 0x76, 0x00, 0x3130, 0x24, 0x25, 0x01},
+	{SENSOR_MI1320,     0x80 | 0xc8, 0x00, 0x148c, 0x64, 0x65, 0x01},
+	{SENSOR_OV7670,     0x80 | 0x21, 0x0a, 0x7673, 0x66, 0x67, 0x05},
+	{SENSOR_MI1310_SOC, 0x80 | 0x5d, 0x00, 0x143a, 0x24, 0x25, 0x01},
+};
+
+static void reg_r(struct usb_device *dev,
+			   __u16 req,
+			   __u16 index,
+			   __u8 *buffer, __u16 length)
+{
+	usb_control_msg(dev,
+			usb_rcvctrlpipe(dev, 0),
+			req,
+			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			1,			/* value */
+			index, buffer, length,
+			500);
+}
+
+static void reg_w(struct usb_device *dev,
+			    __u16 req,
+			    __u16 value,
+			    __u16 index)
+{
+	usb_control_msg(dev,
+			usb_sndctrlpipe(dev, 0),
+			req,
+			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			value, index, NULL, 0,
+			500);
+}
+
+static void vc032x_read_sensor_register(struct usb_device *dev,
+				__u16 address, __u16 *value)
+{
+	__u8 ldata, mdata, hdata;
+	__u8 tmpvalue = 0;
+	int retry = 50;
+	ldata = 0;
+	mdata = 0;
+	hdata = 0;
+	*value = 0;
+
+	reg_r(dev, 0xa1, 0xb33f, &tmpvalue, 1);
+	/*PDEBUG(D_PROBE, " I2c Bus Busy Wait  0x%02X ", tmpvalue); */
+	if (!(tmpvalue & 0x02)) {
+		PDEBUG(D_ERR, "I2c Bus Busy Wait %d", tmpvalue & 0x02);
+		return;
+	}
+	reg_w(dev, 0xa0, address, 0xb33a);
+	reg_w(dev, 0xa0, 0x02, 0xb339);
+
+	tmpvalue = 0;
+	reg_r(dev, 0xa1, 0xb33b, &tmpvalue, 1);
+	while (retry-- && tmpvalue) {
+		reg_r(dev, 0xa1, 0xb33b, &tmpvalue, 1);
+/*		PDEBUG(D_PROBE, "Read again 0xb33b %d", tmpvalue); */
+		msleep(1);
+	}
+	reg_r(dev, 0xa1, 0xb33e, &hdata, 1);
+	reg_r(dev, 0xa1, 0xb33d, &mdata, 1);
+	reg_r(dev, 0xa1, 0xb33c, &ldata, 1);
+	PDEBUG(D_PROBE, "Read Sensor h (0x%02X) m (0x%02X) l (0x%02X)",
+		hdata, mdata, ldata);
+	tmpvalue = 0;
+	reg_r(dev, 0xa1, 0xb334, &tmpvalue, 1);
+	if (tmpvalue == 0x02)
+		*value = (ldata << 8) + mdata;
+	else
+		*value = ldata;
+}
+static int vc032x_probe_sensor(struct gspca_dev *gspca_dev)
+{
+	struct usb_device *dev = gspca_dev->dev;
+	int i;
+	__u8 data;
+	__u16 value;
+	struct sensor_info *ptsensor_info;
+
+	reg_r(dev, 0xa1, 0xbfcf, &data, 1);
+	PDEBUG(D_PROBE, "check sensor header %d", data);
+	for (i = 0; i < ARRAY_SIZE(sensor_info_data); i++) {
+		ptsensor_info = &sensor_info_data[i];
+		reg_w(dev, 0xa0, 0x02, 0xb334);
+		reg_w(dev, 0xa0, ptsensor_info->m1, 0xb300);
+		reg_w(dev, 0xa0, ptsensor_info->m2, 0xb300);
+		reg_w(dev, 0xa0, 0x01, 0xb308);
+		reg_w(dev, 0xa0, 0x0c, 0xb309);
+		reg_w(dev, 0xa0, ptsensor_info->I2cAdd, 0xb335);
+/*		PDEBUG(D_PROBE,
+			"check sensor VC032X -> %d Add -> ox%02X!",
+			i, ptsensor_info->I2cAdd); */
+		reg_w(dev, 0xa0, ptsensor_info->op, 0xb301);
+		vc032x_read_sensor_register(dev, ptsensor_info->IdAdd, &value);
+		if (value == ptsensor_info->VpId) {
+/*			PDEBUG(D_PROBE, "find sensor VC032X -> ox%04X!",
+				ptsensor_info->VpId); */
+			return ptsensor_info->sensorId;
+		}
+	}
+	return -1;
+}
+
+static __u8 i2c_write(struct usb_device *dev,
+				__u8 reg, __u8 *val, __u8 size)
+{
+	__u8 retbyte;
+
+	if (size > 3 || size < 1)
+		return -EINVAL;
+	reg_r(dev, 0xa1, 0xb33f, &retbyte, 1);
+	reg_w(dev, 0xa0, size , 0xb334);
+	reg_w(dev, 0xa0, reg , 0xb33a);
+	switch (size) {
+	case 1:
+		reg_w(dev, 0xa0, val[0] , 0xb336);
+		break;
+	case 2:
+		reg_w(dev, 0xa0, val[0] , 0xb336);
+		reg_w(dev, 0xa0, val[1] , 0xb337);
+		break;
+	case 3:
+		reg_w(dev, 0xa0, val[0] , 0xb336);
+		reg_w(dev, 0xa0, val[1] , 0xb337);
+		reg_w(dev, 0xa0, val[2] , 0xb338);
+		break;
+	default:
+		reg_w(dev, 0xa0, 0x01, 0xb334);
+		return -EINVAL;
+	}
+	reg_w(dev, 0xa0, 0x01, 0xb339);
+	reg_r(dev, 0xa1, 0xb33b, &retbyte, 1);
+	return retbyte == 0;
+}
+
+static void put_tab_to_reg(struct gspca_dev *gspca_dev,
+			__u8 *tab, __u8 tabsize, __u16 addr)
+{
+	int j;
+	__u16 ad = addr;
+
+	for (j = 0; j < tabsize; j++)
+		reg_w(gspca_dev->dev, 0xa0, tab[j], ad++);
+}
+
+static void usb_exchange(struct gspca_dev *gspca_dev,
+				__u8 data[][4])
+{
+	struct usb_device *dev = gspca_dev->dev;
+	int i = 0;
+
+	for (;;) {
+		switch (data[i][3]) {
+		default:
+			return;
+		case 0xcc:			/* normal write */
+			reg_w(dev, 0xa0, data[i][2],
+					((data[i][0])<<8) | data[i][1]);
+			break;
+		case 0xaa:			/* i2c op */
+			i2c_write(dev, data[i][1], &data[i][2], 1);
+			break;
+		case 0xbb:			/* i2c op */
+			i2c_write(dev, data[i][0], &data[i][1], 2);
+			break;
+		case 0xdd:
+			msleep(data[i][2] + 10);
+			break;
+		}
+		i++;
+	}
+	/*not reached*/
+}
+
+/*
+ "GammaT"=hex:04,17,31,4f,6a,83,99,ad,bf,ce,da,e5,ee,f5,fb,ff,ff
+ "MatrixT"=hex:60,f9,e5,e7,50,05,f3,e6,66
+ */
+
+static void vc0321_reset(struct gspca_dev *gspca_dev)
+{
+	reg_w(gspca_dev->dev, 0xa0, 0x00, 0xb04d);
+	reg_w(gspca_dev->dev, 0xa0, 0x01, 0xb301);
+	msleep(100);
+	reg_w(gspca_dev->dev, 0xa0, 0x01, 0xb003);
+	msleep(100);
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+			const struct usb_device_id *id)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct usb_device *dev = gspca_dev->dev;
+	struct cam *cam;
+	__u8 tmp2[4];
+	int sensor;
+	__u16 vendor;
+	__u16 product;
+
+	vendor = id->idVendor;
+	product = id->idProduct;
+	switch (vendor) {
+	case 0x046d:		/* Logitech Labtec */
+/*		switch (product) { */
+/*		case 0x0892: */
+/*		case 0x0896: */
+			sd->bridge = BRIDGE_VC0321;
+/*			break; */
+/*		} */
+		break;
+	case 0x0ac8:		/* Vimicro z-star */
+		switch (product) {
+		case 0x0321:
+		case 0x0328:
+		case 0xc001:
+		case 0xc002:
+			sd->bridge = BRIDGE_VC0321;
+			break;
+		case 0x0323:
+			sd->bridge = BRIDGE_VC0323;
+			break;
+		}
+		break;
+	case 0x17ef:		/* Lenovo */
+/*		switch (product) { */
+/*		case 0x4802:	 * Lenovo MI1310_SOC */
+			sd->bridge = BRIDGE_VC0323;
+/*			break; */
+/*		} */
+		break;
+	}
+
+	cam = &gspca_dev->cam;
+	cam->dev_name = (char *) id->driver_info;
+	cam->epaddr = 0x02;
+	if (sd->bridge == BRIDGE_VC0321) {
+		cam->cam_mode = vc0321_mode;
+		cam->nmodes = sizeof vc0321_mode / sizeof vc0321_mode[0];
+	} else {
+		cam->cam_mode = vc0323_mode;
+		cam->nmodes = sizeof vc0323_mode / sizeof vc0323_mode[0];
+	}
+
+	vc0321_reset(gspca_dev);
+	sensor = vc032x_probe_sensor(gspca_dev);
+	switch (sensor) {
+	case -1:
+		PDEBUG(D_PROBE, "Unknown sensor...");
+		return -EINVAL;
+	case SENSOR_HV7131R:
+		PDEBUG(D_PROBE, "Find Sensor HV7131R");
+		sd->sensor = SENSOR_HV7131R;
+		break;
+	case SENSOR_MI1310_SOC:
+		PDEBUG(D_PROBE, "Find Sensor MI1310_SOC");
+		sd->sensor = SENSOR_MI1310_SOC;
+		break;
+	case SENSOR_MI1320:
+		PDEBUG(D_PROBE, "Find Sensor MI1320");
+		sd->sensor = SENSOR_MI1320;
+		break;
+	case SENSOR_OV7660:
+		PDEBUG(D_PROBE, "Find Sensor OV7660");
+		sd->sensor = SENSOR_OV7660;
+		break;
+	case SENSOR_OV7670:
+		PDEBUG(D_PROBE, "Find Sensor OV7670");
+		sd->sensor = SENSOR_OV7670;
+		break;
+	case SENSOR_PO3130NC:
+		PDEBUG(D_PROBE, "Find Sensor PO3130NC");
+		sd->sensor = SENSOR_PO3130NC;
+		break;
+	}
+
+	sd->qindex = 7;
+	sd->autogain = sd_ctrls[SD_AUTOGAIN].qctrl.default_value;
+
+	if (sd->bridge == BRIDGE_VC0321) {
+		reg_r(dev, 0x8a, 0, tmp2, 3);
+		reg_w(dev, 0x87, 0x00, 0x0f0f);
+
+		reg_r(dev, 0x8b, 0, tmp2, 3);
+		reg_w(dev, 0x88, 0x00, 0x0202);
+	}
+	return 0;
+}
+
+/* this function is called at open time */
+static int sd_open(struct gspca_dev *gspca_dev)
+{
+	return 0;
+}
+
+static void setquality(struct gspca_dev *gspca_dev)
+{
+}
+
+static void setautogain(struct gspca_dev *gspca_dev)
+{
+}
+
+static void setlightfreq(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	static __u8 (*ov7660_freq_tb[3])[4] =
+		{ov7660_NoFliker, ov7660_50HZ, ov7660_60HZ};
+
+	if (sd->sensor != SENSOR_OV7660)
+		return;
+	usb_exchange(gspca_dev, ov7660_freq_tb[sd->lightfreq]);
+}
+
+static void sd_start(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+/*	__u8 tmp2; */
+	__u8 *GammaT = NULL;
+	__u8 *MatrixT = NULL;
+	int mode;
+
+	/* Assume start use the good resolution from gspca_dev->mode */
+	if (sd->bridge == BRIDGE_VC0321) {
+		reg_w(gspca_dev->dev, 0xa0, 0xff, 0xbfec);
+		reg_w(gspca_dev->dev, 0xa0, 0xff, 0xbfed);
+		reg_w(gspca_dev->dev, 0xa0, 0xff, 0xbfee);
+		reg_w(gspca_dev->dev, 0xa0, 0xff, 0xbfef);
+	}
+
+	mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].mode;
+	switch (sd->sensor) {
+	case SENSOR_HV7131R:
+		GammaT = hv7131r_gamma;
+		MatrixT = hv7131r_matrix;
+		if (mode) {
+			/* 320x240 */
+			usb_exchange(gspca_dev, hv7131r_initQVGA_data);
+		} else {
+			/* 640x480 */
+			usb_exchange(gspca_dev, hv7131r_initVGA_data);
+		}
+		break;
+	case SENSOR_OV7660:
+		GammaT = ov7660_gamma;
+		MatrixT = ov7660_matrix;
+		if (mode) {
+			/* 320x240 */
+			usb_exchange(gspca_dev, ov7660_initQVGA_data);
+		} else {
+			/* 640x480 */
+			usb_exchange(gspca_dev, ov7660_initVGA_data);
+		}
+		break;
+	case SENSOR_OV7670:
+		/*GammaT = ov7660_gamma; */
+		/*MatrixT = ov7660_matrix; */
+		if (mode) {
+			/* 320x240 */
+			usb_exchange(gspca_dev, ov7670_initQVGA_JPG);
+		} else {
+			/* 640x480 */
+			usb_exchange(gspca_dev, ov7670_initVGA_JPG);
+		}
+		break;
+	case SENSOR_MI1310_SOC:
+		if (mode) {
+			/* 320x240 */
+			usb_exchange(gspca_dev, mi1310_socinitQVGA_JPG);
+		} else {
+			/* 640x480 */
+			usb_exchange(gspca_dev, mi1310_socinitVGA_JPG);
+		}
+		break;
+	case SENSOR_MI1320:
+		GammaT = mi1320_gamma;
+		MatrixT = mi1320_matrix;
+		if (mode) {
+			/* 320x240 */
+			usb_exchange(gspca_dev, mi1320_initQVGA_data);
+		} else {
+			/* 640x480 */
+			usb_exchange(gspca_dev, mi1320_initVGA_data);
+		}
+		break;
+	case SENSOR_PO3130NC:
+		GammaT = po3130_gamma;
+		MatrixT = po3130_matrix;
+		if (mode) {
+			/* 320x240 */
+			usb_exchange(gspca_dev, po3130_initQVGA_data);
+		} else {
+			/* 640x480 */
+			usb_exchange(gspca_dev, po3130_initVGA_data);
+		}
+		usb_exchange(gspca_dev, po3130_rundata);
+		break;
+	default:
+		PDEBUG(D_PROBE, "Damned !! no sensor found Bye");
+		return;
+	}
+	if (GammaT && MatrixT) {
+		put_tab_to_reg(gspca_dev, GammaT, 17, 0xb84a);
+		put_tab_to_reg(gspca_dev, GammaT, 17, 0xb85b);
+		put_tab_to_reg(gspca_dev, GammaT, 17, 0xb86c);
+		put_tab_to_reg(gspca_dev, MatrixT, 9, 0xb82c);
+
+		/* Seem SHARPNESS */
+		/*
+		reg_w(gspca_dev->dev, 0xa0, 0x80, 0xb80a);
+		reg_w(gspca_dev->dev, 0xa0, 0xff, 0xb80b);
+		reg_w(gspca_dev->dev, 0xa0, 0xff, 0xb80e);
+		*/
+		/* all 0x40 ??? do nothing
+		reg_w(gspca_dev->dev, 0xa0, 0x40, 0xb822);
+		reg_w(gspca_dev->dev, 0xa0, 0x40, 0xb823);
+		reg_w(gspca_dev->dev, 0xa0, 0x40, 0xb824);
+		*/
+		/* Only works for HV7131R ??
+		reg_r (gspca_dev->dev, 0xa1, 0xb881, &tmp2, 1);
+		reg_w(gspca_dev->dev, 0xa0, 0xfe01, 0xb881);
+		reg_w(gspca_dev->dev, 0xa0, 0x79, 0xb801);
+		*/
+		/* only hv7131r et ov7660
+		reg_w(gspca_dev->dev, 0xa0, 0x20, 0xb827);
+		reg_w(gspca_dev->dev, 0xa0, 0xff, 0xb826); * ISP_GAIN 80
+		reg_w(gspca_dev->dev, 0xa0, 0x23, 0xb800); * ISP CTRL_BAS
+		*/
+		/* set the led on 0x0892 0x0896 */
+		reg_w(gspca_dev->dev, 0x89, 0xffff, 0xfdff);
+		msleep(100);
+		setquality(gspca_dev);
+		setautogain(gspca_dev);
+		setlightfreq(gspca_dev);
+	}
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+	struct usb_device *dev = gspca_dev->dev;
+
+	reg_w(dev, 0x89, 0xffff, 0xffff);
+	reg_w(dev, 0xa0, 0x01, 0xb301);
+	reg_w(dev, 0xa0, 0x09, 0xb003);
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+	struct usb_device *dev = gspca_dev->dev;
+
+	reg_w(dev, 0x89, 0xffff, 0xffff);
+}
+
+/* this function is called at close time */
+static void sd_close(struct gspca_dev *gspca_dev)
+{
+/*	struct usb_device *dev = gspca_dev->dev;
+	__u8 buffread;
+
+	reg_w(dev, 0x89, 0xffff, 0xffff);
+	reg_w(dev, 0xa0, 0x01, 0xb301);
+	reg_w(dev, 0xa0, 0x09, 0xb303);
+	reg_w(dev, 0x89, 0xffff, 0xffff);
+*/
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+			struct gspca_frame *frame,	/* target */
+			unsigned char *data,		/* isoc packet */
+			int len)			/* iso pkt length */
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	if (data[0] == 0xff && data[1] == 0xd8) {
+		PDEBUG(D_PACK,
+			"vc032x header packet found len %d", len);
+		frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+						data, 0);
+		if (sd->bridge == BRIDGE_VC0321) {
+#define VCHDRSZ 46
+			data += VCHDRSZ;
+			len -= VCHDRSZ;
+#undef VCHDRSZ
+		}
+		gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+				data, len);
+		return;
+	}
+	gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+}
+
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->autogain = val;
+	if (gspca_dev->streaming)
+		setautogain(gspca_dev);
+	return 0;
+}
+
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->autogain;
+	return 0;
+}
+
+static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->lightfreq = val;
+	if (gspca_dev->streaming)
+		setlightfreq(gspca_dev);
+	return 0;
+}
+
+static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->lightfreq;
+	return 0;
+}
+
+static int sd_querymenu(struct gspca_dev *gspca_dev,
+			struct v4l2_querymenu *menu)
+{
+	switch (menu->id) {
+	case V4L2_CID_POWER_LINE_FREQUENCY:
+		switch (menu->index) {
+		case 0:		/* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */
+			strcpy(menu->name, "NoFliker");
+			return 0;
+		case 1:		/* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
+			strcpy(menu->name, "50 Hz");
+			return 0;
+		case 2:		/* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
+			strcpy(menu->name, "60 Hz");
+			return 0;
+		}
+		break;
+	}
+	return -EINVAL;
+}
+
+/* sub-driver description */
+static struct sd_desc sd_desc = {
+	.name = MODULE_NAME,
+	.ctrls = sd_ctrls,
+	.nctrls = ARRAY_SIZE(sd_ctrls),
+	.config = sd_config,
+	.open = sd_open,
+	.start = sd_start,
+	.stopN = sd_stopN,
+	.stop0 = sd_stop0,
+	.close = sd_close,
+	.pkt_scan = sd_pkt_scan,
+	.querymenu = sd_querymenu,
+};
+
+/* -- module initialisation -- */
+#define DVNM(name) .driver_info = (kernel_ulong_t) name
+static __devinitdata struct usb_device_id device_table[] = {
+	{USB_DEVICE(0x046d, 0x0892), DVNM("Logitech Orbicam")},
+	{USB_DEVICE(0x046d, 0x0896), DVNM("Logitech Orbicam")},
+	{USB_DEVICE(0x0ac8, 0x0321), DVNM("Vimicro generic vc0321")},
+	{USB_DEVICE(0x0ac8, 0x0323), DVNM("Vimicro Vc0323")},
+	{USB_DEVICE(0x0ac8, 0x0328), DVNM("A4Tech PK-130MG")},
+	{USB_DEVICE(0x0ac8, 0xc001), DVNM("Sony embedded vimicro")},
+	{USB_DEVICE(0x0ac8, 0xc002), DVNM("Sony embedded vimicro")},
+	{USB_DEVICE(0x17ef, 0x4802), DVNM("Lenovo Vc0323+MI1310_SOC")},
+	{}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+			const struct usb_device_id *id)
+{
+	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+				THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+	.name = MODULE_NAME,
+	.id_table = device_table,
+	.probe = sd_probe,
+	.disconnect = gspca_disconnect,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+	if (usb_register(&sd_driver) < 0)
+		return -1;
+	PDEBUG(D_PROBE, "v%s registered", version);
+	return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+	usb_deregister(&sd_driver);
+	PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/zc3xx.c b/drivers/media/video/gspca/zc3xx.c
index 03cc7fc..b767f32 100644
--- a/drivers/media/video/gspca/zc3xx.c
+++ b/drivers/media/video/gspca/zc3xx.c
@@ -3,7 +3,7 @@
  *	Copyright (C) 2004 2005 2006 Michel Xhaard
  *		mxhaard@magic.fr
  *
- * V4L2 by Jean-François Moine <http://moinejf.free.fr>
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -24,15 +24,14 @@
 
 #include "gspca.h"
 
-#define DRIVER_VERSION_NUMBER	KERNEL_VERSION(0, 2, 13)
-static const char version[] = "0.2.13";
+#define DRIVER_VERSION_NUMBER	KERNEL_VERSION(2, 1, 0)
+static const char version[] = "2.1.0";
 
 MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>, "
 		"Serge A. Suchkov <Serge.A.S@tochka.ru>");
 MODULE_DESCRIPTION("GSPCA ZC03xx/VC3xx USB Camera Driver");
 MODULE_LICENSE("GPL");
 
-static int lightfreq = 50;
 static int force_sensor = -1;
 
 #include "jpeg.h"
@@ -41,10 +40,12 @@
 struct sd {
 	struct gspca_dev gspca_dev;	/* !! must be the first item */
 
-	unsigned char brightness;
-	unsigned char contrast;
-	unsigned char autogain;
-	unsigned char gamma;
+	__u8 brightness;
+	__u8 contrast;
+	__u8 gamma;
+	__u8 autogain;
+	__u8 lightfreq;
+	__u8 sharpness;
 
 	char qindex;
 	char sensor;			/* Type of image sensor chip */
@@ -61,14 +62,13 @@
 #define SENSOR_OV7620 9
 /*#define SENSOR_OV7648 9 - same values */
 #define SENSOR_OV7630C 10
-/*#define SENSOR_free 11 */
-#define SENSOR_PAS106 12
-#define SENSOR_PB0330 13
-#define SENSOR_PO2030 14
-#define SENSOR_TAS5130CK 15
-#define SENSOR_TAS5130CXX 16
-#define SENSOR_TAS5130C_VF0250 17
-#define SENSOR_MAX 18
+#define SENSOR_PAS106 11
+#define SENSOR_PB0330 12
+#define SENSOR_PO2030 13
+#define SENSOR_TAS5130CK 14
+#define SENSOR_TAS5130CXX 15
+#define SENSOR_TAS5130C_VF0250 16
+#define SENSOR_MAX 17
 	unsigned short chip_revision;
 };
 
@@ -79,7 +79,12 @@
 static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
 static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val);
 
 static struct ctrl sd_ctrls[] = {
 #define SD_BRIGHTNESS 0
@@ -110,7 +115,21 @@
 	    .set = sd_setcontrast,
 	    .get = sd_getcontrast,
 	},
-#define SD_AUTOGAIN 2
+#define SD_GAMMA 2
+	{
+	    {
+		.id      = V4L2_CID_GAMMA,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Gamma",
+		.minimum = 1,
+		.maximum = 6,
+		.step    = 1,
+		.default_value = 4,
+	    },
+	    .set = sd_setgamma,
+	    .get = sd_getgamma,
+	},
+#define SD_AUTOGAIN 3
 	{
 	    {
 		.id      = V4L2_CID_AUTOGAIN,
@@ -124,19 +143,33 @@
 	    .set = sd_setautogain,
 	    .get = sd_getautogain,
 	},
-#define SD_GAMMA 3
+#define SD_FREQ 4
 	{
 	    {
-		.id      = V4L2_CID_GAMMA,
-		.type    = V4L2_CTRL_TYPE_INTEGER,
-		.name    = "Gamma",
-		.minimum = 1,
-		.maximum = 6,
+		.id	 = V4L2_CID_POWER_LINE_FREQUENCY,
+		.type    = V4L2_CTRL_TYPE_MENU,
+		.name    = "Light frequency filter",
+		.minimum = 0,
+		.maximum = 2,	/* 0: 0, 1: 50Hz, 2:60Hz */
 		.step    = 1,
-		.default_value = 4,
+		.default_value = 1,
 	    },
-	    .set = sd_setcontrast,
-	    .get = sd_getgamma,
+	    .set = sd_setfreq,
+	    .get = sd_getfreq,
+	},
+#define SD_SHARPNESS 5
+	{
+	    {
+		.id	 = V4L2_CID_SHARPNESS,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Sharpness",
+		.minimum = 0,
+		.maximum = 3,
+		.step    = 1,
+		.default_value = 2,
+	    },
+	    .set = sd_setsharpness,
+	    .get = sd_getsharpness,
 	},
 };
 
@@ -211,11 +244,11 @@
 	{0xa1, 0x01, 0x0002},
 	{0xa1, 0x01, 0x0008},
 	{0xa0, 0x03, 0x0008},	/* 00 */
-	{0xa0, 0x08, 0x01c6},	/* clock ? */
+	{0xa0, 0x08, 0x01c6},	/* sharpness+ */
 	{0xa1, 0x01, 0x01c8},
 	{0xa1, 0x01, 0x01c9},
 	{0xa1, 0x01, 0x01ca},
-	{0xa0, 0x0f, 0x01cb},
+	{0xa0, 0x0f, 0x01cb},	/* sharpness- */
 	{0xa0, 0x24, 0x0120},	/* gamma 5 */
 	{0xa0, 0x44, 0x0121},
 	{0xa0, 0x64, 0x0122},
@@ -284,7 +317,7 @@
 	{0xa0, 0x40, 0x0116},
 	{0xa0, 0x40, 0x0117},
 	{0xa0, 0x40, 0x0118},
-	{0, 0, 0}
+	{}
 };
 
 static struct usb_action cs2102_InitialScale[] = {
@@ -341,11 +374,11 @@
 	{0xa1, 0x01, 0x0002},
 	{0xa1, 0x01, 0x0008},
 	{0xa0, 0x03, 0x0008},	/* 00 */
-	{0xa0, 0x08, 0x01c6},	/* clock ? */
+	{0xa0, 0x08, 0x01c6},	/* sharpness+ */
 	{0xa1, 0x01, 0x01c8},
 	{0xa1, 0x01, 0x01c9},
 	{0xa1, 0x01, 0x01ca},
-	{0xa0, 0x0f, 0x01cb},
+	{0xa0, 0x0f, 0x01cb},	/* sharpness- */
 	{0xa0, 0x24, 0x0120},	/* gamma 5 */
 	{0xa0, 0x44, 0x0121},
 	{0xa0, 0x64, 0x0122},
@@ -414,7 +447,7 @@
 	{0xa0, 0x40, 0x0116},
 	{0xa0, 0x40, 0x0117},
 	{0xa0, 0x40, 0x0118},
-	{0, 0, 0}
+	{}
 };
 static struct usb_action cs2102_50HZ[] = {
 	{0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
@@ -439,7 +472,7 @@
 	{0xa0, 0x8c, 0x001d}, /* 00,1d,8c,cc */
 	{0xa0, 0xb0, 0x001e}, /* 00,1e,b0,cc */
 	{0xa0, 0xd0, 0x001f}, /* 00,1f,d0,cc */
-	{0, 0, 0}
+	{}
 };
 static struct usb_action cs2102_50HZScale[] = {
 	{0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
@@ -464,7 +497,7 @@
 	{0xa0, 0x93, 0x001d}, /* 00,1d,93,cc */
 	{0xa0, 0xb0, 0x001e}, /* 00,1e,b0,cc */
 	{0xa0, 0xd0, 0x001f}, /* 00,1f,d0,cc */
-	{0, 0, 0}
+	{}
 };
 static struct usb_action cs2102_60HZ[] = {
 	{0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
@@ -489,7 +522,7 @@
 	{0xa0, 0x5d, 0x001d}, /* 00,1d,5d,cc */
 	{0xa0, 0x90, 0x001e}, /* 00,1e,90,cc */
 	{0xa0, 0xd0, 0x00c8}, /* 00,c8,d0,cc */
-	{0, 0, 0}
+	{}
 };
 static struct usb_action cs2102_60HZScale[] = {
 	{0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
@@ -514,7 +547,7 @@
 	{0xa0, 0xb7, 0x001d}, /* 00,1d,b7,cc */
 	{0xa0, 0xd0, 0x001e}, /* 00,1e,d0,cc */
 	{0xa0, 0xe8, 0x001f}, /* 00,1f,e8,cc */
-	{0, 0, 0}
+	{}
 };
 static struct usb_action cs2102_NoFliker[] = {
 	{0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
@@ -539,7 +572,7 @@
 	{0xa0, 0x59, 0x001d}, /* 00,1d,59,cc */
 	{0xa0, 0x90, 0x001e}, /* 00,1e,90,cc */
 	{0xa0, 0xc8, 0x001f}, /* 00,1f,c8,cc */
-	{0, 0, 0}
+	{}
 };
 static struct usb_action cs2102_NoFlikerScale[] = {
 	{0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
@@ -564,7 +597,7 @@
 	{0xa0, 0x59, 0x001d}, /* 00,1d,59,cc */
 	{0xa0, 0x90, 0x001e}, /* 00,1e,90,cc */
 	{0xa0, 0xc8, 0x001f}, /* 00,1f,c8,cc */
-	{0, 0, 0}
+	{}
 };
 
 /* CS2102_KOCOM */
@@ -676,8 +709,8 @@
 	{0xa0, 0x40, 0x0117},
 	{0xa0, 0x4c, 0x0118},
 	{0xa0, 0x03, 0x0008},	/* clock ? */
-	{0xa0, 0x08, 0x01c6},
-	{0xa0, 0x0f, 0x01cb},
+	{0xa0, 0x08, 0x01c6},	/* sharpness+ */
+	{0xa0, 0x0f, 0x01cb},	/* sharpness- */
 	{0xa0, 0x13, 0x0120},	/* gamma 4 */
 	{0xa0, 0x38, 0x0121},
 	{0xa0, 0x59, 0x0122},
@@ -824,7 +857,7 @@
 	{0xa0, 0x00, 0x01a7},
 	{0xa0, 0x04, 0x01a7},
 	{0xa0, 0x00, 0x01a7},
-	{0, 0, 0}
+	{}
 };
 
 static struct usb_action cs2102K_InitialScale[] = {
@@ -936,8 +969,8 @@
 	{0xa0, 0x40, 0x0117},
 	{0xa0, 0x4c, 0x0118},
 	{0xa0, 0x03, 0x0008},	/* clock ? */
-	{0xa0, 0x08, 0x01c6},
-	{0xa0, 0x0f, 0x01cb},
+	{0xa0, 0x08, 0x01c6},	/* sharpness+ */
+	{0xa0, 0x0f, 0x01cb},	/* sharpness- */
 	{0xa0, 0x13, 0x0120},	/* gamma 4 */
 	{0xa0, 0x38, 0x0121},
 	{0xa0, 0x59, 0x0122},
@@ -1137,8 +1170,8 @@
 	{0xa0, 0x40, 0x0117},
 	{0xa0, 0x4c, 0x0118},
 	{0xa0, 0x03, 0x0008},	/* clock ? */
-	{0xa0, 0x08, 0x01c6},
-	{0xa0, 0x0f, 0x01cb},
+	{0xa0, 0x08, 0x01c6},	/* sharpness+ */
+	{0xa0, 0x0f, 0x01cb},	/* sharpness- */
 	{0xa0, 0x13, 0x0120},	/* gamma 4 */
 	{0xa0, 0x38, 0x0121},
 	{0xa0, 0x59, 0x0122},
@@ -1401,7 +1434,7 @@
 	{0xa0, 0x04, 0x01a7},
 	{0xa0, 0x00, 0x01a7},
 	{0xa0, 0x04, 0x01a7},
-	{0, 0, 0}
+	{}
 };
 
 static struct usb_action gc0305_Initial[] = {		/* 640x480 */
@@ -1466,7 +1499,7 @@
 	{0xa0, 0x40, 0x0117},	/* 01,17,40,cc */
 	{0xa0, 0x52, 0x0118},	/* 01,18,52,cc */
 	{0xa0, 0x03, 0x0113},	/* 01,13,03,cc */
-	{0,0,0}
+	{}
 };
 static struct usb_action gc0305_InitialScale[] = {	/* 320x240 */
 	{0xa0, 0x01, 0x0000},	/* 00,00,01,cc */
@@ -1529,7 +1562,7 @@
 	{0xa0, 0x40, 0x0117},	/* 01,17,40,cc */
 	{0xa0, 0x52, 0x0118},	/* 01,18,52,cc */
 	{0xa0, 0x03, 0x0113},	/* 01,13,03,cc */
-	{0,0,0}
+	{}
 };
 static struct usb_action gc0305_50HZ[] = {
 	{0xaa, 0x82, 0x0000},	/* 00,82,00,aa */
@@ -1552,7 +1585,7 @@
 	{0xa0, 0x60, 0x011d},	/* 01,1d,60,cc */
 	{0xa0, 0x42, 0x0180},	/* 01,80,42,cc */
 /*	{0xa0, 0x85, 0x018d},	 * 01,8d,85,cc *	 * if 640x480 */
-	{0,0,0}
+	{}
 };
 static struct usb_action gc0305_60HZ[] = {
 	{0xaa, 0x82, 0x0000},	/* 00,82,00,aa */
@@ -1575,7 +1608,7 @@
 	{0xa0, 0x60, 0x011d},	/* 01,1d,60,cc */
 	{0xa0, 0x42, 0x0180},	/* 01,80,42,cc */
 	{0xa0, 0x80, 0x018d},	/* 01,8d,80,cc */
-	{0,0,0}
+	{}
 };
 
 static struct usb_action gc0305_NoFliker[] = {
@@ -1598,7 +1631,7 @@
 	{0xa0, 0x60, 0x011d},	/* 01,1d,60,cc */
 	{0xa0, 0x03, 0x0180},	/* 01,80,03,cc */
 	{0xa0, 0x80, 0x018d},	/* 01,8d,80,cc */
-	{0,0,0}
+	{}
 };
 
 /* play poker with registers at your own risk !! */
@@ -1647,11 +1680,11 @@
 	{0xa1, 0x01, 0x0002},
 	{0xa1, 0x01, 0x0008},
 	{0xa0, 0x03, 0x0008},	/* clock ? */
-	{0xa0, 0x04, 0x01c6},
+	{0xa0, 0x04, 0x01c6},	/* sharpness+ */
 	{0xa1, 0x01, 0x01c8},
 	{0xa1, 0x01, 0x01c9},
 	{0xa1, 0x01, 0x01ca},
-	{0xa0, 0x07, 0x01cb},
+	{0xa0, 0x07, 0x01cb},	/* sharpness- */
 	{0xa0, 0x11, 0x0120},	/* gamma ~4 */
 	{0xa0, 0x37, 0x0121},
 	{0xa0, 0x58, 0x0122},
@@ -1744,7 +1777,7 @@
 	{0xa1, 0x01, 0x0118},
 /*	{0xa0, 0x02, 0x0008}, */
 	{0xa0, 0x00, 0x0007},
-	{0, 0, 0}
+	{}
 };
 
 static struct usb_action hdcs2020xx_InitialScale[] = {
@@ -1792,11 +1825,11 @@
 	{0xa1, 0x01, 0x0002},
 	{0xa1, 0x01, 0x0008},
 	{0xa0, 0x03, 0x0008},	/* clock ? */
-	{0xa0, 0x04, 0x01c6},
+	{0xa0, 0x04, 0x01c6},	/* sharpness+ */
 	{0xa1, 0x01, 0x01c8},
 	{0xa1, 0x01, 0x01c9},
 	{0xa1, 0x01, 0x01ca},
-	{0xa0, 0x07, 0x01cb},
+	{0xa0, 0x07, 0x01cb},	/* sharpness- */
 	{0xa0, 0x11, 0x0120},	/* gamma ~4*/
 	{0xa0, 0x37, 0x0121},
 	{0xa0, 0x58, 0x0122},
@@ -1887,7 +1920,7 @@
 /*	{0xa0, 0x02, 0x0008}, */
 	{0xa0, 0x00, 0x0007},
 /*	{0xa0, 0x18, 0x00fe}, */
-	{0, 0, 0}
+	{}
 };
 static struct usb_action hdcs2020xb_Initial[] = {
 	{0xa0, 0x01, 0x0000},
@@ -1942,11 +1975,11 @@
 	{0xa0, 0x40, 0x0118},
 	{0xa1, 0x01, 0x0008},
 	{0xa0, 0x03, 0x0008},	/* clock ? */
-	{0xa0, 0x08, 0x01c6},
+	{0xa0, 0x08, 0x01c6},	/* sharpness+ */
 	{0xa1, 0x01, 0x01c8},
 	{0xa1, 0x01, 0x01c9},
 	{0xa1, 0x01, 0x01ca},
-	{0xa0, 0x0f, 0x01cb},
+	{0xa0, 0x0f, 0x01cb},	/* sharpness- */
 	{0xa0, 0x13, 0x0120},	/* gamma 4 */
 	{0xa0, 0x38, 0x0121},
 	{0xa0, 0x59, 0x0122},
@@ -2019,7 +2052,7 @@
 	{0xa0, 0x40, 0x0116},
 	{0xa0, 0x40, 0x0117},
 	{0xa0, 0x40, 0x0118},
-	{0, 0, 0}
+	{}
 };
 static struct usb_action hdcs2020xb_InitialScale[] = {
 	{0xa0, 0x01, 0x0000},
@@ -2072,11 +2105,11 @@
 	{0xa0, 0x40, 0x0118},
 	{0xa1, 0x01, 0x0008},
 	{0xa0, 0x03, 0x0008},	/* clock ? */
-	{0xa0, 0x08, 0x01c6},
+	{0xa0, 0x08, 0x01c6},	/* sharpness+ */
 	{0xa1, 0x01, 0x01c8},
 	{0xa1, 0x01, 0x01c9},
 	{0xa1, 0x01, 0x01ca},
-	{0xa0, 0x0f, 0x01cb},
+	{0xa0, 0x0f, 0x01cb},	/* sharpness- */
 	{0xa0, 0x13, 0x0120},	/* gamma 4 */
 	{0xa0, 0x38, 0x0121},
 	{0xa0, 0x59, 0x0122},
@@ -2147,7 +2180,7 @@
 	{0xa0, 0x40, 0x0116},
 	{0xa0, 0x40, 0x0117},
 	{0xa0, 0x40, 0x0118},
-	{0, 0, 0}
+	{}
 };
 static struct usb_action hdcs2020b_50HZ[] = {
 	{0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
@@ -2168,7 +2201,7 @@
 	{0xa0, 0x05, 0x001d}, /* 00,1d,05,cc */
 	{0xa0, 0x1a, 0x001e}, /* 00,1e,1a,cc */
 	{0xa0, 0x2f, 0x001f}, /* 00,1f,2f,cc */
-	{0, 0, 0}
+	{}
 };
 static struct usb_action hdcs2020b_60HZ[] = {
 	{0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
@@ -2189,7 +2222,7 @@
 	{0xa0, 0x04, 0x001d}, /* 00,1d,04,cc */
 	{0xa0, 0x18, 0x001e}, /* 00,1e,18,cc */
 	{0xa0, 0x2c, 0x001f}, /* 00,1f,2c,cc */
-	{0, 0, 0}
+	{}
 };
 static struct usb_action hdcs2020b_NoFliker[] = {
 	{0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
@@ -2210,7 +2243,7 @@
 	{0xa0, 0x04, 0x001d}, /* 00,1d,04,cc */
 	{0xa0, 0x17, 0x001e}, /* 00,1e,17,cc */
 	{0xa0, 0x2a, 0x001f}, /* 00,1f,2a,cc */
-	{0, 0, 0}
+	{}
 };
 
 static struct usb_action hv7131bxx_Initial[] = {
@@ -2266,11 +2299,11 @@
 
 	{0xa1, 0x01, 0x0008},
 	{0xa0, 0x03, 0x0008},	/* clock ? */
-	{0xa0, 0x08, 0x01c6},
+	{0xa0, 0x08, 0x01c6},	/* sharpness+ */
 	{0xa1, 0x01, 0x01c8},
 	{0xa1, 0x01, 0x01c9},
 	{0xa1, 0x01, 0x01ca},
-	{0xa0, 0x0f, 0x01cb},
+	{0xa0, 0x0f, 0x01cb},	/* sharpness- */
 
 	{0xa0, 0x50, 0x010a},	/* matrix */
 	{0xa0, 0xf8, 0x010b},
@@ -2318,7 +2351,7 @@
 	{0xa0, 0x40, 0x0117},
 	{0xa0, 0x40, 0x0118},
 /*	{0xa0, 0x02, 0x0008}, */
-	{0, 0, 0}
+	{}
 };
 
 static struct usb_action hv7131bxx_InitialScale[] = {
@@ -2373,11 +2406,11 @@
 	{0xa1, 0x01, 0x0096},
 	{0xa1, 0x01, 0x0008},
 	{0xa0, 0x03, 0x0008},	/* clock ? */
-	{0xa0, 0x08, 0x01c6},
+	{0xa0, 0x08, 0x01c6},	/* sharpness+ */
 	{0xa1, 0x01, 0x01c8},
 	{0xa1, 0x01, 0x01c9},
 	{0xa1, 0x01, 0x01ca},
-	{0xa0, 0x0f, 0x01cb},
+	{0xa0, 0x0f, 0x01cb},	/* sharpness- */
 
 	{0xa0, 0x50, 0x010a},	/* matrix */
 	{0xa0, 0xf8, 0x010b},
@@ -2424,7 +2457,7 @@
 	{0xa0, 0x40, 0x0117},
 	{0xa0, 0x40, 0x0118},
 /*	{0xa0, 0x02, 0x0008}, */
-	{0, 0, 0}
+	{}
 };
 
 static struct usb_action hv7131cxx_Initial[] = {
@@ -2478,11 +2511,11 @@
 
 	{0xa1, 0x01, 0x0008},
 	{0xa0, 0x03, 0x0008},	/* clock ? */
-	{0xa0, 0x08, 0x01c6},
+	{0xa0, 0x08, 0x01c6},	/* sharpness+ */
 	{0xa1, 0x01, 0x01c8},
 	{0xa1, 0x01, 0x01c9},
 	{0xa1, 0x01, 0x01ca},
-	{0xa0, 0x0f, 0x01cb},
+	{0xa0, 0x0f, 0x01cb},	/* sharpness- */
 
 	{0xa0, 0x60, 0x010a},	/* matrix */
 	{0xa0, 0xf0, 0x010b},
@@ -2518,7 +2551,7 @@
 	{0xa0, 0x40, 0x0180},
 	{0xa1, 0x01, 0x0180},
 	{0xa0, 0x42, 0x0180},
-	{0, 0, 0}
+	{}
 };
 
 static struct usb_action hv7131cxx_InitialScale[] = {
@@ -2577,11 +2610,11 @@
 
 	{0xa1, 0x01, 0x0008},
 	{0xa0, 0x03, 0x0008},	/* clock ? */
-	{0xa0, 0x08, 0x01c6},
+	{0xa0, 0x08, 0x01c6},	/* sharpness+ */
 	{0xa1, 0x01, 0x01c8},
 	{0xa1, 0x01, 0x01c9},
 	{0xa1, 0x01, 0x01ca},
-	{0xa0, 0x0f, 0x01cb},
+	{0xa0, 0x0f, 0x01cb},	/* sharpness- */
 
 	{0xa0, 0x60, 0x010a},	/* matrix */
 	{0xa0, 0xf0, 0x010b},
@@ -2619,7 +2652,7 @@
 	{0xa0, 0x40, 0x0180},
 	{0xa1, 0x01, 0x0180},
 	{0xa0, 0x42, 0x0180},
-	{0, 0, 0}
+	{}
 };
 
 static struct usb_action icm105axx_Initial[] = {
@@ -2743,11 +2776,11 @@
 	{0xa1, 0x01, 0x0008},
 
 	{0xa0, 0x03, 0x0008},	/* clock ? */
-	{0xa0, 0x08, 0x01c6},
+	{0xa0, 0x08, 0x01c6},	/* sharpness+ */
 	{0xa1, 0x01, 0x01c8},
 	{0xa1, 0x01, 0x01c9},
 	{0xa1, 0x01, 0x01ca},
-	{0xa0, 0x0f, 0x01cb},
+	{0xa0, 0x0f, 0x01cb},	/* sharpness- */
 	{0xa0, 0x52, 0x010a},	/* matrix */
 	{0xa0, 0xf7, 0x010b},
 	{0xa0, 0xf7, 0x010c},
@@ -2796,7 +2829,7 @@
 	{0xa0, 0x40, 0x0116},
 	{0xa0, 0x40, 0x0117},
 	{0xa0, 0x40, 0x0118},
-	{0, 0, 0}
+	{}
 };
 
 static struct usb_action icm105axx_InitialScale[] = {
@@ -2924,11 +2957,11 @@
 	{0xa1, 0x01, 0x0008},
 
 	{0xa0, 0x03, 0x0008},	/* clock ? */
-	{0xa0, 0x08, 0x01c6},
+	{0xa0, 0x08, 0x01c6},	/* sharpness+ */
 	{0xa1, 0x01, 0x01c8},
 	{0xa1, 0x01, 0x01c9},
 	{0xa1, 0x01, 0x01ca},
-	{0xa0, 0x0f, 0x01cb},
+	{0xa0, 0x0f, 0x01cb},	/* sharpness- */
 
 	{0xa0, 0x52, 0x010a},	/* matrix */
 	{0xa0, 0xf7, 0x010b},
@@ -2976,7 +3009,7 @@
 	{0xa0, 0x40, 0x0116},
 	{0xa0, 0x40, 0x0117},
 	{0xa0, 0x40, 0x0118},
-	{0, 0, 0}
+	{}
 };
 static struct usb_action icm105a_50HZ[] = {
 	{0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
@@ -3007,7 +3040,7 @@
 	{0xa0, 0xd8, 0x001e}, /* 00,1e,d8,cc */
 	{0xa0, 0xea, 0x001f}, /* 00,1f,ea,cc */
 	{0xa0, 0xff, 0x0020}, /* 00,20,ff,cc */
-	{0, 0, 0}
+	{}
 };
 static struct usb_action icm105a_50HZScale[] = {
 	{0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
@@ -3040,7 +3073,7 @@
 	{0xa0, 0xff, 0x0020}, /* 00,20,ff,cc */
 	{0xa0, 0x00, 0x01a7}, /* 01,a7,00,cc */
 	{0xa0, 0xc0, 0x01a8}, /* 01,a8,c0,cc */
-	{0, 0, 0}
+	{}
 };
 static struct usb_action icm105a_60HZ[] = {
 	{0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
@@ -3071,7 +3104,7 @@
 	{0xa0, 0xd4, 0x001e}, /* 00,1e,d4,cc */
 	{0xa0, 0xe8, 0x001f}, /* 00,1f,e8,cc */
 	{0xa0, 0xff, 0x0020}, /* 00,20,ff,cc */
-	{0, 0, 0}
+	{}
 };
 static struct usb_action icm105a_60HZScale[] = {
 	{0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
@@ -3104,7 +3137,7 @@
 	{0xa0, 0xff, 0x0020}, /* 00,20,ff,cc */
 	{0xa0, 0x00, 0x01a7}, /* 01,a7,00,cc */
 	{0xa0, 0xc0, 0x01a8}, /* 01,a8,c0,cc */
-	{0, 0, 0}
+	{}
 };
 static struct usb_action icm105a_NoFliker[] = {
 	{0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
@@ -3135,7 +3168,7 @@
 	{0xa0, 0xd4, 0x001e}, /* 00,1e,d4,cc */
 	{0xa0, 0xe8, 0x001f}, /* 00,1f,e8,cc */
 	{0xa0, 0xff, 0x0020}, /* 00,20,ff,cc */
-	{0, 0, 0}
+	{}
 };
 static struct usb_action icm105a_NoFlikerScale[] = {
 	{0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
@@ -3168,7 +3201,7 @@
 	{0xa0, 0xff, 0x0020}, /* 00,20,ff,cc */
 	{0xa0, 0x00, 0x01a7}, /* 01,a7,00,cc */
 	{0xa0, 0xc0, 0x01a8}, /* 01,a8,c0,cc */
-	{0, 0, 0}
+	{}
 };
 
 static struct usb_action MC501CB_InitialScale[] = {
@@ -3288,7 +3321,7 @@
 	{0xaa, 0x36, 0x001d}, /* 00,36,1D,aa */
 	{0xaa, 0x37, 0x004c}, /* 00,37,4C,aa */
 	{0xaa, 0x3b, 0x001d}, /* 00,3B,1D,aa */
-	{0, 0, 0}
+	{}
 };
 
 static struct usb_action MC501CB_Initial[] = {	 /* 320x240 */
@@ -3407,7 +3440,7 @@
 	{0xaa, 0x36, 0x001d}, /* 00,36,1D,aa */
 	{0xaa, 0x37, 0x004c}, /* 00,37,4C,aa */
 	{0xaa, 0x3b, 0x001d}, /* 00,3B,1D,aa */
-	{0, 0, 0}
+	{}
 };
 
 static struct usb_action MC501CB_50HZ[] = {
@@ -3424,7 +3457,7 @@
 	{0xaa, 0x36, 0x003a}, /* 00,36,3A,aa */
 	{0xaa, 0x37, 0x0098}, /* 00,37,98,aa */
 	{0xaa, 0x3b, 0x003a}, /* 00,3B,3A,aa */
-	{0, 0, 0}
+	{}
 };
 
 static struct usb_action MC501CB_50HZScale[] = {
@@ -3441,7 +3474,7 @@
 	{0xaa, 0x36, 0x0018}, /* 00,36,18,aa */
 	{0xaa, 0x37, 0x006a}, /* 00,37,6A,aa */
 	{0xaa, 0x3d, 0x0018}, /* 00,3D,18,aa */
-	{0, 0, 0}
+	{}
 };
 
 static struct usb_action MC501CB_60HZ[] = {
@@ -3458,7 +3491,7 @@
 	{0xaa, 0x36, 0x0030}, /* 00,36,30,aa */
 	{0xaa, 0x37, 0x00d4}, /* 00,37,D4,aa */
 	{0xaa, 0x3d, 0x0030}, /* 00,3D,30,aa */
-	{0, 0, 0}
+	{}
 };
 
 static struct usb_action MC501CB_60HZScale[] = {
@@ -3475,7 +3508,7 @@
 	{0xaa, 0x36, 0x0018}, /* 00,36,18,aa */
 	{0xaa, 0x37, 0x006a}, /* 00,37,6A,aa */
 	{0xaa, 0x3d, 0x0018}, /* 00,3D,18,aa */
-	{0, 0, 0}
+	{}
 };
 
 static struct usb_action MC501CB_NoFliker[] = {
@@ -3492,7 +3525,7 @@
 	{0xaa, 0x36, 0x0030}, /* 00,36,30,aa */
 	{0xaa, 0x37, 0x00d4}, /* 00,37,D4,aa */
 	{0xaa, 0x3d, 0x0030}, /* 00,3D,30,aa */
-	{0, 0, 0}
+	{}
 };
 
 static struct usb_action MC501CB_NoFlikerScale[] = {
@@ -3504,7 +3537,7 @@
 	{0xaa, 0x3e, 0x00d4}, /* 00,3E,D4,aa */
 	{0xaa, 0x3b, 0x0030}, /* 00,3B,30,aa */
 	{0xaa, 0x3c, 0x00d4}, /* 00,3C,D4,aa */
-	{0, 0, 0}
+	{}
 };
 
 /* from zs211.inf - HKR,%OV7620%,Initial - 640x480 */
@@ -3575,7 +3608,7 @@
 	{0xa0, 0x40, 0x011d}, /* 01,1d,40,cc */
 	{0xa0, 0x02, 0x0180}, /* 01,80,02,cc */
 	{0xa0, 0x50, 0x01a8}, /* 01,a8,50,cc */
-	{0, 0, 0}
+	{}
 };
 
 /* from zs211.inf - HKR,%OV7620%,InitialScale - 320x240 */
@@ -3646,7 +3679,7 @@
 	{0xa0, 0x50, 0x011d}, /* 01,1d,50,cc */
 	{0xa0, 0x02, 0x0180}, /* 01,80,02,cc */
 	{0xa0, 0x50, 0x01a8}, /* 01,a8,50,cc */
-	{0, 0, 0}
+	{}
 };
 
 /* from zs211.inf - HKR,%OV7620%\AE,50HZ */
@@ -3665,7 +3698,7 @@
 	{0xaa, 0x10, 0x0082},	/* 00,10,82,aa */
 	{0xaa, 0x76, 0x0003},	/* 00,76,03,aa */
 /*	{0xa0, 0x40, 0x0002},	 * 00,02,40,cc - if mode0 (640x480) */
-	{0, 0, 0}
+	{}
 };
 
 /* from zs211.inf - HKR,%OV7620%\AE,60HZ */
@@ -3687,7 +3720,7 @@
 /* ?? in gspca v1, it was
 	{0xa0, 0x00, 0x0039},  * 00,00,00,dd *
 	{0xa1, 0x01, 0x0037},		*/
-	{0, 0, 0}
+	{}
 };
 
 /* from zs211.inf - HKR,%OV7620%\AE,NoFliker */
@@ -3707,7 +3740,7 @@
 /* ?? was
 	{0xa0, 0x00, 0x0039},  * 00,00,00,dd *
 	{0xa1, 0x01, 0x0037},		*/
-	{0, 0, 0}
+	{}
 };
 
 static struct usb_action ov7630c_Initial[] = {
@@ -3795,14 +3828,11 @@
 /* 0x03, */
 	{0xa1, 0x01, 0x0008},
 	{0xa0, 0x03, 0x0008},	/* clock ? */
-	{0xa0, 0x08, 0x01c6},
-/* 0x05, */
+	{0xa0, 0x08, 0x01c6},	/* sharpness+ */
 	{0xa1, 0x01, 0x01c8},
-/* 0x07, */
 	{0xa1, 0x01, 0x01c9},
-/* 0x0f, */
 	{0xa1, 0x01, 0x01ca},
-	{0xa0, 0x0f, 0x01cb},
+	{0xa0, 0x0f, 0x01cb},	/* sharpness- */
 	{0xa0, 0x01, 0x0120},	/* gamma 2 ?*/
 	{0xa0, 0x0c, 0x0121},
 	{0xa0, 0x1f, 0x0122},
@@ -3867,7 +3897,7 @@
 	{0xaa, 0x13, 0x0083},	/* 40 */
 	{0xa1, 0x01, 0x0180},
 	{0xa0, 0x42, 0x0180},
-	{0, 0, 0}
+	{}
 };
 
 static struct usb_action ov7630c_InitialScale[] = {
@@ -3954,14 +3984,11 @@
 
 	{0xa1, 0x01, 0x0008},
 	{0xa0, 0x03, 0x0008},	/* clock ? */
-	{0xa0, 0x08, 0x01c6},
-
+	{0xa0, 0x08, 0x01c6},	/* sharpness+ */
 	{0xa1, 0x01, 0x01c8},
-
 	{0xa1, 0x01, 0x01c9},
-
 	{0xa1, 0x01, 0x01ca},
-	{0xa0, 0x0f, 0x01cb},
+	{0xa0, 0x0f, 0x01cb},	/* sharpness- */
 	{0xa0, 0x16, 0x0120},	/* gamma ~4 */
 	{0xa0, 0x3a, 0x0121},
 	{0xa0, 0x5b, 0x0122},
@@ -4027,7 +4054,7 @@
 
 	{0xa1, 0x01, 0x0180},
 	{0xa0, 0x42, 0x0180},
-	{0, 0, 0}
+	{}
 };
 
 static struct usb_action pas106b_Initial_com[] = {
@@ -4041,7 +4068,7 @@
 	{0xa0, 0x03, 0x003a},
 	{0xa0, 0x0c, 0x003b},
 	{0xa0, 0x04, 0x0038},
-	{0, 0, 0}
+	{}
 };
 
 static struct usb_action pas106b_Initial[] = {	/* 176x144 */
@@ -4099,10 +4126,8 @@
 	{0xa0, 0x08, 0x0301},	/* EEPROMAccess */
 /* JPEG control */
 	{0xa0, 0x03, 0x0008},	/* ClockSetting */
-/* Unknown */
-	{0xa0, 0x08, 0x01c6},
-/* Sharpness */
-	{0xa0, 0x0f, 0x01cb},	/* Sharpness05 */
+	{0xa0, 0x08, 0x01c6},	/* sharpness+ */
+	{0xa0, 0x0f, 0x01cb},	/* sharpness- */
 /* Other registers */
 	{0xa0, 0x0d, 0x0100},	/* OperationMode */
 /* Auto exposure and white balance */
@@ -4113,9 +4138,8 @@
 	{0xa0, 0x08, 0x0301},	/* EEPROMAccess */
 /* JPEG control */
 	{0xa0, 0x03, 0x0008},	/* ClockSetting */
-/* Sharpness */
-	{0xa0, 0x08, 0x01c6},	/* Sharpness00 */
-	{0xa0, 0x0f, 0x01cb},	/* Sharpness05 */
+	{0xa0, 0x08, 0x01c6},	/* sharpness+ */
+	{0xa0, 0x0f, 0x01cb},	/* sharpness- */
 
 	{0xa0, 0x58, 0x010a},	/* matrix */
 	{0xa0, 0xf4, 0x010b},
@@ -4162,7 +4186,7 @@
 	{0xa0, 0x40, 0x0116},	/* RGain */
 	{0xa0, 0x40, 0x0117},	/* GGain */
 	{0xa0, 0x40, 0x0118},	/* BGain */
-	{0, 0, 0}
+	{}
 };
 
 static struct usb_action pas106b_InitialScale[] = {	/* 352x288 */
@@ -4221,10 +4245,8 @@
 	{0xa0, 0x08, 0x0301},	/* EEPROMAccess */
 /* JPEG control */
 	{0xa0, 0x03, 0x0008},	/* ClockSetting */
-/* Unknown */
-	{0xa0, 0x08, 0x01c6},
-/* Sharpness */
-	{0xa0, 0x0f, 0x01cb},	/* Sharpness05 */
+	{0xa0, 0x08, 0x01c6},	/* sharpness+ */
+	{0xa0, 0x0f, 0x01cb},	/* sharpness- */
 /* Other registers */
 	{0xa0, 0x0d, 0x0100},	/* OperationMode */
 /* Auto exposure and white balance */
@@ -4235,9 +4257,8 @@
 	{0xa0, 0x08, 0x0301},	/* EEPROMAccess */
 /* JPEG control */
 	{0xa0, 0x03, 0x0008},	/* ClockSetting */
-/* Sharpness */
-	{0xa0, 0x08, 0x01c6},	/* Sharpness00 */
-	{0xa0, 0x0f, 0x01cb},	/* Sharpness05 */
+	{0xa0, 0x08, 0x01c6},	/* sharpness+ */
+	{0xa0, 0x0f, 0x01cb},	/* sharpness- */
 
 	{0xa0, 0x58, 0x010a},	/* matrix */
 	{0xa0, 0xf4, 0x010b},
@@ -4289,7 +4310,7 @@
 
 	{0xa0, 0x00, 0x0007},	/* AutoCorrectEnable */
 	{0xa0, 0xff, 0x0018},	/* Frame adjust */
-	{0, 0, 0}
+	{}
 };
 static struct usb_action pas106b_50HZ[] = {
 	{0xa0, 0x00, 0x0190}, /* 01,90,00,cc */
@@ -4305,7 +4326,7 @@
 	{0xaa, 0x05, 0x0002}, /* 00,05,02,aa */
 	{0xaa, 0x07, 0x001c}, /* 00,07,1c,aa */
 	{0xa0, 0x04, 0x01a9}, /* 01,a9,04,cc */
-	{0, 0, 0}
+	{}
 };
 static struct usb_action pas106b_60HZ[] = {
 	{0xa0, 0x00, 0x0190}, /* 01,90,00,cc */
@@ -4321,7 +4342,7 @@
 	{0xaa, 0x05, 0x0001}, /* 00,05,01,aa */
 	{0xaa, 0x07, 0x00c4}, /* 00,07,c4,aa */
 	{0xa0, 0x04, 0x01a9}, /* 01,a9,04,cc */
-	{0, 0, 0}
+	{}
 };
 static struct usb_action pas106b_NoFliker[] = {
 	{0xa0, 0x00, 0x0190}, /* 01,90,00,cc */
@@ -4337,10 +4358,9 @@
 	{0xaa, 0x05, 0x0001}, /* 00,05,01,aa */
 	{0xaa, 0x07, 0x0030}, /* 00,07,30,aa */
 	{0xa0, 0x00, 0x01a9}, /* 01,a9,00,cc */
-	{0, 0, 0}
+	{}
 };
 
-/* Aurelien setting from snoop */
 static struct usb_action pb03303x_Initial[] = {
 	{0xa0, 0x01, 0x0000},
 	{0xa0, 0x03, 0x0008},
@@ -4411,11 +4431,11 @@
 
 	{0xa1, 0x01, 0x0008},
 	{0xa0, 0x03, 0x0008},	/* clock ? */
-	{0xa0, 0x08, 0x01c6},
+	{0xa0, 0x08, 0x01c6},	/* sharpness+ */
 	{0xa1, 0x01, 0x01c8},
 	{0xa1, 0x01, 0x01c9},
 	{0xa1, 0x01, 0x01ca},
-	{0xa0, 0x0f, 0x01cb},
+	{0xa0, 0x0f, 0x01cb},	/* sharpness- */
 	{0xa0, 0x13, 0x0120},	/* gamma 4 */
 	{0xa0, 0x38, 0x0121},
 	{0xa0, 0x59, 0x0122},
@@ -4484,7 +4504,7 @@
 	{0xa0, 0x40, 0x0180},
 	{0xa1, 0x01, 0x0180},
 	{0xa0, 0x42, 0x0180},
-	{0, 0, 0}
+	{}
 };
 
 static struct usb_action pb03303x_InitialScale[] = {
@@ -4559,11 +4579,11 @@
 
 	{0xa1, 0x01, 0x0008},
 	{0xa0, 0x03, 0x0008},	/* clock ? */
-	{0xa0, 0x08, 0x01c6},
+	{0xa0, 0x08, 0x01c6},	/* sharpness+ */
 	{0xa1, 0x01, 0x01c8},
 	{0xa1, 0x01, 0x01c9},
 	{0xa1, 0x01, 0x01ca},
-	{0xa0, 0x0f, 0x01cb},
+	{0xa0, 0x0f, 0x01cb},	/* sharpness- */
 
 	{0xa0, 0x13, 0x0120},	/* gamma 4 */
 	{0xa0, 0x38, 0x0121},
@@ -4633,7 +4653,7 @@
 	{0xa0, 0x40, 0x0180},
 	{0xa1, 0x01, 0x0180},
 	{0xa0, 0x42, 0x0180},
-	{0, 0, 0}
+	{}
 };
 static struct usb_action pb0330xx_Initial[] = {
 	{0xa1, 0x01, 0x0008},
@@ -4701,11 +4721,11 @@
 	{0xa0, 0x50, 0x0112},
 	{0xa1, 0x01, 0x0008},
 	{0xa0, 0x03, 0x0008},	/* clock ? */
-	{0xa0, 0x08, 0x01c6},
+	{0xa0, 0x08, 0x01c6},	/* sharpness+ */
 	{0xa1, 0x01, 0x01c8},
 	{0xa1, 0x01, 0x01c9},
 	{0xa1, 0x01, 0x01ca},
-	{0xa0, 0x0f, 0x01cb},
+	{0xa0, 0x0f, 0x01cb},	/* sharpness- */
 
 	{0xa0, 0x50, 0x010a},	/* matrix */
 	{0xa0, 0xf8, 0x010b},
@@ -4747,7 +4767,7 @@
 	{0xa1, 0x01, 0x0007},
 /*	{0xa0, 0x30, 0x0007}, */
 /*	{0xa0, 0x00, 0x0007}, */
-	{0, 0, 0}
+	{}
 };
 
 static struct usb_action pb0330xx_InitialScale[] = {
@@ -4816,11 +4836,11 @@
 	{0xa0, 0x50, 0x0112},
 	{0xa1, 0x01, 0x0008},
 	{0xa0, 0x03, 0x0008},	/* clock ? */
-	{0xa0, 0x08, 0x01c6},
+	{0xa0, 0x08, 0x01c6},	/* sharpness+ */
 	{0xa1, 0x01, 0x01c8},
 	{0xa1, 0x01, 0x01c9},
 	{0xa1, 0x01, 0x01ca},
-	{0xa0, 0x0f, 0x01cb},
+	{0xa0, 0x0f, 0x01cb},	/* sharpness- */
 
 	{0xa0, 0x50, 0x010a},	/* matrix */
 	{0xa0, 0xf8, 0x010b},
@@ -4861,7 +4881,7 @@
 	{0xa1, 0x01, 0x0007},
 /*	{0xa0, 0x30, 0x0007}, */
 /*	{0xa0, 0x00, 0x0007}, */
-	{0, 0, 0}
+	{}
 };
 static struct usb_action pb0330_50HZ[] = {
 	{0xa0, 0x00, 0x0190}, /* 01,90,00,cc */
@@ -4877,7 +4897,7 @@
 	{0xa0, 0x68, 0x001d}, /* 00,1d,68,cc */
 	{0xa0, 0x90, 0x001e}, /* 00,1e,90,cc */
 	{0xa0, 0xc8, 0x001f}, /* 00,1f,c8,cc */
-	{0, 0, 0}
+	{}
 };
 static struct usb_action pb0330_50HZScale[] = {
 	{0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
@@ -4894,7 +4914,7 @@
 	{0xa0, 0xe5, 0x001d}, /* 00,1d,e5,cc */
 	{0xa0, 0xf0, 0x001e}, /* 00,1e,f0,cc */
 	{0xa0, 0xf8, 0x001f}, /* 00,1f,f8,cc */
-	{0, 0, 0}
+	{}
 };
 static struct usb_action pb0330_60HZ[] = {
 	{0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
@@ -4911,7 +4931,7 @@
 	{0xa0, 0x43, 0x001d}, /* 00,1d,43,cc */
 	{0xa0, 0x50, 0x001e}, /* 00,1e,50,cc */
 	{0xa0, 0x90, 0x001f}, /* 00,1f,90,cc */
-	{0, 0, 0}
+	{}
 };
 static struct usb_action pb0330_60HZScale[] = {
 	{0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
@@ -4928,7 +4948,7 @@
 	{0xa0, 0x41, 0x001d}, /* 00,1d,41,cc */
 	{0xa0, 0x50, 0x001e}, /* 00,1e,50,cc */
 	{0xa0, 0x90, 0x001f}, /* 00,1f,90,cc */
-	{0, 0, 0}
+	{}
 };
 static struct usb_action pb0330_NoFliker[] = {
 	{0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
@@ -4945,7 +4965,7 @@
 	{0xa0, 0x09, 0x001d}, /* 00,1d,09,cc */
 	{0xa0, 0x40, 0x001e}, /* 00,1e,40,cc */
 	{0xa0, 0x90, 0x001f}, /* 00,1f,90,cc */
-	{0, 0, 0}
+	{}
 };
 static struct usb_action pb0330_NoFlikerScale[] = {
 	{0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
@@ -4962,7 +4982,7 @@
 	{0xa0, 0x09, 0x001d}, /* 00,1d,09,cc */
 	{0xa0, 0x40, 0x001e}, /* 00,1e,40,cc */
 	{0xa0, 0x90, 0x001f}, /* 00,1f,90,cc */
-	{0, 0, 0}
+	{}
 };
 
 /* from oem9.inf - HKR,%PO2030%,Initial - 640x480 - (close to CS2102) */
@@ -5039,7 +5059,7 @@
 	{0xa0, 0x08, 0x0301}, /* 03,01,08,cc */
 	{0xa0, 0x7a, 0x0116}, /* 01,16,7a,cc */
 	{0xa0, 0x4a, 0x0118}, /* 01,18,4a,cc */
-	{0, 0, 0}
+	{}
 };
 
 /* from oem9.inf - HKR,%PO2030%,InitialScale - 320x240 */
@@ -5116,7 +5136,7 @@
 	{0xa0, 0x08, 0x0301}, /* 03,01,08,cc */
 	{0xa0, 0x7a, 0x0116}, /* 01,16,7a,cc */
 	{0xa0, 0x4a, 0x0118}, /* 01,18,4a,cc */
-	{0, 0, 0}
+	{}
 };
 
 static struct usb_action PO2030_50HZ[] = {
@@ -5138,7 +5158,7 @@
 	{0xa0, 0x88, 0x018d}, /* 01,8d,88,cc */
 	{0xa0, 0x58, 0x011d}, /* 01,1d,58,cc */
 	{0xa0, 0x42, 0x0180}, /* 01,80,42,cc */
-	{0, 0, 0}
+	{}
 };
 
 static struct usb_action PO2030_60HZ[] = {
@@ -5160,7 +5180,7 @@
 	{0xa0, 0x88, 0x018d}, /* 01,8d,88,cc */	/* win: 01,8d,80 */
 	{0xa0, 0x58, 0x011d}, /* 01,1d,58,cc */
 	{0xa0, 0x42, 0x0180}, /* 01,80,42,cc */
-	{0, 0, 0}
+	{}
 };
 
 static struct usb_action PO2030_NoFliker[] = {
@@ -5171,7 +5191,7 @@
 	{0xaa, 0x1c, 0x0078}, /* 00,1c,78,aa */
 	{0xaa, 0x46, 0x0000}, /* 00,46,00,aa */
 	{0xaa, 0x15, 0x0000}, /* 00,15,00,aa */
-	{0, 0, 0}
+	{}
 };
 
 /* TEST */
@@ -5302,8 +5322,8 @@
 	{0xa0, 0x03, 0x0111},
 	{0xa0, 0x51, 0x0112},
 	{0xa0, 0x03, 0x0008},
-	{0xa0, 0x08, 0x01c6},
-	{0xa0, 0x0f, 0x01cb},
+	{0xa0, 0x08, 0x01c6},	/* sharpness+ */
+	{0xa0, 0x0f, 0x01cb},	/* sharpness- */
 	{0xa0, 0x38, 0x0120},	/* gamma > 5 */
 	{0xa0, 0x51, 0x0121},
 	{0xa0, 0x6e, 0x0122},
@@ -5375,7 +5395,7 @@
 	{0xa0, 0x15, 0x01ae},
 	{0xa0, 0x40, 0x0180},
 	{0xa0, 0x42, 0x0180},
-	{0, 0, 0}
+	{}
 };
 
 static struct usb_action tas5130CK_InitialScale[] = {
@@ -5505,8 +5525,8 @@
 	{0xa0, 0x03, 0x0111},
 	{0xa0, 0x51, 0x0112},
 	{0xa0, 0x03, 0x0008},
-	{0xa0, 0x08, 0x01c6},
-	{0xa0, 0x0f, 0x01cb},
+	{0xa0, 0x08, 0x01c6},	/* sharpness+ */
+	{0xa0, 0x0f, 0x01cb},	/* sharpness- */
 	{0xa0, 0x38, 0x0120},	/* gamma > 5 */
 	{0xa0, 0x51, 0x0121},
 	{0xa0, 0x6e, 0x0122},
@@ -5583,7 +5603,7 @@
 	{0xa0, 0x02, 0x0008},
 	{0xa0, 0x00, 0x0007},
 	{0xa0, 0x03, 0x0008},
-	{0, 0, 0}
+	{}
 };
 
 static struct usb_action tas5130cxx_Initial[] = {
@@ -5625,11 +5645,11 @@
 	{0xa1, 0x01, 0x0002},
 	{0xa1, 0x01, 0x0008},
 	{0xa0, 0x03, 0x0008},	/* clock ? */
-	{0xa0, 0x08, 0x01c6},
+	{0xa0, 0x08, 0x01c6},	/* sharpness+ */
 	{0xa1, 0x01, 0x01c8},
 	{0xa1, 0x01, 0x01c9},
 	{0xa1, 0x01, 0x01ca},
-	{0xa0, 0x0f, 0x01cb},
+	{0xa0, 0x0f, 0x01cb},	/* sharpness- */
 
 	{0xa0, 0x68, 0x010a},	/* matrix */
 	{0xa0, 0xec, 0x010b},
@@ -5673,7 +5693,7 @@
 	{0xa0, 0x40, 0x0180},
 	{0xa1, 0x01, 0x0180},
 	{0xa0, 0x42, 0x0180},
-	{0, 0, 0}
+	{}
 };
 static struct usb_action tas5130cxx_InitialScale[] = {
 	{0xa0, 0x01, 0x0000},
@@ -5718,11 +5738,11 @@
 
 	{0xa0, 0x03, 0x0008},
 	{0xa1, 0x01, 0x0008},	/* clock ? */
-	{0xa0, 0x08, 0x01c6},
+	{0xa0, 0x08, 0x01c6},	/* sharpness+ */
 	{0xa1, 0x01, 0x01c8},
 	{0xa1, 0x01, 0x01c9},
 	{0xa1, 0x01, 0x01ca},
-	{0xa0, 0x0f, 0x01cb},
+	{0xa0, 0x0f, 0x01cb},	/* sharpness- */
 
 	{0xa0, 0x68, 0x010a},	/* matrix */
 	{0xa0, 0xec, 0x010b},
@@ -5763,7 +5783,7 @@
 	{0xa0, 0x40, 0x0180},
 	{0xa1, 0x01, 0x0180},
 	{0xa0, 0x42, 0x0180},
-	{0, 0, 0}
+	{}
 };
 static struct usb_action tas5130cxx_50HZ[] = {
 	{0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
@@ -5786,7 +5806,7 @@
 	{0xa0, 0xea, 0x001f}, /* 00,1f,ea,cc */
 	{0xa0, 0xff, 0x0020}, /* 00,20,ff,cc */
 	{0xa0, 0x03, 0x009f}, /* 00,9f,03,cc */
-	{0, 0, 0}
+	{}
 };
 static struct usb_action tas5130cxx_50HZScale[] = {
 	{0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
@@ -5809,7 +5829,7 @@
 	{0xa0, 0xf8, 0x001f}, /* 00,1f,f8,cc */
 	{0xa0, 0xff, 0x0020}, /* 00,20,ff,cc */
 	{0xa0, 0x03, 0x009f}, /* 00,9f,03,cc */
-	{0, 0, 0}
+	{}
 };
 static struct usb_action tas5130cxx_60HZ[] = {
 	{0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
@@ -5832,7 +5852,7 @@
 	{0xa0, 0xe0, 0x001f}, /* 00,1f,e0,cc */
 	{0xa0, 0xff, 0x0020}, /* 00,20,ff,cc */
 	{0xa0, 0x03, 0x009f}, /* 00,9f,03,cc */
-	{0, 0, 0}
+	{}
 };
 static struct usb_action tas5130cxx_60HZScale[] = {
 	{0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
@@ -5855,7 +5875,7 @@
 	{0xa0, 0xe0, 0x001f}, /* 00,1f,e0,cc */
 	{0xa0, 0xff, 0x0020}, /* 00,20,ff,cc */
 	{0xa0, 0x03, 0x009f}, /* 00,9f,03,cc */
-	{0, 0, 0}
+	{}
 };
 static struct usb_action tas5130cxx_NoFliker[] = {
 	{0xa0, 0x00, 0x0019}, /* 00,19,00,cc */
@@ -5878,7 +5898,7 @@
 	{0xa0, 0xe0, 0x001f}, /* 00,1f,e0,cc */
 	{0xa0, 0xff, 0x0020}, /* 00,20,ff,cc */
 	{0xa0, 0x02, 0x009f}, /* 00,9f,02,cc */
-	{0, 0, 0}
+	{}
 };
 
 static struct usb_action tas5130cxx_NoFlikerScale[] = {
@@ -5902,7 +5922,7 @@
 	{0xa0, 0xe0, 0x001f}, /* 00,1f,e0,cc */
 	{0xa0, 0xff, 0x0020}, /* 00,20,ff,cc */
 	{0xa0, 0x02, 0x009f}, /* 00,9f,02,cc */
-	{0, 0, 0}
+	{}
 };
 
 static struct usb_action tas5130c_vf0250_Initial[] = {
@@ -5966,7 +5986,7 @@
 	{0xa0, 0x60, 0x01a8},		/* 01,a8,60,cc, */
 	{0xa0, 0x61, 0x0116},		/* 01,16,61,cc, */
 	{0xa0, 0x65, 0x0118},		/* 01,18,65,cc */
-	{0, 0, 0}
+	{}
 };
 
 static struct usb_action tas5130c_vf0250_InitialScale[] = {
@@ -6030,7 +6050,7 @@
 	{0xa0, 0x60, 0x01a8},		/* 01,a8,60,cc, */
 	{0xa0, 0x61, 0x0116},		/* 01,16,61,cc, */
 	{0xa0, 0x65, 0x0118},		/* 01,18,65,cc */
-	{0, 0, 0}
+	{}
 };
 /* "50HZ" light frequency banding filter */
 static struct usb_action tas5130c_vf0250_50HZ[] = {
@@ -6054,7 +6074,7 @@
 	{0xa0, 0x58, 0x011d},		/* 01,1d,58,cc, */
 	{0xa0, 0x42, 0x0180},		/* 01,80,42,cc, */
 	{0xa0, 0x78, 0x018d},		/* 01,8d,78,cc */
-	{0, 0, 0}
+	{}
 };
 
 /* "50HZScale" light frequency banding filter */
@@ -6079,7 +6099,7 @@
 	{0xa0, 0x58, 0x011d},		/* 01,1d,58,cc, */
 	{0xa0, 0x42, 0x0180},		/* 01,80,42,cc, */
 	{0xa0, 0x78, 0x018d},		/* 01,8d,78,cc */
-	{0, 0, 0}
+	{}
 };
 
 /* "60HZ" light frequency banding filter */
@@ -6104,7 +6124,7 @@
 	{0xa0, 0x58, 0x011d},		/* 01,1d,58,cc, */
 	{0xa0, 0x42, 0x0180},		/* 01,80,42,cc, */
 	{0xa0, 0x78, 0x018d},		/* 01,8d,78,cc */
-	{0, 0, 0}
+	{}
 };
 
 /* "60HZScale" light frequency banding ilter */
@@ -6129,7 +6149,7 @@
 	{0xa0, 0x58, 0x011d},		/* 01,d,58,cc, */
 	{0xa0, 0x42, 0x0180},		/* 01,80,42,cc, */
 	{0xa0, 0x78, 0x018d},		/* 01,d,78,cc */
-	{0, 0, 0}
+	{}
 };
 
 /* "NoFliker" light frequency banding flter */
@@ -6152,7 +6172,7 @@
 	{0xa0, 0xff, 0x0020},		/* 00,20,ff,cc, */
 	{0xa0, 0x58, 0x011d},		/* 01,1d,58,cc, */
 	{0xa0, 0x03, 0x0180},		/* 01,80,03,cc */
-	{0, 0, 0}
+	{}
 };
 
 /* "NoFlikerScale" light frequency banding filter */
@@ -6175,7 +6195,7 @@
 	{0xa0, 0xff, 0x0020},		/* 00,20,ff,cc, */
 	{0xa0, 0x58, 0x011d},		/* 01,1d,58,cc, */
 	{0xa0, 0x03, 0x0180},		/* 01,80,03,cc */
-	{0, 0, 0}
+	{}
 };
 
 static void reg_r_i(struct usb_device *dev,
@@ -6325,7 +6345,7 @@
 	case SENSOR_PO2030:
 		return;
 	}
-/*fixme: is it really 011d 018d for all other sensors? */
+/*fixme: is it really write to 011d and 018d for all other sensors? */
 	brightness = sd->brightness;
 	reg_w(gspca_dev->dev, brightness, 0x011d);
 	if (brightness < 0x70)
@@ -6348,20 +6368,7 @@
 		{0x10, 0x1e}
 	};
 
-	switch (sd->sensor) {
-	case SENSOR_GC0305:
-		sharpness = 3;
-		break;
-	case SENSOR_OV7620:
-		sharpness = 2;
-		break;
-	case SENSOR_PO2030:
-		sharpness = 0;
-		break;
-	default:
-		return;
-	}
-/*fixme: sharpness set by V4L2_CID_SATURATION?*/
+	sharpness = sd->sharpness;
 	reg_w(dev, sharpness_tb[sharpness][0], 0x01c6);
 	reg_r(dev, 0x01c8, &retbyte);
 	reg_r(dev, 0x01c9, &retbyte);
@@ -6411,7 +6418,7 @@
 	static __u8 Tgradient_5[16] =
 		{0x37, 0x26, 0x20, 0x1a, 0x14, 0x10, 0x0e, 0x0b,
 		 0x09, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x02};
-	static __u8 Tgamma_6[16] =		/* ?? was gama 5 */
+	static __u8 Tgamma_6[16] =		/* ?? was gamma 5 */
 		{0x24, 0x44, 0x64, 0x84, 0x9d, 0xb2, 0xc4, 0xd3,
 		 0xe0, 0xeb, 0xf4, 0xff, 0xff, 0xff, 0xff, 0xff};
 	static __u8 Tgradient_6[16] =
@@ -6425,7 +6432,7 @@
 		0, Tgradient_1, Tgradient_2,
 		Tgradient_3, Tgradient_4, Tgradient_5, Tgradient_6
 	};
-#ifdef GSPCA_DEBUG
+#ifdef VIDEO_ADV_DEBUG
 	__u8 v[16];
 #endif
 
@@ -6443,7 +6450,7 @@
 		else if (g <= 0)
 			g = 1;
 		reg_w(dev, g, 0x0120 + i);	/* gamma */
-#ifdef GSPCA_DEBUG
+#ifdef VIDEO_ADV_DEBUG
 		if (gspca_debug & D_CONF)
 			v[i] = g;
 #endif
@@ -6463,7 +6470,7 @@
 				g = 1;
 		}
 		reg_w(dev, g, 0x0130 + i);	/* gradient */
-#ifdef GSPCA_DEBUG
+#ifdef VIDEO_ADV_DEBUG
 		if (gspca_debug & D_CONF)
 			v[i] = g;
 #endif
@@ -6488,7 +6495,7 @@
 		return;
 	}
 /*fixme: is it really 0008 0007 0018 for all other sensors? */
-	quality = sd->qindex & 0x0f;
+	quality = sd->qindex;
 	reg_w(dev, quality, 0x0008);
 	frxt = 0x30;
 	reg_w(dev, frxt, 0x0007);
@@ -6525,25 +6532,25 @@
 	struct usb_action *zc3_freq;
 	static struct usb_action *freq_tb[SENSOR_MAX][6] = {
 /* SENSOR_CS2102 0 */
-		{cs2102_50HZ, cs2102_50HZScale,
-		 cs2102_60HZ, cs2102_60HZScale,
-		 cs2102_NoFliker, cs2102_NoFlikerScale},
+		{cs2102_NoFliker, cs2102_NoFlikerScale,
+		 cs2102_50HZ, cs2102_50HZScale,
+		 cs2102_60HZ, cs2102_60HZScale},
 /* SENSOR_CS2102K 1 */
-		{cs2102_50HZ, cs2102_50HZScale,
-		 cs2102_60HZ, cs2102_60HZScale,
-		 cs2102_NoFliker, cs2102_NoFlikerScale},
+		{cs2102_NoFliker, cs2102_NoFlikerScale,
+		 cs2102_50HZ, cs2102_50HZScale,
+		 cs2102_60HZ, cs2102_60HZScale},
 /* SENSOR_GC0305 2 */
-		{gc0305_50HZ, gc0305_50HZ,
-		 gc0305_60HZ, gc0305_60HZ,
-		 gc0305_NoFliker, gc0305_NoFliker},
+		{gc0305_NoFliker, gc0305_NoFliker,
+		 gc0305_50HZ, gc0305_50HZ,
+		 gc0305_60HZ, gc0305_60HZ},
 /* SENSOR_HDCS2020 3 */
 		{0, 0,
 		 0, 0,
 		 0, 0},
 /* SENSOR_HDCS2020b 4 */
-		{hdcs2020b_50HZ, hdcs2020b_50HZ,
-		 hdcs2020b_60HZ, hdcs2020b_60HZ,
-		 hdcs2020b_NoFliker, hdcs2020b_NoFliker},
+		{hdcs2020b_NoFliker, hdcs2020b_NoFliker,
+		 hdcs2020b_50HZ, hdcs2020b_50HZ,
+		 hdcs2020b_60HZ, hdcs2020b_60HZ},
 /* SENSOR_HV7131B 5 */
 		{0, 0,
 		 0, 0,
@@ -6553,66 +6560,48 @@
 		 0, 0,
 		 0, 0},
 /* SENSOR_ICM105A 7 */
-		{icm105a_50HZ, icm105a_50HZScale,
-		 icm105a_60HZ, icm105a_60HZScale,
-		 icm105a_NoFliker, icm105a_NoFlikerScale},
+		{icm105a_NoFliker, icm105a_NoFlikerScale,
+		 icm105a_50HZ, icm105a_50HZScale,
+		 icm105a_60HZ, icm105a_60HZScale},
 /* SENSOR_MC501CB 8 */
-		{MC501CB_50HZ, MC501CB_50HZScale,
-		 MC501CB_60HZ, MC501CB_60HZScale,
-		 MC501CB_NoFliker, MC501CB_NoFlikerScale},
+		{MC501CB_NoFliker, MC501CB_NoFlikerScale,
+		 MC501CB_50HZ, MC501CB_50HZScale,
+		 MC501CB_60HZ, MC501CB_60HZScale},
 /* SENSOR_OV7620 9 */
-		{OV7620_50HZ, OV7620_50HZ,
-		 OV7620_60HZ, OV7620_60HZ,
-		 OV7620_NoFliker, OV7620_NoFliker},
+		{OV7620_NoFliker, OV7620_NoFliker,
+		 OV7620_50HZ, OV7620_50HZ,
+		 OV7620_60HZ, OV7620_60HZ},
 /* SENSOR_OV7630C 10 */
 		{0, 0,
 		 0, 0,
 		 0, 0},
-/* SENSOR_free 11 */
-		{0, 0,
-		 0, 0,
-		 0, 0},
-/* SENSOR_PAS106 12 */
-		{pas106b_50HZ, pas106b_50HZ,
-		 pas106b_60HZ, pas106b_60HZ,
-		 pas106b_NoFliker, pas106b_NoFliker},
-/* SENSOR_PB0330 13 */
-		{pb0330_50HZ, pb0330_50HZScale,
-		 pb0330_60HZ, pb0330_60HZScale,
-		 pb0330_NoFliker, pb0330_NoFlikerScale},
-/* SENSOR_PO2030 14 */
-		{PO2030_50HZ, PO2030_50HZ,
-		 PO2030_60HZ, PO2030_60HZ,
-		 PO2030_NoFliker, PO2030_NoFliker},
-/* SENSOR_TAS5130CK 15 */
-		{tas5130cxx_50HZ, tas5130cxx_50HZScale,
-		 tas5130cxx_60HZ, tas5130cxx_60HZScale,
-		 tas5130cxx_NoFliker, tas5130cxx_NoFlikerScale},
-/* SENSOR_TAS5130CXX 16 */
-		{tas5130cxx_50HZ, tas5130cxx_50HZScale,
-		 tas5130cxx_60HZ, tas5130cxx_60HZScale,
-		 tas5130cxx_NoFliker, tas5130cxx_NoFlikerScale},
-/* SENSOR_TAS5130C_VF0250 17 */
-		{tas5130c_vf0250_50HZ, tas5130c_vf0250_50HZScale,
-		 tas5130c_vf0250_60HZ, tas5130c_vf0250_60HZScale,
-		 tas5130c_vf0250_NoFliker, tas5130c_vf0250_NoFlikerScale},
+/* SENSOR_PAS106 11 */
+		{pas106b_NoFliker, pas106b_NoFliker,
+		 pas106b_50HZ, pas106b_50HZ,
+		 pas106b_60HZ, pas106b_60HZ},
+/* SENSOR_PB0330 12 */
+		{pb0330_NoFliker, pb0330_NoFlikerScale,
+		 pb0330_50HZ, pb0330_50HZScale,
+		 pb0330_60HZ, pb0330_60HZScale},
+/* SENSOR_PO2030 13 */
+		{PO2030_NoFliker, PO2030_NoFliker,
+		 PO2030_50HZ, PO2030_50HZ,
+		 PO2030_60HZ, PO2030_60HZ},
+/* SENSOR_TAS5130CK 14 */
+		{tas5130cxx_NoFliker, tas5130cxx_NoFlikerScale,
+		 tas5130cxx_50HZ, tas5130cxx_50HZScale,
+		 tas5130cxx_60HZ, tas5130cxx_60HZScale},
+/* SENSOR_TAS5130CXX 15 */
+		{tas5130cxx_NoFliker, tas5130cxx_NoFlikerScale,
+		 tas5130cxx_50HZ, tas5130cxx_50HZScale,
+		 tas5130cxx_60HZ, tas5130cxx_60HZScale},
+/* SENSOR_TAS5130C_VF0250 16 */
+		{tas5130c_vf0250_NoFliker, tas5130c_vf0250_NoFlikerScale,
+		 tas5130c_vf0250_50HZ, tas5130c_vf0250_50HZScale,
+		 tas5130c_vf0250_60HZ, tas5130c_vf0250_60HZScale},
 	};
 
-	switch (lightfreq) {
-	case 50:
-		i = 0;
-		break;
-	case 60:
-		i = 2;
-		break;
-	default:
-		PDEBUG(D_ERR, "Invalid light freq value %d", lightfreq);
-		lightfreq = 0;		/* set to default filter value */
-		/* fall thru */
-	case 0:
-		i = 4;
-		break;
-	}
+	i = sd->lightfreq * 2;
 	mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].mode;
 	if (!mode)
 		i++;			/* 640x480 */
@@ -6622,13 +6611,13 @@
 		switch (sd->sensor) {
 		case SENSOR_GC0305:
 			if (mode			/* if 320x240 */
-			    && lightfreq == 50)
+			    && sd->lightfreq == 1)	/* and 50Hz */
 				reg_w(gspca_dev->dev, 0x85, 0x018d);
 						/* win: 0x80, 0x018d */
 			break;
 		case SENSOR_OV7620:
 			if (!mode) {			/* if 640x480 */
-				if (lightfreq != 0)	/* 50 or 60 Hz */
+				if (sd->lightfreq != 0)	/* and 50 or 60 Hz */
 					reg_w(gspca_dev->dev, 0x40, 0x0002);
 				else
 					reg_w(gspca_dev->dev, 0x44, 0x0002);
@@ -6653,9 +6642,9 @@
 
 static void send_unknown(struct usb_device *dev, int sensor)
 {
+	reg_w(dev, 0x01, 0x0000);		/* led off */
 	switch (sensor) {
 	case SENSOR_PAS106:
-		reg_w(dev, 0x01, 0x0000);
 		reg_w(dev, 0x03, 0x003a);
 		reg_w(dev, 0x0c, 0x003b);
 		reg_w(dev, 0x08, 0x0038);
@@ -6664,7 +6653,6 @@
 	case SENSOR_OV7620:
 	case SENSOR_PB0330:
 	case SENSOR_PO2030:
-		reg_w(dev, 0x01, 0x0000);
 		reg_w(dev, 0x0d, 0x003a);
 		reg_w(dev, 0x02, 0x003b);
 		reg_w(dev, 0x00, 0x0038);
@@ -6817,7 +6805,7 @@
 
 /*fixme: lack of 8b=b3 (11,12)-> 10, 8b=e0 (14,15,16)-> 12 found in gspcav1*/
 	reg_w(dev, 0x02, 0x0010);
-	reg_r(dev, 0x0010, &retbyte);
+	reg_r(dev, 0x10, &retbyte);
 	reg_w(dev, 0x01, 0x0000);
 	reg_w(dev, 0x00, 0x0010);
 	reg_w(dev, 0x01, 0x0001);
@@ -6964,7 +6952,7 @@
 	int sensor;
 	__u8 bsensor;
 	int vga = 1;		/* 1: vga, 0: sif */
-	static unsigned char gamma[SENSOR_MAX] = {
+	static __u8 gamma[SENSOR_MAX] = {
 		5,	/* SENSOR_CS2102 0 */
 		5,	/* SENSOR_CS2102K 1 */
 		4,	/* SENSOR_GC0305 2 */
@@ -6976,16 +6964,16 @@
 		4,	/* SENSOR_MC501CB 8 */
 		3,	/* SENSOR_OV7620 9 */
 		4,	/* SENSOR_OV7630C 10 */
-		4,	/* SENSOR_free 11 */
-		4,	/* SENSOR_PAS106 12 */
-		4,	/* SENSOR_PB0330 13 */
-		4,	/* SENSOR_PO2030 14 */
-		4,	/* SENSOR_TAS5130CK 15 */
-		4,	/* SENSOR_TAS5130CXX 16 */
-		3,	/* SENSOR_TAS5130C_VF0250 17 */
+		4,	/* SENSOR_PAS106 11 */
+		4,	/* SENSOR_PB0330 12 */
+		4,	/* SENSOR_PO2030 13 */
+		4,	/* SENSOR_TAS5130CK 14 */
+		4,	/* SENSOR_TAS5130CXX 15 */
+		3,	/* SENSOR_TAS5130C_VF0250 16 */
 	};
 
 	/* define some sensors from the vendor/product */
+	sd->sharpness = 2;
 	switch (id->idVendor) {
 	case 0x041e:				/* Creative */
 		switch (id->idProduct) {
@@ -7055,8 +7043,9 @@
 			sd->sensor = SENSOR_ICM105A;
 			break;
 		case 0x0e:
-			PDEBUG(D_PROBE, "Find Sensor PAS202BCB");
+			PDEBUG(D_PROBE, "Find Sensor HDCS2020");
 			sd->sensor = SENSOR_HDCS2020;
+			sd->sharpness = 1;
 			break;
 		case 0x0f:
 			PDEBUG(D_PROBE, "Find Sensor PAS106");
@@ -7097,6 +7086,7 @@
 		case 0x2030:
 			PDEBUG(D_PROBE, "Find Sensor PO2030");
 			sd->sensor = SENSOR_PO2030;
+			sd->sharpness = 0;		/* from win traces */
 			break;
 		case 0x7620:
 			PDEBUG(D_PROBE, "Find Sensor OV7620");
@@ -7134,13 +7124,13 @@
 	sd->qindex = 1;
 	sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
 	sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
-	sd->autogain = sd_ctrls[SD_AUTOGAIN].qctrl.default_value;
 	sd->gamma = gamma[(int) sd->sensor];
+	sd->autogain = sd_ctrls[SD_AUTOGAIN].qctrl.default_value;
+	sd->lightfreq = sd_ctrls[SD_FREQ].qctrl.default_value;
+	sd->sharpness = sd_ctrls[SD_SHARPNESS].qctrl.default_value;
 
 	/* switch the led off */
-/*fixme: other sensors? */
-	if (sensor == 0x06 || sensor == 0x11)
-		reg_w(gspca_dev->dev, 0x01, 0x0000);
+	reg_w(gspca_dev->dev, 0x01, 0x0000);
 	return 0;
 }
 
@@ -7170,15 +7160,14 @@
 		{MC501CB_InitialScale, MC501CB_Initial},	/* 9 */
 		{OV7620_mode0, OV7620_mode1},			/* 9 */
 		{ov7630c_InitialScale, ov7630c_Initial},	/* 10 */
-		{0, 0},						/* 11 */
-		{pas106b_InitialScale, pas106b_Initial},	/* 12 */
-		{pb0330xx_InitialScale, pb0330xx_Initial},	/* 13 */
+		{pas106b_InitialScale, pas106b_Initial},	/* 11 */
+		{pb0330xx_InitialScale, pb0330xx_Initial},	/* 12 */
 /* or		{pb03303x_InitialScale, pb03303x_Initial}, */
-		{PO2030_mode0, PO2030_mode1},			/* 14 */
-		{tas5130CK_InitialScale, tas5130CK_Initial},	/* 15 */
-		{tas5130cxx_InitialScale, tas5130cxx_Initial},	/* 16 */
+		{PO2030_mode0, PO2030_mode1},			/* 13 */
+		{tas5130CK_InitialScale, tas5130CK_Initial},	/* 14 */
+		{tas5130cxx_InitialScale, tas5130cxx_Initial},	/* 15 */
 		{tas5130c_vf0250_InitialScale, tas5130c_vf0250_Initial},
-								/* 17 */
+								/* 16 */
 	};
 
 	mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].mode;
@@ -7324,7 +7313,7 @@
 
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 			struct gspca_frame *frame,
-			unsigned char *data,
+			__u8 *data,
 			int len)
 {
 
@@ -7401,6 +7390,16 @@
 	return 0;
 }
 
+static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->gamma = val;
+	if (gspca_dev->streaming)
+		setcontrast(gspca_dev);
+	return 0;
+}
+
 static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
@@ -7409,6 +7408,63 @@
 	return 0;
 }
 
+static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->lightfreq = val;
+	if (gspca_dev->streaming)
+		setlightfreq(gspca_dev);
+	return 0;
+}
+
+static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->lightfreq;
+	return 0;
+}
+
+static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->sharpness = val;
+	if (gspca_dev->streaming)
+		setsharpness(gspca_dev);
+	return 0;
+}
+
+static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->sharpness;
+	return 0;
+}
+
+static int sd_querymenu(struct gspca_dev *gspca_dev,
+			struct v4l2_querymenu *menu)
+{
+	switch (menu->id) {
+	case V4L2_CID_POWER_LINE_FREQUENCY:
+		switch (menu->index) {
+		case 0:		/* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */
+			strcpy(menu->name, "NoFliker");
+			return 0;
+		case 1:		/* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
+			strcpy(menu->name, "50 Hz");
+			return 0;
+		case 2:		/* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
+			strcpy(menu->name, "60 Hz");
+			return 0;
+		}
+		break;
+	}
+	return -EINVAL;
+}
+
 static struct sd_desc sd_desc = {
 	.name = MODULE_NAME,
 	.ctrls = sd_ctrls,
@@ -7420,6 +7476,7 @@
 	.stop0 = sd_stop0,
 	.close = sd_close,
 	.pkt_scan = sd_pkt_scan,
+	.querymenu = sd_querymenu,
 };
 
 #define DVNM(name) .driver_info = (kernel_ulong_t) name
@@ -7514,10 +7571,6 @@
 module_init(sd_mod_init);
 module_exit(sd_mod_exit);
 
-module_param(lightfreq, int, 0644);
-MODULE_PARM_DESC(lightfreq,
-	"Light frequency banding filter: 50, 60 Hz or"
-	" 0 to NoFliker (default=50)");
 module_param(force_sensor, int, 0644);
 MODULE_PARM_DESC(force_sensor,
 	"Force sensor. Only for experts!!!");
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 9385c82..43a6c81 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -324,6 +324,8 @@
 #define V4L2_PIX_FMT_PWC1     v4l2_fourcc('P','W','C','1') /* pwc older webcam */
 #define V4L2_PIX_FMT_PWC2     v4l2_fourcc('P','W','C','2') /* pwc newer webcam */
 #define V4L2_PIX_FMT_ET61X251 v4l2_fourcc('E','6','2','5') /* ET61X251 compression */
+#define V4L2_PIX_FMT_SPCA501  v4l2_fourcc('S','5','0','1') /* YUYV per line */
+#define V4L2_PIX_FMT_SPCA561  v4l2_fourcc('S','5','6','1') /* compressed BGGR bayer */
 
 /*
  *	F O R M A T   E N U M E R A T I O N