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>
This commit is contained in:
Jean-Francois Moine 2008-06-30 15:50:11 -03:00 committed by Mauro Carvalho Chehab
parent d43fa32fec
commit 6a7eba24e4
27 changed files with 21990 additions and 1010 deletions

View file

@ -1,4 +1,4 @@
Here the list of the known working cameras with gspca.
List of the webcams know by gspca.
The modules are:
gspca_main main driver
@ -6,203 +6,50 @@ The modules are:
xxxx vend:prod
----
conex 0572:0041 Creative Notebook cx11646
etoms 102c:6151 Qcam Sangha CIF
etoms 102c:6251 Qcam xxxxxx VGA
mars 093a:050f Mars-Semi Pc-Camera
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:08d9 Logitech QuickCam IM/Connect
zc3xx 046d:08d8 Logitech Notebook Deluxe
zc3xx 046d:08da Logitech QuickCam Messenger
zc3xx 046d:08dd Logitech QuickCam for Notebooks
spca500 046d:0900 Logitech Inc. ClickSmart 310
spca500 046d:0901 Logitech Inc. ClickSmart 510
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

View file

@ -117,6 +117,7 @@ obj-$(CONFIG_USB_SN9C102) += sn9c102/
obj-$(CONFIG_USB_ET61X251) += et61x251/
obj-$(CONFIG_USB_PWC) += pwc/
obj-$(CONFIG_USB_ZC0301) += zc0301/
obj-$(CONFIG_USB_GSPCA) += gspca/
obj-$(CONFIG_USB_IBMCAM) += usbvideo/
obj-$(CONFIG_USB_KONICAWC) += usbvideo/

View file

@ -2,7 +2,7 @@ config USB_GSPCA
tristate "USB GSPCA driver"
depends on VIDEO_V4L2
---help---
Say Y here if you want support for various USB cameras.
Say Y here if you want support for various USB webcams.
See <file:Documentation/video4linux/gspca.txt> for more info.

View file

@ -1,7 +1,29 @@
obj-$(CONFIG_GSPCA) += gspca_main.o \
gspca_pac207.o gspca_stk014.o gspca_zc3xx.o
obj-$(CONFIG_USB_GSPCA) += gspca_main.o \
gspca_conex.o gspca_etoms.o gspca_mars.o \
gspca_ov519.o gspca_pac207.o gspca_pac7311.o \
gspca_sonixb.o gspca_sonixj.o gspca_spca500.o gspca_spca501.o \
gspca_spca505.o gspca_spca506.o gspca_spca508.o gspca_spca561.o \
gspca_sunplus.o gspca_stk014.o gspca_t613.o gspca_tv8532.o \
gspca_vc032x.o gspca_zc3xx.o
gspca_main-objs := gspca.o
gspca_conex-objs := conex.o
gspca_etoms-objs := etoms.o
gspca_mars-objs := mars.o
gspca_ov519-objs := ov519.o
gspca_pac207-objs := pac207.o
gspca_pac7311-objs := pac7311.o
gspca_sonixb-objs := sonixb.o
gspca_sonixj-objs := sonixj.o
gspca_spca500-objs := spca500.o
gspca_spca501-objs := spca501.o
gspca_spca505-objs := spca505.o
gspca_spca506-objs := spca506.o
gspca_spca508-objs := spca508.o
gspca_spca561-objs := spca561.o
gspca_stk014-objs := stk014.o
gspca_sunplus-objs := sunplus.o
gspca_t613-objs := t613.o
gspca_tv8532-objs := tv8532.o
gspca_vc032x-objs := vc032x.o
gspca_zc3xx-objs := zc3xx.o

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -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 @@ static void PDEBUG_MODE(char *txt, __u32 pixfmt, int w, int h)
#define GSPCA_MEMORY_NO 0 /* V4L2_MEMORY_xxx starts from 1 */
#define GSPCA_MEMORY_READ 7
#ifndef GSPCA_HLP
#define BUF_ALL_FLAGS (V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE)
#else
#define GSPCA_BUF_FLAG_DECODE 0x1000 /* internal buffer flag */
#define BUF_ALL_FLAGS (V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE \
| GSPCA_BUF_FLAG_DECODE)
static int autostart = 4;
module_param(autostart, int, 0644);
MODULE_PARM_DESC(autostart,
"Automatically start the helper process");
/* try to start the helper process */
static void start_hlp(void)
{
int ret;
static char *argv[] = {"gspca_hlp", NULL};
static char *env[] = {NULL};
if (autostart <= 0) {
if (autostart < 0)
PDEBUG(D_ERR|D_PROBE, "Too many helper restart");
return;
}
autostart--;
if (autostart == 0)
autostart = -1;
ret = call_usermodehelper("/sbin/gspca_hlp", argv, env,
UMH_WAIT_EXEC);
if (ret != 0)
PDEBUG(D_ERR|D_PROBE,
"/sbin/gspca_hlp start failed %d", ret);
}
/* /dev/gspca_hlp stuff */
#include <linux/miscdevice.h>
#include "gspca_hlp.h"
/* !! possible decodings defined in decoder.c */
static __u32 bayer_to_tb[] = {
V4L2_PIX_FMT_SBGGR8,
V4L2_PIX_FMT_YUYV,
V4L2_PIX_FMT_YUV420,
V4L2_PIX_FMT_RGB24,
V4L2_PIX_FMT_BGR24,
V4L2_PIX_FMT_RGB565,
};
static __u32 jpeg_to_tb[] = {
V4L2_PIX_FMT_JPEG,
V4L2_PIX_FMT_YUYV,
V4L2_PIX_FMT_YUV420,
V4L2_PIX_FMT_RGB24,
V4L2_PIX_FMT_BGR24,
V4L2_PIX_FMT_RGB565,
};
/* /dev/gspca_hlp device */
struct hlp_dev {
struct gspca_dev *gspca_dev; /* associated device */
struct gspca_frame *frame; /* frame being decoded */
__u32 pixfmt; /* webcam pixel format */
atomic_t nevent; /* nb of frames ready to decode */
wait_queue_head_t wq; /* wait queue */
char fr_d; /* next frame to decode */
} *hlp;
static int hlp_open(struct inode *inode, struct file *file)
{
struct hlp_dev *hlp_dev;
PDEBUG(D_CONF, "hlp open");
if (hlp != 0)
return -EBUSY;
hlp_dev = kzalloc(sizeof *hlp_dev, GFP_KERNEL);
if (hlp_dev == NULL) {
err("couldn't kzalloc hlp struct");
return -EIO;
}
init_waitqueue_head(&hlp_dev->wq);
file->private_data = hlp_dev;
hlp = hlp_dev;
return 0;
}
static int hlp_close(struct inode *inode, struct file *file)
{
struct gspca_dev *gspca_dev;
int mode;
PDEBUG(D_CONF, "hlp close");
file->private_data = NULL;
/* stop decoding */
gspca_dev = hlp->gspca_dev;
if (gspca_dev != 0) {
mode = gspca_dev->curr_mode;
gspca_dev->pixfmt = gspca_dev->cam.cam_mode[mode].pixfmt;
}
/* destroy the helper structure */
kfree(hlp);
hlp = 0;
/* try to restart the helper process */
start_hlp();
return 0;
}
static ssize_t hlp_read(struct file *file, char __user *buf,
size_t cnt, loff_t *ppos)
{
struct hlp_dev *hlp_dev = file->private_data;
struct gspca_dev *gspca_dev;
struct gspca_frame *frame;
struct gspca_hlp_read_hd head;
int i, j, len, ret;
PDEBUG(D_FRAM, "hlp read (%d)", cnt);
/* check / wait till a frame is ready */
for (;;) {
gspca_dev = hlp_dev->gspca_dev;
if (gspca_dev != 0 && gspca_dev->streaming) {
i = hlp_dev->fr_d; /* frame to decode */
j = gspca_dev->fr_queue[i];
frame = &gspca_dev->frame[j];
if (frame->v4l2_buf.flags & GSPCA_BUF_FLAG_DECODE)
break;
}
ret = wait_event_interruptible(hlp_dev->wq,
atomic_read(&hlp_dev->nevent) > 0);
if (ret < 0) { /* helper process is killed */
autostart = 0; /* don't restart it */
return ret;
}
}
atomic_dec(&hlp_dev->nevent);
hlp_dev->fr_d = (i + 1) % gspca_dev->nframes;
PDEBUG(D_FRAM, "hlp read q:%d i:%d d:%d o:%d",
gspca_dev->fr_q,
gspca_dev->fr_i,
hlp_dev->fr_d,
gspca_dev->fr_o);
hlp_dev->frame = frame; /* memorize the current frame */
len = frame->v4l2_buf.bytesused;
if (cnt < sizeof head - sizeof head.data + len)
/*fixme: special errno?*/
return -EINVAL;
head.pixfmt_out = gspca_dev->pixfmt;
head.pixfmt_in = hlp_dev->pixfmt;
head.width = gspca_dev->width;
head.height = gspca_dev->height;
copy_to_user(buf, &head, sizeof head);
copy_to_user(buf + sizeof head - sizeof head.data,
frame->data, len);
return sizeof head - sizeof head.data + len;
}
static ssize_t hlp_write(struct file *file,
const char __user *buf,
size_t cnt, loff_t *ppos)
{
struct hlp_dev *hlp_dev = file->private_data;
struct gspca_dev *gspca_dev;
struct gspca_frame *frame;
PDEBUG(D_FRAM, "hlp write (%d)", cnt);
gspca_dev = hlp_dev->gspca_dev;
if (gspca_dev == 0)
return cnt;
if (mutex_lock_interruptible(&gspca_dev->queue_lock))
return -ERESTARTSYS;
if (!gspca_dev->streaming)
goto out;
frame = hlp_dev->frame;
hlp_dev->frame = 0;
if (frame == 0)
goto out;
if (cnt > frame->v4l2_buf.length) {
PDEBUG(D_ERR|D_FRAM, "bad frame size %d - %d",
cnt, frame->v4l2_buf.length);
cnt = -EINVAL;
goto out;
}
copy_from_user(frame->data, buf, cnt);
frame->v4l2_buf.bytesused = cnt;
frame->v4l2_buf.flags &= ~(V4L2_BUF_FLAG_QUEUED
| GSPCA_BUF_FLAG_DECODE);
frame->v4l2_buf.flags |= V4L2_BUF_FLAG_DONE;
mutex_unlock(&gspca_dev->queue_lock);
atomic_inc(&gspca_dev->nevent);
wake_up_interruptible(&gspca_dev->wq); /* event = new frame */
PDEBUG(D_FRAM, "hlp write q:%d i:%d d:%d o:%d",
gspca_dev->fr_q,
gspca_dev->fr_i,
hlp_dev->fr_d,
gspca_dev->fr_o);
return cnt;
out:
mutex_unlock(&gspca_dev->queue_lock);
return cnt;
}
static struct file_operations hlp_fops = {
.owner = THIS_MODULE,
.open = hlp_open,
.release = hlp_close,
.read = hlp_read,
.write = hlp_write,
.llseek = no_llseek
};
static struct miscdevice hlp_device = {
.minor = MISC_DYNAMIC_MINOR,
.name = "gspca_hlp",
.fops = &hlp_fops,
};
#endif
/*
* VMA operations.
@ -331,10 +114,14 @@ static void fill_frame(struct gspca_dev *gspca_dev,
struct urb *urb)
{
struct gspca_frame *frame;
unsigned char *data; /* address of data in the iso message */
__u8 *data; /* address of data in the iso message */
int i, j, len, st;
cam_pkt_op pkt_scan;
if (urb->status != 0) {
PDEBUG(D_ERR|D_PACK, "urb status: %d", urb->status);
return; /* disconnection ? */
}
pkt_scan = gspca_dev->sd_desc->pkt_scan;
for (i = 0; i < urb->number_of_packets; i++) {
@ -350,20 +137,21 @@ static void fill_frame(struct gspca_dev *gspca_dev,
/* check the packet status and length */
len = urb->iso_frame_desc[i].actual_length;
if (len == 0)
continue;
st = urb->iso_frame_desc[i].status;
if (st) {
PDEBUG(D_ERR, "ISOC data error: [%d] len=%d, status=%d",
PDEBUG(D_ERR,
"ISOC data error: [%d] len=%d, status=%d",
i, len, st);
gspca_dev->last_packet_type = DISCARD_PACKET;
continue;
}
if (len == 0)
continue;
/* let the packet be analyzed by the subdriver */
PDEBUG(D_PACK, "packet [%d] o:%d l:%d",
i, urb->iso_frame_desc[i].offset, len);
data = (unsigned char *) urb->transfer_buffer
data = (__u8 *) urb->transfer_buffer
+ urb->iso_frame_desc[i].offset;
pkt_scan(gspca_dev, frame, data, len);
}
@ -390,7 +178,8 @@ static void fill_frame(struct gspca_dev *gspca_dev,
* buffers are in user space (userptr). The frame detection
* and copy is done by the application.
*/
static void isoc_irq_mmap(struct urb *urb)
static void isoc_irq_mmap(struct urb *urb
)
{
struct gspca_dev *gspca_dev = (struct gspca_dev *) urb->context;
@ -400,7 +189,8 @@ static void isoc_irq_mmap(struct urb *urb)
fill_frame(gspca_dev, urb);
}
static void isoc_irq_user(struct urb *urb)
static void isoc_irq_user(struct urb *urb
)
{
struct gspca_dev *gspca_dev = (struct gspca_dev *) urb->context;
int i;
@ -459,7 +249,7 @@ static void isoc_transfer(struct gspca_dev *gspca_dev)
struct gspca_frame *gspca_frame_add(struct gspca_dev *gspca_dev,
int packet_type,
struct gspca_frame *frame,
unsigned char *data,
__u8 *data,
int len)
{
int i, j;
@ -503,23 +293,10 @@ struct gspca_frame *gspca_frame_add(struct gspca_dev *gspca_dev,
/* if last packet, wake the application and advance in the queue */
if (packet_type == LAST_PACKET) {
frame->v4l2_buf.bytesused = frame->data_end - frame->data;
#ifndef GSPCA_HLP
frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_QUEUED;
frame->v4l2_buf.flags |= V4L2_BUF_FLAG_DONE;
atomic_inc(&gspca_dev->nevent);
wake_up_interruptible(&gspca_dev->wq); /* event = new frame */
#else /*GSPCA_HLP*/
if (hlp != 0 && hlp->gspca_dev == gspca_dev) {
frame->v4l2_buf.flags |= GSPCA_BUF_FLAG_DECODE;
atomic_inc(&hlp->nevent);
wake_up_interruptible(&hlp->wq);
} else {
frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_QUEUED;
frame->v4l2_buf.flags |= V4L2_BUF_FLAG_DONE;
atomic_inc(&gspca_dev->nevent);
wake_up_interruptible(&gspca_dev->wq); /* new frame */
}
#endif /*GSPCA_HLP*/
i = (gspca_dev->fr_i + 1) % gspca_dev->nframes;
gspca_dev->fr_i = i;
PDEBUG(D_FRAM, "frame complete len:%d q:%d i:%d o:%d",
@ -581,13 +358,13 @@ static void rvfree(void *mem, unsigned long size)
static __u32 get_v4l2_depth(__u32 pixfmt)
{
switch (pixfmt) {
case V4L2_PIX_FMT_BGR32:
/* case V4L2_PIX_FMT_BGR32:
case V4L2_PIX_FMT_RGB32:
return 32;
return 32; */
case V4L2_PIX_FMT_RGB24: /* 'RGB3' */
case V4L2_PIX_FMT_BGR24:
return 24;
case V4L2_PIX_FMT_RGB565: /* 'RGBP' */
/* case V4L2_PIX_FMT_RGB565: * 'RGBP' */
case V4L2_PIX_FMT_YUYV: /* 'YUYV' packed 4.2.2 */
case V4L2_PIX_FMT_YYUV: /* 'YYUV' */
return 16;
@ -596,6 +373,9 @@ static __u32 get_v4l2_depth(__u32 pixfmt)
case V4L2_PIX_FMT_MJPEG:
case V4L2_PIX_FMT_JPEG:
case V4L2_PIX_FMT_SBGGR8: /* 'BA81' Bayer */
case V4L2_PIX_FMT_SN9C10X: /* 'S910' SN9C10x compression */
case V4L2_PIX_FMT_SPCA501: /* 'S501' YUYV per line */
case V4L2_PIX_FMT_SPCA561: /* 'S561' compressed BGGR bayer */
return 8;
}
PDEBUG(D_ERR|D_CONF, "Unknown pixel format %c%c%c%c",
@ -603,7 +383,7 @@ static __u32 get_v4l2_depth(__u32 pixfmt)
(pixfmt >> 8) & 0xff,
(pixfmt >> 16) & 0xff,
pixfmt >> 24);
return -EINVAL;
return 24;
}
static int gspca_get_buff_size(struct gspca_dev *gspca_dev)
@ -632,7 +412,7 @@ static int frame_alloc(struct gspca_dev *gspca_dev,
count = GSPCA_MAX_FRAMES;
/* if compressed (JPEG), reduce the buffer size */
if (gspca_is_compressed(gspca_dev->pixfmt))
frsz = (frsz * comp_fac) / 100 + 600; /* plus JPEG header */
frsz = (frsz * comp_fac) / 100 + 600; /* (+ JPEG header sz) */
frsz = PAGE_ALIGN(frsz);
PDEBUG(D_STREAM, "new fr_sz: %d", frsz);
gspca_dev->frsz = frsz;
@ -660,17 +440,6 @@ static int frame_alloc(struct gspca_dev *gspca_dev,
}
}
gspca_dev->fr_i = gspca_dev->fr_o = gspca_dev->fr_q = 0;
#ifdef GSPCA_HLP
{
struct hlp_dev *hlp_dev;
hlp_dev = hlp;
if (hlp != 0 && hlp_dev->gspca_dev == gspca_dev) {
hlp_dev->fr_d = 0;
atomic_set(&hlp_dev->nevent, 0);
}
}
#endif /*GSPCA_HLP*/
gspca_dev->last_packet_type = DISCARD_PACKET;
gspca_dev->sequence = 0;
atomic_set(&gspca_dev->nevent, 0);
@ -752,13 +521,14 @@ struct usb_host_endpoint *get_isoc_ep(struct gspca_dev *gspca_dev)
int i, ret;
intf = usb_ifnum_to_if(gspca_dev->dev, gspca_dev->iface);
ep = NULL;
i = gspca_dev->alt; /* previous alt setting */
while (--i > 0) { /* alt 0 is unusable */
ep = alt_isoc(&intf->altsetting[i], gspca_dev->cam.epaddr);
if (ep)
break;
}
if (i <= 0) {
if (ep == NULL) {
err("no ISOC endpoint found");
return NULL;
}
@ -796,11 +566,14 @@ static int create_urbs(struct gspca_dev *gspca_dev,
"isoc %d pkts size %d (bsize:%d)", npkt, psize, bsize);
/*fixme:change for userptr*/
/*fixme:don't submit all URBs when userptr*/
gspca_dev->nurbs = nurbs = DEF_NURBS;
if (gspca_dev->memory == V4L2_MEMORY_MMAP)
if (gspca_dev->memory == V4L2_MEMORY_MMAP) {
usb_complete = isoc_irq_mmap;
else
nurbs = DEF_NURBS;
} else {
usb_complete = isoc_irq_user;
nurbs = USR_NURBS;
}
gspca_dev->nurbs = nurbs;
for (n = 0; n < nurbs; n++) {
urb = usb_alloc_urb(npkt, GFP_KERNEL);
if (!urb) {
@ -904,16 +677,6 @@ static void gspca_stream_off(struct gspca_dev *gspca_dev)
{
gspca_dev->streaming = 0;
atomic_set(&gspca_dev->nevent, 0);
#ifdef GSPCA_HLP
{
struct hlp_dev *hlp_dev;
hlp_dev = hlp;
if (hlp_dev != 0
&& hlp_dev->gspca_dev == gspca_dev)
atomic_set(&hlp_dev->nevent, 0);
}
#endif
if (gspca_dev->present) {
gspca_dev->sd_desc->stopN(gspca_dev);
destroy_urbs(gspca_dev);
@ -979,15 +742,11 @@ static int vidioc_enum_fmt_cap(struct file *file, void *priv,
struct v4l2_fmtdesc *fmtdesc)
{
struct gspca_dev *gspca_dev = priv;
int i;
#ifndef GSPCA_HLP
int j, index;
int i, j, index;
__u32 fmt_tb[8];
#endif
PDEBUG(D_CONF, "enum fmt cap");
#ifndef GSPCA_HLP
/* give an index to each format */
index = 0;
j = 0;
@ -1013,36 +772,6 @@ static int vidioc_enum_fmt_cap(struct file *file, void *priv,
fmtdesc->pixelformat = fmt_tb[index];
if (gspca_is_compressed(fmt_tb[index]))
fmtdesc->flags = V4L2_FMT_FLAG_COMPRESSED;
#else /*GSPCA_HLP*/
/* !! code tied to the decoding functions in decoder.c */
i = gspca_dev->cam.nmodes - 1;
if (fmtdesc->index == 0) { /* (assume one format per subdriver) */
fmtdesc->pixelformat = gspca_dev->cam.cam_mode[i].pixfmt;
if (gspca_is_compressed(fmtdesc->pixelformat))
fmtdesc->flags = V4L2_FMT_FLAG_COMPRESSED;
} else {
if (hlp == 0
|| (hlp->gspca_dev != 0
&& hlp->gspca_dev != gspca_dev))
return -EINVAL;
switch (gspca_dev->cam.cam_mode[i].pixfmt) {
case V4L2_PIX_FMT_JPEG:
if (fmtdesc->index >= sizeof jpeg_to_tb
/ sizeof jpeg_to_tb[0])
return -EINVAL;
fmtdesc->pixelformat = jpeg_to_tb[fmtdesc->index];
break;
case V4L2_PIX_FMT_SBGGR8:
if (fmtdesc->index >= sizeof bayer_to_tb
/ sizeof bayer_to_tb[0])
return -EINVAL;
fmtdesc->pixelformat = bayer_to_tb[fmtdesc->index];
break;
default:
return -EINVAL;
}
}
#endif /*GSPCA_HLP*/
fmtdesc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmtdesc->description[0] = fmtdesc->pixelformat & 0xff;
fmtdesc->description[1] = (fmtdesc->pixelformat >> 8) & 0xff;
@ -1057,25 +786,12 @@ static int vidioc_g_fmt_cap(struct file *file, void *priv,
{
struct gspca_dev *gspca_dev = priv;
#ifdef GSPCA_HLP
int i;
/* if the pixel format is not the one of the device and
* if the helper is inactive or busy, restore */
i = gspca_dev->curr_mode;
if (gspca_dev->pixfmt != gspca_dev->cam.cam_mode[i].pixfmt) {
struct hlp_dev *hlp_dev;
hlp_dev = hlp;
if (hlp_dev == 0 || hlp_dev->gspca_dev != gspca_dev)
gspca_dev->pixfmt = gspca_dev->cam.cam_mode[i].pixfmt;
}
#endif /*GSPCA_HLP*/
if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
fmt->fmt.pix.width = gspca_dev->width;
fmt->fmt.pix.height = gspca_dev->height;
fmt->fmt.pix.pixelformat = gspca_dev->pixfmt;
#ifdef GSPCA_DEBUG
#ifdef VIDEO_ADV_DEBUG
if (gspca_debug & D_CONF) {
PDEBUG_MODE("get fmt cap",
fmt->fmt.pix.pixelformat,
@ -1099,13 +815,15 @@ static int try_fmt_cap(struct gspca_dev *gspca_dev,
{
int w, h, mode, mode2, frsz;
if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
w = fmt->fmt.pix.width;
h = fmt->fmt.pix.height;
/* (luvcview problem) */
if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG)
fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_JPEG;
#ifdef GSPCA_DEBUG
#ifdef VIDEO_ADV_DEBUG
if (gspca_debug & D_CONF)
PDEBUG_MODE("try fmt cap", fmt->fmt.pix.pixelformat, w, h);
#endif
@ -1121,44 +839,11 @@ static int try_fmt_cap(struct gspca_dev *gspca_dev,
if (mode2 >= 0) {
mode = mode2;
} else {
__u32 pixfmt;
pixfmt = gspca_dev->cam.cam_mode[mode].pixfmt;
#ifndef GSPCA_HLP
/* no chance, return this mode */
fmt->fmt.pix.pixelformat = pixfmt;
#else /*GSPCA_HLP*/
if (hlp != 0
&& (hlp->gspca_dev == 0
|| hlp->gspca_dev == gspca_dev)
/* decoding works for JPEG and Bayer only */
&& (pixfmt == V4L2_PIX_FMT_JPEG
|| pixfmt == V4L2_PIX_FMT_SBGGR8)) {
switch (fmt->fmt.pix.pixelformat) {
case V4L2_PIX_FMT_YUYV: /* 'YUYV' */
case V4L2_PIX_FMT_BGR24: /* 'BGR3' */
case V4L2_PIX_FMT_RGB24: /* 'RGB3' */
case V4L2_PIX_FMT_YUV420: /* 'YU12' */
case V4L2_PIX_FMT_RGB565: /* 'RGBP' */
break;
default: {
/* return any of the supported fmt's */
__u8 u;
u = get_jiffies_64();
u %= sizeof bayer_to_tb
/ sizeof bayer_to_tb[0] - 1;
fmt->fmt.pix.pixelformat =
bayer_to_tb[u + 1];
break;
}
}
} else {
fmt->fmt.pix.pixelformat = pixfmt;
}
#endif /*GSPCA_HLP*/
#ifdef GSPCA_DEBUG
fmt->fmt.pix.pixelformat =
gspca_dev->cam.cam_mode[mode].pixfmt;
#ifdef VIDEO_ADV_DEBUG
if (gspca_debug & D_CONF) {
PDEBUG_MODE("new format",
fmt->fmt.pix.pixelformat,
@ -1198,7 +883,17 @@ static int vidioc_s_fmt_cap(struct file *file, void *priv,
struct gspca_dev *gspca_dev = priv;
int ret;
#ifdef GSPCA_DEBUG
#ifdef CONFIG_VIDEO_V4L1_COMPAT
/* if v4l1 got JPEG */
if (fmt->fmt.pix.pixelformat == 0
&& gspca_dev->streaming) {
fmt->fmt.pix.width = gspca_dev->width;
fmt->fmt.pix.height = gspca_dev->height;
fmt->fmt.pix.pixelformat = gspca_dev->pixfmt;
return 0;
}
#endif
#ifdef VIDEO_ADV_DEBUG
if (gspca_debug & D_CONF) {
PDEBUG_MODE("set fmt cap",
fmt->fmt.pix.pixelformat,
@ -1218,14 +913,8 @@ static int vidioc_s_fmt_cap(struct file *file, void *priv,
goto out;
}
#ifndef GSPCA_HLP
if (ret == gspca_dev->curr_mode)
goto out; /* same mode */
#else /*GSPCA_HLP*/
if (ret == gspca_dev->curr_mode
&& gspca_dev->pixfmt == fmt->fmt.pix.pixelformat)
goto out; /* same mode */
#endif /*GSPCA_HLP*/
if (gspca_dev->streaming) {
ret = -EBUSY;
@ -1236,26 +925,6 @@ static int vidioc_s_fmt_cap(struct file *file, void *priv,
gspca_dev->pixfmt = fmt->fmt.pix.pixelformat;
gspca_dev->curr_mode = ret;
#ifdef GSPCA_HLP
/* if frame decoding is required */
if (gspca_dev->pixfmt != gspca_dev->cam.cam_mode[ret].pixfmt) {
struct hlp_dev *hlp_dev;
hlp_dev = hlp;
if (hlp_dev == 0
|| (hlp_dev->gspca_dev != 0
&& hlp_dev->gspca_dev != gspca_dev)) { /* helper busy */
fmt->fmt.pix.pixelformat =
gspca_dev->pixfmt =
gspca_dev->cam.cam_mode[ret].pixfmt;
} else { /* helper active */
hlp_dev->gspca_dev = gspca_dev;
hlp_dev->pixfmt = gspca_dev->cam.cam_mode[ret].pixfmt;
hlp_dev->fr_d = gspca_dev->fr_i;
}
} else if (hlp != 0 && hlp->gspca_dev == gspca_dev)
hlp->gspca_dev = 0;
#endif /*GSPCA_HLP*/
ret = 0;
out:
mutex_unlock(&gspca_dev->queue_lock);
@ -1294,7 +963,7 @@ static int dev_open(struct inode *inode, struct file *file)
}
gspca_dev->users++;
file->private_data = gspca_dev;
#ifdef GSPCA_DEBUG
#ifdef VIDEO_ADV_DEBUG
/* activate the v4l2 debug */
if (gspca_debug & D_V4L2)
gspca_dev->vdev.debug |= 3;
@ -1329,22 +998,6 @@ static int dev_close(struct inode *inode, struct file *file)
frame_free(gspca_dev);
gspca_dev->capt_file = 0;
gspca_dev->memory = GSPCA_MEMORY_NO;
#ifdef GSPCA_HLP
{
struct hlp_dev *hlp_dev;
int mode;
hlp_dev = hlp;
if (hlp_dev != 0
&& hlp_dev->gspca_dev == gspca_dev) {
hlp_dev->gspca_dev = 0;
hlp_dev->frame = 0;
mode = gspca_dev->curr_mode;
gspca_dev->pixfmt =
gspca_dev->cam.cam_mode[mode].pixfmt;
}
}
#endif /*GSPCA_HLP*/
}
file->private_data = NULL;
mutex_unlock(&gspca_dev->queue_lock);
@ -1370,23 +1023,38 @@ static int vidioc_querycap(struct file *file, void *priv,
return 0;
}
/* the use of V4L2_CTRL_FLAG_NEXT_CTRL asks for the controls to be sorted */
static int vidioc_queryctrl(struct file *file, void *priv,
struct v4l2_queryctrl *q_ctrl)
{
struct gspca_dev *gspca_dev = priv;
int i;
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 @@ static int vidioc_reqbufs(struct file *file, void *priv,
return -EINVAL;
switch (rb->memory) {
case V4L2_MEMORY_MMAP:
break;
case V4L2_MEMORY_USERPTR:
#ifdef GSPCA_HLP
if (hlp == 0 || hlp->gspca_dev != gspca_dev)
break;
#endif
return -EINVAL;
break;
default:
return -EINVAL;
}
@ -1578,7 +1241,7 @@ static int vidioc_streamon(struct file *file, void *priv,
if (ret < 0)
goto out;
}
#ifdef GSPCA_DEBUG
#ifdef VIDEO_ADV_DEBUG
if (gspca_debug & D_STREAM) {
PDEBUG_MODE("stream on OK",
gspca_dev->pixfmt,
@ -1657,7 +1320,7 @@ static int vidioc_g_parm(struct file *filp, void *priv,
{
struct gspca_dev *gspca_dev = priv;
memset(parm, 0, sizeof parm);
memset(parm, 0, sizeof *parm);
parm->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
parm->parm.capture.readbuffers = gspca_dev->nbufread;
return 0;
@ -1677,6 +1340,12 @@ static int vidioc_s_parm(struct file *filp, void *priv,
return 0;
}
static int vidioc_s_std(struct file *filp, void *priv,
v4l2_std_id *parm)
{
return 0;
}
#ifdef CONFIG_VIDEO_V4L1_COMPAT
static int vidiocgmbuf(struct file *file, void *priv,
struct video_mbuf *mbuf)
@ -1686,29 +1355,32 @@ static int vidiocgmbuf(struct file *file, void *priv,
PDEBUG(D_STREAM, "cgmbuf");
if (gspca_dev->nframes == 0) {
struct v4l2_requestbuffers rb;
int ret;
__u32 pixfmt;
short width, height;
/* as the final format is not yet defined, allocate
buffers with the max size */
pixfmt = gspca_dev->pixfmt;
width = gspca_dev->width;
height = gspca_dev->height;
gspca_dev->pixfmt = V4L2_PIX_FMT_BGR32;
gspca_dev->width = 640;
gspca_dev->height = 480;
memset(&rb, 0, sizeof rb);
rb.count = 4;
rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
rb.memory = V4L2_MEMORY_MMAP;
ret = vidioc_reqbufs(file, priv, &rb);
gspca_dev->pixfmt = pixfmt;
gspca_dev->width = width;
gspca_dev->height = height;
if (ret != 0)
return ret;
{
struct v4l2_format fmt;
memset(&fmt, 0, sizeof fmt);
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
i = gspca_dev->cam.nmodes - 1; /* highest mode */
fmt.fmt.pix.width = gspca_dev->cam.cam_mode[i].width;
fmt.fmt.pix.height = gspca_dev->cam.cam_mode[i].height;
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_BGR24;
ret = vidioc_s_fmt_cap(file, priv, &fmt);
if (ret != 0)
return ret;
}
{
struct v4l2_requestbuffers rb;
memset(&rb, 0, sizeof rb);
rb.count = 4;
rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
rb.memory = V4L2_MEMORY_MMAP;
ret = vidioc_reqbufs(file, priv, &rb);
if (ret != 0)
return ret;
}
}
mbuf->frames = gspca_dev->nframes;
mbuf->size = gspca_dev->frsz * gspca_dev->nframes;
@ -1951,7 +1623,7 @@ static int vidioc_qbuf(struct file *file, void *priv,
if (frame->v4l2_buf.memory == V4L2_MEMORY_USERPTR) {
frame->data = frame->data_end =
(unsigned char *) v4l2_buf->m.userptr;
(__u8 *) v4l2_buf->m.userptr;
frame->v4l2_buf.m.userptr = v4l2_buf->m.userptr;
frame->v4l2_buf.length = v4l2_buf->length;
}
@ -2154,6 +1826,9 @@ static struct file_operations dev_fops = {
.read = dev_read,
.mmap = dev_mmap,
.ioctl = video_ioctl2,
#ifdef CONFIG_COMPAT
.compat_ioctl = v4l_compat_ioctl32,
#endif
.llseek = no_llseek,
.poll = dev_poll,
};
@ -2186,6 +1861,7 @@ static struct video_device gspca_template = {
.vidioc_s_jpegcomp = vidioc_s_jpegcomp,
.vidioc_g_parm = vidioc_g_parm,
.vidioc_s_parm = vidioc_s_parm,
.vidioc_s_std = vidioc_s_std,
#ifdef CONFIG_VIDEO_V4L1_COMPAT
.vidiocgmbuf = vidiocgmbuf,
#endif
@ -2207,12 +1883,8 @@ int gspca_dev_probe(struct usb_interface *intf,
struct gspca_dev *gspca_dev;
struct usb_device *dev = interface_to_usbdev(intf);
int ret;
__u16 vendor;
__u16 product;
vendor = id->idVendor;
product = id->idProduct;
PDEBUG(D_PROBE, "probing %04x:%04x", vendor, product);
PDEBUG(D_PROBE, "probing %04x:%04x", id->idVendor, id->idProduct);
/* we don't handle multi-config cameras */
if (dev->descriptor.bNumConfigurations != 1)
@ -2309,35 +1981,24 @@ EXPORT_SYMBOL(gspca_disconnect);
/* -- module insert / remove -- */
static int __init gspca_init(void)
{
#ifdef GSPCA_HLP
int ret;
/* create /dev/gspca_hlp */
ret = misc_register(&hlp_device);
if (ret < 0)
err("misc_register err %d", ret);
start_hlp(); /* try to start the helper process */
#endif
info("main v%s registered", version);
return 0;
}
static void __exit gspca_exit(void)
{
#ifdef GSPCA_HLP
misc_deregister(&hlp_device);
#endif
info("main deregistered");
}
module_init(gspca_init);
module_exit(gspca_exit);
#ifdef VIDEO_ADV_DEBUG
module_param_named(debug, gspca_debug, int, 0644);
MODULE_PARM_DESC(debug,
"Debug (bit) 0x01:error 0x02:probe 0x04:config"
" 0x08:stream 0x10:frame 0x20:packet 0x40:USBin 0x80:USBout"
" 0x0100: v4l2");
#endif
module_param(comp_fac, int, 0644);
MODULE_PARM_DESC(comp_fac,
"Buffer size ratio when compressed in percent");

View file

@ -9,7 +9,26 @@
#include <media/v4l2-common.h>
#include <linux/mutex.h>
#ifdef GSPCA_DEBUG
/* values in 2.6.27 */
#ifndef V4L2_PIX_FMT_SPCA501
#define V4L2_PIX_FMT_SPCA501 v4l2_fourcc('S', '5', '0', '1')
#endif
#ifndef V4L2_PIX_FMT_SPCA561
#define V4L2_PIX_FMT_SPCA561 v4l2_fourcc('S', '5', '6', '1')
#endif
/* values in 2.6.26 */
#ifndef V4L2_CID_POWER_LINE_FREQUENCY
#define V4L2_CID_POWER_LINE_FREQUENCY (V4L2_CID_BASE+24)
#endif
#ifndef V4L2_CID_WHITE_BALANCE_TEMPERATURE
#define V4L2_CID_WHITE_BALANCE_TEMPERATURE (V4L2_CID_BASE + 26)
#endif
#ifndef V4L2_CID_SHARPNESS
#define V4L2_CID_SHARPNESS (V4L2_CID_BASE+27)
#endif
#ifdef VIDEO_ADV_DEBUG
/* GSPCA our debug messages */
extern int gspca_debug;
#define PDEBUG(level, fmt, args...) \
@ -47,7 +66,7 @@ extern int gspca_debug;
#define GSPCA_MAX_FRAMES 16 /* maximum number of video frame buffers */
/* ISOC transfers */
#define MAX_NURBS 32 /* max number of URBs (read & userptr) */
#define MAX_NURBS 16 /* max number of URBs */
#define ISO_MAX_PKT 32 /* max number of packets in an ISOC transfer */
#define ISO_MAX_SIZE 0x8000 /* max size of one URB buffer (32 Kb) */
@ -79,7 +98,7 @@ typedef int (*cam_qmnu_op) (struct gspca_dev *,
struct v4l2_querymenu *);
typedef void (*cam_pkt_op) (struct gspca_dev *gspca_dev,
struct gspca_frame *frame,
unsigned char *data,
__u8 *data,
int len);
struct ctrl {
@ -116,8 +135,8 @@ struct sd_desc {
#define LAST_PACKET 3
struct gspca_frame {
unsigned char *data; /* frame buffer */
unsigned char *data_end; /* end of frame while filling */
__u8 *data; /* frame buffer */
__u8 *data_end; /* end of frame while filling */
int vma_use_count;
struct v4l2_buffer v4l2_buf;
};
@ -135,7 +154,7 @@ struct gspca_dev {
__u8 *frbuf; /* buffer for nframes */
struct gspca_frame frame[GSPCA_MAX_FRAMES];
unsigned int frsz; /* frame size */
__u32 frsz; /* frame size */
char nframes; /* number of frames */
char fr_i; /* frame being filled */
char fr_q; /* next frame to queue */
@ -145,10 +164,10 @@ struct gspca_dev {
__u8 iface; /* USB interface number */
__u8 alt; /* USB alternate setting */
unsigned char curr_mode; /* current camera mode */
__u8 curr_mode; /* current camera mode */
__u32 pixfmt; /* current mode parameters */
short width;
short height;
__u16 width;
__u16 height;
atomic_t nevent; /* number of frames done */
wait_queue_head_t wq; /* wait queue */
@ -176,6 +195,6 @@ void gspca_disconnect(struct usb_interface *intf);
struct gspca_frame *gspca_frame_add(struct gspca_dev *gspca_dev,
int packet_type,
struct gspca_frame *frame,
unsigned char *data,
__u8 *data,
int len);
#endif /* GSPCAV2_H */

View file

@ -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);

File diff suppressed because it is too large Load diff

View file

@ -27,8 +27,8 @@
#include "gspca.h"
#define DRIVER_VERSION_NUMBER KERNEL_VERSION(0, 2, 15)
static const char version[] = "0.2.15";
#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 0)
static const char version[] = "2.1.0";
MODULE_AUTHOR("Hans de Goede <j.w.r.degoede@hhs.nl>");
MODULE_DESCRIPTION("Pixart PAC207");
@ -297,7 +297,6 @@ static int sd_open(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev;
sd->autogain = 1;
return 0;
}
@ -338,7 +337,7 @@ static void sd_start(struct gspca_dev *gspca_dev)
pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */
pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */
udelay(1000); /* taken from gspca */
msleep(10);
pac207_write_reg(gspca_dev, 0x40, 0x01); /* Start ISO pipe */
sd->sof_read = 0;
@ -743,8 +742,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
PDEBUG(D_STREAM, "Incomplete frame");
}
pac207_decode_frame_init(gspca_dev);
gspca_frame_add(gspca_dev, FIRST_PACKET, frame, NULL,
0);
gspca_frame_add(gspca_dev, FIRST_PACKET, frame, NULL, 0);
len -= sof - data;
data = sof;
}

View file

@ -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);

View file

@ -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);

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -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);

View file

@ -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);

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -23,8 +23,8 @@
#include "gspca.h"
#include "jpeg.h"
#define DRIVER_VERSION_NUMBER KERNEL_VERSION(0, 2, 7)
static const char version[] = "0.2.7";
#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 0)
static const char version[] = "2.1.0";
MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>");
MODULE_DESCRIPTION("Syntek DV4000 (STK014) USB Camera Driver");
@ -37,10 +37,10 @@ struct sd {
unsigned char brightness;
unsigned char contrast;
unsigned char colors;
unsigned char lightfreq;
};
/* global parameters */
static int lightfreq = 50;
static int sd_quant = 7; /* <= 4 KO - 7: good (enough!) */
/* V4L2 controls supported by the driver */
@ -50,6 +50,8 @@ static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
static struct ctrl sd_ctrls[] = {
#define SD_BRIGHTNESS 0
@ -94,6 +96,20 @@ static struct ctrl sd_ctrls[] = {
.set = sd_setcolors,
.get = sd_getcolors,
},
#define SD_FREQ 3
{
{
.id = V4L2_CID_POWER_LINE_FREQUENCY,
.type = V4L2_CTRL_TYPE_MENU,
.name = "Light frequency filter",
.minimum = 1,
.maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */
.step = 1,
.default_value = 1,
},
.set = sd_setfreq,
.get = sd_getfreq,
},
};
static struct cam_mode vga_mode[] = {
@ -102,11 +118,11 @@ static struct cam_mode vga_mode[] = {
};
/* -- read a register -- */
static int reg_read(struct gspca_dev *gspca_dev,
static int reg_r(struct gspca_dev *gspca_dev,
__u16 index, __u8 *buf)
{
int ret;
struct usb_device *dev = gspca_dev->dev;
int ret;
ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
0x00,
@ -116,12 +132,12 @@ static int reg_read(struct gspca_dev *gspca_dev,
buf, 1,
500);
if (ret < 0)
PDEBUG(D_ERR, "reg_read err %d", ret);
PDEBUG(D_ERR, "reg_r err %d", ret);
return ret;
}
/* -- write a register -- */
static int reg_write(struct gspca_dev *gspca_dev,
static int reg_w(struct gspca_dev *gspca_dev,
__u16 index, __u16 value)
{
struct usb_device *dev = gspca_dev->dev;
@ -136,7 +152,7 @@ static int reg_write(struct gspca_dev *gspca_dev,
0,
500);
if (ret < 0)
PDEBUG(D_ERR, "reg_write err %d", ret);
PDEBUG(D_ERR, "reg_w err %d", ret);
return ret;
}
@ -149,15 +165,15 @@ static int rcv_val(struct gspca_dev *gspca_dev,
int alen, ret;
unsigned char bulk_buf[4];
reg_write(gspca_dev, 0x634, (ads >> 16) & 0xff);
reg_write(gspca_dev, 0x635, (ads >> 8) & 0xff);
reg_write(gspca_dev, 0x636, ads & 0xff);
reg_write(gspca_dev, 0x637, 0);
reg_write(gspca_dev, 0x638, len & 0xff);
reg_write(gspca_dev, 0x639, len >> 8);
reg_write(gspca_dev, 0x63a, 0);
reg_write(gspca_dev, 0x63b, 0);
reg_write(gspca_dev, 0x630, 5);
reg_w(gspca_dev, 0x634, (ads >> 16) & 0xff);
reg_w(gspca_dev, 0x635, (ads >> 8) & 0xff);
reg_w(gspca_dev, 0x636, ads & 0xff);
reg_w(gspca_dev, 0x637, 0);
reg_w(gspca_dev, 0x638, len & 0xff);
reg_w(gspca_dev, 0x639, len >> 8);
reg_w(gspca_dev, 0x63a, 0);
reg_w(gspca_dev, 0x63b, 0);
reg_w(gspca_dev, 0x630, 5);
if (len > sizeof bulk_buf)
return -1;
ret = usb_bulk_msg(dev,
@ -180,26 +196,26 @@ static int snd_val(struct gspca_dev *gspca_dev,
unsigned char bulk_buf[4];
if (ads == 0x003f08) {
ret = reg_read(gspca_dev, 0x0704, &value);
ret = reg_r(gspca_dev, 0x0704, &value);
if (ret < 0)
goto ko;
ret = reg_read(gspca_dev, 0x0705, &seq);
ret = reg_r(gspca_dev, 0x0705, &seq);
if (ret < 0)
goto ko;
ret = reg_read(gspca_dev, 0x0650, &value);
ret = reg_r(gspca_dev, 0x0650, &value);
if (ret < 0)
goto ko;
reg_write(gspca_dev, 0x654, seq);
reg_w(gspca_dev, 0x654, seq);
} else
reg_write(gspca_dev, 0x654, (ads >> 16) & 0xff);
reg_write(gspca_dev, 0x655, (ads >> 8) & 0xff);
reg_write(gspca_dev, 0x656, ads & 0xff);
reg_write(gspca_dev, 0x657, 0);
reg_write(gspca_dev, 0x658, 0x04); /* size */
reg_write(gspca_dev, 0x659, 0);
reg_write(gspca_dev, 0x65a, 0);
reg_write(gspca_dev, 0x65b, 0);
reg_write(gspca_dev, 0x650, 5);
reg_w(gspca_dev, 0x654, (ads >> 16) & 0xff);
reg_w(gspca_dev, 0x655, (ads >> 8) & 0xff);
reg_w(gspca_dev, 0x656, ads & 0xff);
reg_w(gspca_dev, 0x657, 0);
reg_w(gspca_dev, 0x658, 0x04); /* size */
reg_w(gspca_dev, 0x659, 0);
reg_w(gspca_dev, 0x65a, 0);
reg_w(gspca_dev, 0x65b, 0);
reg_w(gspca_dev, 0x650, 5);
bulk_buf[0] = (val >> 24) & 0xff;
bulk_buf[1] = (val >> 16) & 0xff;
bulk_buf[2] = (val >> 8) & 0xff;
@ -215,7 +231,7 @@ static int snd_val(struct gspca_dev *gspca_dev,
if (ads == 0x003f08) {
seq += 4;
seq &= 0x3f;
reg_write(gspca_dev, 0x705, seq);
reg_w(gspca_dev, 0x705, seq);
}
return ret;
ko:
@ -235,7 +251,6 @@ static void setbrightness(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev;
int parval;
PDEBUG(D_CONF, "brightness: %d", sd->brightness);
parval = 0x06000000 /* whiteness */
+ (sd->brightness << 16);
set_par(gspca_dev, parval);
@ -246,7 +261,6 @@ static void setcontrast(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev;
int parval;
PDEBUG(D_CONF, "contrast: %d", sd->contrast);
parval = 0x07000000 /* contrast */
+ (sd->contrast << 16);
set_par(gspca_dev, parval);
@ -257,13 +271,20 @@ static void setcolors(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev;
int parval;
PDEBUG(D_CONF, "saturation: %d",
sd->colors);
parval = 0x08000000 /* saturation */
+ (sd->colors << 16);
set_par(gspca_dev, parval);
}
static void setfreq(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
set_par(gspca_dev, sd->lightfreq == 1
? 0x33640000 /* 50 Hz */
: 0x33780000); /* 60 Hz */
}
/* this function is called at probe time */
static int sd_config(struct gspca_dev *gspca_dev,
const struct usb_device_id *id)
@ -278,6 +299,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value;
sd->lightfreq = sd_ctrls[SD_FREQ].qctrl.default_value;
return 0;
}
@ -289,7 +311,7 @@ static int sd_open(struct gspca_dev *gspca_dev)
/* check if the device responds */
usb_set_interface(gspca_dev->dev, gspca_dev->iface, 1);
ret = reg_read(gspca_dev, 0x0740, &value);
ret = reg_r(gspca_dev, 0x0740, &value);
if (ret < 0)
return ret;
if (value != 0xff) {
@ -320,21 +342,24 @@ static void sd_start(struct gspca_dev *gspca_dev)
ret = usb_set_interface(gspca_dev->dev,
gspca_dev->iface,
gspca_dev->alt);
if (ret < 0)
if (ret < 0) {
PDEBUG(D_ERR|D_STREAM, "set intf %d %d failed",
gspca_dev->iface, gspca_dev->alt);
goto out;
ret = reg_read(gspca_dev, 0x0630, &dum);
}
ret = reg_r(gspca_dev, 0x0630, &dum);
if (ret < 0)
goto out;
rcv_val(gspca_dev, 0x000020, 4); /* << (value ff ff ff ff) */
ret = reg_read(gspca_dev, 0x0650, &dum);
ret = reg_r(gspca_dev, 0x0650, &dum);
if (ret < 0)
goto out;
snd_val(gspca_dev, 0x000020, 0xffffffff);
reg_write(gspca_dev, 0x0620, 0);
reg_write(gspca_dev, 0x0630, 0);
reg_write(gspca_dev, 0x0640, 0);
reg_write(gspca_dev, 0x0650, 0);
reg_write(gspca_dev, 0x0660, 0);
reg_w(gspca_dev, 0x0620, 0);
reg_w(gspca_dev, 0x0630, 0);
reg_w(gspca_dev, 0x0640, 0);
reg_w(gspca_dev, 0x0650, 0);
reg_w(gspca_dev, 0x0660, 0);
setbrightness(gspca_dev); /* whiteness */
setcontrast(gspca_dev); /* contrast */
setcolors(gspca_dev); /* saturation */
@ -342,9 +367,7 @@ static void sd_start(struct gspca_dev *gspca_dev)
set_par(gspca_dev, 0x0a800000); /* Green ? */
set_par(gspca_dev, 0x0b800000); /* Blue ? */
set_par(gspca_dev, 0x0d030000); /* Gamma ? */
set_par(gspca_dev, lightfreq == 60
? 0x33780000 /* 60 Hz */
: 0x33640000); /* 50 Hz */
setfreq(gspca_dev); /* light frequency */
/* start the video flow */
set_par(gspca_dev, 0x01000000);
@ -363,15 +386,15 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
set_par(gspca_dev, 0x02000000);
set_par(gspca_dev, 0x02000000);
usb_set_interface(dev, gspca_dev->iface, 1);
reg_read(gspca_dev, 0x0630, &value);
reg_r(gspca_dev, 0x0630, &value);
rcv_val(gspca_dev, 0x000020, 4); /* << (value ff ff ff ff) */
reg_read(gspca_dev, 0x0650, &value);
reg_r(gspca_dev, 0x0650, &value);
snd_val(gspca_dev, 0x000020, 0xffffffff);
reg_write(gspca_dev, 0x0620, 0);
reg_write(gspca_dev, 0x0630, 0);
reg_write(gspca_dev, 0x0640, 0);
reg_write(gspca_dev, 0x0650, 0);
reg_write(gspca_dev, 0x0660, 0);
reg_w(gspca_dev, 0x0620, 0);
reg_w(gspca_dev, 0x0630, 0);
reg_w(gspca_dev, 0x0640, 0);
reg_w(gspca_dev, 0x0650, 0);
reg_w(gspca_dev, 0x0660, 0);
PDEBUG(D_STREAM, "camera stopped");
}
@ -470,6 +493,42 @@ static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
return 0;
}
static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
sd->lightfreq = val;
if (gspca_dev->streaming)
setfreq(gspca_dev);
return 0;
}
static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
*val = sd->lightfreq;
return 0;
}
static int sd_querymenu(struct gspca_dev *gspca_dev,
struct v4l2_querymenu *menu)
{
switch (menu->id) {
case V4L2_CID_POWER_LINE_FREQUENCY:
switch (menu->index) {
case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
strcpy(menu->name, "50 Hz");
return 0;
case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
strcpy(menu->name, "60 Hz");
return 0;
}
break;
}
return -EINVAL;
}
/* sub-driver description */
static struct sd_desc sd_desc = {
.name = MODULE_NAME,
@ -482,6 +541,7 @@ static struct sd_desc sd_desc = {
.stop0 = sd_stop0,
.close = sd_close,
.pkt_scan = sd_pkt_scan,
.querymenu = sd_querymenu,
};
/* -- module initialisation -- */
@ -524,7 +584,5 @@ static void __exit sd_mod_exit(void)
module_init(sd_mod_init);
module_exit(sd_mod_exit);
module_param(lightfreq, int, 0644);
MODULE_PARM_DESC(lightfreq, "Light frequency 50 or 60 Hz");
module_param_named(quant, sd_quant, int, 0644);
MODULE_PARM_DESC(quant, "Quantization index (0..8)");

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -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);

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -324,6 +324,8 @@ struct v4l2_pix_format
#define V4L2_PIX_FMT_PWC1 v4l2_fourcc('P','W','C','1') /* pwc older webcam */
#define V4L2_PIX_FMT_PWC2 v4l2_fourcc('P','W','C','2') /* pwc newer webcam */
#define V4L2_PIX_FMT_ET61X251 v4l2_fourcc('E','6','2','5') /* ET61X251 compression */
#define V4L2_PIX_FMT_SPCA501 v4l2_fourcc('S','5','0','1') /* YUYV per line */
#define V4L2_PIX_FMT_SPCA561 v4l2_fourcc('S','5','6','1') /* compressed BGGR bayer */
/*
* F O R M A T E N U M E R A T I O N