mirror of
https://github.com/torvalds/linux.git
synced 2024-11-11 22:51:42 +00:00
Merge git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/v4l-dvb
* git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/v4l-dvb: (277 commits) V4L/DVB (8415): gspca: Infinite loop in i2c_w() of etoms. V4L/DVB (8414): videodev/cx18: fix get_index bug and error-handling lock-ups V4L/DVB (8411): videobuf-dma-contig.c: fix 64-bit build for pre-2.6.24 kernels V4L/DVB (8410): sh_mobile_ceu_camera: fix 64-bit compiler warnings V4L/DVB (8397): video: convert select VIDEO_ZORAN_ZR36060 into depends on V4L/DVB (8396): video: Fix Kbuild dependency for VIDEO_IR_I2C V4L/DVB (8395): saa7134: Fix Kbuild dependency of ir-kbd-i2c V4L/DVB (8394): ir-common: CodingStyle fix: move EXPORT_SYMBOL_GPL to their proper places V4L/DVB (8393): media/video: Fix depencencies for VIDEOBUF V4L/DVB (8392): media/Kconfig: Convert V4L1_COMPAT select into "depends on" V4L/DVB (8390): videodev: add comment and remove magic number. V4L/DVB (8389): videodev: simplify get_index() V4L/DVB (8387): Some cosmetic changes V4L/DVB (8381): ov7670: fix compile warnings V4L/DVB (8380): saa7115: use saa7115_auto instead of saa711x as the autodetect driver name. V4L/DVB (8379): saa7127: Make device detection optional V4L/DVB (8378): cx18: move cx18_av_vbi_setup to av-core.c and rename to cx18_av_std_setup V4L/DVB (8377): ivtv/cx18: ensure the default control values are correct V4L/DVB (8376): cx25840: move cx25840_vbi_setup to core.c and rename to cx25840_std_setup V4L/DVB (8374): gspca: No conflict of 0c45:6011 with the sn9c102 driver. ...
This commit is contained in:
commit
f894d18380
@ -8,3 +8,4 @@
|
||||
7 -> Hauppauge WinTV-HVR1200 [0070:71d1,0070:71d3]
|
||||
8 -> Hauppauge WinTV-HVR1700 [0070:8101]
|
||||
9 -> Hauppauge WinTV-HVR1400 [0070:8010]
|
||||
10 -> DViCO FusionHDTV7 Dual Express [18ac:d618]
|
||||
|
@ -8,10 +8,13 @@
|
||||
7 -> Leadtek Winfast USB II (em2800)
|
||||
8 -> Kworld USB2800 (em2800)
|
||||
9 -> Pinnacle Dazzle DVC 90/DVC 100 (em2820/em2840) [2304:0207,2304:021a]
|
||||
10 -> Hauppauge WinTV HVR 900 (em2880) [2040:6500,2040:6502]
|
||||
10 -> Hauppauge WinTV HVR 900 (em2880) [2040:6500]
|
||||
11 -> Terratec Hybrid XS (em2880) [0ccd:0042]
|
||||
12 -> Kworld PVR TV 2800 RF (em2820/em2840)
|
||||
13 -> Terratec Prodigy XS (em2880) [0ccd:0047]
|
||||
14 -> Pixelview Prolink PlayTV USB 2.0 (em2820/em2840)
|
||||
15 -> V-Gear PocketTV (em2800)
|
||||
16 -> Hauppauge WinTV HVR 950 (em2880) [2040:6513,2040:6517,2040:651b,2040:651f]
|
||||
17 -> Pinnacle PCTV HD Pro Stick (em2880) [2304:0227]
|
||||
18 -> Hauppauge WinTV HVR 900 (R2) (em2880) [2040:6502]
|
||||
19 -> PointNix Intra-Oral Camera (em2860)
|
||||
|
@ -37,7 +37,7 @@
|
||||
36 -> UPMOST PURPLE TV [12ab:0800]
|
||||
37 -> Items MuchTV Plus / IT-005
|
||||
38 -> Terratec Cinergy 200 TV [153b:1152]
|
||||
39 -> LifeView FlyTV Platinum Mini [5168:0212,4e42:0212]
|
||||
39 -> LifeView FlyTV Platinum Mini [5168:0212,4e42:0212,5169:1502]
|
||||
40 -> Compro VideoMate TV PVR/FM [185b:c100]
|
||||
41 -> Compro VideoMate TV Gold+ [185b:c100]
|
||||
42 -> Sabrent SBT-TVFM (saa7130)
|
||||
@ -128,7 +128,7 @@
|
||||
127 -> Beholder BeholdTV 507 FM/RDS / BeholdTV 509 FM [0000:5071,0000:507B,5ace:5070,5ace:5090]
|
||||
128 -> Beholder BeholdTV Columbus TVFM [0000:5201]
|
||||
129 -> Beholder BeholdTV 607 / BeholdTV 609 [5ace:6070,5ace:6071,5ace:6072,5ace:6073,5ace:6090,5ace:6091,5ace:6092,5ace:6093]
|
||||
130 -> Beholder BeholdTV M6 / BeholdTV M6 Extra [5ace:6190,5ace:6193,5ace:6191]
|
||||
130 -> Beholder BeholdTV M6 [5ace:6190]
|
||||
131 -> Twinhan Hybrid DTV-DVB 3056 PCI [1822:0022]
|
||||
132 -> Genius TVGO AM11MCE
|
||||
133 -> NXP Snake DVB-S reference design
|
||||
@ -141,3 +141,7 @@
|
||||
140 -> Avermedia DVB-S Pro A700 [1461:a7a1]
|
||||
141 -> Avermedia DVB-S Hybrid+FM A700 [1461:a7a2]
|
||||
142 -> Beholder BeholdTV H6 [5ace:6290]
|
||||
143 -> Beholder BeholdTV M63 [5ace:6191]
|
||||
144 -> Beholder BeholdTV M6 Extra [5ace:6193]
|
||||
145 -> AVerMedia MiniPCI DVB-T Hybrid M103 [1461:f636]
|
||||
146 -> ASUSTeK P7131 Analog
|
||||
|
@ -1,36 +1,30 @@
|
||||
Some notes regarding the cx18 driver for the Conexant CX23418 MPEG
|
||||
encoder chip:
|
||||
|
||||
1) The only hardware currently supported is the Hauppauge HVR-1600
|
||||
card and the Compro VideoMate H900 (note that this card only
|
||||
supports analog input, it has no digital tuner!).
|
||||
1) Currently supported are:
|
||||
|
||||
2) Some people have problems getting the i2c bus to work. Cause unknown.
|
||||
- Hauppauge HVR-1600
|
||||
- Compro VideoMate H900
|
||||
- Yuan MPC718
|
||||
- Conexant Raptor PAL/SECAM devkit
|
||||
|
||||
2) Some people have problems getting the i2c bus to work.
|
||||
The symptom is that the eeprom cannot be read and the card is
|
||||
unusable.
|
||||
unusable. This is probably fixed, but if you have problems
|
||||
then post to the video4linux or ivtv-users mailinglist.
|
||||
|
||||
3) The audio from the analog tuner is mono only. Probably caused by
|
||||
incorrect audio register information in the datasheet. We are
|
||||
waiting for updated information from Conexant.
|
||||
3) VBI (raw or sliced) has not yet been implemented.
|
||||
|
||||
4) VBI (raw or sliced) has not yet been implemented.
|
||||
4) MPEG indexing is not yet implemented.
|
||||
|
||||
5) MPEG indexing is not yet implemented.
|
||||
|
||||
6) The driver is still a bit rough around the edges, this should
|
||||
5) The driver is still a bit rough around the edges, this should
|
||||
improve over time.
|
||||
|
||||
|
||||
Firmware:
|
||||
|
||||
The firmware needs to be extracted from the Windows Hauppauge HVR-1600
|
||||
driver, available here:
|
||||
You can obtain the firmware files here:
|
||||
|
||||
http://hauppauge.lightpath.net/software/install_cd/hauppauge_cd_3.4d1.zip
|
||||
http://dl.ivtvdriver.org/ivtv/firmware/cx18-firmware.tar.gz
|
||||
|
||||
Unzip, then copy the following files to the firmware directory
|
||||
and rename them as follows:
|
||||
|
||||
Drivers/Driver18/hcw18apu.rom -> v4l-cx23418-apu.fw
|
||||
Drivers/Driver18/hcw18enc.rom -> v4l-cx23418-cpu.fw
|
||||
Drivers/Driver18/hcw18mlC.rom -> v4l-cx23418-dig.fw
|
||||
Untar and copy the .fw files to your firmware directory.
|
||||
|
243
Documentation/video4linux/gspca.txt
Normal file
243
Documentation/video4linux/gspca.txt
Normal file
@ -0,0 +1,243 @@
|
||||
List of the webcams know by gspca.
|
||||
|
||||
The modules are:
|
||||
gspca_main main driver
|
||||
gspca_xxxx subdriver module with xxxx as follows
|
||||
|
||||
xxxx vend:prod
|
||||
----
|
||||
spca501 0000:0000 MystFromOri Unknow Camera
|
||||
spca501 040a:0002 Kodak DVC-325
|
||||
spca500 040a:0300 Kodak EZ200
|
||||
zc3xx 041e:041e Creative WebCam Live!
|
||||
spca500 041e:400a Creative PC-CAM 300
|
||||
sunplus 041e:400b Creative PC-CAM 600
|
||||
sunplus 041e:4012 PC-Cam350
|
||||
sunplus 041e:4013 Creative Pccam750
|
||||
zc3xx 041e:4017 Creative Webcam Mobile PD1090
|
||||
spca508 041e:4018 Creative Webcam Vista (PD1100)
|
||||
spca561 041e:401a Creative Webcam Vista (PD1100)
|
||||
zc3xx 041e:401c Creative NX
|
||||
spca505 041e:401d Creative Webcam NX ULTRA
|
||||
zc3xx 041e:401e Creative Nx Pro
|
||||
zc3xx 041e:401f Creative Webcam Notebook PD1171
|
||||
pac207 041e:4028 Creative Webcam Vista Plus
|
||||
zc3xx 041e:4029 Creative WebCam Vista Pro
|
||||
zc3xx 041e:4034 Creative Instant P0620
|
||||
zc3xx 041e:4035 Creative Instant P0620D
|
||||
zc3xx 041e:4036 Creative Live !
|
||||
zc3xx 041e:403a Creative Nx Pro 2
|
||||
spca561 041e:403b Creative Webcam Vista (VF0010)
|
||||
zc3xx 041e:4051 Creative Live!Cam Notebook Pro (VF0250)
|
||||
ov519 041e:4052 Creative Live! VISTA IM
|
||||
zc3xx 041e:4053 Creative Live!Cam Video IM
|
||||
ov519 041e:405f Creative Live! VISTA VF0330
|
||||
ov519 041e:4060 Creative Live! VISTA VF0350
|
||||
ov519 041e:4061 Creative Live! VISTA VF0400
|
||||
ov519 041e:4064 Creative Live! VISTA VF0420
|
||||
ov519 041e:4068 Creative Live! VISTA VF0470
|
||||
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
|
||||
sunplus 0461:0821 Fujifilm MV-1
|
||||
zc3xx 0461:0a00 MicroInnovation WebCam320
|
||||
spca500 046d:0890 Logitech QuickCam traveler
|
||||
vc032x 046d:0892 Logitech Orbicam
|
||||
vc032x 046d:0896 Logitech Orbicam
|
||||
zc3xx 046d:08a0 Logitech QC IM
|
||||
zc3xx 046d:08a1 Logitech QC IM 0x08A1 +sound
|
||||
zc3xx 046d:08a2 Labtec Webcam Pro
|
||||
zc3xx 046d:08a3 Logitech QC Chat
|
||||
zc3xx 046d:08a6 Logitech QCim
|
||||
zc3xx 046d:08a7 Logitech QuickCam Image
|
||||
zc3xx 046d:08a9 Logitech Notebook Deluxe
|
||||
zc3xx 046d:08aa Labtec Webcam Notebook
|
||||
zc3xx 046d:08ac Logitech QuickCam Cool
|
||||
zc3xx 046d:08ad Logitech QCCommunicate STX
|
||||
zc3xx 046d:08ae Logitech QuickCam for Notebooks
|
||||
zc3xx 046d:08af Logitech QuickCam Cool
|
||||
zc3xx 046d:08b9 Logitech QC IM ???
|
||||
zc3xx 046d:08d7 Logitech QCam STX
|
||||
zc3xx 046d:08d9 Logitech QuickCam IM/Connect
|
||||
zc3xx 046d:08d8 Logitech Notebook Deluxe
|
||||
zc3xx 046d:08da Logitech QuickCam Messenger
|
||||
zc3xx 046d:08dd Logitech QuickCam for Notebooks
|
||||
spca500 046d:0900 Logitech Inc. ClickSmart 310
|
||||
spca500 046d:0901 Logitech Inc. ClickSmart 510
|
||||
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
|
||||
spca508 0130:0130 Clone Digital Webcam 11043
|
||||
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:2050 Medion MD 41437
|
||||
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 Microdia Sweex Mini Webcam
|
||||
sonixb 0c45:6007 Sonix sn9c101 + Tas5110D
|
||||
sonixb 0c45:6009 spcaCam@120
|
||||
sonixb 0c45:600d spcaCam@120
|
||||
sonixb 0c45:6011 Microdia PC Camera (SN9C102)
|
||||
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
|
@ -38,7 +38,6 @@ config VIDEO_ALLOW_V4L1
|
||||
bool "Enable Video For Linux API 1 (DEPRECATED)"
|
||||
depends on VIDEO_DEV && VIDEO_V4L2_COMMON
|
||||
default VIDEO_DEV && VIDEO_V4L2_COMMON
|
||||
select VIDEO_V4L1_COMPAT
|
||||
---help---
|
||||
Enables drivers based on the legacy V4L1 API.
|
||||
|
||||
@ -49,9 +48,9 @@ config VIDEO_ALLOW_V4L1
|
||||
If you are unsure as to whether this is required, answer Y.
|
||||
|
||||
config VIDEO_V4L1_COMPAT
|
||||
bool "Enable Video For Linux API 1 compatible Layer"
|
||||
bool "Enable Video For Linux API 1 compatible Layer" if !VIDEO_ALLOW_V4L1
|
||||
depends on VIDEO_DEV
|
||||
default VIDEO_DEV
|
||||
default y
|
||||
---help---
|
||||
Enables a compatibility API used by most V4L2 devices to allow
|
||||
its usage with legacy applications that supports only V4L1 api.
|
||||
|
@ -66,7 +66,6 @@ void ir_input_init(struct input_dev *dev, struct ir_input_state *ir,
|
||||
if (ir_codes)
|
||||
memcpy(ir->ir_codes, ir_codes, sizeof(ir->ir_codes));
|
||||
|
||||
|
||||
dev->keycode = ir->ir_codes;
|
||||
dev->keycodesize = sizeof(IR_KEYTAB_TYPE);
|
||||
dev->keycodemax = IR_KEYTAB_SIZE;
|
||||
@ -78,6 +77,7 @@ void ir_input_init(struct input_dev *dev, struct ir_input_state *ir,
|
||||
if (repeat)
|
||||
set_bit(EV_REP, dev->evbit);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ir_input_init);
|
||||
|
||||
void ir_input_nokey(struct input_dev *dev, struct ir_input_state *ir)
|
||||
{
|
||||
@ -86,6 +86,7 @@ void ir_input_nokey(struct input_dev *dev, struct ir_input_state *ir)
|
||||
ir_input_key_event(dev,ir);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ir_input_nokey);
|
||||
|
||||
void ir_input_keydown(struct input_dev *dev, struct ir_input_state *ir,
|
||||
u32 ir_key, u32 ir_raw)
|
||||
@ -104,6 +105,7 @@ void ir_input_keydown(struct input_dev *dev, struct ir_input_state *ir,
|
||||
ir_input_key_event(dev,ir);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ir_input_keydown);
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* extract mask bits out of data and pack them into the result */
|
||||
@ -122,6 +124,7 @@ u32 ir_extract_bits(u32 data, u32 mask)
|
||||
|
||||
return value;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ir_extract_bits);
|
||||
|
||||
static int inline getbit(u32 *samples, int bit)
|
||||
{
|
||||
@ -146,6 +149,7 @@ int ir_dump_samples(u32 *samples, int count)
|
||||
printk("\n");
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ir_dump_samples);
|
||||
|
||||
/* decode raw samples, pulse distance coding used by NEC remotes */
|
||||
int ir_decode_pulsedistance(u32 *samples, int count, int low, int high)
|
||||
@ -212,6 +216,7 @@ int ir_decode_pulsedistance(u32 *samples, int count, int low, int high)
|
||||
|
||||
return value;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ir_decode_pulsedistance);
|
||||
|
||||
/* decode raw samples, biphase coding, used by rc5 for example */
|
||||
int ir_decode_biphase(u32 *samples, int count, int low, int high)
|
||||
@ -253,6 +258,7 @@ int ir_decode_biphase(u32 *samples, int count, int low, int high)
|
||||
}
|
||||
return value;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ir_decode_biphase);
|
||||
|
||||
/* RC5 decoding stuff, moved from bttv-input.c to share it with
|
||||
* saa7134 */
|
||||
@ -353,6 +359,7 @@ void ir_rc5_timer_end(unsigned long data)
|
||||
}
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ir_rc5_timer_end);
|
||||
|
||||
void ir_rc5_timer_keyup(unsigned long data)
|
||||
{
|
||||
@ -361,21 +368,4 @@ void ir_rc5_timer_keyup(unsigned long data)
|
||||
dprintk(1, "ir-common: key released\n");
|
||||
ir_input_nokey(ir->dev, &ir->ir);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(ir_input_init);
|
||||
EXPORT_SYMBOL_GPL(ir_input_nokey);
|
||||
EXPORT_SYMBOL_GPL(ir_input_keydown);
|
||||
|
||||
EXPORT_SYMBOL_GPL(ir_extract_bits);
|
||||
EXPORT_SYMBOL_GPL(ir_dump_samples);
|
||||
EXPORT_SYMBOL_GPL(ir_decode_biphase);
|
||||
EXPORT_SYMBOL_GPL(ir_decode_pulsedistance);
|
||||
|
||||
EXPORT_SYMBOL_GPL(ir_rc5_timer_end);
|
||||
EXPORT_SYMBOL_GPL(ir_rc5_timer_keyup);
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-basic-offset: 8
|
||||
* End:
|
||||
*/
|
||||
|
@ -233,7 +233,7 @@ void saa7146_pgtable_free(struct pci_dev *pci, struct saa7146_pgtable *pt)
|
||||
|
||||
int saa7146_pgtable_alloc(struct pci_dev *pci, struct saa7146_pgtable *pt)
|
||||
{
|
||||
u32 *cpu;
|
||||
__le32 *cpu;
|
||||
dma_addr_t dma_addr;
|
||||
|
||||
cpu = pci_alloc_consistent(pci, PAGE_SIZE, &dma_addr);
|
||||
@ -250,7 +250,7 @@ int saa7146_pgtable_alloc(struct pci_dev *pci, struct saa7146_pgtable *pt)
|
||||
int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt,
|
||||
struct scatterlist *list, int sglen )
|
||||
{
|
||||
u32 *ptr, fill;
|
||||
__le32 *ptr, fill;
|
||||
int nr_pages = 0;
|
||||
int i,p;
|
||||
|
||||
|
@ -338,7 +338,7 @@ static void calculate_clipping_registers_rect(struct saa7146_dev *dev, struct sa
|
||||
struct saa7146_video_dma *vdma2, u32* clip_format, u32* arbtr_ctrl, enum v4l2_field field)
|
||||
{
|
||||
struct saa7146_vv *vv = dev->vv_data;
|
||||
u32 *clipping = vv->d_clipping.cpu_addr;
|
||||
__le32 *clipping = vv->d_clipping.cpu_addr;
|
||||
|
||||
int width = fh->ov.win.w.width;
|
||||
int height = fh->ov.win.w.height;
|
||||
|
@ -24,7 +24,7 @@ static inline u32 saa7146_i2c_status(struct saa7146_dev *dev)
|
||||
sent through the saa7146. have a look at the specifications p. 122 ff
|
||||
to understand this. it returns the number of u32s to send, or -1
|
||||
in case of an error. */
|
||||
static int saa7146_i2c_msg_prepare(const struct i2c_msg *m, int num, u32 *op)
|
||||
static int saa7146_i2c_msg_prepare(const struct i2c_msg *m, int num, __le32 *op)
|
||||
{
|
||||
int h1, h2;
|
||||
int i, j, addr;
|
||||
@ -47,7 +47,7 @@ static int saa7146_i2c_msg_prepare(const struct i2c_msg *m, int num, u32 *op)
|
||||
}
|
||||
|
||||
/* be careful: clear out the i2c-mem first */
|
||||
memset(op,0,sizeof(u32)*mem);
|
||||
memset(op,0,sizeof(__le32)*mem);
|
||||
|
||||
/* loop through all messages */
|
||||
for(i = 0; i < num; i++) {
|
||||
@ -57,16 +57,16 @@ static int saa7146_i2c_msg_prepare(const struct i2c_msg *m, int num, u32 *op)
|
||||
so we have to perform a translation */
|
||||
addr = (m[i].addr*2) + ( (0 != (m[i].flags & I2C_M_RD)) ? 1 : 0);
|
||||
h1 = op_count/3; h2 = op_count%3;
|
||||
op[h1] |= ( (u8)addr << ((3-h2)*8));
|
||||
op[h1] |= (SAA7146_I2C_START << ((3-h2)*2));
|
||||
op[h1] |= cpu_to_le32( (u8)addr << ((3-h2)*8));
|
||||
op[h1] |= cpu_to_le32(SAA7146_I2C_START << ((3-h2)*2));
|
||||
op_count++;
|
||||
|
||||
/* loop through all bytes of message i */
|
||||
for(j = 0; j < m[i].len; j++) {
|
||||
/* insert the data bytes */
|
||||
h1 = op_count/3; h2 = op_count%3;
|
||||
op[h1] |= ( (u32)((u8)m[i].buf[j]) << ((3-h2)*8));
|
||||
op[h1] |= ( SAA7146_I2C_CONT << ((3-h2)*2));
|
||||
op[h1] |= cpu_to_le32( (u32)((u8)m[i].buf[j]) << ((3-h2)*8));
|
||||
op[h1] |= cpu_to_le32( SAA7146_I2C_CONT << ((3-h2)*2));
|
||||
op_count++;
|
||||
}
|
||||
|
||||
@ -75,9 +75,9 @@ static int saa7146_i2c_msg_prepare(const struct i2c_msg *m, int num, u32 *op)
|
||||
/* have a look at the last byte inserted:
|
||||
if it was: ...CONT change it to ...STOP */
|
||||
h1 = (op_count-1)/3; h2 = (op_count-1)%3;
|
||||
if ( SAA7146_I2C_CONT == (0x3 & (op[h1] >> ((3-h2)*2))) ) {
|
||||
op[h1] &= ~(0x2 << ((3-h2)*2));
|
||||
op[h1] |= (SAA7146_I2C_STOP << ((3-h2)*2));
|
||||
if ( SAA7146_I2C_CONT == (0x3 & (le32_to_cpu(op[h1]) >> ((3-h2)*2))) ) {
|
||||
op[h1] &= ~cpu_to_le32(0x2 << ((3-h2)*2));
|
||||
op[h1] |= cpu_to_le32(SAA7146_I2C_STOP << ((3-h2)*2));
|
||||
}
|
||||
|
||||
/* return the number of u32s to send */
|
||||
@ -88,7 +88,7 @@ static int saa7146_i2c_msg_prepare(const struct i2c_msg *m, int num, u32 *op)
|
||||
which bytes were read through the adapter and write them back to the corresponding
|
||||
i2c-message. but instead, we simply write back all bytes.
|
||||
fixme: this could be improved. */
|
||||
static int saa7146_i2c_msg_cleanup(const struct i2c_msg *m, int num, u32 *op)
|
||||
static int saa7146_i2c_msg_cleanup(const struct i2c_msg *m, int num, __le32 *op)
|
||||
{
|
||||
int i, j;
|
||||
int op_count = 0;
|
||||
@ -101,7 +101,7 @@ static int saa7146_i2c_msg_cleanup(const struct i2c_msg *m, int num, u32 *op)
|
||||
/* loop throgh all bytes of message i */
|
||||
for(j = 0; j < m[i].len; j++) {
|
||||
/* write back all bytes that could have been read */
|
||||
m[i].buf[j] = (op[op_count/3] >> ((3-(op_count%3))*8));
|
||||
m[i].buf[j] = (le32_to_cpu(op[op_count/3]) >> ((3-(op_count%3))*8));
|
||||
op_count++;
|
||||
}
|
||||
}
|
||||
@ -174,7 +174,7 @@ static int saa7146_i2c_reset(struct saa7146_dev *dev)
|
||||
/* this functions writes out the data-byte 'dword' to the i2c-device.
|
||||
it returns 0 if ok, -1 if the transfer failed, -2 if the transfer
|
||||
failed badly (e.g. address error) */
|
||||
static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_delay)
|
||||
static int saa7146_i2c_writeout(struct saa7146_dev *dev, __le32 *dword, int short_delay)
|
||||
{
|
||||
u32 status = 0, mc2 = 0;
|
||||
int trial = 0;
|
||||
@ -186,7 +186,7 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_d
|
||||
if( 0 != (SAA7146_USE_I2C_IRQ & dev->ext->flags)) {
|
||||
|
||||
saa7146_write(dev, I2C_STATUS, dev->i2c_bitrate);
|
||||
saa7146_write(dev, I2C_TRANSFER, *dword);
|
||||
saa7146_write(dev, I2C_TRANSFER, le32_to_cpu(*dword));
|
||||
|
||||
dev->i2c_op = 1;
|
||||
SAA7146_ISR_CLEAR(dev, MASK_16|MASK_17);
|
||||
@ -209,7 +209,7 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_d
|
||||
status = saa7146_read(dev, I2C_STATUS);
|
||||
} else {
|
||||
saa7146_write(dev, I2C_STATUS, dev->i2c_bitrate);
|
||||
saa7146_write(dev, I2C_TRANSFER, *dword);
|
||||
saa7146_write(dev, I2C_TRANSFER, le32_to_cpu(*dword));
|
||||
saa7146_write(dev, MC2, (MASK_00 | MASK_16));
|
||||
|
||||
/* do not poll for i2c-status before upload is complete */
|
||||
@ -282,7 +282,7 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_d
|
||||
}
|
||||
|
||||
/* read back data, just in case we were reading ... */
|
||||
*dword = saa7146_read(dev, I2C_TRANSFER);
|
||||
*dword = cpu_to_le32(saa7146_read(dev, I2C_TRANSFER));
|
||||
|
||||
DEB_I2C(("after: 0x%08x\n",*dword));
|
||||
return 0;
|
||||
@ -291,7 +291,7 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_d
|
||||
static int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg *msgs, int num, int retries)
|
||||
{
|
||||
int i = 0, count = 0;
|
||||
u32* buffer = dev->d_i2c.cpu_addr;
|
||||
__le32 *buffer = dev->d_i2c.cpu_addr;
|
||||
int err = 0;
|
||||
int address_err = 0;
|
||||
int short_delay = 0;
|
||||
@ -376,7 +376,7 @@ out:
|
||||
/* another bug in revision 0: the i2c-registers get uploaded randomly by other
|
||||
uploads, so we better clear them out before continueing */
|
||||
if( 0 == dev->revision ) {
|
||||
u32 zero = 0;
|
||||
__le32 zero = 0;
|
||||
saa7146_i2c_reset(dev);
|
||||
if( 0 != saa7146_i2c_writeout(dev, &zero, short_delay)) {
|
||||
INFO(("revision 0 error. this should never happen.\n"));
|
||||
|
@ -605,8 +605,8 @@ static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *bu
|
||||
struct saa7146_pgtable *pt1 = &buf->pt[0];
|
||||
struct saa7146_pgtable *pt2 = &buf->pt[1];
|
||||
struct saa7146_pgtable *pt3 = &buf->pt[2];
|
||||
u32 *ptr1, *ptr2, *ptr3;
|
||||
u32 fill;
|
||||
__le32 *ptr1, *ptr2, *ptr3;
|
||||
__le32 fill;
|
||||
|
||||
int size = buf->fmt->width*buf->fmt->height;
|
||||
int i,p,m1,m2,m3,o1,o2;
|
||||
|
@ -34,6 +34,7 @@ config MEDIA_TUNER
|
||||
menuconfig MEDIA_TUNER_CUSTOMIZE
|
||||
bool "Customize analog and hybrid tuner modules to build"
|
||||
depends on MEDIA_TUNER
|
||||
default n
|
||||
help
|
||||
This allows the user to deselect tuner drivers unnecessary
|
||||
for their hardware from the build. Use this option with care
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
tda18271-tables.c - driver for the Philips / NXP TDA18271 silicon tuner
|
||||
tda18271-maps.c - driver for the Philips / NXP TDA18271 silicon tuner
|
||||
|
||||
Copyright (C) 2007, 2008 Michael Krufky <mkrufky@linuxtv.org>
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <linux/delay.h>
|
||||
#include <media/tuner.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <asm/unaligned.h>
|
||||
#include "tuner-i2c.h"
|
||||
#include "tuner-xc2028.h"
|
||||
#include "tuner-xc2028-types.h"
|
||||
@ -292,10 +293,10 @@ static int load_all_firmwares(struct dvb_frontend *fe)
|
||||
name[sizeof(name) - 1] = 0;
|
||||
p += sizeof(name) - 1;
|
||||
|
||||
priv->firm_version = le16_to_cpu(*(__u16 *) p);
|
||||
priv->firm_version = get_unaligned_le16(p);
|
||||
p += 2;
|
||||
|
||||
n_array = le16_to_cpu(*(__u16 *) p);
|
||||
n_array = get_unaligned_le16(p);
|
||||
p += 2;
|
||||
|
||||
tuner_info("Loading %d firmware images from %s, type: %s, ver %d.%d\n",
|
||||
@ -324,26 +325,26 @@ static int load_all_firmwares(struct dvb_frontend *fe)
|
||||
}
|
||||
|
||||
/* Checks if there's enough bytes to read */
|
||||
if (p + sizeof(type) + sizeof(id) + sizeof(size) > endp) {
|
||||
tuner_err("Firmware header is incomplete!\n");
|
||||
goto corrupt;
|
||||
}
|
||||
if (endp - p < sizeof(type) + sizeof(id) + sizeof(size))
|
||||
goto header;
|
||||
|
||||
type = le32_to_cpu(*(__u32 *) p);
|
||||
type = get_unaligned_le32(p);
|
||||
p += sizeof(type);
|
||||
|
||||
id = le64_to_cpu(*(v4l2_std_id *) p);
|
||||
id = get_unaligned_le64(p);
|
||||
p += sizeof(id);
|
||||
|
||||
if (type & HAS_IF) {
|
||||
int_freq = le16_to_cpu(*(__u16 *) p);
|
||||
int_freq = get_unaligned_le16(p);
|
||||
p += sizeof(int_freq);
|
||||
if (endp - p < sizeof(size))
|
||||
goto header;
|
||||
}
|
||||
|
||||
size = le32_to_cpu(*(__u32 *) p);
|
||||
size = get_unaligned_le32(p);
|
||||
p += sizeof(size);
|
||||
|
||||
if ((!size) || (size + p > endp)) {
|
||||
if (!size || size > endp - p) {
|
||||
tuner_err("Firmware type ");
|
||||
dump_firm_type(type);
|
||||
printk("(%x), id %llx is corrupted "
|
||||
@ -382,6 +383,8 @@ static int load_all_firmwares(struct dvb_frontend *fe)
|
||||
|
||||
goto done;
|
||||
|
||||
header:
|
||||
tuner_err("Firmware header is incomplete!\n");
|
||||
corrupt:
|
||||
rc = -EINVAL;
|
||||
tuner_err("Error: firmware file is corrupted!\n");
|
||||
|
@ -36,6 +36,10 @@ static int debug;
|
||||
module_param(debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
|
||||
|
||||
static int xc5000_load_fw_on_attach;
|
||||
module_param_named(init_fw, xc5000_load_fw_on_attach, int, 0644);
|
||||
MODULE_PARM_DESC(init_fw, "Load firmware during driver initialization.");
|
||||
|
||||
#define dprintk(level,fmt, arg...) if (debug >= level) \
|
||||
printk(KERN_INFO "%s: " fmt, "xc5000", ## arg)
|
||||
|
||||
@ -972,6 +976,9 @@ struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
|
||||
|
||||
fe->tuner_priv = priv;
|
||||
|
||||
if (xc5000_load_fw_on_attach)
|
||||
xc5000_init(fe);
|
||||
|
||||
return fe;
|
||||
}
|
||||
EXPORT_SYMBOL(xc5000_attach);
|
||||
|
@ -21,6 +21,7 @@ source "drivers/media/dvb/dvb-usb/Kconfig"
|
||||
source "drivers/media/dvb/ttusb-budget/Kconfig"
|
||||
source "drivers/media/dvb/ttusb-dec/Kconfig"
|
||||
source "drivers/media/dvb/cinergyT2/Kconfig"
|
||||
source "drivers/media/dvb/siano/Kconfig"
|
||||
|
||||
comment "Supported FlexCopII (B2C2) Adapters"
|
||||
depends on DVB_CORE && (PCI || USB) && I2C
|
||||
|
@ -2,4 +2,4 @@
|
||||
# Makefile for the kernel multimedia device drivers.
|
||||
#
|
||||
|
||||
obj-y := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ cinergyT2/ dvb-usb/ pluto2/
|
||||
obj-y := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ cinergyT2/ dvb-usb/ pluto2/ siano/
|
||||
|
@ -128,7 +128,7 @@ struct bt878 {
|
||||
dma_addr_t buf_dma;
|
||||
|
||||
u32 risc_size;
|
||||
u32 *risc_cpu;
|
||||
__le32 *risc_cpu;
|
||||
dma_addr_t risc_dma;
|
||||
u32 risc_pos;
|
||||
|
||||
|
@ -247,7 +247,7 @@ struct dmx_demux {
|
||||
void* priv; /* Pointer to private data of the API client */
|
||||
int (*open) (struct dmx_demux* demux);
|
||||
int (*close) (struct dmx_demux* demux);
|
||||
int (*write) (struct dmx_demux* demux, const char* buf, size_t count);
|
||||
int (*write) (struct dmx_demux* demux, const char __user *buf, size_t count);
|
||||
int (*allocate_ts_feed) (struct dmx_demux* demux,
|
||||
struct dmx_ts_feed** feed,
|
||||
dmx_ts_cb callback);
|
||||
|
@ -96,7 +96,7 @@ static ssize_t dvb_dmxdev_buffer_read(struct dvb_ringbuffer *src,
|
||||
if (avail > todo)
|
||||
avail = todo;
|
||||
|
||||
ret = dvb_ringbuffer_read(src, (u8 *)buf, avail, 1);
|
||||
ret = dvb_ringbuffer_read_user(src, buf, avail);
|
||||
if (ret < 0)
|
||||
break;
|
||||
|
||||
|
@ -1357,7 +1357,7 @@ static int dvb_ca_en50221_io_read_condition(struct dvb_ca_private *ca,
|
||||
|
||||
idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, -1, &fraglen);
|
||||
while (idx != -1) {
|
||||
dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 0, hdr, 2, 0);
|
||||
dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 0, hdr, 2);
|
||||
if (connection_id == -1)
|
||||
connection_id = hdr[0];
|
||||
if ((hdr[0] == connection_id) && ((hdr[1] & 0x80) == 0)) {
|
||||
@ -1438,7 +1438,7 @@ static ssize_t dvb_ca_en50221_io_read(struct file *file, char __user * buf,
|
||||
goto exit;
|
||||
}
|
||||
|
||||
dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 0, hdr, 2, 0);
|
||||
dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 0, hdr, 2);
|
||||
if (connection_id == -1)
|
||||
connection_id = hdr[0];
|
||||
if (hdr[0] == connection_id) {
|
||||
@ -1449,8 +1449,8 @@ static ssize_t dvb_ca_en50221_io_read(struct file *file, char __user * buf,
|
||||
fraglen -= 2;
|
||||
}
|
||||
|
||||
if ((status = dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 2,
|
||||
(u8 *)buf + pktlen, fraglen, 1)) < 0) {
|
||||
if ((status = dvb_ringbuffer_pkt_read_user(&ca->slot_info[slot].rx_buffer, idx, 2,
|
||||
buf + pktlen, fraglen)) < 0) {
|
||||
goto exit;
|
||||
}
|
||||
pktlen += fraglen;
|
||||
|
@ -1056,16 +1056,27 @@ static int dvbdmx_close(struct dmx_demux *demux)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dvbdmx_write(struct dmx_demux *demux, const char *buf, size_t count)
|
||||
static int dvbdmx_write(struct dmx_demux *demux, const char __user *buf, size_t count)
|
||||
{
|
||||
struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
|
||||
void *p;
|
||||
|
||||
if ((!demux->frontend) || (demux->frontend->source != DMX_MEMORY_FE))
|
||||
return -EINVAL;
|
||||
|
||||
if (mutex_lock_interruptible(&dvbdemux->mutex))
|
||||
p = kmalloc(count, GFP_USER);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
if (copy_from_user(p, buf, count)) {
|
||||
kfree(p);
|
||||
return -EFAULT;
|
||||
}
|
||||
if (mutex_lock_interruptible(&dvbdemux->mutex)) {
|
||||
kfree(p);
|
||||
return -ERESTARTSYS;
|
||||
dvb_dmx_swfilter(dvbdemux, (u8 *)buf, count);
|
||||
}
|
||||
dvb_dmx_swfilter(dvbdemux, p, count);
|
||||
kfree(p);
|
||||
mutex_unlock(&dvbdemux->mutex);
|
||||
|
||||
if (signal_pending(current))
|
||||
|
@ -606,7 +606,7 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
|
||||
if (priv->ule_dbit) {
|
||||
/* Set D-bit for CRC32 verification,
|
||||
* if it was set originally. */
|
||||
ulen |= 0x0080;
|
||||
ulen |= htons(0x8000);
|
||||
}
|
||||
|
||||
ule_crc = iov_crc32(ule_crc, iov, 3);
|
||||
|
@ -107,35 +107,43 @@ void dvb_ringbuffer_flush_spinlock_wakeup(struct dvb_ringbuffer *rbuf)
|
||||
wake_up(&rbuf->queue);
|
||||
}
|
||||
|
||||
|
||||
|
||||
ssize_t dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf, size_t len, int usermem)
|
||||
ssize_t dvb_ringbuffer_read_user(struct dvb_ringbuffer *rbuf, u8 __user *buf, size_t len)
|
||||
{
|
||||
size_t todo = len;
|
||||
size_t split;
|
||||
|
||||
split = (rbuf->pread + len > rbuf->size) ? rbuf->size - rbuf->pread : 0;
|
||||
if (split > 0) {
|
||||
if (!usermem)
|
||||
memcpy(buf, rbuf->data+rbuf->pread, split);
|
||||
else
|
||||
if (copy_to_user(buf, rbuf->data+rbuf->pread, split))
|
||||
return -EFAULT;
|
||||
if (copy_to_user(buf, rbuf->data+rbuf->pread, split))
|
||||
return -EFAULT;
|
||||
buf += split;
|
||||
todo -= split;
|
||||
rbuf->pread = 0;
|
||||
}
|
||||
if (!usermem)
|
||||
memcpy(buf, rbuf->data+rbuf->pread, todo);
|
||||
else
|
||||
if (copy_to_user(buf, rbuf->data+rbuf->pread, todo))
|
||||
return -EFAULT;
|
||||
if (copy_to_user(buf, rbuf->data+rbuf->pread, todo))
|
||||
return -EFAULT;
|
||||
|
||||
rbuf->pread = (rbuf->pread + todo) % rbuf->size;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
void dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf, size_t len)
|
||||
{
|
||||
size_t todo = len;
|
||||
size_t split;
|
||||
|
||||
split = (rbuf->pread + len > rbuf->size) ? rbuf->size - rbuf->pread : 0;
|
||||
if (split > 0) {
|
||||
memcpy(buf, rbuf->data+rbuf->pread, split);
|
||||
buf += split;
|
||||
todo -= split;
|
||||
rbuf->pread = 0;
|
||||
}
|
||||
memcpy(buf, rbuf->data+rbuf->pread, todo);
|
||||
|
||||
rbuf->pread = (rbuf->pread + todo) % rbuf->size;
|
||||
}
|
||||
|
||||
|
||||
ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf, size_t len)
|
||||
@ -171,8 +179,8 @@ ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf, size_t le
|
||||
return status;
|
||||
}
|
||||
|
||||
ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx,
|
||||
int offset, u8* buf, size_t len, int usermem)
|
||||
ssize_t dvb_ringbuffer_pkt_read_user(struct dvb_ringbuffer *rbuf, size_t idx,
|
||||
int offset, u8 __user *buf, size_t len)
|
||||
{
|
||||
size_t todo;
|
||||
size_t split;
|
||||
@ -187,24 +195,43 @@ ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx,
|
||||
todo = len;
|
||||
split = ((idx + len) > rbuf->size) ? rbuf->size - idx : 0;
|
||||
if (split > 0) {
|
||||
if (!usermem)
|
||||
memcpy(buf, rbuf->data+idx, split);
|
||||
else
|
||||
if (copy_to_user(buf, rbuf->data+idx, split))
|
||||
return -EFAULT;
|
||||
if (copy_to_user(buf, rbuf->data+idx, split))
|
||||
return -EFAULT;
|
||||
buf += split;
|
||||
todo -= split;
|
||||
idx = 0;
|
||||
}
|
||||
if (!usermem)
|
||||
memcpy(buf, rbuf->data+idx, todo);
|
||||
else
|
||||
if (copy_to_user(buf, rbuf->data+idx, todo))
|
||||
return -EFAULT;
|
||||
if (copy_to_user(buf, rbuf->data+idx, todo))
|
||||
return -EFAULT;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx,
|
||||
int offset, u8* buf, size_t len)
|
||||
{
|
||||
size_t todo;
|
||||
size_t split;
|
||||
size_t pktlen;
|
||||
|
||||
pktlen = rbuf->data[idx] << 8;
|
||||
pktlen |= rbuf->data[(idx + 1) % rbuf->size];
|
||||
if (offset > pktlen) return -EINVAL;
|
||||
if ((offset + len) > pktlen) len = pktlen - offset;
|
||||
|
||||
idx = (idx + DVB_RINGBUFFER_PKTHDRSIZE + offset) % rbuf->size;
|
||||
todo = len;
|
||||
split = ((idx + len) > rbuf->size) ? rbuf->size - idx : 0;
|
||||
if (split > 0) {
|
||||
memcpy(buf, rbuf->data+idx, split);
|
||||
buf += split;
|
||||
todo -= split;
|
||||
idx = 0;
|
||||
}
|
||||
memcpy(buf, rbuf->data+idx, todo);
|
||||
return len;
|
||||
}
|
||||
|
||||
void dvb_ringbuffer_pkt_dispose(struct dvb_ringbuffer *rbuf, size_t idx)
|
||||
{
|
||||
size_t pktlen;
|
||||
@ -266,5 +293,6 @@ EXPORT_SYMBOL(dvb_ringbuffer_empty);
|
||||
EXPORT_SYMBOL(dvb_ringbuffer_free);
|
||||
EXPORT_SYMBOL(dvb_ringbuffer_avail);
|
||||
EXPORT_SYMBOL(dvb_ringbuffer_flush_spinlock_wakeup);
|
||||
EXPORT_SYMBOL(dvb_ringbuffer_read_user);
|
||||
EXPORT_SYMBOL(dvb_ringbuffer_read);
|
||||
EXPORT_SYMBOL(dvb_ringbuffer_write);
|
||||
|
@ -61,7 +61,7 @@ struct dvb_ringbuffer {
|
||||
** *** read min. 1000, max. <bufsize> bytes ***
|
||||
** avail = dvb_ringbuffer_avail(rbuf);
|
||||
** if (avail >= 1000)
|
||||
** count = dvb_ringbuffer_read(rbuf, buffer, min(avail, bufsize), 0);
|
||||
** count = dvb_ringbuffer_read(rbuf, buffer, min(avail, bufsize));
|
||||
** else
|
||||
** ...
|
||||
**
|
||||
@ -114,8 +114,10 @@ extern void dvb_ringbuffer_flush_spinlock_wakeup(struct dvb_ringbuffer *rbuf);
|
||||
** <usermem> specifies whether <buf> resides in user space
|
||||
** returns number of bytes transferred or -EFAULT
|
||||
*/
|
||||
extern ssize_t dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf,
|
||||
size_t len, int usermem);
|
||||
extern ssize_t dvb_ringbuffer_read_user(struct dvb_ringbuffer *rbuf,
|
||||
u8 __user *buf, size_t len);
|
||||
extern void dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf,
|
||||
u8 *buf, size_t len);
|
||||
|
||||
|
||||
/* write routines & macros */
|
||||
@ -157,8 +159,10 @@ extern ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf,
|
||||
* <usermem> Set to 1 if <buf> is in userspace.
|
||||
* returns Number of bytes read, or -EFAULT.
|
||||
*/
|
||||
extern ssize_t dvb_ringbuffer_pkt_read_user(struct dvb_ringbuffer *rbuf, size_t idx,
|
||||
int offset, u8 __user *buf, size_t len);
|
||||
extern ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx,
|
||||
int offset, u8* buf, size_t len, int usermem);
|
||||
int offset, u8 *buf, size_t len);
|
||||
|
||||
/**
|
||||
* Dispose of a packet in the ring buffer.
|
||||
|
@ -76,6 +76,7 @@ config DVB_USB_DIB0700
|
||||
select DVB_DIB3000MC
|
||||
select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE
|
||||
select MEDIA_TUNER_MT2266 if !DVB_FE_CUSTOMISE
|
||||
select MEDIA_TUNER_XC2028 if !DVB_FE_CUSTOMISE
|
||||
select DVB_TUNER_DIB0070
|
||||
help
|
||||
Support for USB2.0/1.1 DVB receivers based on the DiB0700 USB bridge. The
|
||||
@ -107,6 +108,8 @@ config DVB_USB_CXUSB
|
||||
select DVB_MT352 if !DVB_FE_CUSTOMISE
|
||||
select DVB_ZL10353 if !DVB_FE_CUSTOMISE
|
||||
select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE
|
||||
select MEDIA_TUNER_XC2028 if !DVB_FE_CUSTOMISE
|
||||
select MEDIA_TUNER_MXL5005S if !DVB_FE_CUSTOMISE
|
||||
help
|
||||
Say Y here to support the Conexant USB2.0 hybrid reference design.
|
||||
Currently, only DVB and ATSC modes are supported, analog mode
|
||||
@ -120,6 +123,8 @@ config DVB_USB_M920X
|
||||
depends on DVB_USB
|
||||
select DVB_MT352 if !DVB_FE_CUSTOMISE
|
||||
select MEDIA_TUNER_QT1010 if !DVB_FE_CUSTOMISE
|
||||
select MEDIA_TUNER_TDA827X if !DVB_FE_CUSTOMISE
|
||||
select DVB_TDA1004X if !DVB_FE_CUSTOMISE
|
||||
help
|
||||
Say Y here to support the MSI Mega Sky 580 USB2.0 DVB-T receiver.
|
||||
Currently, only devices with a product id of
|
||||
@ -241,3 +246,13 @@ config DVB_USB_AF9005_REMOTE
|
||||
Say Y here to support the default remote control decoding for the
|
||||
Afatech AF9005 based receiver.
|
||||
|
||||
config DVB_USB_ANYSEE
|
||||
tristate "Anysee DVB-T/C USB2.0 support"
|
||||
depends on DVB_USB
|
||||
select DVB_PLL if !DVB_FE_CUSTOMISE
|
||||
select DVB_MT352 if !DVB_FE_CUSTOMISE
|
||||
select DVB_ZL10353 if !DVB_FE_CUSTOMISE
|
||||
select DVB_TDA10023 if !DVB_FE_CUSTOMISE
|
||||
help
|
||||
Say Y here to support the Anysee E30, Anysee E30 Plus or
|
||||
Anysee E30 C Plus DVB USB2.0 receiver.
|
||||
|
@ -61,6 +61,9 @@ obj-$(CONFIG_DVB_USB_AF9005) += dvb-usb-af9005.o
|
||||
dvb-usb-af9005-remote-objs = af9005-remote.o
|
||||
obj-$(CONFIG_DVB_USB_AF9005_REMOTE) += dvb-usb-af9005-remote.o
|
||||
|
||||
dvb-usb-anysee-objs = anysee.o
|
||||
obj-$(CONFIG_DVB_USB_ANYSEE) += dvb-usb-anysee.o
|
||||
|
||||
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
|
||||
# due to tuner-xc3028
|
||||
EXTRA_CFLAGS += -Idrivers/media/common/tuners
|
||||
|
553
drivers/media/dvb/dvb-usb/anysee.c
Normal file
553
drivers/media/dvb/dvb-usb/anysee.c
Normal file
@ -0,0 +1,553 @@
|
||||
/*
|
||||
* DVB USB Linux driver for Anysee E30 DVB-C & DVB-T USB2.0 receiver
|
||||
*
|
||||
* Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* TODO:
|
||||
* - add smart card reader support for Conditional Access (CA)
|
||||
*
|
||||
* Card reader in Anysee is nothing more than ISO 7816 card reader.
|
||||
* There is no hardware CAM in any Anysee device sold.
|
||||
* In my understanding it should be implemented by making own module
|
||||
* for ISO 7816 card reader, like dvb_ca_en50221 is implemented. This
|
||||
* module registers serial interface that can be used to communicate
|
||||
* with any ISO 7816 smart card.
|
||||
*
|
||||
* Any help according to implement serial smart card reader support
|
||||
* is highly welcome!
|
||||
*/
|
||||
|
||||
#include "anysee.h"
|
||||
#include "tda1002x.h"
|
||||
#include "mt352.h"
|
||||
#include "mt352_priv.h"
|
||||
#include "zl10353.h"
|
||||
|
||||
/* debug */
|
||||
static int dvb_usb_anysee_debug;
|
||||
module_param_named(debug, dvb_usb_anysee_debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);
|
||||
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
|
||||
|
||||
struct mutex anysee_usb_mutex;
|
||||
|
||||
static int anysee_ctrl_msg(struct dvb_usb_device *d, u8 *sbuf, u8 slen,
|
||||
u8 *rbuf, u8 rlen)
|
||||
{
|
||||
struct anysee_state *state = d->priv;
|
||||
int act_len, ret;
|
||||
u8 buf[64];
|
||||
|
||||
if (slen > sizeof(buf))
|
||||
slen = sizeof(buf);
|
||||
memcpy(&buf[0], sbuf, slen);
|
||||
buf[60] = state->seq++;
|
||||
|
||||
if (mutex_lock_interruptible(&anysee_usb_mutex) < 0)
|
||||
return -EAGAIN;
|
||||
|
||||
/* We need receive one message more after dvb_usb_generic_rw due
|
||||
to weird transaction flow, which is 1 x send + 2 x receive. */
|
||||
ret = dvb_usb_generic_rw(d, buf, sizeof(buf), buf, sizeof(buf), 0);
|
||||
|
||||
if (!ret) {
|
||||
/* receive 2nd answer */
|
||||
ret = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev,
|
||||
d->props.generic_bulk_ctrl_endpoint), buf, sizeof(buf),
|
||||
&act_len, 2000);
|
||||
if (ret)
|
||||
err("%s: recv bulk message failed: %d", __func__, ret);
|
||||
else {
|
||||
deb_xfer("<<< ");
|
||||
debug_dump(buf, act_len, deb_xfer);
|
||||
}
|
||||
}
|
||||
|
||||
/* read request, copy returned data to return buf */
|
||||
if (!ret && rbuf && rlen)
|
||||
memcpy(rbuf, buf, rlen);
|
||||
|
||||
mutex_unlock(&anysee_usb_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int anysee_read_reg(struct dvb_usb_device *d, u16 reg, u8 *val)
|
||||
{
|
||||
u8 buf[] = {CMD_REG_READ, reg >> 8, reg & 0xff, 0x01};
|
||||
int ret;
|
||||
ret = anysee_ctrl_msg(d, buf, sizeof(buf), val, 1);
|
||||
deb_info("%s: reg:%04x val:%02x\n", __func__, reg, *val);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int anysee_write_reg(struct dvb_usb_device *d, u16 reg, u8 val)
|
||||
{
|
||||
u8 buf[] = {CMD_REG_WRITE, reg >> 8, reg & 0xff, 0x01, val};
|
||||
deb_info("%s: reg:%04x val:%02x\n", __func__, reg, val);
|
||||
return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0);
|
||||
}
|
||||
|
||||
static int anysee_get_hw_info(struct dvb_usb_device *d, u8 *id)
|
||||
{
|
||||
u8 buf[] = {CMD_GET_HW_INFO};
|
||||
return anysee_ctrl_msg(d, buf, sizeof(buf), id, 3);
|
||||
}
|
||||
|
||||
static int anysee_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
|
||||
{
|
||||
u8 buf[] = {CMD_STREAMING_CTRL, (u8)onoff, 0x00};
|
||||
deb_info("%s: onoff:%02x\n", __func__, onoff);
|
||||
return anysee_ctrl_msg(adap->dev, buf, sizeof(buf), NULL, 0);
|
||||
}
|
||||
|
||||
static int anysee_led_ctrl(struct dvb_usb_device *d, u8 mode, u8 interval)
|
||||
{
|
||||
u8 buf[] = {CMD_LED_AND_IR_CTRL, 0x01, mode, interval};
|
||||
deb_info("%s: state:%02x interval:%02x\n", __func__, mode, interval);
|
||||
return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0);
|
||||
}
|
||||
|
||||
static int anysee_ir_ctrl(struct dvb_usb_device *d, u8 onoff)
|
||||
{
|
||||
u8 buf[] = {CMD_LED_AND_IR_CTRL, 0x02, onoff};
|
||||
deb_info("%s: onoff:%02x\n", __func__, onoff);
|
||||
return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0);
|
||||
}
|
||||
|
||||
static int anysee_init(struct dvb_usb_device *d)
|
||||
{
|
||||
int ret;
|
||||
/* LED light */
|
||||
ret = anysee_led_ctrl(d, 0x01, 0x03);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* enable IR */
|
||||
ret = anysee_ir_ctrl(d, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* I2C */
|
||||
static int anysee_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
|
||||
int num)
|
||||
{
|
||||
struct dvb_usb_device *d = i2c_get_adapdata(adap);
|
||||
int ret, inc, i = 0;
|
||||
|
||||
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
|
||||
return -EAGAIN;
|
||||
|
||||
while (i < num) {
|
||||
if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) {
|
||||
u8 buf[6];
|
||||
buf[0] = CMD_I2C_READ;
|
||||
buf[1] = msg[i].addr + 1;
|
||||
buf[2] = msg[i].buf[0];
|
||||
buf[3] = 0x00;
|
||||
buf[4] = 0x00;
|
||||
buf[5] = 0x01;
|
||||
ret = anysee_ctrl_msg(d, buf, sizeof(buf), msg[i+1].buf,
|
||||
msg[i+1].len);
|
||||
inc = 2;
|
||||
} else {
|
||||
u8 buf[4+msg[i].len];
|
||||
buf[0] = CMD_I2C_WRITE;
|
||||
buf[1] = msg[i].addr;
|
||||
buf[2] = msg[i].len;
|
||||
buf[3] = 0x01;
|
||||
memcpy(&buf[4], msg[i].buf, msg[i].len);
|
||||
ret = anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0);
|
||||
inc = 1;
|
||||
}
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
i += inc;
|
||||
}
|
||||
|
||||
mutex_unlock(&d->i2c_mutex);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static u32 anysee_i2c_func(struct i2c_adapter *adapter)
|
||||
{
|
||||
return I2C_FUNC_I2C;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm anysee_i2c_algo = {
|
||||
.master_xfer = anysee_master_xfer,
|
||||
.functionality = anysee_i2c_func,
|
||||
};
|
||||
|
||||
static int anysee_mt352_demod_init(struct dvb_frontend *fe)
|
||||
{
|
||||
static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x28 };
|
||||
static u8 reset [] = { RESET, 0x80 };
|
||||
static u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 };
|
||||
static u8 agc_cfg [] = { AGC_TARGET, 0x28, 0x20 };
|
||||
static u8 gpp_ctl_cfg [] = { GPP_CTL, 0x33 };
|
||||
static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 };
|
||||
|
||||
mt352_write(fe, clock_config, sizeof(clock_config));
|
||||
udelay(200);
|
||||
mt352_write(fe, reset, sizeof(reset));
|
||||
mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg));
|
||||
|
||||
mt352_write(fe, agc_cfg, sizeof(agc_cfg));
|
||||
mt352_write(fe, gpp_ctl_cfg, sizeof(gpp_ctl_cfg));
|
||||
mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Callbacks for DVB USB */
|
||||
static struct tda10023_config anysee_tda10023_config = {
|
||||
.demod_address = 0x1a,
|
||||
.invert = 0,
|
||||
.xtal = 16000000,
|
||||
.pll_m = 11,
|
||||
.pll_p = 3,
|
||||
.pll_n = 1,
|
||||
.output_mode = TDA10023_OUTPUT_MODE_PARALLEL_C,
|
||||
.deltaf = 0xfeeb,
|
||||
};
|
||||
|
||||
static struct mt352_config anysee_mt352_config = {
|
||||
.demod_address = 0x1e,
|
||||
.demod_init = anysee_mt352_demod_init,
|
||||
};
|
||||
|
||||
static struct zl10353_config anysee_zl10353_config = {
|
||||
.demod_address = 0x1e,
|
||||
.parallel_ts = 1,
|
||||
};
|
||||
|
||||
static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
int ret;
|
||||
struct anysee_state *state = adap->dev->priv;
|
||||
u8 hw_info[3];
|
||||
u8 io_d; /* IO port D */
|
||||
|
||||
/* check which hardware we have
|
||||
We must do this call two times to get reliable values (hw bug). */
|
||||
ret = anysee_get_hw_info(adap->dev, hw_info);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = anysee_get_hw_info(adap->dev, hw_info);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Meaning of these info bytes are guessed. */
|
||||
info("firmware version:%d.%d.%d hardware id:%d",
|
||||
0, hw_info[1], hw_info[2], hw_info[0]);
|
||||
|
||||
ret = anysee_read_reg(adap->dev, 0xb0, &io_d); /* IO port D */
|
||||
if (ret)
|
||||
return ret;
|
||||
deb_info("%s: IO port D:%02x\n", __func__, io_d);
|
||||
|
||||
/* Select demod using trial and error method. */
|
||||
|
||||
/* Try to attach demodulator in following order:
|
||||
model demod hw firmware
|
||||
1. E30 MT352 02 0.2.1
|
||||
2. E30 ZL10353 02 0.2.1
|
||||
3. E30 Plus ZL10353 06 0.1.0
|
||||
4. E30C Plus TDA10023 0a 0.1.0 rev 0.2
|
||||
4. E30C Plus TDA10023 0f 0.1.2 rev 0.4
|
||||
*/
|
||||
|
||||
/* Zarlink MT352 DVB-T demod inside of Samsung DNOS404ZH102A NIM */
|
||||
adap->fe = dvb_attach(mt352_attach, &anysee_mt352_config,
|
||||
&adap->dev->i2c_adap);
|
||||
if (adap->fe != NULL) {
|
||||
state->tuner = DVB_PLL_THOMSON_DTT7579;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Zarlink ZL10353 DVB-T demod inside of Samsung DNOS404ZH103A NIM */
|
||||
adap->fe = dvb_attach(zl10353_attach, &anysee_zl10353_config,
|
||||
&adap->dev->i2c_adap);
|
||||
if (adap->fe != NULL) {
|
||||
state->tuner = DVB_PLL_THOMSON_DTT7579;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* connect demod on IO port D for TDA10023 & ZL10353 */
|
||||
ret = anysee_write_reg(adap->dev, 0xb0, 0x25);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Zarlink ZL10353 DVB-T demod inside of Samsung DNOS404ZH103A NIM */
|
||||
adap->fe = dvb_attach(zl10353_attach, &anysee_zl10353_config,
|
||||
&adap->dev->i2c_adap);
|
||||
if (adap->fe != NULL) {
|
||||
state->tuner = DVB_PLL_THOMSON_DTT7579;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* IO port E - E30C rev 0.4 board requires this */
|
||||
ret = anysee_write_reg(adap->dev, 0xb1, 0xa7);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Philips TDA10023 DVB-C demod */
|
||||
adap->fe = dvb_attach(tda10023_attach, &anysee_tda10023_config,
|
||||
&adap->dev->i2c_adap, 0x48);
|
||||
if (adap->fe != NULL) {
|
||||
state->tuner = DVB_PLL_SAMSUNG_DTOS403IH102A;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* return IO port D to init value for safe */
|
||||
ret = anysee_write_reg(adap->dev, 0xb0, io_d);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
err("Unkown Anysee version: %02x %02x %02x. "\
|
||||
"Please report the <linux-dvb@linuxtv.org>.",
|
||||
hw_info[0], hw_info[1], hw_info[2]);
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
struct anysee_state *state = adap->dev->priv;
|
||||
deb_info("%s: \n", __func__);
|
||||
|
||||
switch (state->tuner) {
|
||||
case DVB_PLL_THOMSON_DTT7579:
|
||||
/* Thomson dtt7579 (not sure) PLL inside of:
|
||||
Samsung DNOS404ZH102A NIM
|
||||
Samsung DNOS404ZH103A NIM */
|
||||
dvb_attach(dvb_pll_attach, adap->fe, 0x61,
|
||||
NULL, DVB_PLL_THOMSON_DTT7579);
|
||||
break;
|
||||
case DVB_PLL_SAMSUNG_DTOS403IH102A:
|
||||
/* Unknown PLL inside of Samsung DTOS403IH102A tuner module */
|
||||
dvb_attach(dvb_pll_attach, adap->fe, 0xc0,
|
||||
&adap->dev->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int anysee_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
|
||||
{
|
||||
u8 buf[] = {CMD_GET_IR_CODE};
|
||||
struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
|
||||
u8 ircode[2];
|
||||
int i, ret;
|
||||
|
||||
ret = anysee_ctrl_msg(d, buf, sizeof(buf), &ircode[0], 2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*event = 0;
|
||||
*state = REMOTE_NO_KEY_PRESSED;
|
||||
|
||||
for (i = 0; i < d->props.rc_key_map_size; i++) {
|
||||
if (keymap[i].custom == ircode[0] &&
|
||||
keymap[i].data == ircode[1]) {
|
||||
*event = keymap[i].event;
|
||||
*state = REMOTE_KEY_PRESSED;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dvb_usb_rc_key anysee_rc_keys[] = {
|
||||
{ 0x01, 0x00, KEY_0 },
|
||||
{ 0x01, 0x01, KEY_1 },
|
||||
{ 0x01, 0x02, KEY_2 },
|
||||
{ 0x01, 0x03, KEY_3 },
|
||||
{ 0x01, 0x04, KEY_4 },
|
||||
{ 0x01, 0x05, KEY_5 },
|
||||
{ 0x01, 0x06, KEY_6 },
|
||||
{ 0x01, 0x07, KEY_7 },
|
||||
{ 0x01, 0x08, KEY_8 },
|
||||
{ 0x01, 0x09, KEY_9 },
|
||||
{ 0x01, 0x0a, KEY_POWER },
|
||||
{ 0x01, 0x0b, KEY_DOCUMENTS }, /* * */
|
||||
{ 0x01, 0x19, KEY_FAVORITES },
|
||||
{ 0x01, 0x20, KEY_SLEEP },
|
||||
{ 0x01, 0x21, KEY_MODE }, /* 4:3 / 16:9 select */
|
||||
{ 0x01, 0x22, KEY_ZOOM },
|
||||
{ 0x01, 0x47, KEY_TEXT },
|
||||
{ 0x01, 0x16, KEY_TV }, /* TV / radio select */
|
||||
{ 0x01, 0x1e, KEY_LANGUAGE }, /* Second Audio Program */
|
||||
{ 0x01, 0x1a, KEY_SUBTITLE },
|
||||
{ 0x01, 0x1b, KEY_CAMERA }, /* screenshot */
|
||||
{ 0x01, 0x42, KEY_MUTE },
|
||||
{ 0x01, 0x0e, KEY_MENU },
|
||||
{ 0x01, 0x0f, KEY_EPG },
|
||||
{ 0x01, 0x17, KEY_INFO },
|
||||
{ 0x01, 0x10, KEY_EXIT },
|
||||
{ 0x01, 0x13, KEY_VOLUMEUP },
|
||||
{ 0x01, 0x12, KEY_VOLUMEDOWN },
|
||||
{ 0x01, 0x11, KEY_CHANNELUP },
|
||||
{ 0x01, 0x14, KEY_CHANNELDOWN },
|
||||
{ 0x01, 0x15, KEY_OK },
|
||||
{ 0x01, 0x1d, KEY_RED },
|
||||
{ 0x01, 0x1f, KEY_GREEN },
|
||||
{ 0x01, 0x1c, KEY_YELLOW },
|
||||
{ 0x01, 0x44, KEY_BLUE },
|
||||
{ 0x01, 0x0c, KEY_SHUFFLE }, /* snapshot */
|
||||
{ 0x01, 0x48, KEY_STOP },
|
||||
{ 0x01, 0x50, KEY_PLAY },
|
||||
{ 0x01, 0x51, KEY_PAUSE },
|
||||
{ 0x01, 0x49, KEY_RECORD },
|
||||
{ 0x01, 0x18, KEY_PREVIOUS }, /* |<< */
|
||||
{ 0x01, 0x0d, KEY_NEXT }, /* >>| */
|
||||
{ 0x01, 0x24, KEY_PROG1 }, /* F1 */
|
||||
{ 0x01, 0x25, KEY_PROG2 }, /* F2 */
|
||||
};
|
||||
|
||||
/* DVB USB Driver stuff */
|
||||
static struct dvb_usb_device_properties anysee_properties;
|
||||
|
||||
static int anysee_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
struct dvb_usb_device *d;
|
||||
struct usb_host_interface *alt;
|
||||
int ret;
|
||||
|
||||
mutex_init(&anysee_usb_mutex);
|
||||
|
||||
/* There is one interface with two alternate settings.
|
||||
Alternate setting 0 is for bulk transfer.
|
||||
Alternate setting 1 is for isochronous transfer.
|
||||
We use bulk transfer (alternate setting 0). */
|
||||
if (intf->num_altsetting < 1)
|
||||
return -ENODEV;
|
||||
|
||||
ret = dvb_usb_device_init(intf, &anysee_properties, THIS_MODULE, &d,
|
||||
adapter_nr);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
alt = usb_altnum_to_altsetting(intf, 0);
|
||||
if (alt == NULL) {
|
||||
deb_info("%s: no alt found!\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber,
|
||||
alt->desc.bAlternateSetting);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (d)
|
||||
ret = anysee_init(d);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct usb_device_id anysee_table [] = {
|
||||
{ USB_DEVICE(USB_VID_CYPRESS, USB_PID_ANYSEE) },
|
||||
{ USB_DEVICE(USB_VID_AMT, USB_PID_ANYSEE) },
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
MODULE_DEVICE_TABLE(usb, anysee_table);
|
||||
|
||||
static struct dvb_usb_device_properties anysee_properties = {
|
||||
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
|
||||
|
||||
.usb_ctrl = DEVICE_SPECIFIC,
|
||||
|
||||
.size_of_priv = sizeof(struct anysee_state),
|
||||
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.streaming_ctrl = anysee_streaming_ctrl,
|
||||
.frontend_attach = anysee_frontend_attach,
|
||||
.tuner_attach = anysee_tuner_attach,
|
||||
.stream = {
|
||||
.type = USB_BULK,
|
||||
.count = 8,
|
||||
.endpoint = 0x82,
|
||||
.u = {
|
||||
.bulk = {
|
||||
.buffersize = 512,
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
.rc_key_map = anysee_rc_keys,
|
||||
.rc_key_map_size = ARRAY_SIZE(anysee_rc_keys),
|
||||
.rc_query = anysee_rc_query,
|
||||
.rc_interval = 200, /* windows driver uses 500ms */
|
||||
|
||||
.i2c_algo = &anysee_i2c_algo,
|
||||
|
||||
.generic_bulk_ctrl_endpoint = 1,
|
||||
|
||||
.num_device_descs = 1,
|
||||
.devices = {
|
||||
{
|
||||
.name = "Anysee DVB USB2.0",
|
||||
.cold_ids = {NULL},
|
||||
.warm_ids = {&anysee_table[0],
|
||||
&anysee_table[1], NULL},
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
static struct usb_driver anysee_driver = {
|
||||
.name = "dvb_usb_anysee",
|
||||
.probe = anysee_probe,
|
||||
.disconnect = dvb_usb_device_exit,
|
||||
.id_table = anysee_table,
|
||||
};
|
||||
|
||||
/* module stuff */
|
||||
static int __init anysee_module_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = usb_register(&anysee_driver);
|
||||
if (ret)
|
||||
err("%s: usb_register failed. Error number %d", __func__, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit anysee_module_exit(void)
|
||||
{
|
||||
/* deregister this driver from the USB subsystem */
|
||||
usb_deregister(&anysee_driver);
|
||||
}
|
||||
|
||||
module_init(anysee_module_init);
|
||||
module_exit(anysee_module_exit);
|
||||
|
||||
MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
|
||||
MODULE_DESCRIPTION("Driver Anysee E30 DVB-C & DVB-T USB2.0");
|
||||
MODULE_LICENSE("GPL");
|
304
drivers/media/dvb/dvb-usb/anysee.h
Normal file
304
drivers/media/dvb/dvb-usb/anysee.h
Normal file
@ -0,0 +1,304 @@
|
||||
/*
|
||||
* DVB USB Linux driver for Anysee E30 DVB-C & DVB-T USB2.0 receiver
|
||||
*
|
||||
* Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* TODO:
|
||||
* - add smart card reader support for Conditional Access (CA)
|
||||
*
|
||||
* Card reader in Anysee is nothing more than ISO 7816 card reader.
|
||||
* There is no hardware CAM in any Anysee device sold.
|
||||
* In my understanding it should be implemented by making own module
|
||||
* for ISO 7816 card reader, like dvb_ca_en50221 is implemented. This
|
||||
* module registers serial interface that can be used to communicate
|
||||
* with any ISO 7816 smart card.
|
||||
*
|
||||
* Any help according to implement serial smart card reader support
|
||||
* is highly welcome!
|
||||
*/
|
||||
|
||||
#ifndef _DVB_USB_ANYSEE_H_
|
||||
#define _DVB_USB_ANYSEE_H_
|
||||
|
||||
#define DVB_USB_LOG_PREFIX "anysee"
|
||||
#include "dvb-usb.h"
|
||||
|
||||
#define deb_info(args...) dprintk(dvb_usb_anysee_debug, 0x01, args)
|
||||
#define deb_xfer(args...) dprintk(dvb_usb_anysee_debug, 0x02, args)
|
||||
#define deb_rc(args...) dprintk(dvb_usb_anysee_debug, 0x04, args)
|
||||
#define deb_reg(args...) dprintk(dvb_usb_anysee_debug, 0x08, args)
|
||||
#define deb_i2c(args...) dprintk(dvb_usb_anysee_debug, 0x10, args)
|
||||
#define deb_fw(args...) dprintk(dvb_usb_anysee_debug, 0x20, args)
|
||||
|
||||
enum cmd {
|
||||
CMD_I2C_READ = 0x33,
|
||||
CMD_I2C_WRITE = 0x31,
|
||||
CMD_REG_READ = 0xb0,
|
||||
CMD_REG_WRITE = 0xb1,
|
||||
CMD_STREAMING_CTRL = 0x12,
|
||||
CMD_LED_AND_IR_CTRL = 0x16,
|
||||
CMD_GET_IR_CODE = 0x41,
|
||||
CMD_GET_HW_INFO = 0x19,
|
||||
CMD_SMARTCARD = 0x34,
|
||||
};
|
||||
|
||||
struct anysee_state {
|
||||
u8 tuner;
|
||||
u8 seq;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/***************************************************************************
|
||||
* USB API description (reverse engineered)
|
||||
***************************************************************************
|
||||
|
||||
Transaction flow:
|
||||
=================
|
||||
BULK[00001] >>> REQUEST PACKET 64 bytes
|
||||
BULK[00081] <<< REPLY PACKET #1 64 bytes (PREVIOUS TRANSACTION REPLY)
|
||||
BULK[00081] <<< REPLY PACKET #2 64 bytes (CURRENT TRANSACTION REPLY)
|
||||
|
||||
General reply packet(s) are always used if not own reply defined.
|
||||
|
||||
============================================================================
|
||||
| 00-63 | GENERAL REPLY PACKET #1 (PREVIOUS REPLY)
|
||||
============================================================================
|
||||
| 00 | reply data (if any) from previous transaction
|
||||
| | Just same reply packet as returned during previous transaction.
|
||||
| | Needed only if reply is missed in previous transaction.
|
||||
| | Just skip normally.
|
||||
----------------------------------------------------------------------------
|
||||
| 01-59 | don't care
|
||||
----------------------------------------------------------------------------
|
||||
| 60 | packet sequence number
|
||||
----------------------------------------------------------------------------
|
||||
| 61-63 | don't care
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
============================================================================
|
||||
| 00-63 | GENERAL REPLY PACKET #2 (CURRENT REPLY)
|
||||
============================================================================
|
||||
| 00 | reply data (if any)
|
||||
----------------------------------------------------------------------------
|
||||
| 01-59 | don't care
|
||||
----------------------------------------------------------------------------
|
||||
| 60 | packet sequence number
|
||||
----------------------------------------------------------------------------
|
||||
| 61-63 | don't care
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
============================================================================
|
||||
| 00-63 | I2C WRITE REQUEST PACKET
|
||||
============================================================================
|
||||
| 00 | 0x31 I2C write command
|
||||
----------------------------------------------------------------------------
|
||||
| 01 | i2c address
|
||||
----------------------------------------------------------------------------
|
||||
| 02 | data length
|
||||
| | 0x02 (for typical I2C reg / val pair)
|
||||
----------------------------------------------------------------------------
|
||||
| 03 | 0x01
|
||||
----------------------------------------------------------------------------
|
||||
| 04- | data
|
||||
----------------------------------------------------------------------------
|
||||
| -59 | don't care
|
||||
----------------------------------------------------------------------------
|
||||
| 60 | packet sequence number
|
||||
----------------------------------------------------------------------------
|
||||
| 61-63 | don't care
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
============================================================================
|
||||
| 00-63 | I2C READ REQUEST PACKET
|
||||
============================================================================
|
||||
| 00 | 0x33 I2C read command
|
||||
----------------------------------------------------------------------------
|
||||
| 01 | i2c address + 1
|
||||
----------------------------------------------------------------------------
|
||||
| 02 | register
|
||||
----------------------------------------------------------------------------
|
||||
| 03 | 0x00
|
||||
----------------------------------------------------------------------------
|
||||
| 04 | 0x00
|
||||
----------------------------------------------------------------------------
|
||||
| 05 | 0x01
|
||||
----------------------------------------------------------------------------
|
||||
| 06-59 | don't care
|
||||
----------------------------------------------------------------------------
|
||||
| 60 | packet sequence number
|
||||
----------------------------------------------------------------------------
|
||||
| 61-63 | don't care
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
============================================================================
|
||||
| 00-63 | USB CONTROLLER REGISTER WRITE REQUEST PACKET
|
||||
============================================================================
|
||||
| 00 | 0xb1 register write command
|
||||
----------------------------------------------------------------------------
|
||||
| 01-02 | register
|
||||
----------------------------------------------------------------------------
|
||||
| 03 | 0x01
|
||||
----------------------------------------------------------------------------
|
||||
| 04 | value
|
||||
----------------------------------------------------------------------------
|
||||
| 05-59 | don't care
|
||||
----------------------------------------------------------------------------
|
||||
| 60 | packet sequence number
|
||||
----------------------------------------------------------------------------
|
||||
| 61-63 | don't care
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
============================================================================
|
||||
| 00-63 | USB CONTROLLER REGISTER READ REQUEST PACKET
|
||||
============================================================================
|
||||
| 00 | 0xb0 register read command
|
||||
----------------------------------------------------------------------------
|
||||
| 01-02 | register
|
||||
----------------------------------------------------------------------------
|
||||
| 03 | 0x01
|
||||
----------------------------------------------------------------------------
|
||||
| 04-59 | don't care
|
||||
----------------------------------------------------------------------------
|
||||
| 60 | packet sequence number
|
||||
----------------------------------------------------------------------------
|
||||
| 61-63 | don't care
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
============================================================================
|
||||
| 00-63 | LED CONTROL REQUEST PACKET
|
||||
============================================================================
|
||||
| 00 | 0x16 LED and IR control command
|
||||
----------------------------------------------------------------------------
|
||||
| 01 | 0x01 (LED)
|
||||
----------------------------------------------------------------------------
|
||||
| 03 | 0x00 blink
|
||||
| | 0x01 lights continuously
|
||||
----------------------------------------------------------------------------
|
||||
| 04 | blink interval
|
||||
| | 0x00 fastest (looks like LED lights continuously)
|
||||
| | 0xff slowest
|
||||
----------------------------------------------------------------------------
|
||||
| 05-59 | don't care
|
||||
----------------------------------------------------------------------------
|
||||
| 60 | packet sequence number
|
||||
----------------------------------------------------------------------------
|
||||
| 61-63 | don't care
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
============================================================================
|
||||
| 00-63 | IR CONTROL REQUEST PACKET
|
||||
============================================================================
|
||||
| 00 | 0x16 LED and IR control command
|
||||
----------------------------------------------------------------------------
|
||||
| 01 | 0x02 (IR)
|
||||
----------------------------------------------------------------------------
|
||||
| 03 | 0x00 IR disabled
|
||||
| | 0x01 IR enabled
|
||||
----------------------------------------------------------------------------
|
||||
| 04-59 | don't care
|
||||
----------------------------------------------------------------------------
|
||||
| 60 | packet sequence number
|
||||
----------------------------------------------------------------------------
|
||||
| 61-63 | don't care
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
============================================================================
|
||||
| 00-63 | STREAMING CONTROL REQUEST PACKET
|
||||
============================================================================
|
||||
| 00 | 0x12 streaming control command
|
||||
----------------------------------------------------------------------------
|
||||
| 01 | 0x00 streaming disabled
|
||||
| | 0x01 streaming enabled
|
||||
----------------------------------------------------------------------------
|
||||
| 02 | 0x00
|
||||
----------------------------------------------------------------------------
|
||||
| 03-59 | don't care
|
||||
----------------------------------------------------------------------------
|
||||
| 60 | packet sequence number
|
||||
----------------------------------------------------------------------------
|
||||
| 61-63 | don't care
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
============================================================================
|
||||
| 00-63 | REMOTE CONTROL REQUEST PACKET
|
||||
============================================================================
|
||||
| 00 | 0x41 remote control command
|
||||
----------------------------------------------------------------------------
|
||||
| 01-59 | don't care
|
||||
----------------------------------------------------------------------------
|
||||
| 60 | packet sequence number
|
||||
----------------------------------------------------------------------------
|
||||
| 61-63 | don't care
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
============================================================================
|
||||
| 00-63 | REMOTE CONTROL REPLY PACKET
|
||||
============================================================================
|
||||
| 00 | 0x00 code not received
|
||||
| | 0x01 code received
|
||||
----------------------------------------------------------------------------
|
||||
| 01 | remote control code
|
||||
----------------------------------------------------------------------------
|
||||
| 02-59 | don't care
|
||||
----------------------------------------------------------------------------
|
||||
| 60 | packet sequence number
|
||||
----------------------------------------------------------------------------
|
||||
| 61-63 | don't care
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
============================================================================
|
||||
| 00-63 | GET HARDWARE INFO REQUEST PACKET
|
||||
============================================================================
|
||||
| 00 | 0x19 get hardware info command
|
||||
----------------------------------------------------------------------------
|
||||
| 01-59 | don't care
|
||||
----------------------------------------------------------------------------
|
||||
| 60 | packet sequence number
|
||||
----------------------------------------------------------------------------
|
||||
| 61-63 | don't care
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
============================================================================
|
||||
| 00-63 | GET HARDWARE INFO REPLY PACKET
|
||||
============================================================================
|
||||
| 00 | hardware id
|
||||
----------------------------------------------------------------------------
|
||||
| 01-02 | firmware version
|
||||
----------------------------------------------------------------------------
|
||||
| 03-59 | don't care
|
||||
----------------------------------------------------------------------------
|
||||
| 60 | packet sequence number
|
||||
----------------------------------------------------------------------------
|
||||
| 61-63 | don't care
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
============================================================================
|
||||
| 00-63 | SMART CARD READER PACKET
|
||||
============================================================================
|
||||
| 00 | 0x34 smart card reader command
|
||||
----------------------------------------------------------------------------
|
||||
| xx |
|
||||
----------------------------------------------------------------------------
|
||||
| xx-59 | don't care
|
||||
----------------------------------------------------------------------------
|
||||
| 60 | packet sequence number
|
||||
----------------------------------------------------------------------------
|
||||
| 61-63 | don't care
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
*/
|
@ -1,24 +1,31 @@
|
||||
/* DVB USB compliant linux driver for Sigmatek DVB-110 DVB-T USB2.0 receiver
|
||||
/*
|
||||
* DVB USB Linux driver for Alcor Micro AU6610 DVB-T USB2.0.
|
||||
*
|
||||
* Copyright (C) 2006 Antti Palosaari <crope@iki.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 2.
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* see Documentation/dvb/README.dvb-usb for more information
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "au6610.h"
|
||||
|
||||
#include "zl10353.h"
|
||||
#include "qt1010.h"
|
||||
|
||||
/* debug */
|
||||
static int dvb_usb_au6610_debug;
|
||||
module_param_named(debug, dvb_usb_au6610_debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
|
||||
|
||||
MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);
|
||||
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
|
||||
|
||||
static int au6610_usb_msg(struct dvb_usb_device *d, u8 operation, u8 addr,
|
||||
@ -42,9 +49,8 @@ static int au6610_usb_msg(struct dvb_usb_device *d, u8 operation, u8 addr,
|
||||
}
|
||||
|
||||
ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), operation,
|
||||
USB_TYPE_VENDOR|USB_DIR_IN, addr << 1, index, usb_buf,
|
||||
sizeof(usb_buf), AU6610_USB_TIMEOUT);
|
||||
|
||||
USB_TYPE_VENDOR|USB_DIR_IN, addr << 1, index,
|
||||
usb_buf, sizeof(usb_buf), AU6610_USB_TIMEOUT);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@ -116,15 +122,6 @@ static struct i2c_algorithm au6610_i2c_algo = {
|
||||
};
|
||||
|
||||
/* Callbacks for DVB USB */
|
||||
static int au6610_identify_state(struct usb_device *udev,
|
||||
struct dvb_usb_device_properties *props,
|
||||
struct dvb_usb_device_description **desc,
|
||||
int *cold)
|
||||
{
|
||||
*cold = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct zl10353_config au6610_zl10353_config = {
|
||||
.demod_address = 0x0f,
|
||||
.no_tuner = 1,
|
||||
@ -133,12 +130,12 @@ static struct zl10353_config au6610_zl10353_config = {
|
||||
|
||||
static int au6610_zl10353_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
if ((adap->fe = dvb_attach(zl10353_attach, &au6610_zl10353_config,
|
||||
&adap->dev->i2c_adap)) != NULL) {
|
||||
return 0;
|
||||
}
|
||||
adap->fe = dvb_attach(zl10353_attach, &au6610_zl10353_config,
|
||||
&adap->dev->i2c_adap);
|
||||
if (adap->fe == NULL)
|
||||
return -ENODEV;
|
||||
|
||||
return -EIO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct qt1010_config au6610_qt1010_config = {
|
||||
@ -171,7 +168,7 @@ static int au6610_probe(struct usb_interface *intf,
|
||||
alt = usb_altnum_to_altsetting(intf, AU6610_ALTSETTING);
|
||||
|
||||
if (alt == NULL) {
|
||||
deb_rc("no alt found!\n");
|
||||
deb_info("%s: no alt found!\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber,
|
||||
@ -181,18 +178,19 @@ static int au6610_probe(struct usb_interface *intf,
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static struct usb_device_id au6610_table [] = {
|
||||
{ USB_DEVICE(USB_VID_ALCOR_MICRO, USB_PID_SIGMATEK_DVB_110) },
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
MODULE_DEVICE_TABLE (usb, au6610_table);
|
||||
MODULE_DEVICE_TABLE(usb, au6610_table);
|
||||
|
||||
static struct dvb_usb_device_properties au6610_properties = {
|
||||
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
|
||||
|
||||
.usb_ctrl = DEVICE_SPECIFIC,
|
||||
.size_of_priv = 0,
|
||||
.identify_state = au6610_identify_state,
|
||||
|
||||
.size_of_priv = 0,
|
||||
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
@ -206,20 +204,22 @@ static struct dvb_usb_device_properties au6610_properties = {
|
||||
.u = {
|
||||
.isoc = {
|
||||
.framesperurb = 40,
|
||||
.framesize = 942, /* maximum packet size */
|
||||
.interval = 1.25, /* 125 us */
|
||||
.framesize = 942,
|
||||
.interval = 1,
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
.i2c_algo = &au6610_i2c_algo,
|
||||
|
||||
.num_device_descs = 1,
|
||||
.devices = {
|
||||
{
|
||||
"Sigmatek DVB-110 DVB-T USB2.0",
|
||||
{ &au6610_table[0], NULL },
|
||||
{ NULL },
|
||||
.name = "Sigmatek DVB-110 DVB-T USB2.0",
|
||||
.cold_ids = {NULL},
|
||||
.warm_ids = {&au6610_table[0], NULL},
|
||||
},
|
||||
}
|
||||
};
|
||||
@ -236,12 +236,11 @@ static int __init au6610_module_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if ((ret = usb_register(&au6610_driver))) {
|
||||
ret = usb_register(&au6610_driver);
|
||||
if (ret)
|
||||
err("usb_register failed. Error number %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit au6610_module_exit(void)
|
||||
@ -250,10 +249,10 @@ static void __exit au6610_module_exit(void)
|
||||
usb_deregister(&au6610_driver);
|
||||
}
|
||||
|
||||
module_init (au6610_module_init);
|
||||
module_exit (au6610_module_exit);
|
||||
module_init(au6610_module_init);
|
||||
module_exit(au6610_module_exit);
|
||||
|
||||
MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
|
||||
MODULE_DESCRIPTION("Driver Sigmatek DVB-110 DVB-T USB2.0 / AU6610");
|
||||
MODULE_DESCRIPTION("Driver for Alcor Micro AU6610 DVB-T USB2.0");
|
||||
MODULE_VERSION("0.1");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -1,10 +1,30 @@
|
||||
/*
|
||||
* DVB USB Linux driver for Alcor Micro AU6610 DVB-T USB2.0.
|
||||
*
|
||||
* Copyright (C) 2006 Antti Palosaari <crope@iki.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef _DVB_USB_AU6610_H_
|
||||
#define _DVB_USB_AU6610_H_
|
||||
|
||||
#define DVB_USB_LOG_PREFIX "au6610"
|
||||
#include "dvb-usb.h"
|
||||
|
||||
#define deb_rc(args...) dprintk(dvb_usb_au6610_debug,0x01,args)
|
||||
#define deb_info(args...) dprintk(dvb_usb_au6610_debug, 0x01, args)
|
||||
|
||||
#define AU6610_REQ_I2C_WRITE 0x14
|
||||
#define AU6610_REQ_I2C_READ 0x13
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include "zl10353.h"
|
||||
#include "tuner-xc2028.h"
|
||||
#include "tuner-simple.h"
|
||||
#include "mxl5005s.h"
|
||||
|
||||
/* debug */
|
||||
static int dvb_usb_cxusb_debug;
|
||||
@ -43,9 +44,8 @@ MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_ST
|
||||
|
||||
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
|
||||
|
||||
#define deb_info(args...) dprintk(dvb_usb_cxusb_debug,0x01,args)
|
||||
#define deb_i2c(args...) if (d->udev->descriptor.idVendor == USB_VID_MEDION) \
|
||||
dprintk(dvb_usb_cxusb_debug,0x01,args)
|
||||
#define deb_info(args...) dprintk(dvb_usb_cxusb_debug, 0x03, args)
|
||||
#define deb_i2c(args...) dprintk(dvb_usb_cxusb_debug, 0x02, args)
|
||||
|
||||
static int cxusb_ctrl_msg(struct dvb_usb_device *d,
|
||||
u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen)
|
||||
@ -202,6 +202,46 @@ static int cxusb_power_ctrl(struct dvb_usb_device *d, int onoff)
|
||||
return cxusb_ctrl_msg(d, CMD_POWER_OFF, &b, 1, NULL, 0);
|
||||
}
|
||||
|
||||
static int cxusb_aver_power_ctrl(struct dvb_usb_device *d, int onoff)
|
||||
{
|
||||
int ret;
|
||||
if (!onoff)
|
||||
return cxusb_ctrl_msg(d, CMD_POWER_OFF, NULL, 0, NULL, 0);
|
||||
if (d->state == DVB_USB_STATE_INIT &&
|
||||
usb_set_interface(d->udev, 0, 0) < 0)
|
||||
err("set interface failed");
|
||||
do; while (!(ret = cxusb_ctrl_msg(d, CMD_POWER_ON, NULL, 0, NULL, 0)) &&
|
||||
!(ret = cxusb_ctrl_msg(d, 0x15, NULL, 0, NULL, 0)) &&
|
||||
!(ret = cxusb_ctrl_msg(d, 0x17, NULL, 0, NULL, 0)) && 0);
|
||||
if (!ret) {
|
||||
/* FIXME: We don't know why, but we need to configure the
|
||||
* lgdt3303 with the register settings below on resume */
|
||||
int i;
|
||||
u8 buf, bufs[] = {
|
||||
0x0e, 0x2, 0x00, 0x7f,
|
||||
0x0e, 0x2, 0x02, 0xfe,
|
||||
0x0e, 0x2, 0x02, 0x01,
|
||||
0x0e, 0x2, 0x00, 0x03,
|
||||
0x0e, 0x2, 0x0d, 0x40,
|
||||
0x0e, 0x2, 0x0e, 0x87,
|
||||
0x0e, 0x2, 0x0f, 0x8e,
|
||||
0x0e, 0x2, 0x10, 0x01,
|
||||
0x0e, 0x2, 0x14, 0xd7,
|
||||
0x0e, 0x2, 0x47, 0x88,
|
||||
};
|
||||
msleep(20);
|
||||
for (i = 0; i < sizeof(bufs)/sizeof(u8); i += 4/sizeof(u8)) {
|
||||
ret = cxusb_ctrl_msg(d, CMD_I2C_WRITE,
|
||||
bufs+i, 4, &buf, 1);
|
||||
if (ret)
|
||||
break;
|
||||
if (buf != 0x8)
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cxusb_bluebird_power_ctrl(struct dvb_usb_device *d, int onoff)
|
||||
{
|
||||
u8 b = 0;
|
||||
@ -233,6 +273,16 @@ static int cxusb_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cxusb_aver_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
|
||||
{
|
||||
if (onoff)
|
||||
cxusb_ctrl_msg(adap->dev, CMD_AVER_STREAM_ON, NULL, 0, NULL, 0);
|
||||
else
|
||||
cxusb_ctrl_msg(adap->dev, CMD_AVER_STREAM_OFF,
|
||||
NULL, 0, NULL, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cxusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
|
||||
{
|
||||
struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
|
||||
@ -423,6 +473,12 @@ static struct lgdt330x_config cxusb_lgdt3303_config = {
|
||||
.demod_chip = LGDT3303,
|
||||
};
|
||||
|
||||
static struct lgdt330x_config cxusb_aver_lgdt3303_config = {
|
||||
.demod_address = 0x0e,
|
||||
.demod_chip = LGDT3303,
|
||||
.clock_polarity_flip = 2,
|
||||
};
|
||||
|
||||
static struct mt352_config cxusb_dee1601_config = {
|
||||
.demod_address = 0x0f,
|
||||
.demod_init = cxusb_dee1601_demod_init,
|
||||
@ -453,6 +509,24 @@ static struct mt352_config cxusb_mt352_xc3028_config = {
|
||||
.demod_init = cxusb_mt352_demod_init,
|
||||
};
|
||||
|
||||
/* FIXME: needs tweaking */
|
||||
static struct mxl5005s_config aver_a868r_tuner = {
|
||||
.i2c_address = 0x63,
|
||||
.if_freq = 6000000UL,
|
||||
.xtal_freq = CRYSTAL_FREQ_16000000HZ,
|
||||
.agc_mode = MXL_SINGLE_AGC,
|
||||
.tracking_filter = MXL_TF_C,
|
||||
.rssi_enable = MXL_RSSI_ENABLE,
|
||||
.cap_select = MXL_CAP_SEL_ENABLE,
|
||||
.div_out = MXL_DIV_OUT_4,
|
||||
.clock_out = MXL_CLOCK_OUT_DISABLE,
|
||||
.output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM,
|
||||
.top = MXL5005S_TOP_25P2,
|
||||
.mod_mode = MXL_DIGITAL_MODE,
|
||||
.if_mode = MXL_ZERO_IF,
|
||||
.AgcMasterByte = 0x00,
|
||||
};
|
||||
|
||||
/* Callbacks for DVB USB */
|
||||
static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
@ -533,6 +607,13 @@ static int cxusb_dvico_xc3028_tuner_attach(struct dvb_usb_adapter *adap)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cxusb_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
dvb_attach(mxl5005s_attach, adap->fe,
|
||||
&adap->dev->i2c_adap, &aver_a868r_tuner);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cxusb_cx22702_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
u8 b;
|
||||
@ -562,6 +643,16 @@ static int cxusb_lgdt3303_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static int cxusb_aver_lgdt3303_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
adap->fe = dvb_attach(lgdt330x_attach, &cxusb_aver_lgdt3303_config,
|
||||
&adap->dev->i2c_adap);
|
||||
if (adap->fe != NULL)
|
||||
return 0;
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static int cxusb_mt352_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
/* used in both lgz201 and th7579 */
|
||||
@ -736,6 +827,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties;
|
||||
static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties;
|
||||
static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties;
|
||||
static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_properties;
|
||||
static struct dvb_usb_device_properties cxusb_aver_a868r_properties;
|
||||
|
||||
static int cxusb_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
@ -756,7 +848,10 @@ static int cxusb_probe(struct usb_interface *intf,
|
||||
THIS_MODULE, NULL, adapter_nr) ||
|
||||
0 == dvb_usb_device_init(intf,
|
||||
&cxusb_bluebird_nano2_needsfirmware_properties,
|
||||
THIS_MODULE, NULL, adapter_nr))
|
||||
THIS_MODULE, NULL, adapter_nr) ||
|
||||
0 == dvb_usb_device_init(intf, &cxusb_aver_a868r_properties,
|
||||
THIS_MODULE, NULL, adapter_nr) ||
|
||||
0)
|
||||
return 0;
|
||||
|
||||
return -EINVAL;
|
||||
@ -779,6 +874,7 @@ static struct usb_device_id cxusb_table [] = {
|
||||
{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_4) },
|
||||
{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2) },
|
||||
{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM) },
|
||||
{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_A868R) },
|
||||
{} /* Terminating entry */
|
||||
};
|
||||
MODULE_DEVICE_TABLE (usb, cxusb_table);
|
||||
@ -1182,6 +1278,48 @@ static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_prope
|
||||
}
|
||||
};
|
||||
|
||||
static struct dvb_usb_device_properties cxusb_aver_a868r_properties = {
|
||||
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
|
||||
|
||||
.usb_ctrl = CYPRESS_FX2,
|
||||
|
||||
.size_of_priv = sizeof(struct cxusb_state),
|
||||
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.streaming_ctrl = cxusb_aver_streaming_ctrl,
|
||||
.frontend_attach = cxusb_aver_lgdt3303_frontend_attach,
|
||||
.tuner_attach = cxusb_mxl5003s_tuner_attach,
|
||||
/* parameter for the MPEG2-data transfer */
|
||||
.stream = {
|
||||
.type = USB_BULK,
|
||||
.count = 5,
|
||||
.endpoint = 0x04,
|
||||
.u = {
|
||||
.bulk = {
|
||||
.buffersize = 8192,
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
},
|
||||
},
|
||||
.power_ctrl = cxusb_aver_power_ctrl,
|
||||
|
||||
.i2c_algo = &cxusb_i2c_algo,
|
||||
|
||||
.generic_bulk_ctrl_endpoint = 0x01,
|
||||
|
||||
.num_device_descs = 1,
|
||||
.devices = {
|
||||
{ "AVerMedia AVerTVHD Volar (A868R)",
|
||||
{ NULL },
|
||||
{ &cxusb_table[16], NULL },
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
static struct usb_driver cxusb_driver = {
|
||||
.name = "dvb_usb_cxusb",
|
||||
.probe = cxusb_probe,
|
||||
|
@ -20,6 +20,9 @@
|
||||
#define CMD_STREAMING_ON 0x36
|
||||
#define CMD_STREAMING_OFF 0x37
|
||||
|
||||
#define CMD_AVER_STREAM_ON 0x18
|
||||
#define CMD_AVER_STREAM_OFF 0x19
|
||||
|
||||
#define CMD_GET_IR_CODE 0x47
|
||||
|
||||
#define CMD_ANALOG 0x50
|
||||
|
@ -1117,6 +1117,7 @@ struct usb_device_id dib0700_usb_id_table[] = {
|
||||
{ USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_HT_EXPRESS) },
|
||||
{ USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_XXS) },
|
||||
{ USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_STK7700P_2) },
|
||||
{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK_52009) },
|
||||
{ 0 } /* Terminating entry */
|
||||
};
|
||||
MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
|
||||
@ -1372,7 +1373,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
|
||||
}
|
||||
},
|
||||
|
||||
.num_device_descs = 2,
|
||||
.num_device_descs = 3,
|
||||
.devices = {
|
||||
{ "DiBcom STK7070PD reference design",
|
||||
{ &dib0700_usb_id_table[17], NULL },
|
||||
@ -1381,6 +1382,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
|
||||
{ "Pinnacle PCTV Dual DVB-T Diversity Stick",
|
||||
{ &dib0700_usb_id_table[18], NULL },
|
||||
{ NULL },
|
||||
},
|
||||
{ "Hauppauge Nova-TD Stick (52009)",
|
||||
{ &dib0700_usb_id_table[35], NULL },
|
||||
{ NULL },
|
||||
}
|
||||
}
|
||||
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
|
||||
|
@ -20,11 +20,7 @@ int dvb_usb_i2c_init(struct dvb_usb_device *d)
|
||||
}
|
||||
|
||||
strncpy(d->i2c_adap.name, d->desc->name, sizeof(d->i2c_adap.name));
|
||||
#ifdef I2C_ADAP_CLASS_TV_DIGITAL
|
||||
d->i2c_adap.class = I2C_ADAP_CLASS_TV_DIGITAL,
|
||||
#else
|
||||
d->i2c_adap.class = I2C_CLASS_TV_DIGITAL,
|
||||
#endif
|
||||
d->i2c_adap.algo = d->props.i2c_algo;
|
||||
d->i2c_adap.algo_data = NULL;
|
||||
d->i2c_adap.dev.parent = &d->udev->dev;
|
||||
|
@ -14,6 +14,7 @@
|
||||
#define USB_VID_AFATECH 0x15a4
|
||||
#define USB_VID_ALCOR_MICRO 0x058f
|
||||
#define USB_VID_ALINK 0x05e3
|
||||
#define USB_VID_AMT 0x1c73
|
||||
#define USB_VID_ANCHOR 0x0547
|
||||
#define USB_VID_ANSONIC 0x10b9
|
||||
#define USB_VID_ANUBIS_ELECTRONIC 0x10fd
|
||||
@ -57,6 +58,7 @@
|
||||
#define USB_PID_AFATECH_AF9005 0x9020
|
||||
#define USB_VID_ALINK_DTU 0xf170
|
||||
#define USB_PID_ANSONIC_DVBT_USB 0x6000
|
||||
#define USB_PID_ANYSEE 0x861f
|
||||
#define USB_PID_AVERMEDIA_DVBT_USB_COLD 0x0001
|
||||
#define USB_PID_AVERMEDIA_DVBT_USB_WARM 0x0002
|
||||
#define USB_PID_AVERMEDIA_DVBT_USB2_COLD 0xa800
|
||||
@ -132,9 +134,15 @@
|
||||
#define USB_PID_HAUPPAUGE_NOVA_T_STICK_3 0x7070
|
||||
#define USB_PID_HAUPPAUGE_MYTV_T 0x7080
|
||||
#define USB_PID_HAUPPAUGE_NOVA_TD_STICK 0x9580
|
||||
#define USB_PID_HAUPPAUGE_NOVA_TD_STICK_52009 0x5200
|
||||
#define USB_PID_AVERMEDIA_EXPRESS 0xb568
|
||||
#define USB_PID_AVERMEDIA_VOLAR 0xa807
|
||||
#define USB_PID_AVERMEDIA_VOLAR_2 0xb808
|
||||
#define USB_PID_AVERMEDIA_VOLAR_A868R 0xa868
|
||||
#define USB_PID_AVERMEDIA_MCE_USB_M038 0x1228
|
||||
#define USB_PID_AVERMEDIA_HYBRID_ULTRA_USB_M039R 0x0039
|
||||
#define USB_PID_AVERMEDIA_HYBRID_ULTRA_USB_M039R_ATSC 0x1039
|
||||
#define USB_PID_AVERMEDIA_HYBRID_ULTRA_USB_M039R_DVBT 0x2039
|
||||
#define USB_PID_TECHNOTREND_CONNECT_S2400 0x3006
|
||||
#define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY 0x005a
|
||||
#define USB_PID_TERRATEC_CINERGY_HT_USB_XE 0x0058
|
||||
|
@ -1,8 +1,8 @@
|
||||
/* DVB USB compliant linux driver for GL861 USB2.0 devices.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 2.
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation, version 2.
|
||||
*
|
||||
* see Documentation/dvb/README.dvb-usb for more information
|
||||
*/
|
||||
@ -13,9 +13,9 @@
|
||||
|
||||
/* debug */
|
||||
static int dvb_usb_gl861_debug;
|
||||
module_param_named(debug,dvb_usb_gl861_debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
|
||||
|
||||
module_param_named(debug, dvb_usb_gl861_debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))."
|
||||
DVB_USB_DEBUG_STATUS);
|
||||
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
|
||||
|
||||
static int gl861_i2c_msg(struct dvb_usb_device *d, u8 addr,
|
||||
@ -70,7 +70,7 @@ static int gl861_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
|
||||
/* write/read request */
|
||||
if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
|
||||
if (gl861_i2c_msg(d, msg[i].addr, msg[i].buf,
|
||||
msg[i].len, msg[i+1].buf, msg[i+1].len) < 0)
|
||||
msg[i].len, msg[i+1].buf, msg[i+1].len) < 0)
|
||||
break;
|
||||
i++;
|
||||
} else
|
||||
@ -102,12 +102,13 @@ static struct zl10353_config gl861_zl10353_config = {
|
||||
|
||||
static int gl861_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
if ((adap->fe = dvb_attach(zl10353_attach, &gl861_zl10353_config,
|
||||
&adap->dev->i2c_adap)) != NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EIO;
|
||||
adap->fe = dvb_attach(zl10353_attach, &gl861_zl10353_config,
|
||||
&adap->dev->i2c_adap);
|
||||
if (adap->fe == NULL)
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct qt1010_config gl861_qt1010_config = {
|
||||
@ -156,7 +157,7 @@ static struct usb_device_id gl861_table [] = {
|
||||
{ USB_DEVICE(USB_VID_ALINK, USB_VID_ALINK_DTU) },
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
MODULE_DEVICE_TABLE (usb, gl861_table);
|
||||
MODULE_DEVICE_TABLE(usb, gl861_table);
|
||||
|
||||
static struct dvb_usb_device_properties gl861_properties = {
|
||||
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
|
||||
@ -180,7 +181,7 @@ static struct dvb_usb_device_properties gl861_properties = {
|
||||
}
|
||||
}
|
||||
},
|
||||
}},
|
||||
} },
|
||||
.i2c_algo = &gl861_i2c_algo,
|
||||
|
||||
.num_device_descs = 2,
|
||||
@ -210,12 +211,11 @@ static int __init gl861_module_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if ((ret = usb_register(&gl861_driver))) {
|
||||
ret = usb_register(&gl861_driver);
|
||||
if (ret)
|
||||
err("usb_register failed. Error number %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit gl861_module_exit(void)
|
||||
@ -224,8 +224,8 @@ static void __exit gl861_module_exit(void)
|
||||
usb_deregister(&gl861_driver);
|
||||
}
|
||||
|
||||
module_init (gl861_module_init);
|
||||
module_exit (gl861_module_exit);
|
||||
module_init(gl861_module_init);
|
||||
module_exit(gl861_module_exit);
|
||||
|
||||
MODULE_AUTHOR("Carl Lundqvist <comabug@gmail.com>");
|
||||
MODULE_DESCRIPTION("Driver MSI Mega Sky 580 DVB-T USB2.0 / GL861");
|
||||
|
@ -4,7 +4,7 @@
|
||||
#define DVB_USB_LOG_PREFIX "gl861"
|
||||
#include "dvb-usb.h"
|
||||
|
||||
#define deb_rc(args...) dprintk(dvb_usb_gl861_debug,0x01,args)
|
||||
#define deb_rc(args...) dprintk(dvb_usb_gl861_debug, 0x01, args)
|
||||
|
||||
#define GL861_WRITE 0x40
|
||||
#define GL861_READ 0xc0
|
||||
|
@ -26,7 +26,6 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include "dvb_frontend.h"
|
||||
#include "dvb-pll.h"
|
||||
#include "au8522.h"
|
||||
|
||||
struct au8522_state {
|
||||
|
@ -343,6 +343,52 @@ static struct dvb_pll_desc dvb_pll_opera1 = {
|
||||
}
|
||||
};
|
||||
|
||||
static void samsung_dtos403ih102a_set(struct dvb_frontend *fe, u8 *buf,
|
||||
const struct dvb_frontend_parameters *params)
|
||||
{
|
||||
struct dvb_pll_priv *priv = fe->tuner_priv;
|
||||
struct i2c_msg msg = {
|
||||
.addr = priv->pll_i2c_address,
|
||||
.flags = 0,
|
||||
.buf = buf,
|
||||
.len = 4
|
||||
};
|
||||
int result;
|
||||
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
|
||||
result = i2c_transfer(priv->i2c, &msg, 1);
|
||||
if (result != 1)
|
||||
printk(KERN_ERR "%s: i2c_transfer failed:%d",
|
||||
__func__, result);
|
||||
|
||||
buf[2] = 0x9e;
|
||||
buf[3] = 0x90;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* unknown pll used in Samsung DTOS403IH102A DVB-C tuner */
|
||||
static struct dvb_pll_desc dvb_pll_samsung_dtos403ih102a = {
|
||||
.name = "Samsung DTOS403IH102A",
|
||||
.min = 44250000,
|
||||
.max = 858000000,
|
||||
.iffreq = 36125000,
|
||||
.count = 8,
|
||||
.set = samsung_dtos403ih102a_set,
|
||||
.entries = {
|
||||
{ 135000000, 62500, 0xbe, 0x01 },
|
||||
{ 177000000, 62500, 0xf6, 0x01 },
|
||||
{ 370000000, 62500, 0xbe, 0x02 },
|
||||
{ 450000000, 62500, 0xf6, 0x02 },
|
||||
{ 466000000, 62500, 0xfe, 0x02 },
|
||||
{ 538000000, 62500, 0xbe, 0x08 },
|
||||
{ 826000000, 62500, 0xf6, 0x08 },
|
||||
{ 999999999, 62500, 0xfe, 0x08 },
|
||||
}
|
||||
};
|
||||
|
||||
/* ----------------------------------------------------------- */
|
||||
|
||||
static struct dvb_pll_desc *pll_list[] = {
|
||||
@ -360,6 +406,7 @@ static struct dvb_pll_desc *pll_list[] = {
|
||||
[DVB_PLL_SAMSUNG_TBMV] = &dvb_pll_samsung_tbmv,
|
||||
[DVB_PLL_PHILIPS_SD1878_TDA8261] = &dvb_pll_philips_sd1878_tda8261,
|
||||
[DVB_PLL_OPERA1] = &dvb_pll_opera1,
|
||||
[DVB_PLL_SAMSUNG_DTOS403IH102A] = &dvb_pll_samsung_dtos403ih102a,
|
||||
};
|
||||
|
||||
/* ----------------------------------------------------------- */
|
||||
|
@ -22,6 +22,7 @@
|
||||
#define DVB_PLL_SAMSUNG_TBMV 11
|
||||
#define DVB_PLL_PHILIPS_SD1878_TDA8261 12
|
||||
#define DVB_PLL_OPERA1 13
|
||||
#define DVB_PLL_SAMSUNG_DTOS403IH102A 14
|
||||
|
||||
/**
|
||||
* Attach a dvb-pll to the supplied frontend structure.
|
||||
|
@ -226,11 +226,16 @@ static int lgdt330x_init(struct dvb_frontend* fe)
|
||||
0x4c, 0x14
|
||||
};
|
||||
|
||||
static u8 flip_lgdt3303_init_data[] = {
|
||||
static u8 flip_1_lgdt3303_init_data[] = {
|
||||
0x4c, 0x14,
|
||||
0x87, 0xf3
|
||||
};
|
||||
|
||||
static u8 flip_2_lgdt3303_init_data[] = {
|
||||
0x4c, 0x14,
|
||||
0x87, 0xda
|
||||
};
|
||||
|
||||
struct lgdt330x_state* state = fe->demodulator_priv;
|
||||
char *chip_name;
|
||||
int err;
|
||||
@ -243,10 +248,19 @@ static int lgdt330x_init(struct dvb_frontend* fe)
|
||||
break;
|
||||
case LGDT3303:
|
||||
chip_name = "LGDT3303";
|
||||
if (state->config->clock_polarity_flip) {
|
||||
err = i2c_write_demod_bytes(state, flip_lgdt3303_init_data,
|
||||
sizeof(flip_lgdt3303_init_data));
|
||||
} else {
|
||||
switch (state->config->clock_polarity_flip) {
|
||||
case 2:
|
||||
err = i2c_write_demod_bytes(state,
|
||||
flip_2_lgdt3303_init_data,
|
||||
sizeof(flip_2_lgdt3303_init_data));
|
||||
break;
|
||||
case 1:
|
||||
err = i2c_write_demod_bytes(state,
|
||||
flip_1_lgdt3303_init_data,
|
||||
sizeof(flip_1_lgdt3303_init_data));
|
||||
break;
|
||||
case 0:
|
||||
default:
|
||||
err = i2c_write_demod_bytes(state, lgdt3303_init_data,
|
||||
sizeof(lgdt3303_init_data));
|
||||
}
|
||||
|
@ -26,7 +26,6 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include "dvb_frontend.h"
|
||||
#include "dvb-pll.h"
|
||||
#include "s5h1409.h"
|
||||
|
||||
struct s5h1409_state {
|
||||
|
@ -26,7 +26,6 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include "dvb_frontend.h"
|
||||
#include "dvb-pll.h"
|
||||
#include "s5h1411.h"
|
||||
|
||||
struct s5h1411_state {
|
||||
|
@ -38,75 +38,29 @@
|
||||
#include "dvb_frontend.h"
|
||||
#include "tda1002x.h"
|
||||
|
||||
#define REG0_INIT_VAL 0x23
|
||||
|
||||
struct tda10023_state {
|
||||
struct i2c_adapter* i2c;
|
||||
/* configuration settings */
|
||||
const struct tda1002x_config* config;
|
||||
const struct tda10023_config *config;
|
||||
struct dvb_frontend frontend;
|
||||
|
||||
u8 pwm;
|
||||
u8 reg0;
|
||||
};
|
||||
|
||||
/* clock settings */
|
||||
u32 xtal;
|
||||
u8 pll_m;
|
||||
u8 pll_p;
|
||||
u8 pll_n;
|
||||
u32 sysclk;
|
||||
};
|
||||
|
||||
#define dprintk(x...)
|
||||
|
||||
static int verbose;
|
||||
|
||||
#define XTAL 28920000UL
|
||||
#define PLL_M 8UL
|
||||
#define PLL_P 4UL
|
||||
#define PLL_N 1UL
|
||||
#define SYSCLK (XTAL*PLL_M/(PLL_N*PLL_P)) // -> 57840000
|
||||
|
||||
static u8 tda10023_inittab[]={
|
||||
// reg mask val
|
||||
0x2a,0xff,0x02, // PLL3, Bypass, Power Down
|
||||
0xff,0x64,0x00, // Sleep 100ms
|
||||
0x2a,0xff,0x03, // PLL3, Bypass, Power Down
|
||||
0xff,0x64,0x00, // Sleep 100ms
|
||||
0x28,0xff,PLL_M-1, // PLL1 M=8
|
||||
0x29,0xff,((PLL_P-1)<<6)|(PLL_N-1), // PLL2
|
||||
0x00,0xff,0x23, // GPR FSAMPLING=1
|
||||
0x2a,0xff,0x08, // PLL3 PSACLK=1
|
||||
0xff,0x64,0x00, // Sleep 100ms
|
||||
0x1f,0xff,0x00, // RESET
|
||||
0xff,0x64,0x00, // Sleep 100ms
|
||||
0xe6,0x0c,0x04, // RSCFG_IND
|
||||
0x10,0xc0,0x80, // DECDVBCFG1 PBER=1
|
||||
|
||||
0x0e,0xff,0x82, // GAIN1
|
||||
0x03,0x08,0x08, // CLKCONF DYN=1
|
||||
0x2e,0xbf,0x30, // AGCCONF2 TRIAGC=0,POSAGC=ENAGCIF=1 PPWMTUN=0 PPWMIF=0
|
||||
0x01,0xff,0x30, // AGCREF
|
||||
0x1e,0x84,0x84, // CONTROL SACLK_ON=1
|
||||
0x1b,0xff,0xc8, // ADC TWOS=1
|
||||
0x3b,0xff,0xff, // IFMAX
|
||||
0x3c,0xff,0x00, // IFMIN
|
||||
0x34,0xff,0x00, // PWMREF
|
||||
0x35,0xff,0xff, // TUNMAX
|
||||
0x36,0xff,0x00, // TUNMIN
|
||||
0x06,0xff,0x7f, // EQCONF1 POSI=7 ENADAPT=ENEQUAL=DFE=1 // 0x77
|
||||
0x1c,0x30,0x30, // EQCONF2 STEPALGO=SGNALGO=1
|
||||
0x37,0xff,0xf6, // DELTAF_LSB
|
||||
0x38,0xff,0xff, // DELTAF_MSB
|
||||
0x02,0xff,0x93, // AGCCONF1 IFS=1 KAGCIF=2 KAGCTUN=3
|
||||
0x2d,0xff,0xf6, // SWEEP SWPOS=1 SWDYN=7 SWSTEP=1 SWLEN=2
|
||||
0x04,0x10,0x00, // SWRAMP=1
|
||||
0x12,0xff,0xa1, // INTP1 POCLKP=1 FEL=1 MFS=0
|
||||
0x2b,0x01,0xa1, // INTS1
|
||||
0x20,0xff,0x04, // INTP2 SWAPP=? MSBFIRSTP=? INTPSEL=?
|
||||
0x2c,0xff,0x0d, // INTP/S TRIP=0 TRIS=0
|
||||
0xc4,0xff,0x00,
|
||||
0xc3,0x30,0x00,
|
||||
0xb5,0xff,0x19, // ERAGC_THD
|
||||
0x00,0x03,0x01, // GPR, CLBS soft reset
|
||||
0x00,0x03,0x03, // GPR, CLBS soft reset
|
||||
0xff,0x64,0x00, // Sleep 100ms
|
||||
0xff,0xff,0xff
|
||||
};
|
||||
|
||||
static u8 tda10023_readreg (struct tda10023_state* state, u8 reg)
|
||||
{
|
||||
u8 b0 [] = { reg };
|
||||
@ -219,30 +173,34 @@ static int tda10023_set_symbolrate (struct tda10023_state* state, u32 sr)
|
||||
s16 SFIL=0;
|
||||
u16 NDEC = 0;
|
||||
|
||||
if (sr < (u32)(SYSCLK/98.40)) {
|
||||
/* avoid floating point operations multiplying syscloc and divider
|
||||
by 10 */
|
||||
u32 sysclk_x_10 = state->sysclk * 10;
|
||||
|
||||
if (sr < (u32)(sysclk_x_10/984)) {
|
||||
NDEC=3;
|
||||
SFIL=1;
|
||||
} else if (sr<(u32)(SYSCLK/64.0)) {
|
||||
} else if (sr < (u32)(sysclk_x_10/640)) {
|
||||
NDEC=3;
|
||||
SFIL=0;
|
||||
} else if (sr<(u32)(SYSCLK/49.2)) {
|
||||
} else if (sr < (u32)(sysclk_x_10/492)) {
|
||||
NDEC=2;
|
||||
SFIL=1;
|
||||
} else if (sr<(u32)(SYSCLK/32.0)) {
|
||||
} else if (sr < (u32)(sysclk_x_10/320)) {
|
||||
NDEC=2;
|
||||
SFIL=0;
|
||||
} else if (sr<(u32)(SYSCLK/24.6)) {
|
||||
} else if (sr < (u32)(sysclk_x_10/246)) {
|
||||
NDEC=1;
|
||||
SFIL=1;
|
||||
} else if (sr<(u32)(SYSCLK/16.0)) {
|
||||
} else if (sr < (u32)(sysclk_x_10/160)) {
|
||||
NDEC=1;
|
||||
SFIL=0;
|
||||
} else if (sr<(u32)(SYSCLK/12.3)) {
|
||||
} else if (sr < (u32)(sysclk_x_10/123)) {
|
||||
NDEC=0;
|
||||
SFIL=1;
|
||||
}
|
||||
|
||||
BDRI=SYSCLK*16;
|
||||
BDRI = (state->sysclk)*16;
|
||||
BDRI>>=NDEC;
|
||||
BDRI +=sr/2;
|
||||
BDRI /=sr;
|
||||
@ -255,11 +213,12 @@ static int tda10023_set_symbolrate (struct tda10023_state* state, u32 sr)
|
||||
|
||||
BDRX=1<<(24+NDEC);
|
||||
BDRX*=sr;
|
||||
do_div(BDRX,SYSCLK); // BDRX/=SYSCLK;
|
||||
do_div(BDRX, state->sysclk); /* BDRX/=SYSCLK; */
|
||||
|
||||
BDR=(s32)BDRX;
|
||||
}
|
||||
// printk("Symbolrate %i, BDR %i BDRI %i, NDEC %i\n",sr,BDR,BDRI,NDEC);
|
||||
dprintk("Symbolrate %i, BDR %i BDRI %i, NDEC %i\n",
|
||||
sr, BDR, BDRI, NDEC);
|
||||
tda10023_writebit (state, 0x03, 0xc0, NDEC<<6);
|
||||
tda10023_writereg (state, 0x0a, BDR&255);
|
||||
tda10023_writereg (state, 0x0b, (BDR>>8)&255);
|
||||
@ -272,8 +231,67 @@ static int tda10023_set_symbolrate (struct tda10023_state* state, u32 sr)
|
||||
static int tda10023_init (struct dvb_frontend *fe)
|
||||
{
|
||||
struct tda10023_state* state = fe->demodulator_priv;
|
||||
u8 tda10023_inittab[] = {
|
||||
/* reg mask val */
|
||||
/* 000 */ 0x2a, 0xff, 0x02, /* PLL3, Bypass, Power Down */
|
||||
/* 003 */ 0xff, 0x64, 0x00, /* Sleep 100ms */
|
||||
/* 006 */ 0x2a, 0xff, 0x03, /* PLL3, Bypass, Power Down */
|
||||
/* 009 */ 0xff, 0x64, 0x00, /* Sleep 100ms */
|
||||
/* PLL1 */
|
||||
/* 012 */ 0x28, 0xff, (state->pll_m-1),
|
||||
/* PLL2 */
|
||||
/* 015 */ 0x29, 0xff, ((state->pll_p-1)<<6)|(state->pll_n-1),
|
||||
/* GPR FSAMPLING=1 */
|
||||
/* 018 */ 0x00, 0xff, REG0_INIT_VAL,
|
||||
/* 021 */ 0x2a, 0xff, 0x08, /* PLL3 PSACLK=1 */
|
||||
/* 024 */ 0xff, 0x64, 0x00, /* Sleep 100ms */
|
||||
/* 027 */ 0x1f, 0xff, 0x00, /* RESET */
|
||||
/* 030 */ 0xff, 0x64, 0x00, /* Sleep 100ms */
|
||||
/* 033 */ 0xe6, 0x0c, 0x04, /* RSCFG_IND */
|
||||
/* 036 */ 0x10, 0xc0, 0x80, /* DECDVBCFG1 PBER=1 */
|
||||
|
||||
dprintk("DVB: TDA10023(%d): init chip\n", fe->adapter->num);
|
||||
/* 039 */ 0x0e, 0xff, 0x82, /* GAIN1 */
|
||||
/* 042 */ 0x03, 0x08, 0x08, /* CLKCONF DYN=1 */
|
||||
/* 045 */ 0x2e, 0xbf, 0x30, /* AGCCONF2 TRIAGC=0,POSAGC=ENAGCIF=1
|
||||
PPWMTUN=0 PPWMIF=0 */
|
||||
/* 048 */ 0x01, 0xff, 0x30, /* AGCREF */
|
||||
/* 051 */ 0x1e, 0x84, 0x84, /* CONTROL SACLK_ON=1 */
|
||||
/* 054 */ 0x1b, 0xff, 0xc8, /* ADC TWOS=1 */
|
||||
/* 057 */ 0x3b, 0xff, 0xff, /* IFMAX */
|
||||
/* 060 */ 0x3c, 0xff, 0x00, /* IFMIN */
|
||||
/* 063 */ 0x34, 0xff, 0x00, /* PWMREF */
|
||||
/* 066 */ 0x35, 0xff, 0xff, /* TUNMAX */
|
||||
/* 069 */ 0x36, 0xff, 0x00, /* TUNMIN */
|
||||
/* 072 */ 0x06, 0xff, 0x7f, /* EQCONF1 POSI=7 ENADAPT=ENEQUAL=DFE=1 */
|
||||
/* 075 */ 0x1c, 0x30, 0x30, /* EQCONF2 STEPALGO=SGNALGO=1 */
|
||||
/* 078 */ 0x37, 0xff, 0xf6, /* DELTAF_LSB */
|
||||
/* 081 */ 0x38, 0xff, 0xff, /* DELTAF_MSB */
|
||||
/* 084 */ 0x02, 0xff, 0x93, /* AGCCONF1 IFS=1 KAGCIF=2 KAGCTUN=3 */
|
||||
/* 087 */ 0x2d, 0xff, 0xf6, /* SWEEP SWPOS=1 SWDYN=7 SWSTEP=1 SWLEN=2 */
|
||||
/* 090 */ 0x04, 0x10, 0x00, /* SWRAMP=1 */
|
||||
/* 093 */ 0x12, 0xff, TDA10023_OUTPUT_MODE_PARALLEL_B, /*
|
||||
INTP1 POCLKP=1 FEL=1 MFS=0 */
|
||||
/* 096 */ 0x2b, 0x01, 0xa1, /* INTS1 */
|
||||
/* 099 */ 0x20, 0xff, 0x04, /* INTP2 SWAPP=? MSBFIRSTP=? INTPSEL=? */
|
||||
/* 102 */ 0x2c, 0xff, 0x0d, /* INTP/S TRIP=0 TRIS=0 */
|
||||
/* 105 */ 0xc4, 0xff, 0x00,
|
||||
/* 108 */ 0xc3, 0x30, 0x00,
|
||||
/* 111 */ 0xb5, 0xff, 0x19, /* ERAGC_THD */
|
||||
/* 114 */ 0x00, 0x03, 0x01, /* GPR, CLBS soft reset */
|
||||
/* 117 */ 0x00, 0x03, 0x03, /* GPR, CLBS soft reset */
|
||||
/* 120 */ 0xff, 0x64, 0x00, /* Sleep 100ms */
|
||||
/* 123 */ 0xff, 0xff, 0xff
|
||||
};
|
||||
dprintk("DVB: TDA10023(%d): init chip\n", fe->dvb->num);
|
||||
|
||||
/* override default values if set in config */
|
||||
if (state->config->deltaf) {
|
||||
tda10023_inittab[80] = (state->config->deltaf & 0xff);
|
||||
tda10023_inittab[83] = (state->config->deltaf >> 8);
|
||||
}
|
||||
|
||||
if (state->config->output_mode)
|
||||
tda10023_inittab[95] = state->config->output_mode;
|
||||
|
||||
tda10023_writetab(state, tda10023_inittab);
|
||||
|
||||
@ -460,12 +478,11 @@ static void tda10023_release(struct dvb_frontend* fe)
|
||||
|
||||
static struct dvb_frontend_ops tda10023_ops;
|
||||
|
||||
struct dvb_frontend* tda10023_attach(const struct tda1002x_config* config,
|
||||
struct i2c_adapter* i2c,
|
||||
struct dvb_frontend *tda10023_attach(const struct tda10023_config *config,
|
||||
struct i2c_adapter *i2c,
|
||||
u8 pwm)
|
||||
{
|
||||
struct tda10023_state* state = NULL;
|
||||
int i;
|
||||
|
||||
/* allocate memory for the internal state */
|
||||
state = kzalloc(sizeof(struct tda10023_state), GFP_KERNEL);
|
||||
@ -474,22 +491,40 @@ struct dvb_frontend* tda10023_attach(const struct tda1002x_config* config,
|
||||
/* setup the state */
|
||||
state->config = config;
|
||||
state->i2c = i2c;
|
||||
memcpy(&state->frontend.ops, &tda10023_ops, sizeof(struct dvb_frontend_ops));
|
||||
state->pwm = pwm;
|
||||
for (i=0; i < ARRAY_SIZE(tda10023_inittab);i+=3) {
|
||||
if (tda10023_inittab[i] == 0x00) {
|
||||
state->reg0 = tda10023_inittab[i+2];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Wakeup if in standby
|
||||
/* wakeup if in standby */
|
||||
tda10023_writereg (state, 0x00, 0x33);
|
||||
/* check if the demod is there */
|
||||
if ((tda10023_readreg(state, 0x1a) & 0xf0) != 0x70) goto error;
|
||||
|
||||
/* create dvb_frontend */
|
||||
memcpy(&state->frontend.ops, &tda10023_ops, sizeof(struct dvb_frontend_ops));
|
||||
state->pwm = pwm;
|
||||
state->reg0 = REG0_INIT_VAL;
|
||||
if (state->config->xtal) {
|
||||
state->xtal = state->config->xtal;
|
||||
state->pll_m = state->config->pll_m;
|
||||
state->pll_p = state->config->pll_p;
|
||||
state->pll_n = state->config->pll_n;
|
||||
} else {
|
||||
/* set default values if not defined in config */
|
||||
state->xtal = 28920000;
|
||||
state->pll_m = 8;
|
||||
state->pll_p = 4;
|
||||
state->pll_n = 1;
|
||||
}
|
||||
|
||||
/* calc sysclk */
|
||||
state->sysclk = (state->xtal * state->pll_m / \
|
||||
(state->pll_n * state->pll_p));
|
||||
|
||||
state->frontend.ops.info.symbol_rate_min = (state->sysclk/2)/64;
|
||||
state->frontend.ops.info.symbol_rate_max = (state->sysclk/2)/4;
|
||||
|
||||
dprintk("DVB: TDA10023 %s: xtal:%d pll_m:%d pll_p:%d pll_n:%d\n",
|
||||
__func__, state->xtal, state->pll_m, state->pll_p,
|
||||
state->pll_n);
|
||||
|
||||
state->frontend.demodulator_priv = state;
|
||||
return &state->frontend;
|
||||
|
||||
@ -504,10 +539,10 @@ static struct dvb_frontend_ops tda10023_ops = {
|
||||
.name = "Philips TDA10023 DVB-C",
|
||||
.type = FE_QAM,
|
||||
.frequency_stepsize = 62500,
|
||||
.frequency_min = 47000000,
|
||||
.frequency_min = 47000000,
|
||||
.frequency_max = 862000000,
|
||||
.symbol_rate_min = (SYSCLK/2)/64, /* SACLK/64 == (SYSCLK/2)/64 */
|
||||
.symbol_rate_max = (SYSCLK/2)/4, /* SACLK/4 */
|
||||
.symbol_rate_min = 0, /* set in tda10023_attach */
|
||||
.symbol_rate_max = 0, /* set in tda10023_attach */
|
||||
.caps = 0x400 | //FE_CAN_QAM_4
|
||||
FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 |
|
||||
FE_CAN_QAM_128 | FE_CAN_QAM_256 |
|
||||
|
@ -26,13 +26,37 @@
|
||||
|
||||
#include <linux/dvb/frontend.h>
|
||||
|
||||
struct tda1002x_config
|
||||
{
|
||||
struct tda1002x_config {
|
||||
/* the demodulator's i2c address */
|
||||
u8 demod_address;
|
||||
u8 invert;
|
||||
};
|
||||
|
||||
enum tda10023_output_mode {
|
||||
TDA10023_OUTPUT_MODE_PARALLEL_A = 0xe0,
|
||||
TDA10023_OUTPUT_MODE_PARALLEL_B = 0xa1,
|
||||
TDA10023_OUTPUT_MODE_PARALLEL_C = 0xa0,
|
||||
TDA10023_OUTPUT_MODE_SERIAL, /* TODO: not implemented */
|
||||
};
|
||||
|
||||
struct tda10023_config {
|
||||
/* the demodulator's i2c address */
|
||||
u8 demod_address;
|
||||
u8 invert;
|
||||
|
||||
/* clock settings */
|
||||
u32 xtal; /* defaults: 28920000 */
|
||||
u8 pll_m; /* defaults: 8 */
|
||||
u8 pll_p; /* defaults: 4 */
|
||||
u8 pll_n; /* defaults: 1 */
|
||||
|
||||
/* MPEG2 TS output mode */
|
||||
u8 output_mode;
|
||||
|
||||
/* input freq offset + baseband conversion type */
|
||||
u16 deltaf;
|
||||
};
|
||||
|
||||
#if defined(CONFIG_DVB_TDA10021) || (defined(CONFIG_DVB_TDA10021_MODULE) && defined(MODULE))
|
||||
extern struct dvb_frontend* tda10021_attach(const struct tda1002x_config* config,
|
||||
struct i2c_adapter* i2c, u8 pwm);
|
||||
@ -45,12 +69,15 @@ static inline struct dvb_frontend* tda10021_attach(const struct tda1002x_config*
|
||||
}
|
||||
#endif // CONFIG_DVB_TDA10021
|
||||
|
||||
#if defined(CONFIG_DVB_TDA10023) || (defined(CONFIG_DVB_TDA10023_MODULE) && defined(MODULE))
|
||||
extern struct dvb_frontend* tda10023_attach(const struct tda1002x_config* config,
|
||||
struct i2c_adapter* i2c, u8 pwm);
|
||||
#if defined(CONFIG_DVB_TDA10023) || \
|
||||
(defined(CONFIG_DVB_TDA10023_MODULE) && defined(MODULE))
|
||||
extern struct dvb_frontend *tda10023_attach(
|
||||
const struct tda10023_config *config,
|
||||
struct i2c_adapter *i2c, u8 pwm);
|
||||
#else
|
||||
static inline struct dvb_frontend* tda10023_attach(const struct tda1002x_config* config,
|
||||
struct i2c_adapter* i2c, u8 pwm)
|
||||
static inline struct dvb_frontend *tda10023_attach(
|
||||
const struct tda10023_config *config,
|
||||
struct i2c_adapter *i2c, u8 pwm)
|
||||
{
|
||||
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
|
||||
return NULL;
|
||||
|
@ -234,7 +234,7 @@ static void pluto_reset_ts(struct pluto *pluto, int reenable)
|
||||
|
||||
static void pluto_set_dma_addr(struct pluto *pluto)
|
||||
{
|
||||
pluto_writereg(pluto, REG_PCAR, cpu_to_le32(pluto->dma_addr));
|
||||
pluto_writereg(pluto, REG_PCAR, pluto->dma_addr);
|
||||
}
|
||||
|
||||
static int __devinit pluto_dma_map(struct pluto *pluto)
|
||||
|
26
drivers/media/dvb/siano/Kconfig
Normal file
26
drivers/media/dvb/siano/Kconfig
Normal file
@ -0,0 +1,26 @@
|
||||
#
|
||||
# Siano Mobile Silicon Digital TV device configuration
|
||||
#
|
||||
|
||||
config DVB_SIANO_SMS1XXX
|
||||
tristate "Siano SMS1XXX USB dongle support"
|
||||
depends on DVB_CORE && USB
|
||||
---help---
|
||||
Choose Y here if you have a USB dongle with a SMS1XXX chipset.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called sms1xxx.
|
||||
|
||||
config DVB_SIANO_SMS1XXX_SMS_IDS
|
||||
bool "Enable support for Siano Mobile Silicon default USB IDs"
|
||||
depends on DVB_SIANO_SMS1XXX
|
||||
default y
|
||||
---help---
|
||||
Choose Y here if you have a USB dongle with a SMS1XXX chipset
|
||||
that uses Siano Mobile Silicon's default usb vid:pid.
|
||||
|
||||
Choose N here if you would prefer to use Siano's external driver.
|
||||
|
||||
Further documentation on this driver can be found on the WWW at
|
||||
<http://www.siano-ms.com/>.
|
||||
|
8
drivers/media/dvb/siano/Makefile
Normal file
8
drivers/media/dvb/siano/Makefile
Normal file
@ -0,0 +1,8 @@
|
||||
sms1xxx-objs := smscoreapi.o smsusb.o smsdvb.o sms-cards.o
|
||||
|
||||
obj-$(CONFIG_DVB_SIANO_SMS1XXX) += sms1xxx.o
|
||||
|
||||
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
|
||||
|
||||
EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m)
|
||||
|
102
drivers/media/dvb/siano/sms-cards.c
Normal file
102
drivers/media/dvb/siano/sms-cards.c
Normal file
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Card-specific functions for the Siano SMS1xxx USB dongle
|
||||
*
|
||||
* Copyright (c) 2008 Michael Krufky <mkrufky@linuxtv.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 3 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "sms-cards.h"
|
||||
|
||||
struct usb_device_id smsusb_id_table[] = {
|
||||
#ifdef CONFIG_DVB_SIANO_SMS1XXX_SMS_IDS
|
||||
{ USB_DEVICE(0x187f, 0x0010),
|
||||
.driver_info = SMS1XXX_BOARD_SIANO_STELLAR },
|
||||
{ USB_DEVICE(0x187f, 0x0100),
|
||||
.driver_info = SMS1XXX_BOARD_SIANO_STELLAR },
|
||||
{ USB_DEVICE(0x187f, 0x0200),
|
||||
.driver_info = SMS1XXX_BOARD_SIANO_NOVA_A },
|
||||
{ USB_DEVICE(0x187f, 0x0201),
|
||||
.driver_info = SMS1XXX_BOARD_SIANO_NOVA_B },
|
||||
{ USB_DEVICE(0x187f, 0x0300),
|
||||
.driver_info = SMS1XXX_BOARD_SIANO_VEGA },
|
||||
#endif
|
||||
{ USB_DEVICE(0x2040, 0x1700),
|
||||
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT },
|
||||
{ USB_DEVICE(0x2040, 0x1800),
|
||||
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A },
|
||||
{ USB_DEVICE(0x2040, 0x1801),
|
||||
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B },
|
||||
{ USB_DEVICE(0x2040, 0x5500),
|
||||
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
|
||||
{ USB_DEVICE(0x2040, 0x5580),
|
||||
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
|
||||
{ USB_DEVICE(0x2040, 0x5590),
|
||||
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
MODULE_DEVICE_TABLE(usb, smsusb_id_table);
|
||||
|
||||
static struct sms_board sms_boards[] = {
|
||||
[SMS_BOARD_UNKNOWN] = {
|
||||
.name = "Unknown board",
|
||||
},
|
||||
[SMS1XXX_BOARD_SIANO_STELLAR] = {
|
||||
.name = "Siano Stellar Digital Receiver",
|
||||
.type = SMS_STELLAR,
|
||||
.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-stellar-dvbt-01.fw",
|
||||
},
|
||||
[SMS1XXX_BOARD_SIANO_NOVA_A] = {
|
||||
.name = "Siano Nova A Digital Receiver",
|
||||
.type = SMS_NOVA_A0,
|
||||
.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-a-dvbt-01.fw",
|
||||
},
|
||||
[SMS1XXX_BOARD_SIANO_NOVA_B] = {
|
||||
.name = "Siano Nova B Digital Receiver",
|
||||
.type = SMS_NOVA_B0,
|
||||
.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-b-dvbt-01.fw",
|
||||
},
|
||||
[SMS1XXX_BOARD_SIANO_VEGA] = {
|
||||
.name = "Siano Vega Digital Receiver",
|
||||
.type = SMS_VEGA,
|
||||
},
|
||||
[SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT] = {
|
||||
.name = "Hauppauge Catamount",
|
||||
.type = SMS_STELLAR,
|
||||
.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-stellar-dvbt-01.fw",
|
||||
},
|
||||
[SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A] = {
|
||||
.name = "Hauppauge Okemo-A",
|
||||
.type = SMS_NOVA_A0,
|
||||
.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-a-dvbt-01.fw",
|
||||
},
|
||||
[SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B] = {
|
||||
.name = "Hauppauge Okemo-B",
|
||||
.type = SMS_NOVA_B0,
|
||||
.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-b-dvbt-01.fw",
|
||||
},
|
||||
[SMS1XXX_BOARD_HAUPPAUGE_WINDHAM] = {
|
||||
.name = "Hauppauge WinTV-Nova-T-MiniStick",
|
||||
.type = SMS_NOVA_B0,
|
||||
.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-01.fw",
|
||||
},
|
||||
};
|
||||
|
||||
struct sms_board *sms_get_board(int id)
|
||||
{
|
||||
BUG_ON(id >= ARRAY_SIZE(sms_boards));
|
||||
|
||||
return &sms_boards[id];
|
||||
}
|
||||
|
45
drivers/media/dvb/siano/sms-cards.h
Normal file
45
drivers/media/dvb/siano/sms-cards.h
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Card-specific functions for the Siano SMS1xxx USB dongle
|
||||
*
|
||||
* Copyright (c) 2008 Michael Krufky <mkrufky@linuxtv.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 3 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef __SMS_CARDS_H__
|
||||
#define __SMS_CARDS_H__
|
||||
|
||||
#include <linux/usb.h>
|
||||
#include "smscoreapi.h"
|
||||
|
||||
#define SMS_BOARD_UNKNOWN 0
|
||||
#define SMS1XXX_BOARD_SIANO_STELLAR 1
|
||||
#define SMS1XXX_BOARD_SIANO_NOVA_A 2
|
||||
#define SMS1XXX_BOARD_SIANO_NOVA_B 3
|
||||
#define SMS1XXX_BOARD_SIANO_VEGA 4
|
||||
#define SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT 5
|
||||
#define SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A 6
|
||||
#define SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B 7
|
||||
#define SMS1XXX_BOARD_HAUPPAUGE_WINDHAM 8
|
||||
|
||||
struct sms_board {
|
||||
enum sms_device_type_st type;
|
||||
char *name, *fw[DEVICE_MODE_MAX];
|
||||
};
|
||||
|
||||
struct sms_board *sms_get_board(int id);
|
||||
|
||||
extern struct usb_device_id smsusb_id_table[];
|
||||
|
||||
#endif /* __SMS_CARDS_H__ */
|
1251
drivers/media/dvb/siano/smscoreapi.c
Normal file
1251
drivers/media/dvb/siano/smscoreapi.c
Normal file
File diff suppressed because it is too large
Load Diff
434
drivers/media/dvb/siano/smscoreapi.h
Normal file
434
drivers/media/dvb/siano/smscoreapi.h
Normal file
@ -0,0 +1,434 @@
|
||||
/*
|
||||
* Driver for the Siano SMS1xxx USB dongle
|
||||
*
|
||||
* author: Anatoly Greenblat
|
||||
*
|
||||
* Copyright (c), 2005-2008 Siano Mobile Silicon, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 3 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef __smscoreapi_h__
|
||||
#define __smscoreapi_h__
|
||||
|
||||
#include <linux/version.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/types.h>
|
||||
#include <asm/page.h>
|
||||
|
||||
#include "dmxdev.h"
|
||||
#include "dvbdev.h"
|
||||
#include "dvb_demux.h"
|
||||
#include "dvb_frontend.h"
|
||||
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#define kmutex_init(_p_) mutex_init(_p_)
|
||||
#define kmutex_lock(_p_) mutex_lock(_p_)
|
||||
#define kmutex_trylock(_p_) mutex_trylock(_p_)
|
||||
#define kmutex_unlock(_p_) mutex_unlock(_p_)
|
||||
|
||||
#ifndef min
|
||||
#define min(a, b) (((a) < (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#define SMS_ALLOC_ALIGNMENT 128
|
||||
#define SMS_DMA_ALIGNMENT 16
|
||||
#define SMS_ALIGN_ADDRESS(addr) \
|
||||
((((uintptr_t)(addr)) + (SMS_DMA_ALIGNMENT-1)) & ~(SMS_DMA_ALIGNMENT-1))
|
||||
|
||||
#define SMS_DEVICE_FAMILY2 1
|
||||
#define SMS_ROM_NO_RESPONSE 2
|
||||
#define SMS_DEVICE_NOT_READY 0x8000000
|
||||
|
||||
enum sms_device_type_st {
|
||||
SMS_STELLAR = 0,
|
||||
SMS_NOVA_A0,
|
||||
SMS_NOVA_B0,
|
||||
SMS_VEGA,
|
||||
SMS_NUM_OF_DEVICE_TYPES
|
||||
};
|
||||
|
||||
struct smscore_device_t;
|
||||
struct smscore_client_t;
|
||||
struct smscore_buffer_t;
|
||||
|
||||
typedef int (*hotplug_t)(struct smscore_device_t *coredev,
|
||||
struct device *device, int arrival);
|
||||
|
||||
typedef int (*setmode_t)(void *context, int mode);
|
||||
typedef void (*detectmode_t)(void *context, int *mode);
|
||||
typedef int (*sendrequest_t)(void *context, void *buffer, size_t size);
|
||||
typedef int (*loadfirmware_t)(void *context, void *buffer, size_t size);
|
||||
typedef int (*preload_t)(void *context);
|
||||
typedef int (*postload_t)(void *context);
|
||||
|
||||
typedef int (*onresponse_t)(void *context, struct smscore_buffer_t *cb);
|
||||
typedef void (*onremove_t)(void *context);
|
||||
|
||||
struct smscore_buffer_t {
|
||||
/* public members, once passed to clients can be changed freely */
|
||||
struct list_head entry;
|
||||
int size;
|
||||
int offset;
|
||||
|
||||
/* private members, read-only for clients */
|
||||
void *p;
|
||||
dma_addr_t phys;
|
||||
unsigned long offset_in_common;
|
||||
};
|
||||
|
||||
struct smsdevice_params_t {
|
||||
struct device *device;
|
||||
|
||||
int buffer_size;
|
||||
int num_buffers;
|
||||
|
||||
char devpath[32];
|
||||
unsigned long flags;
|
||||
|
||||
setmode_t setmode_handler;
|
||||
detectmode_t detectmode_handler;
|
||||
sendrequest_t sendrequest_handler;
|
||||
preload_t preload_handler;
|
||||
postload_t postload_handler;
|
||||
|
||||
void *context;
|
||||
enum sms_device_type_st device_type;
|
||||
};
|
||||
|
||||
struct smsclient_params_t {
|
||||
int initial_id;
|
||||
int data_type;
|
||||
onresponse_t onresponse_handler;
|
||||
onremove_t onremove_handler;
|
||||
|
||||
void *context;
|
||||
};
|
||||
|
||||
/* GPIO definitions for antenna frequency domain control (SMS8021) */
|
||||
#define SMS_ANTENNA_GPIO_0 1
|
||||
#define SMS_ANTENNA_GPIO_1 0
|
||||
|
||||
#define BW_8_MHZ 0
|
||||
#define BW_7_MHZ 1
|
||||
#define BW_6_MHZ 2
|
||||
#define BW_5_MHZ 3
|
||||
#define BW_ISDBT_1SEG 4
|
||||
#define BW_ISDBT_3SEG 5
|
||||
|
||||
#define MSG_HDR_FLAG_SPLIT_MSG 4
|
||||
|
||||
#define MAX_GPIO_PIN_NUMBER 31
|
||||
|
||||
#define HIF_TASK 11
|
||||
#define SMS_HOST_LIB 150
|
||||
#define DVBT_BDA_CONTROL_MSG_ID 201
|
||||
|
||||
#define SMS_MAX_PAYLOAD_SIZE 240
|
||||
#define SMS_TUNE_TIMEOUT 500
|
||||
|
||||
#define MSG_SMS_GPIO_CONFIG_REQ 507
|
||||
#define MSG_SMS_GPIO_CONFIG_RES 508
|
||||
#define MSG_SMS_GPIO_SET_LEVEL_REQ 509
|
||||
#define MSG_SMS_GPIO_SET_LEVEL_RES 510
|
||||
#define MSG_SMS_GPIO_GET_LEVEL_REQ 511
|
||||
#define MSG_SMS_GPIO_GET_LEVEL_RES 512
|
||||
#define MSG_SMS_RF_TUNE_REQ 561
|
||||
#define MSG_SMS_RF_TUNE_RES 562
|
||||
#define MSG_SMS_INIT_DEVICE_REQ 578
|
||||
#define MSG_SMS_INIT_DEVICE_RES 579
|
||||
#define MSG_SMS_ADD_PID_FILTER_REQ 601
|
||||
#define MSG_SMS_ADD_PID_FILTER_RES 602
|
||||
#define MSG_SMS_REMOVE_PID_FILTER_REQ 603
|
||||
#define MSG_SMS_REMOVE_PID_FILTER_RES 604
|
||||
#define MSG_SMS_DAB_CHANNEL 607
|
||||
#define MSG_SMS_GET_PID_FILTER_LIST_REQ 608
|
||||
#define MSG_SMS_GET_PID_FILTER_LIST_RES 609
|
||||
#define MSG_SMS_GET_STATISTICS_REQ 615
|
||||
#define MSG_SMS_GET_STATISTICS_RES 616
|
||||
#define MSG_SMS_SET_ANTENNA_CONFIG_REQ 651
|
||||
#define MSG_SMS_SET_ANTENNA_CONFIG_RES 652
|
||||
#define MSG_SMS_GET_STATISTICS_EX_REQ 653
|
||||
#define MSG_SMS_GET_STATISTICS_EX_RES 654
|
||||
#define MSG_SMS_SLEEP_RESUME_COMP_IND 655
|
||||
#define MSG_SMS_DATA_DOWNLOAD_REQ 660
|
||||
#define MSG_SMS_DATA_DOWNLOAD_RES 661
|
||||
#define MSG_SMS_SWDOWNLOAD_TRIGGER_REQ 664
|
||||
#define MSG_SMS_SWDOWNLOAD_TRIGGER_RES 665
|
||||
#define MSG_SMS_SWDOWNLOAD_BACKDOOR_REQ 666
|
||||
#define MSG_SMS_SWDOWNLOAD_BACKDOOR_RES 667
|
||||
#define MSG_SMS_GET_VERSION_EX_REQ 668
|
||||
#define MSG_SMS_GET_VERSION_EX_RES 669
|
||||
#define MSG_SMS_SET_CLOCK_OUTPUT_REQ 670
|
||||
#define MSG_SMS_I2C_SET_FREQ_REQ 685
|
||||
#define MSG_SMS_GENERIC_I2C_REQ 687
|
||||
#define MSG_SMS_GENERIC_I2C_RES 688
|
||||
#define MSG_SMS_DVBT_BDA_DATA 693
|
||||
#define MSG_SW_RELOAD_REQ 697
|
||||
#define MSG_SMS_DATA_MSG 699
|
||||
#define MSG_SW_RELOAD_START_REQ 702
|
||||
#define MSG_SW_RELOAD_START_RES 703
|
||||
#define MSG_SW_RELOAD_EXEC_REQ 704
|
||||
#define MSG_SW_RELOAD_EXEC_RES 705
|
||||
#define MSG_SMS_SPI_INT_LINE_SET_REQ 710
|
||||
#define MSG_SMS_ISDBT_TUNE_REQ 776
|
||||
#define MSG_SMS_ISDBT_TUNE_RES 777
|
||||
|
||||
#define SMS_INIT_MSG_EX(ptr, type, src, dst, len) do { \
|
||||
(ptr)->msgType = type; (ptr)->msgSrcId = src; (ptr)->msgDstId = dst; \
|
||||
(ptr)->msgLength = len; (ptr)->msgFlags = 0; \
|
||||
} while (0)
|
||||
#define SMS_INIT_MSG(ptr, type, len) \
|
||||
SMS_INIT_MSG_EX(ptr, type, 0, HIF_TASK, len)
|
||||
|
||||
enum SMS_DEVICE_MODE {
|
||||
DEVICE_MODE_NONE = -1,
|
||||
DEVICE_MODE_DVBT = 0,
|
||||
DEVICE_MODE_DVBH,
|
||||
DEVICE_MODE_DAB_TDMB,
|
||||
DEVICE_MODE_DAB_TDMB_DABIP,
|
||||
DEVICE_MODE_DVBT_BDA,
|
||||
DEVICE_MODE_ISDBT,
|
||||
DEVICE_MODE_ISDBT_BDA,
|
||||
DEVICE_MODE_CMMB,
|
||||
DEVICE_MODE_RAW_TUNER,
|
||||
DEVICE_MODE_MAX,
|
||||
};
|
||||
|
||||
struct SmsMsgHdr_ST {
|
||||
u16 msgType;
|
||||
u8 msgSrcId;
|
||||
u8 msgDstId;
|
||||
u16 msgLength; /* Length of entire message, including header */
|
||||
u16 msgFlags;
|
||||
};
|
||||
|
||||
struct SmsMsgData_ST {
|
||||
struct SmsMsgHdr_ST xMsgHeader;
|
||||
u32 msgData[1];
|
||||
};
|
||||
|
||||
struct SmsDataDownload_ST {
|
||||
struct SmsMsgHdr_ST xMsgHeader;
|
||||
u32 MemAddr;
|
||||
u8 Payload[SMS_MAX_PAYLOAD_SIZE];
|
||||
};
|
||||
|
||||
struct SmsVersionRes_ST {
|
||||
struct SmsMsgHdr_ST xMsgHeader;
|
||||
|
||||
u16 ChipModel; /* e.g. 0x1102 for SMS-1102 "Nova" */
|
||||
u8 Step; /* 0 - Step A */
|
||||
u8 MetalFix; /* 0 - Metal 0 */
|
||||
|
||||
u8 FirmwareId; /* 0xFF <20> ROM, otherwise the
|
||||
* value indicated by
|
||||
* SMSHOSTLIB_DEVICE_MODES_E */
|
||||
u8 SupportedProtocols; /* Bitwise OR combination of
|
||||
* supported protocols */
|
||||
|
||||
u8 VersionMajor;
|
||||
u8 VersionMinor;
|
||||
u8 VersionPatch;
|
||||
u8 VersionFieldPatch;
|
||||
|
||||
u8 RomVersionMajor;
|
||||
u8 RomVersionMinor;
|
||||
u8 RomVersionPatch;
|
||||
u8 RomVersionFieldPatch;
|
||||
|
||||
u8 TextLabel[34];
|
||||
};
|
||||
|
||||
struct SmsFirmware_ST {
|
||||
u32 CheckSum;
|
||||
u32 Length;
|
||||
u32 StartAddress;
|
||||
u8 Payload[1];
|
||||
};
|
||||
|
||||
struct SMSHOSTLIB_STATISTICS_ST {
|
||||
u32 Reserved; /* Reserved */
|
||||
|
||||
/* Common parameters */
|
||||
u32 IsRfLocked; /* 0 - not locked, 1 - locked */
|
||||
u32 IsDemodLocked; /* 0 - not locked, 1 - locked */
|
||||
u32 IsExternalLNAOn; /* 0 - external LNA off, 1 - external LNA on */
|
||||
|
||||
/* Reception quality */
|
||||
s32 SNR; /* dB */
|
||||
u32 BER; /* Post Viterbi BER [1E-5] */
|
||||
u32 FIB_CRC; /* CRC errors percentage, valid only for DAB */
|
||||
u32 TS_PER; /* Transport stream PER, 0xFFFFFFFF indicate N/A,
|
||||
* valid only for DVB-T/H */
|
||||
u32 MFER; /* DVB-H frame error rate in percentage,
|
||||
* 0xFFFFFFFF indicate N/A, valid only for DVB-H */
|
||||
s32 RSSI; /* dBm */
|
||||
s32 InBandPwr; /* In band power in dBM */
|
||||
s32 CarrierOffset; /* Carrier Offset in bin/1024 */
|
||||
|
||||
/* Transmission parameters, valid only for DVB-T/H */
|
||||
u32 Frequency; /* Frequency in Hz */
|
||||
u32 Bandwidth; /* Bandwidth in MHz */
|
||||
u32 TransmissionMode; /* Transmission Mode, for DAB modes 1-4,
|
||||
* for DVB-T/H FFT mode carriers in Kilos */
|
||||
u32 ModemState; /* from SMS_DvbModemState_ET */
|
||||
u32 GuardInterval; /* Guard Interval, 1 divided by value */
|
||||
u32 CodeRate; /* Code Rate from SMS_DvbModemState_ET */
|
||||
u32 LPCodeRate; /* Low Priority Code Rate from SMS_DvbModemState_ET */
|
||||
u32 Hierarchy; /* Hierarchy from SMS_Hierarchy_ET */
|
||||
u32 Constellation; /* Constellation from SMS_Constellation_ET */
|
||||
|
||||
/* Burst parameters, valid only for DVB-H */
|
||||
u32 BurstSize; /* Current burst size in bytes */
|
||||
u32 BurstDuration; /* Current burst duration in mSec */
|
||||
u32 BurstCycleTime; /* Current burst cycle time in mSec */
|
||||
u32 CalculatedBurstCycleTime; /* Current burst cycle time in mSec,
|
||||
* as calculated by demodulator */
|
||||
u32 NumOfRows; /* Number of rows in MPE table */
|
||||
u32 NumOfPaddCols; /* Number of padding columns in MPE table */
|
||||
u32 NumOfPunctCols; /* Number of puncturing columns in MPE table */
|
||||
/* Burst parameters */
|
||||
u32 ErrorTSPackets; /* Number of erroneous transport-stream packets */
|
||||
u32 TotalTSPackets; /* Total number of transport-stream packets */
|
||||
u32 NumOfValidMpeTlbs; /* Number of MPE tables which do not include
|
||||
* errors after MPE RS decoding */
|
||||
u32 NumOfInvalidMpeTlbs; /* Number of MPE tables which include errors
|
||||
* after MPE RS decoding */
|
||||
u32 NumOfCorrectedMpeTlbs; /* Number of MPE tables which were corrected
|
||||
* by MPE RS decoding */
|
||||
|
||||
/* Common params */
|
||||
u32 BERErrorCount; /* Number of errornous SYNC bits. */
|
||||
u32 BERBitCount; /* Total number of SYNC bits. */
|
||||
|
||||
/* Interface information */
|
||||
u32 SmsToHostTxErrors; /* Total number of transmission errors. */
|
||||
|
||||
/* DAB/T-DMB */
|
||||
u32 PreBER; /* DAB/T-DMB only: Pre Viterbi BER [1E-5] */
|
||||
|
||||
/* DVB-H TPS parameters */
|
||||
u32 CellId; /* TPS Cell ID in bits 15..0, bits 31..16 zero;
|
||||
* if set to 0xFFFFFFFF cell_id not yet recovered */
|
||||
|
||||
};
|
||||
|
||||
struct SmsMsgStatisticsInfo_ST {
|
||||
u32 RequestResult;
|
||||
|
||||
struct SMSHOSTLIB_STATISTICS_ST Stat;
|
||||
|
||||
/* Split the calc of the SNR in DAB */
|
||||
u32 Signal; /* dB */
|
||||
u32 Noise; /* dB */
|
||||
|
||||
};
|
||||
|
||||
|
||||
struct smsdvb_client_t {
|
||||
struct list_head entry;
|
||||
|
||||
struct smscore_device_t *coredev;
|
||||
struct smscore_client_t *smsclient;
|
||||
|
||||
struct dvb_adapter adapter;
|
||||
struct dvb_demux demux;
|
||||
struct dmxdev dmxdev;
|
||||
struct dvb_frontend frontend;
|
||||
|
||||
fe_status_t fe_status;
|
||||
int fe_ber, fe_snr, fe_signal_strength;
|
||||
|
||||
struct completion tune_done, stat_done;
|
||||
|
||||
/* todo: save freq/band instead whole struct */
|
||||
struct dvb_frontend_parameters fe_params;
|
||||
|
||||
};
|
||||
|
||||
extern void smscore_registry_setmode(char *devpath, int mode);
|
||||
extern int smscore_registry_getmode(char *devpath);
|
||||
|
||||
extern int smscore_register_hotplug(hotplug_t hotplug);
|
||||
extern void smscore_unregister_hotplug(hotplug_t hotplug);
|
||||
|
||||
extern int smscore_register_device(struct smsdevice_params_t *params,
|
||||
struct smscore_device_t **coredev);
|
||||
extern void smscore_unregister_device(struct smscore_device_t *coredev);
|
||||
|
||||
extern int smscore_start_device(struct smscore_device_t *coredev);
|
||||
extern int smscore_load_firmware(struct smscore_device_t *coredev,
|
||||
char *filename,
|
||||
loadfirmware_t loadfirmware_handler);
|
||||
|
||||
extern int smscore_set_device_mode(struct smscore_device_t *coredev, int mode);
|
||||
extern int smscore_get_device_mode(struct smscore_device_t *coredev);
|
||||
|
||||
extern int smscore_register_client(struct smscore_device_t *coredev,
|
||||
struct smsclient_params_t *params,
|
||||
struct smscore_client_t **client);
|
||||
extern void smscore_unregister_client(struct smscore_client_t *client);
|
||||
|
||||
extern int smsclient_sendrequest(struct smscore_client_t *client,
|
||||
void *buffer, size_t size);
|
||||
extern void smscore_onresponse(struct smscore_device_t *coredev,
|
||||
struct smscore_buffer_t *cb);
|
||||
|
||||
|
||||
extern
|
||||
struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev);
|
||||
extern void smscore_putbuffer(struct smscore_device_t *coredev,
|
||||
struct smscore_buffer_t *cb);
|
||||
|
||||
void smscore_set_board_id(struct smscore_device_t *core, int id);
|
||||
int smscore_get_board_id(struct smscore_device_t *core);
|
||||
|
||||
/* smsdvb.c */
|
||||
int smsdvb_register(void);
|
||||
void smsdvb_unregister(void);
|
||||
|
||||
/* smsusb.c */
|
||||
int smsusb_register(void);
|
||||
void smsusb_unregister(void);
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
extern int sms_debug;
|
||||
|
||||
#define DBG_INFO 1
|
||||
#define DBG_ADV 2
|
||||
|
||||
#define sms_printk(kern, fmt, arg...) \
|
||||
printk(kern "%s: " fmt "\n", __func__, ##arg)
|
||||
|
||||
#define dprintk(kern, lvl, fmt, arg...) do {\
|
||||
if (sms_debug & lvl) \
|
||||
sms_printk(kern, fmt, ##arg); } while (0)
|
||||
|
||||
#define sms_log(fmt, arg...) sms_printk(KERN_INFO, fmt, ##arg)
|
||||
#define sms_err(fmt, arg...) \
|
||||
sms_printk(KERN_ERR, "line: %d: " fmt, __LINE__, ##arg)
|
||||
#define sms_warn(fmt, arg...) sms_printk(KERN_WARNING, fmt, ##arg)
|
||||
#define sms_info(fmt, arg...) \
|
||||
dprintk(KERN_INFO, DBG_INFO, fmt, ##arg)
|
||||
#define sms_debug(fmt, arg...) \
|
||||
dprintk(KERN_DEBUG, DBG_ADV, fmt, ##arg)
|
||||
|
||||
|
||||
#endif /* __smscoreapi_h__ */
|
449
drivers/media/dvb/siano/smsdvb.c
Normal file
449
drivers/media/dvb/siano/smsdvb.c
Normal file
@ -0,0 +1,449 @@
|
||||
/*
|
||||
* Driver for the Siano SMS1xxx USB dongle
|
||||
*
|
||||
* author: Anatoly Greenblat
|
||||
*
|
||||
* Copyright (c), 2005-2008 Siano Mobile Silicon, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 3 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include "smscoreapi.h"
|
||||
#include "sms-cards.h"
|
||||
|
||||
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
|
||||
|
||||
struct list_head g_smsdvb_clients;
|
||||
struct mutex g_smsdvb_clientslock;
|
||||
|
||||
static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
|
||||
{
|
||||
struct smsdvb_client_t *client = (struct smsdvb_client_t *) context;
|
||||
struct SmsMsgHdr_ST *phdr =
|
||||
(struct SmsMsgHdr_ST *)(((u8 *) cb->p) + cb->offset);
|
||||
|
||||
switch (phdr->msgType) {
|
||||
case MSG_SMS_DVBT_BDA_DATA:
|
||||
dvb_dmx_swfilter(&client->demux, (u8 *)(phdr + 1),
|
||||
cb->size - sizeof(struct SmsMsgHdr_ST));
|
||||
break;
|
||||
|
||||
case MSG_SMS_RF_TUNE_RES:
|
||||
complete(&client->tune_done);
|
||||
break;
|
||||
|
||||
case MSG_SMS_GET_STATISTICS_RES:
|
||||
{
|
||||
struct SmsMsgStatisticsInfo_ST *p =
|
||||
(struct SmsMsgStatisticsInfo_ST *)(phdr + 1);
|
||||
|
||||
if (p->Stat.IsDemodLocked) {
|
||||
client->fe_status = FE_HAS_SIGNAL |
|
||||
FE_HAS_CARRIER |
|
||||
FE_HAS_VITERBI |
|
||||
FE_HAS_SYNC |
|
||||
FE_HAS_LOCK;
|
||||
|
||||
client->fe_snr = p->Stat.SNR;
|
||||
client->fe_ber = p->Stat.BER;
|
||||
|
||||
if (p->Stat.InBandPwr < -95)
|
||||
client->fe_signal_strength = 0;
|
||||
else if (p->Stat.InBandPwr > -29)
|
||||
client->fe_signal_strength = 100;
|
||||
else
|
||||
client->fe_signal_strength =
|
||||
(p->Stat.InBandPwr + 95) * 3 / 2;
|
||||
} else {
|
||||
client->fe_status = 0;
|
||||
client->fe_snr =
|
||||
client->fe_ber =
|
||||
client->fe_signal_strength = 0;
|
||||
}
|
||||
|
||||
complete(&client->stat_done);
|
||||
break;
|
||||
} }
|
||||
|
||||
smscore_putbuffer(client->coredev, cb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void smsdvb_unregister_client(struct smsdvb_client_t *client)
|
||||
{
|
||||
/* must be called under clientslock */
|
||||
|
||||
list_del(&client->entry);
|
||||
|
||||
smscore_unregister_client(client->smsclient);
|
||||
dvb_unregister_frontend(&client->frontend);
|
||||
dvb_dmxdev_release(&client->dmxdev);
|
||||
dvb_dmx_release(&client->demux);
|
||||
dvb_unregister_adapter(&client->adapter);
|
||||
kfree(client);
|
||||
}
|
||||
|
||||
static void smsdvb_onremove(void *context)
|
||||
{
|
||||
kmutex_lock(&g_smsdvb_clientslock);
|
||||
|
||||
smsdvb_unregister_client((struct smsdvb_client_t *) context);
|
||||
|
||||
kmutex_unlock(&g_smsdvb_clientslock);
|
||||
}
|
||||
|
||||
static int smsdvb_start_feed(struct dvb_demux_feed *feed)
|
||||
{
|
||||
struct smsdvb_client_t *client =
|
||||
container_of(feed->demux, struct smsdvb_client_t, demux);
|
||||
struct SmsMsgData_ST PidMsg;
|
||||
|
||||
sms_debug("add pid %d(%x)",
|
||||
feed->pid, feed->pid);
|
||||
|
||||
PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
|
||||
PidMsg.xMsgHeader.msgDstId = HIF_TASK;
|
||||
PidMsg.xMsgHeader.msgFlags = 0;
|
||||
PidMsg.xMsgHeader.msgType = MSG_SMS_ADD_PID_FILTER_REQ;
|
||||
PidMsg.xMsgHeader.msgLength = sizeof(PidMsg);
|
||||
PidMsg.msgData[0] = feed->pid;
|
||||
|
||||
return smsclient_sendrequest(client->smsclient,
|
||||
&PidMsg, sizeof(PidMsg));
|
||||
}
|
||||
|
||||
static int smsdvb_stop_feed(struct dvb_demux_feed *feed)
|
||||
{
|
||||
struct smsdvb_client_t *client =
|
||||
container_of(feed->demux, struct smsdvb_client_t, demux);
|
||||
struct SmsMsgData_ST PidMsg;
|
||||
|
||||
sms_debug("remove pid %d(%x)",
|
||||
feed->pid, feed->pid);
|
||||
|
||||
PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
|
||||
PidMsg.xMsgHeader.msgDstId = HIF_TASK;
|
||||
PidMsg.xMsgHeader.msgFlags = 0;
|
||||
PidMsg.xMsgHeader.msgType = MSG_SMS_REMOVE_PID_FILTER_REQ;
|
||||
PidMsg.xMsgHeader.msgLength = sizeof(PidMsg);
|
||||
PidMsg.msgData[0] = feed->pid;
|
||||
|
||||
return smsclient_sendrequest(client->smsclient,
|
||||
&PidMsg, sizeof(PidMsg));
|
||||
}
|
||||
|
||||
static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t *client,
|
||||
void *buffer, size_t size,
|
||||
struct completion *completion)
|
||||
{
|
||||
int rc = smsclient_sendrequest(client->smsclient, buffer, size);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
return wait_for_completion_timeout(completion,
|
||||
msecs_to_jiffies(2000)) ?
|
||||
0 : -ETIME;
|
||||
}
|
||||
|
||||
static int smsdvb_send_statistics_request(struct smsdvb_client_t *client)
|
||||
{
|
||||
struct SmsMsgHdr_ST Msg = { MSG_SMS_GET_STATISTICS_REQ,
|
||||
DVBT_BDA_CONTROL_MSG_ID,
|
||||
HIF_TASK, sizeof(struct SmsMsgHdr_ST), 0 };
|
||||
return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
|
||||
&client->stat_done);
|
||||
}
|
||||
|
||||
static int smsdvb_read_status(struct dvb_frontend *fe, fe_status_t *stat)
|
||||
{
|
||||
struct smsdvb_client_t *client =
|
||||
container_of(fe, struct smsdvb_client_t, frontend);
|
||||
int rc = smsdvb_send_statistics_request(client);
|
||||
|
||||
if (!rc)
|
||||
*stat = client->fe_status;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int smsdvb_read_ber(struct dvb_frontend *fe, u32 *ber)
|
||||
{
|
||||
struct smsdvb_client_t *client =
|
||||
container_of(fe, struct smsdvb_client_t, frontend);
|
||||
int rc = smsdvb_send_statistics_request(client);
|
||||
|
||||
if (!rc)
|
||||
*ber = client->fe_ber;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int smsdvb_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
|
||||
{
|
||||
struct smsdvb_client_t *client =
|
||||
container_of(fe, struct smsdvb_client_t, frontend);
|
||||
int rc = smsdvb_send_statistics_request(client);
|
||||
|
||||
if (!rc)
|
||||
*strength = client->fe_signal_strength;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr)
|
||||
{
|
||||
struct smsdvb_client_t *client =
|
||||
container_of(fe, struct smsdvb_client_t, frontend);
|
||||
int rc = smsdvb_send_statistics_request(client);
|
||||
|
||||
if (!rc)
|
||||
*snr = client->fe_snr;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int smsdvb_get_tune_settings(struct dvb_frontend *fe,
|
||||
struct dvb_frontend_tune_settings *tune)
|
||||
{
|
||||
sms_debug("");
|
||||
|
||||
tune->min_delay_ms = 400;
|
||||
tune->step_size = 250000;
|
||||
tune->max_drift = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int smsdvb_set_frontend(struct dvb_frontend *fe,
|
||||
struct dvb_frontend_parameters *fep)
|
||||
{
|
||||
struct smsdvb_client_t *client =
|
||||
container_of(fe, struct smsdvb_client_t, frontend);
|
||||
|
||||
struct {
|
||||
struct SmsMsgHdr_ST Msg;
|
||||
u32 Data[3];
|
||||
} Msg;
|
||||
|
||||
Msg.Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
|
||||
Msg.Msg.msgDstId = HIF_TASK;
|
||||
Msg.Msg.msgFlags = 0;
|
||||
Msg.Msg.msgType = MSG_SMS_RF_TUNE_REQ;
|
||||
Msg.Msg.msgLength = sizeof(Msg);
|
||||
Msg.Data[0] = fep->frequency;
|
||||
Msg.Data[2] = 12000000;
|
||||
|
||||
sms_debug("freq %d band %d",
|
||||
fep->frequency, fep->u.ofdm.bandwidth);
|
||||
|
||||
switch (fep->u.ofdm.bandwidth) {
|
||||
case BANDWIDTH_8_MHZ: Msg.Data[1] = BW_8_MHZ; break;
|
||||
case BANDWIDTH_7_MHZ: Msg.Data[1] = BW_7_MHZ; break;
|
||||
case BANDWIDTH_6_MHZ: Msg.Data[1] = BW_6_MHZ; break;
|
||||
case BANDWIDTH_AUTO: return -EOPNOTSUPP;
|
||||
default: return -EINVAL;
|
||||
}
|
||||
|
||||
return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
|
||||
&client->tune_done);
|
||||
}
|
||||
|
||||
static int smsdvb_get_frontend(struct dvb_frontend *fe,
|
||||
struct dvb_frontend_parameters *fep)
|
||||
{
|
||||
struct smsdvb_client_t *client =
|
||||
container_of(fe, struct smsdvb_client_t, frontend);
|
||||
|
||||
sms_debug("");
|
||||
|
||||
/* todo: */
|
||||
memcpy(fep, &client->fe_params,
|
||||
sizeof(struct dvb_frontend_parameters));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void smsdvb_release(struct dvb_frontend *fe)
|
||||
{
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
static struct dvb_frontend_ops smsdvb_fe_ops = {
|
||||
.info = {
|
||||
.name = "Siano Mobile Digital SMS1xxx",
|
||||
.type = FE_OFDM,
|
||||
.frequency_min = 44250000,
|
||||
.frequency_max = 867250000,
|
||||
.frequency_stepsize = 250000,
|
||||
.caps = FE_CAN_INVERSION_AUTO |
|
||||
FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
|
||||
FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
|
||||
FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
|
||||
FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO |
|
||||
FE_CAN_GUARD_INTERVAL_AUTO |
|
||||
FE_CAN_RECOVER |
|
||||
FE_CAN_HIERARCHY_AUTO,
|
||||
},
|
||||
|
||||
.release = smsdvb_release,
|
||||
|
||||
.set_frontend = smsdvb_set_frontend,
|
||||
.get_frontend = smsdvb_get_frontend,
|
||||
.get_tune_settings = smsdvb_get_tune_settings,
|
||||
|
||||
.read_status = smsdvb_read_status,
|
||||
.read_ber = smsdvb_read_ber,
|
||||
.read_signal_strength = smsdvb_read_signal_strength,
|
||||
.read_snr = smsdvb_read_snr,
|
||||
};
|
||||
|
||||
static int smsdvb_hotplug(struct smscore_device_t *coredev,
|
||||
struct device *device, int arrival)
|
||||
{
|
||||
struct smsclient_params_t params;
|
||||
struct smsdvb_client_t *client;
|
||||
int rc;
|
||||
|
||||
/* device removal handled by onremove callback */
|
||||
if (!arrival)
|
||||
return 0;
|
||||
|
||||
if (smscore_get_device_mode(coredev) != 4) {
|
||||
sms_err("SMS Device mode is not set for "
|
||||
"DVB operation.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
client = kzalloc(sizeof(struct smsdvb_client_t), GFP_KERNEL);
|
||||
if (!client) {
|
||||
sms_err("kmalloc() failed");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* register dvb adapter */
|
||||
rc = dvb_register_adapter(&client->adapter,
|
||||
sms_get_board(
|
||||
smscore_get_board_id(coredev))->name,
|
||||
THIS_MODULE, device, adapter_nr);
|
||||
if (rc < 0) {
|
||||
sms_err("dvb_register_adapter() failed %d", rc);
|
||||
goto adapter_error;
|
||||
}
|
||||
|
||||
/* init dvb demux */
|
||||
client->demux.dmx.capabilities = DMX_TS_FILTERING;
|
||||
client->demux.filternum = 32; /* todo: nova ??? */
|
||||
client->demux.feednum = 32;
|
||||
client->demux.start_feed = smsdvb_start_feed;
|
||||
client->demux.stop_feed = smsdvb_stop_feed;
|
||||
|
||||
rc = dvb_dmx_init(&client->demux);
|
||||
if (rc < 0) {
|
||||
sms_err("dvb_dmx_init failed %d", rc);
|
||||
goto dvbdmx_error;
|
||||
}
|
||||
|
||||
/* init dmxdev */
|
||||
client->dmxdev.filternum = 32;
|
||||
client->dmxdev.demux = &client->demux.dmx;
|
||||
client->dmxdev.capabilities = 0;
|
||||
|
||||
rc = dvb_dmxdev_init(&client->dmxdev, &client->adapter);
|
||||
if (rc < 0) {
|
||||
sms_err("dvb_dmxdev_init failed %d", rc);
|
||||
goto dmxdev_error;
|
||||
}
|
||||
|
||||
/* init and register frontend */
|
||||
memcpy(&client->frontend.ops, &smsdvb_fe_ops,
|
||||
sizeof(struct dvb_frontend_ops));
|
||||
|
||||
rc = dvb_register_frontend(&client->adapter, &client->frontend);
|
||||
if (rc < 0) {
|
||||
sms_err("frontend registration failed %d", rc);
|
||||
goto frontend_error;
|
||||
}
|
||||
|
||||
params.initial_id = 1;
|
||||
params.data_type = MSG_SMS_DVBT_BDA_DATA;
|
||||
params.onresponse_handler = smsdvb_onresponse;
|
||||
params.onremove_handler = smsdvb_onremove;
|
||||
params.context = client;
|
||||
|
||||
rc = smscore_register_client(coredev, ¶ms, &client->smsclient);
|
||||
if (rc < 0) {
|
||||
sms_err("smscore_register_client() failed %d", rc);
|
||||
goto client_error;
|
||||
}
|
||||
|
||||
client->coredev = coredev;
|
||||
|
||||
init_completion(&client->tune_done);
|
||||
init_completion(&client->stat_done);
|
||||
|
||||
kmutex_lock(&g_smsdvb_clientslock);
|
||||
|
||||
list_add(&client->entry, &g_smsdvb_clients);
|
||||
|
||||
kmutex_unlock(&g_smsdvb_clientslock);
|
||||
|
||||
sms_info("success");
|
||||
|
||||
return 0;
|
||||
|
||||
client_error:
|
||||
dvb_unregister_frontend(&client->frontend);
|
||||
|
||||
frontend_error:
|
||||
dvb_dmxdev_release(&client->dmxdev);
|
||||
|
||||
dmxdev_error:
|
||||
dvb_dmx_release(&client->demux);
|
||||
|
||||
dvbdmx_error:
|
||||
dvb_unregister_adapter(&client->adapter);
|
||||
|
||||
adapter_error:
|
||||
kfree(client);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int smsdvb_register(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
INIT_LIST_HEAD(&g_smsdvb_clients);
|
||||
kmutex_init(&g_smsdvb_clientslock);
|
||||
|
||||
rc = smscore_register_hotplug(smsdvb_hotplug);
|
||||
|
||||
sms_debug("");
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void smsdvb_unregister(void)
|
||||
{
|
||||
smscore_unregister_hotplug(smsdvb_hotplug);
|
||||
|
||||
kmutex_lock(&g_smsdvb_clientslock);
|
||||
|
||||
while (!list_empty(&g_smsdvb_clients))
|
||||
smsdvb_unregister_client(
|
||||
(struct smsdvb_client_t *) g_smsdvb_clients.next);
|
||||
|
||||
kmutex_unlock(&g_smsdvb_clientslock);
|
||||
}
|
459
drivers/media/dvb/siano/smsusb.c
Normal file
459
drivers/media/dvb/siano/smsusb.c
Normal file
@ -0,0 +1,459 @@
|
||||
/*
|
||||
* Driver for the Siano SMS1xxx USB dongle
|
||||
*
|
||||
* author: Anatoly Greenblat
|
||||
*
|
||||
* Copyright (c), 2005-2008 Siano Mobile Silicon, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 3 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/firmware.h>
|
||||
|
||||
#include "smscoreapi.h"
|
||||
#include "sms-cards.h"
|
||||
|
||||
#define USB1_BUFFER_SIZE 0x1000
|
||||
#define USB2_BUFFER_SIZE 0x4000
|
||||
|
||||
#define MAX_BUFFERS 50
|
||||
#define MAX_URBS 10
|
||||
|
||||
struct smsusb_device_t;
|
||||
|
||||
struct smsusb_urb_t {
|
||||
struct smscore_buffer_t *cb;
|
||||
struct smsusb_device_t *dev;
|
||||
|
||||
struct urb urb;
|
||||
};
|
||||
|
||||
struct smsusb_device_t {
|
||||
struct usb_device *udev;
|
||||
struct smscore_device_t *coredev;
|
||||
|
||||
struct smsusb_urb_t surbs[MAX_URBS];
|
||||
|
||||
int response_alignment;
|
||||
int buffer_size;
|
||||
};
|
||||
|
||||
static int smsusb_submit_urb(struct smsusb_device_t *dev,
|
||||
struct smsusb_urb_t *surb);
|
||||
|
||||
static void smsusb_onresponse(struct urb *urb)
|
||||
{
|
||||
struct smsusb_urb_t *surb = (struct smsusb_urb_t *) urb->context;
|
||||
struct smsusb_device_t *dev = surb->dev;
|
||||
|
||||
if (urb->status < 0) {
|
||||
sms_err("error, urb status %d, %d bytes",
|
||||
urb->status, urb->actual_length);
|
||||
return;
|
||||
}
|
||||
|
||||
if (urb->actual_length > 0) {
|
||||
struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) surb->cb->p;
|
||||
|
||||
if (urb->actual_length >= phdr->msgLength) {
|
||||
surb->cb->size = phdr->msgLength;
|
||||
|
||||
if (dev->response_alignment &&
|
||||
(phdr->msgFlags & MSG_HDR_FLAG_SPLIT_MSG)) {
|
||||
|
||||
surb->cb->offset =
|
||||
dev->response_alignment +
|
||||
((phdr->msgFlags >> 8) & 3);
|
||||
|
||||
/* sanity check */
|
||||
if (((int) phdr->msgLength +
|
||||
surb->cb->offset) > urb->actual_length) {
|
||||
sms_err("invalid response "
|
||||
"msglen %d offset %d "
|
||||
"size %d",
|
||||
phdr->msgLength,
|
||||
surb->cb->offset,
|
||||
urb->actual_length);
|
||||
goto exit_and_resubmit;
|
||||
}
|
||||
|
||||
/* move buffer pointer and
|
||||
* copy header to its new location */
|
||||
memcpy((char *) phdr + surb->cb->offset,
|
||||
phdr, sizeof(struct SmsMsgHdr_ST));
|
||||
} else
|
||||
surb->cb->offset = 0;
|
||||
|
||||
smscore_onresponse(dev->coredev, surb->cb);
|
||||
surb->cb = NULL;
|
||||
} else {
|
||||
sms_err("invalid response "
|
||||
"msglen %d actual %d",
|
||||
phdr->msgLength, urb->actual_length);
|
||||
}
|
||||
}
|
||||
|
||||
exit_and_resubmit:
|
||||
smsusb_submit_urb(dev, surb);
|
||||
}
|
||||
|
||||
static int smsusb_submit_urb(struct smsusb_device_t *dev,
|
||||
struct smsusb_urb_t *surb)
|
||||
{
|
||||
if (!surb->cb) {
|
||||
surb->cb = smscore_getbuffer(dev->coredev);
|
||||
if (!surb->cb) {
|
||||
sms_err("smscore_getbuffer(...) returned NULL");
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
usb_fill_bulk_urb(
|
||||
&surb->urb,
|
||||
dev->udev,
|
||||
usb_rcvbulkpipe(dev->udev, 0x81),
|
||||
surb->cb->p,
|
||||
dev->buffer_size,
|
||||
smsusb_onresponse,
|
||||
surb
|
||||
);
|
||||
surb->urb.transfer_dma = surb->cb->phys;
|
||||
surb->urb.transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
||||
|
||||
return usb_submit_urb(&surb->urb, GFP_ATOMIC);
|
||||
}
|
||||
|
||||
static void smsusb_stop_streaming(struct smsusb_device_t *dev)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_URBS; i++) {
|
||||
usb_kill_urb(&dev->surbs[i].urb);
|
||||
|
||||
if (dev->surbs[i].cb) {
|
||||
smscore_putbuffer(dev->coredev, dev->surbs[i].cb);
|
||||
dev->surbs[i].cb = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int smsusb_start_streaming(struct smsusb_device_t *dev)
|
||||
{
|
||||
int i, rc;
|
||||
|
||||
for (i = 0; i < MAX_URBS; i++) {
|
||||
rc = smsusb_submit_urb(dev, &dev->surbs[i]);
|
||||
if (rc < 0) {
|
||||
sms_err("smsusb_submit_urb(...) failed");
|
||||
smsusb_stop_streaming(dev);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int smsusb_sendrequest(void *context, void *buffer, size_t size)
|
||||
{
|
||||
struct smsusb_device_t *dev = (struct smsusb_device_t *) context;
|
||||
int dummy;
|
||||
|
||||
return usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 2),
|
||||
buffer, size, &dummy, 1000);
|
||||
}
|
||||
|
||||
static char *smsusb1_fw_lkup[] = {
|
||||
"dvbt_stellar_usb.inp",
|
||||
"dvbh_stellar_usb.inp",
|
||||
"tdmb_stellar_usb.inp",
|
||||
"none",
|
||||
"dvbt_bda_stellar_usb.inp",
|
||||
};
|
||||
|
||||
static inline char *sms_get_fw_name(int mode, int board_id)
|
||||
{
|
||||
char **fw = sms_get_board(board_id)->fw;
|
||||
return (fw && fw[mode]) ? fw[mode] : smsusb1_fw_lkup[mode];
|
||||
}
|
||||
|
||||
static int smsusb1_load_firmware(struct usb_device *udev, int id, int board_id)
|
||||
{
|
||||
const struct firmware *fw;
|
||||
u8 *fw_buffer;
|
||||
int rc, dummy;
|
||||
char *fw_filename;
|
||||
|
||||
if (id < DEVICE_MODE_DVBT || id > DEVICE_MODE_DVBT_BDA) {
|
||||
sms_err("invalid firmware id specified %d", id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
fw_filename = sms_get_fw_name(id, board_id);
|
||||
|
||||
rc = request_firmware(&fw, fw_filename, &udev->dev);
|
||||
if (rc < 0) {
|
||||
sms_warn("failed to open \"%s\" mode %d, "
|
||||
"trying again with default firmware", fw_filename, id);
|
||||
|
||||
fw_filename = smsusb1_fw_lkup[id];
|
||||
rc = request_firmware(&fw, fw_filename, &udev->dev);
|
||||
if (rc < 0) {
|
||||
sms_warn("failed to open \"%s\" mode %d",
|
||||
fw_filename, id);
|
||||
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
fw_buffer = kmalloc(fw->size, GFP_KERNEL);
|
||||
if (fw_buffer) {
|
||||
memcpy(fw_buffer, fw->data, fw->size);
|
||||
|
||||
rc = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 2),
|
||||
fw_buffer, fw->size, &dummy, 1000);
|
||||
|
||||
sms_info("sent %zd(%d) bytes, rc %d", fw->size, dummy, rc);
|
||||
|
||||
kfree(fw_buffer);
|
||||
} else {
|
||||
sms_err("failed to allocate firmware buffer");
|
||||
rc = -ENOMEM;
|
||||
}
|
||||
sms_info("read FW %s, size=%zd", fw_filename, fw->size);
|
||||
|
||||
release_firmware(fw);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void smsusb1_detectmode(void *context, int *mode)
|
||||
{
|
||||
char *product_string =
|
||||
((struct smsusb_device_t *) context)->udev->product;
|
||||
|
||||
*mode = DEVICE_MODE_NONE;
|
||||
|
||||
if (!product_string) {
|
||||
product_string = "none";
|
||||
sms_err("product string not found");
|
||||
} else if (strstr(product_string, "DVBH"))
|
||||
*mode = 1;
|
||||
else if (strstr(product_string, "BDA"))
|
||||
*mode = 4;
|
||||
else if (strstr(product_string, "DVBT"))
|
||||
*mode = 0;
|
||||
else if (strstr(product_string, "TDMB"))
|
||||
*mode = 2;
|
||||
|
||||
sms_info("%d \"%s\"", *mode, product_string);
|
||||
}
|
||||
|
||||
static int smsusb1_setmode(void *context, int mode)
|
||||
{
|
||||
struct SmsMsgHdr_ST Msg = { MSG_SW_RELOAD_REQ, 0, HIF_TASK,
|
||||
sizeof(struct SmsMsgHdr_ST), 0 };
|
||||
|
||||
if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA) {
|
||||
sms_err("invalid firmware id specified %d", mode);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return smsusb_sendrequest(context, &Msg, sizeof(Msg));
|
||||
}
|
||||
|
||||
static void smsusb_term_device(struct usb_interface *intf)
|
||||
{
|
||||
struct smsusb_device_t *dev =
|
||||
(struct smsusb_device_t *) usb_get_intfdata(intf);
|
||||
|
||||
if (dev) {
|
||||
smsusb_stop_streaming(dev);
|
||||
|
||||
/* unregister from smscore */
|
||||
if (dev->coredev)
|
||||
smscore_unregister_device(dev->coredev);
|
||||
|
||||
kfree(dev);
|
||||
|
||||
sms_info("device %p destroyed", dev);
|
||||
}
|
||||
|
||||
usb_set_intfdata(intf, NULL);
|
||||
}
|
||||
|
||||
static int smsusb_init_device(struct usb_interface *intf, int board_id)
|
||||
{
|
||||
struct smsdevice_params_t params;
|
||||
struct smsusb_device_t *dev;
|
||||
int i, rc;
|
||||
|
||||
/* create device object */
|
||||
dev = kzalloc(sizeof(struct smsusb_device_t), GFP_KERNEL);
|
||||
if (!dev) {
|
||||
sms_err("kzalloc(sizeof(struct smsusb_device_t) failed");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
usb_set_intfdata(intf, dev);
|
||||
dev->udev = interface_to_usbdev(intf);
|
||||
|
||||
params.device_type = sms_get_board(board_id)->type;
|
||||
|
||||
switch (params.device_type) {
|
||||
case SMS_STELLAR:
|
||||
dev->buffer_size = USB1_BUFFER_SIZE;
|
||||
|
||||
params.setmode_handler = smsusb1_setmode;
|
||||
params.detectmode_handler = smsusb1_detectmode;
|
||||
break;
|
||||
default:
|
||||
sms_err("Unspecified sms device type!");
|
||||
/* fall-thru */
|
||||
case SMS_NOVA_A0:
|
||||
case SMS_NOVA_B0:
|
||||
case SMS_VEGA:
|
||||
dev->buffer_size = USB2_BUFFER_SIZE;
|
||||
dev->response_alignment =
|
||||
dev->udev->ep_in[1]->desc.wMaxPacketSize -
|
||||
sizeof(struct SmsMsgHdr_ST);
|
||||
|
||||
params.flags |= SMS_DEVICE_FAMILY2;
|
||||
break;
|
||||
}
|
||||
|
||||
params.device = &dev->udev->dev;
|
||||
params.buffer_size = dev->buffer_size;
|
||||
params.num_buffers = MAX_BUFFERS;
|
||||
params.sendrequest_handler = smsusb_sendrequest;
|
||||
params.context = dev;
|
||||
snprintf(params.devpath, sizeof(params.devpath),
|
||||
"usb\\%d-%s", dev->udev->bus->busnum, dev->udev->devpath);
|
||||
|
||||
/* register in smscore */
|
||||
rc = smscore_register_device(¶ms, &dev->coredev);
|
||||
if (rc < 0) {
|
||||
sms_err("smscore_register_device(...) failed, rc %d", rc);
|
||||
smsusb_term_device(intf);
|
||||
return rc;
|
||||
}
|
||||
|
||||
smscore_set_board_id(dev->coredev, board_id);
|
||||
|
||||
/* initialize urbs */
|
||||
for (i = 0; i < MAX_URBS; i++) {
|
||||
dev->surbs[i].dev = dev;
|
||||
usb_init_urb(&dev->surbs[i].urb);
|
||||
}
|
||||
|
||||
sms_info("smsusb_start_streaming(...).");
|
||||
rc = smsusb_start_streaming(dev);
|
||||
if (rc < 0) {
|
||||
sms_err("smsusb_start_streaming(...) failed");
|
||||
smsusb_term_device(intf);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = smscore_start_device(dev->coredev);
|
||||
if (rc < 0) {
|
||||
sms_err("smscore_start_device(...) failed");
|
||||
smsusb_term_device(intf);
|
||||
return rc;
|
||||
}
|
||||
|
||||
sms_info("device %p created", dev);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int smsusb_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
struct usb_device *udev = interface_to_usbdev(intf);
|
||||
char devpath[32];
|
||||
int i, rc;
|
||||
|
||||
rc = usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x81));
|
||||
rc = usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x02));
|
||||
|
||||
if (intf->num_altsetting > 0) {
|
||||
rc = usb_set_interface(
|
||||
udev, intf->cur_altsetting->desc.bInterfaceNumber, 0);
|
||||
if (rc < 0) {
|
||||
sms_err("usb_set_interface failed, rc %d", rc);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
sms_info("smsusb_probe %d",
|
||||
intf->cur_altsetting->desc.bInterfaceNumber);
|
||||
for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++)
|
||||
sms_info("endpoint %d %02x %02x %d", i,
|
||||
intf->cur_altsetting->endpoint[i].desc.bEndpointAddress,
|
||||
intf->cur_altsetting->endpoint[i].desc.bmAttributes,
|
||||
intf->cur_altsetting->endpoint[i].desc.wMaxPacketSize);
|
||||
|
||||
if ((udev->actconfig->desc.bNumInterfaces == 2) &&
|
||||
(intf->cur_altsetting->desc.bInterfaceNumber == 0)) {
|
||||
sms_err("rom interface 0 is not used");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (intf->cur_altsetting->desc.bInterfaceNumber == 1) {
|
||||
snprintf(devpath, sizeof(devpath), "usb\\%d-%s",
|
||||
udev->bus->busnum, udev->devpath);
|
||||
sms_info("stellar device was found.");
|
||||
return smsusb1_load_firmware(
|
||||
udev, smscore_registry_getmode(devpath),
|
||||
id->driver_info);
|
||||
}
|
||||
|
||||
rc = smsusb_init_device(intf, id->driver_info);
|
||||
sms_info("rc %d", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void smsusb_disconnect(struct usb_interface *intf)
|
||||
{
|
||||
smsusb_term_device(intf);
|
||||
}
|
||||
|
||||
static struct usb_driver smsusb_driver = {
|
||||
.name = "sms1xxx",
|
||||
.probe = smsusb_probe,
|
||||
.disconnect = smsusb_disconnect,
|
||||
.id_table = smsusb_id_table,
|
||||
};
|
||||
|
||||
int smsusb_register(void)
|
||||
{
|
||||
int rc = usb_register(&smsusb_driver);
|
||||
if (rc)
|
||||
sms_err("usb_register failed. Error number %d", rc);
|
||||
|
||||
sms_debug("");
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void smsusb_unregister(void)
|
||||
{
|
||||
sms_debug("");
|
||||
/* Regular USB Cleanup */
|
||||
usb_deregister(&smsusb_driver);
|
||||
}
|
||||
|
@ -106,6 +106,8 @@ config DVB_BUDGET_CI
|
||||
select DVB_STV0299 if !DVB_FE_CUSTOMISE
|
||||
select DVB_TDA1004X if !DVB_FE_CUSTOMISE
|
||||
select DVB_LNBP21 if !DVB_FE_CUSTOMISE
|
||||
select DVB_TDA10023 if !DVB_FE_CUSTOMISE
|
||||
select MEDIA_TUNER_TDA827X if !DVB_FE_CUSTOMISE
|
||||
select VIDEO_IR
|
||||
help
|
||||
Support for simple SAA7146 based DVB cards
|
||||
|
@ -3,7 +3,11 @@
|
||||
# and the AV7110 DVB device driver
|
||||
#
|
||||
|
||||
dvb-ttpci-objs := av7110_hw.o av7110_v4l.o av7110_av.o av7110_ca.o av7110.o av7110_ipack.o av7110_ir.o
|
||||
dvb-ttpci-objs := av7110_hw.o av7110_v4l.o av7110_av.o av7110_ca.o av7110.o av7110_ipack.o
|
||||
|
||||
ifdef CONFIG_INPUT_EVDEV
|
||||
dvb-ttpci-objs += av7110_ir.o
|
||||
endif
|
||||
|
||||
obj-$(CONFIG_TTPCI_EEPROM) += ttpci-eeprom.o
|
||||
obj-$(CONFIG_DVB_BUDGET_CORE) += budget-core.o
|
||||
@ -14,6 +18,7 @@ obj-$(CONFIG_DVB_BUDGET_PATCH) += budget-patch.o
|
||||
obj-$(CONFIG_DVB_AV7110) += dvb-ttpci.o
|
||||
|
||||
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
|
||||
EXTRA_CFLAGS += -Idrivers/media/common/tuners
|
||||
|
||||
hostprogs-y := fdump
|
||||
|
||||
|
@ -587,7 +587,7 @@ static void gpioirq(unsigned long data)
|
||||
}
|
||||
DVB_RINGBUFFER_SKIP(cibuf, 2);
|
||||
|
||||
dvb_ringbuffer_read(cibuf, av7110->debi_virt, len, 0);
|
||||
dvb_ringbuffer_read(cibuf, av7110->debi_virt, len);
|
||||
|
||||
iwdebi(av7110, DEBINOSWAP, TX_LEN, len, 2);
|
||||
iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, len, 2);
|
||||
@ -1198,7 +1198,6 @@ static int start_ts_capture(struct av7110 *budget)
|
||||
if (budget->feeding1)
|
||||
return ++budget->feeding1;
|
||||
memset(budget->grabbing, 0x00, TS_HEIGHT * TS_WIDTH);
|
||||
budget->tsf = 0xff;
|
||||
budget->ttbp = 0;
|
||||
SAA7146_IER_ENABLE(budget->dev, MASK_10); /* VPE */
|
||||
saa7146_write(budget->dev, MC1, (MASK_04 | MASK_20)); /* DMA3 on */
|
||||
@ -2403,18 +2402,18 @@ static int __devinit av7110_attach(struct saa7146_dev* dev,
|
||||
saa7146_write(dev, MC1, MASK_29);
|
||||
/* RPS1 timeout disable */
|
||||
saa7146_write(dev, RPS_TOV1, 0);
|
||||
WRITE_RPS1(cpu_to_le32(CMD_PAUSE | EVT_VBI_B));
|
||||
WRITE_RPS1(cpu_to_le32(CMD_WR_REG_MASK | (GPIO_CTRL>>2)));
|
||||
WRITE_RPS1(cpu_to_le32(GPIO3_MSK));
|
||||
WRITE_RPS1(cpu_to_le32(SAA7146_GPIO_OUTLO<<24));
|
||||
WRITE_RPS1(CMD_PAUSE | EVT_VBI_B);
|
||||
WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2));
|
||||
WRITE_RPS1(GPIO3_MSK);
|
||||
WRITE_RPS1(SAA7146_GPIO_OUTLO<<24);
|
||||
#if RPS_IRQ
|
||||
/* issue RPS1 interrupt to increment counter */
|
||||
WRITE_RPS1(cpu_to_le32(CMD_INTERRUPT));
|
||||
WRITE_RPS1(CMD_INTERRUPT);
|
||||
#endif
|
||||
WRITE_RPS1(cpu_to_le32(CMD_STOP));
|
||||
WRITE_RPS1(CMD_STOP);
|
||||
/* Jump to begin of RPS program as safety measure (p37) */
|
||||
WRITE_RPS1(cpu_to_le32(CMD_JUMP));
|
||||
WRITE_RPS1(cpu_to_le32(dev->d_rps1.dma_handle));
|
||||
WRITE_RPS1(CMD_JUMP);
|
||||
WRITE_RPS1(dev->d_rps1.dma_handle);
|
||||
|
||||
#if RPS_IRQ
|
||||
/* set event counter 1 source as RPS1 interrupt (0x03) (rE4 p53)
|
||||
@ -2472,11 +2471,7 @@ static int __devinit av7110_attach(struct saa7146_dev* dev,
|
||||
get recognized before the main driver is fully loaded */
|
||||
saa7146_write(dev, GPIO_CTRL, 0x500000);
|
||||
|
||||
#ifdef I2C_ADAP_CLASS_TV_DIGITAL
|
||||
av7110->i2c_adap.class = I2C_ADAP_CLASS_TV_DIGITAL;
|
||||
#else
|
||||
av7110->i2c_adap.class = I2C_CLASS_TV_DIGITAL;
|
||||
#endif
|
||||
strlcpy(av7110->i2c_adap.name, pci_ext->ext_priv, sizeof(av7110->i2c_adap.name));
|
||||
|
||||
saa7146_i2c_adapter_prepare(dev, &av7110->i2c_adap, SAA7146_I2C_BUS_BIT_RATE_120); /* 275 kHz */
|
||||
@ -2527,28 +2522,28 @@ static int __devinit av7110_attach(struct saa7146_dev* dev,
|
||||
count = 0;
|
||||
|
||||
/* Wait Source Line Counter Threshold (p36) */
|
||||
WRITE_RPS1(cpu_to_le32(CMD_PAUSE | EVT_HS));
|
||||
WRITE_RPS1(CMD_PAUSE | EVT_HS);
|
||||
/* Set GPIO3=1 (p42) */
|
||||
WRITE_RPS1(cpu_to_le32(CMD_WR_REG_MASK | (GPIO_CTRL>>2)));
|
||||
WRITE_RPS1(cpu_to_le32(GPIO3_MSK));
|
||||
WRITE_RPS1(cpu_to_le32(SAA7146_GPIO_OUTHI<<24));
|
||||
WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2));
|
||||
WRITE_RPS1(GPIO3_MSK);
|
||||
WRITE_RPS1(SAA7146_GPIO_OUTHI<<24);
|
||||
#if RPS_IRQ
|
||||
/* issue RPS1 interrupt */
|
||||
WRITE_RPS1(cpu_to_le32(CMD_INTERRUPT));
|
||||
WRITE_RPS1(CMD_INTERRUPT);
|
||||
#endif
|
||||
/* Wait reset Source Line Counter Threshold (p36) */
|
||||
WRITE_RPS1(cpu_to_le32(CMD_PAUSE | RPS_INV | EVT_HS));
|
||||
WRITE_RPS1(CMD_PAUSE | RPS_INV | EVT_HS);
|
||||
/* Set GPIO3=0 (p42) */
|
||||
WRITE_RPS1(cpu_to_le32(CMD_WR_REG_MASK | (GPIO_CTRL>>2)));
|
||||
WRITE_RPS1(cpu_to_le32(GPIO3_MSK));
|
||||
WRITE_RPS1(cpu_to_le32(SAA7146_GPIO_OUTLO<<24));
|
||||
WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2));
|
||||
WRITE_RPS1(GPIO3_MSK);
|
||||
WRITE_RPS1(SAA7146_GPIO_OUTLO<<24);
|
||||
#if RPS_IRQ
|
||||
/* issue RPS1 interrupt */
|
||||
WRITE_RPS1(cpu_to_le32(CMD_INTERRUPT));
|
||||
WRITE_RPS1(CMD_INTERRUPT);
|
||||
#endif
|
||||
/* Jump to begin of RPS program (p37) */
|
||||
WRITE_RPS1(cpu_to_le32(CMD_JUMP));
|
||||
WRITE_RPS1(cpu_to_le32(dev->d_rps1.dma_handle));
|
||||
WRITE_RPS1(CMD_JUMP);
|
||||
WRITE_RPS1(dev->d_rps1.dma_handle);
|
||||
|
||||
/* Fix VSYNC level */
|
||||
saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
|
||||
|
@ -188,7 +188,6 @@ struct av7110 {
|
||||
struct dvb_net dvb_net1;
|
||||
spinlock_t feedlock1;
|
||||
int feeding1;
|
||||
u8 tsf;
|
||||
u32 ttbp;
|
||||
unsigned char *grabbing;
|
||||
struct saa7146_pgtable pt;
|
||||
|
@ -269,7 +269,7 @@ int av7110_pes_play(void *dest, struct dvb_ringbuffer *buf, int dlen)
|
||||
return -1;
|
||||
}
|
||||
|
||||
dvb_ringbuffer_read(buf, dest, (size_t) blen, 0);
|
||||
dvb_ringbuffer_read(buf, dest, (size_t) blen);
|
||||
|
||||
dprintk(2, "pread=0x%08lx, pwrite=0x%08lx\n",
|
||||
(unsigned long) buf->pread, (unsigned long) buf->pwrite);
|
||||
|
@ -208,7 +208,7 @@ static ssize_t ci_ll_read(struct dvb_ringbuffer *cibuf, struct file *file,
|
||||
return -EINVAL;
|
||||
DVB_RINGBUFFER_SKIP(cibuf, 2);
|
||||
|
||||
return dvb_ringbuffer_read(cibuf, (u8 *)buf, len, 1);
|
||||
return dvb_ringbuffer_read_user(cibuf, buf, len);
|
||||
}
|
||||
|
||||
static int dvb_ca_open(struct inode *inode, struct file *file)
|
||||
|
@ -305,7 +305,6 @@ enum av7110_command_type {
|
||||
#define IRQ_STATE (DPRAM_BASE + 0x0F4)
|
||||
#define IRQ_STATE_EXT (DPRAM_BASE + 0x0F6)
|
||||
#define MSGSTATE (DPRAM_BASE + 0x0F8)
|
||||
#define FILT_STATE (DPRAM_BASE + 0x0FA)
|
||||
#define COMMAND (DPRAM_BASE + 0x0FC)
|
||||
#define COM_BUFF (DPRAM_BASE + 0x100)
|
||||
#define COM_BUFF_SIZE 0x20
|
||||
@ -332,8 +331,6 @@ enum av7110_command_type {
|
||||
|
||||
/* firmware status area */
|
||||
#define STATUS_BASE (DPRAM_BASE + 0x1FC0)
|
||||
#define STATUS_SCR (STATUS_BASE + 0x00)
|
||||
#define STATUS_MODES (STATUS_BASE + 0x04)
|
||||
#define STATUS_LOOPS (STATUS_BASE + 0x08)
|
||||
|
||||
#define STATUS_MPEG_WIDTH (STATUS_BASE + 0x0C)
|
||||
|
@ -667,6 +667,11 @@ static struct tda1002x_config philips_cu1216_config_altaddress = {
|
||||
.invert = 0,
|
||||
};
|
||||
|
||||
static struct tda10023_config philips_cu1216_tda10023_config = {
|
||||
.demod_address = 0x0c,
|
||||
.invert = 1,
|
||||
};
|
||||
|
||||
static int philips_tu1216_tuner_init(struct dvb_frontend *fe)
|
||||
{
|
||||
struct budget *budget = (struct budget *) fe->dvb->priv;
|
||||
@ -1019,9 +1024,10 @@ static void frontend_init(struct budget_av *budget_av)
|
||||
case SUBID_DVBC_KNC1_PLUS_MK3:
|
||||
budget_av->reinitialise_demod = 1;
|
||||
budget_av->budget.dev->i2c_bitrate = SAA7146_I2C_BUS_BIT_RATE_240;
|
||||
fe = dvb_attach(tda10023_attach, &philips_cu1216_config,
|
||||
&budget_av->budget.i2c_adap,
|
||||
read_pwm(budget_av));
|
||||
fe = dvb_attach(tda10023_attach,
|
||||
&philips_cu1216_tda10023_config,
|
||||
&budget_av->budget.i2c_adap,
|
||||
read_pwm(budget_av));
|
||||
if (fe) {
|
||||
fe->ops.tuner_ops.set_params = philips_cu1216_tuner_set_params;
|
||||
}
|
||||
|
@ -46,6 +46,8 @@
|
||||
#include "lnbp21.h"
|
||||
#include "bsbe1.h"
|
||||
#include "bsru6.h"
|
||||
#include "tda1002x.h"
|
||||
#include "tda827x.h"
|
||||
|
||||
/*
|
||||
* Regarding DEBIADDR_IR:
|
||||
@ -225,6 +227,7 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
|
||||
break;
|
||||
case 0x1010:
|
||||
case 0x1017:
|
||||
case 0x101a:
|
||||
/* for the Technotrend 1500 bundled remote */
|
||||
ir_input_init(input_dev, &budget_ci->ir.state,
|
||||
IR_TYPE_RC5, ir_codes_tt_1500);
|
||||
@ -1056,6 +1059,15 @@ static struct stv0297_config dvbc_philips_tdm1316l_config = {
|
||||
.stop_during_read = 1,
|
||||
};
|
||||
|
||||
static struct tda10023_config tda10023_config = {
|
||||
.demod_address = 0xc,
|
||||
.invert = 0,
|
||||
.xtal = 16000000,
|
||||
.pll_m = 11,
|
||||
.pll_p = 3,
|
||||
.pll_n = 1,
|
||||
.deltaf = 0xa511,
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -1126,7 +1138,17 @@ static void frontend_init(struct budget_ci *budget_ci)
|
||||
budget_ci->budget.dvb_frontend = NULL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x101a: /* TT Budget-C-1501 (philips tda10023/philips tda8274A) */
|
||||
budget_ci->budget.dvb_frontend = dvb_attach(tda10023_attach, &tda10023_config, &budget_ci->budget.i2c_adap, 0x48);
|
||||
if (budget_ci->budget.dvb_frontend) {
|
||||
if (dvb_attach(tda827x_attach, budget_ci->budget.dvb_frontend, 0x61, &budget_ci->budget.i2c_adap, NULL) == NULL) {
|
||||
printk(KERN_ERR "%s: No tda827x found!\n", __func__);
|
||||
dvb_frontend_detach(budget_ci->budget.dvb_frontend);
|
||||
budget_ci->budget.dvb_frontend = NULL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1216,6 +1238,7 @@ MAKE_BUDGET_INFO(ttbci, "TT-Budget/WinTV-NOVA-CI PCI", BUDGET_TT_HW_DISEQC);
|
||||
MAKE_BUDGET_INFO(ttbt2, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT);
|
||||
MAKE_BUDGET_INFO(ttbtci, "TT-Budget-T-CI PCI", BUDGET_TT);
|
||||
MAKE_BUDGET_INFO(ttbcci, "TT-Budget-C-CI PCI", BUDGET_TT);
|
||||
MAKE_BUDGET_INFO(ttc1501, "TT-Budget C-1501 PCI", BUDGET_TT);
|
||||
|
||||
static struct pci_device_id pci_tbl[] = {
|
||||
MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100c),
|
||||
@ -1224,6 +1247,7 @@ static struct pci_device_id pci_tbl[] = {
|
||||
MAKE_EXTENSION_PCI(ttbt2, 0x13c2, 0x1011),
|
||||
MAKE_EXTENSION_PCI(ttbtci, 0x13c2, 0x1012),
|
||||
MAKE_EXTENSION_PCI(ttbs2, 0x13c2, 0x1017),
|
||||
MAKE_EXTENSION_PCI(ttc1501, 0x13c2, 0x101a),
|
||||
{
|
||||
.vendor = 0,
|
||||
}
|
||||
|
@ -497,11 +497,7 @@ int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev,
|
||||
if (bi->type != BUDGET_FS_ACTIVY)
|
||||
saa7146_write(dev, GPIO_CTRL, 0x500000); /* GPIO 3 = 1 */
|
||||
|
||||
#ifdef I2C_ADAP_CLASS_TV_DIGITAL
|
||||
budget->i2c_adap.class = I2C_ADAP_CLASS_TV_DIGITAL;
|
||||
#else
|
||||
budget->i2c_adap.class = I2C_CLASS_TV_DIGITAL;
|
||||
#endif
|
||||
|
||||
strlcpy(budget->i2c_adap.name, budget->card->name, sizeof(budget->i2c_adap.name));
|
||||
|
||||
|
@ -431,22 +431,22 @@ static int budget_patch_attach (struct saa7146_dev* dev, struct saa7146_pci_exte
|
||||
// in budget patch GPIO3 is connected to VSYNC_B
|
||||
count = 0;
|
||||
#if 0
|
||||
WRITE_RPS1(cpu_to_le32(CMD_UPLOAD |
|
||||
MASK_10 | MASK_09 | MASK_08 | MASK_06 | MASK_05 | MASK_04 | MASK_03 | MASK_02 ));
|
||||
WRITE_RPS1(CMD_UPLOAD |
|
||||
MASK_10 | MASK_09 | MASK_08 | MASK_06 | MASK_05 | MASK_04 | MASK_03 | MASK_02 );
|
||||
#endif
|
||||
WRITE_RPS1(cpu_to_le32(CMD_PAUSE | EVT_VBI_B));
|
||||
WRITE_RPS1(cpu_to_le32(CMD_WR_REG_MASK | (GPIO_CTRL>>2)));
|
||||
WRITE_RPS1(cpu_to_le32(GPIO3_MSK));
|
||||
WRITE_RPS1(cpu_to_le32(SAA7146_GPIO_OUTLO<<24));
|
||||
WRITE_RPS1(CMD_PAUSE | EVT_VBI_B);
|
||||
WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2));
|
||||
WRITE_RPS1(GPIO3_MSK);
|
||||
WRITE_RPS1(SAA7146_GPIO_OUTLO<<24);
|
||||
#if RPS_IRQ
|
||||
// issue RPS1 interrupt to increment counter
|
||||
WRITE_RPS1(cpu_to_le32(CMD_INTERRUPT));
|
||||
WRITE_RPS1(CMD_INTERRUPT);
|
||||
// at least a NOP is neede between two interrupts
|
||||
WRITE_RPS1(cpu_to_le32(CMD_NOP));
|
||||
WRITE_RPS1(CMD_NOP);
|
||||
// interrupt again
|
||||
WRITE_RPS1(cpu_to_le32(CMD_INTERRUPT));
|
||||
WRITE_RPS1(CMD_INTERRUPT);
|
||||
#endif
|
||||
WRITE_RPS1(cpu_to_le32(CMD_STOP));
|
||||
WRITE_RPS1(CMD_STOP);
|
||||
|
||||
#if RPS_IRQ
|
||||
// set event counter 1 source as RPS1 interrupt (0x03) (rE4 p53)
|
||||
@ -558,28 +558,28 @@ static int budget_patch_attach (struct saa7146_dev* dev, struct saa7146_pci_exte
|
||||
|
||||
|
||||
// Wait Source Line Counter Threshold (p36)
|
||||
WRITE_RPS1(cpu_to_le32(CMD_PAUSE | EVT_HS));
|
||||
WRITE_RPS1(CMD_PAUSE | EVT_HS);
|
||||
// Set GPIO3=1 (p42)
|
||||
WRITE_RPS1(cpu_to_le32(CMD_WR_REG_MASK | (GPIO_CTRL>>2)));
|
||||
WRITE_RPS1(cpu_to_le32(GPIO3_MSK));
|
||||
WRITE_RPS1(cpu_to_le32(SAA7146_GPIO_OUTHI<<24));
|
||||
WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2));
|
||||
WRITE_RPS1(GPIO3_MSK);
|
||||
WRITE_RPS1(SAA7146_GPIO_OUTHI<<24);
|
||||
#if RPS_IRQ
|
||||
// issue RPS1 interrupt
|
||||
WRITE_RPS1(cpu_to_le32(CMD_INTERRUPT));
|
||||
WRITE_RPS1(CMD_INTERRUPT);
|
||||
#endif
|
||||
// Wait reset Source Line Counter Threshold (p36)
|
||||
WRITE_RPS1(cpu_to_le32(CMD_PAUSE | RPS_INV | EVT_HS));
|
||||
WRITE_RPS1(CMD_PAUSE | RPS_INV | EVT_HS);
|
||||
// Set GPIO3=0 (p42)
|
||||
WRITE_RPS1(cpu_to_le32(CMD_WR_REG_MASK | (GPIO_CTRL>>2)));
|
||||
WRITE_RPS1(cpu_to_le32(GPIO3_MSK));
|
||||
WRITE_RPS1(cpu_to_le32(SAA7146_GPIO_OUTLO<<24));
|
||||
WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2));
|
||||
WRITE_RPS1(GPIO3_MSK);
|
||||
WRITE_RPS1(SAA7146_GPIO_OUTLO<<24);
|
||||
#if RPS_IRQ
|
||||
// issue RPS1 interrupt
|
||||
WRITE_RPS1(cpu_to_le32(CMD_INTERRUPT));
|
||||
WRITE_RPS1(CMD_INTERRUPT);
|
||||
#endif
|
||||
// Jump to begin of RPS program (p37)
|
||||
WRITE_RPS1(cpu_to_le32(CMD_JUMP));
|
||||
WRITE_RPS1(cpu_to_le32(dev->d_rps1.dma_handle));
|
||||
WRITE_RPS1(CMD_JUMP);
|
||||
WRITE_RPS1(dev->d_rps1.dma_handle);
|
||||
|
||||
// Fix VSYNC level
|
||||
saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/delay.h>
|
||||
@ -990,22 +991,9 @@ static int stc_open(struct inode *inode, struct file *file)
|
||||
}
|
||||
|
||||
static ssize_t stc_read(struct file *file, char *buf, size_t count,
|
||||
loff_t * offset)
|
||||
loff_t *offset)
|
||||
{
|
||||
int tc = count;
|
||||
|
||||
if ((tc + *offset) > 8192)
|
||||
tc = 8192 - *offset;
|
||||
|
||||
if (tc < 0)
|
||||
return 0;
|
||||
|
||||
if (copy_to_user(buf, stc_firmware + *offset, tc))
|
||||
return -EFAULT;
|
||||
|
||||
*offset += tc;
|
||||
|
||||
return tc;
|
||||
return simple_read_from_buffer(buf, count, offset, stc_firmware, 8192);
|
||||
}
|
||||
|
||||
static int stc_release(struct inode *inode, struct file *file)
|
||||
@ -1693,11 +1681,7 @@ static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *i
|
||||
|
||||
i2c_set_adapdata(&ttusb->i2c_adap, ttusb);
|
||||
|
||||
#ifdef I2C_ADAP_CLASS_TV_DIGITAL
|
||||
ttusb->i2c_adap.class = I2C_ADAP_CLASS_TV_DIGITAL;
|
||||
#else
|
||||
ttusb->i2c_adap.class = I2C_CLASS_TV_DIGITAL;
|
||||
#endif
|
||||
ttusb->i2c_adap.algo = &ttusb_dec_algo;
|
||||
ttusb->i2c_adap.algo_data = NULL;
|
||||
ttusb->i2c_adap.dev.parent = &udev->dev;
|
||||
|
@ -23,6 +23,19 @@
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* User Notes:
|
||||
* - USB Audio is provided by the alsa snd_usb_audio module.
|
||||
* For listing you have to redirect the sound, for example using:
|
||||
* arecord -D hw:1,0 -r96000 -c2 -f S16_LE | artsdsp aplay -B -
|
||||
* - regarding module parameters in /sys/module/radio_si470x/parameters:
|
||||
* the contents of read-only files (0444) are not updated, even if
|
||||
* space, band and de are changed using private video controls
|
||||
* - increase tune_timeout, if you often get -EIO errors
|
||||
* - hw_freq_seek returns -EAGAIN, when timed out or band limit is reached
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* History:
|
||||
* 2008-01-12 Tobias Lorenz <tobias.lorenz@gmx.net>
|
||||
@ -85,10 +98,14 @@
|
||||
* Oliver Neukum <oliver@neukum.org>
|
||||
* Version 1.0.7
|
||||
* - usb autosuspend support
|
||||
* - unplugging fixed
|
||||
* - unplugging fixed
|
||||
* 2008-05-07 Tobias Lorenz <tobias.lorenz@gmx.net>
|
||||
* Version 1.0.8
|
||||
* - hardware frequency seek support
|
||||
* - afc indication
|
||||
* - more safety checks, let si470x_get_freq return errno
|
||||
*
|
||||
* ToDo:
|
||||
* - add seeking support
|
||||
* - add firmware download/update support
|
||||
* - RDS support: interrupt mode, instead of polling
|
||||
* - add LED status output (check if that's not already done in firmware)
|
||||
@ -98,10 +115,10 @@
|
||||
/* driver definitions */
|
||||
#define DRIVER_AUTHOR "Tobias Lorenz <tobias.lorenz@gmx.net>"
|
||||
#define DRIVER_NAME "radio-si470x"
|
||||
#define DRIVER_KERNEL_VERSION KERNEL_VERSION(1, 0, 7)
|
||||
#define DRIVER_KERNEL_VERSION KERNEL_VERSION(1, 0, 8)
|
||||
#define DRIVER_CARD "Silicon Labs Si470x FM Radio Receiver"
|
||||
#define DRIVER_DESC "USB radio driver for Si470x FM Radio Receivers"
|
||||
#define DRIVER_VERSION "1.0.7"
|
||||
#define DRIVER_VERSION "1.0.8"
|
||||
|
||||
|
||||
/* kernel includes */
|
||||
@ -175,6 +192,11 @@ static unsigned int tune_timeout = 3000;
|
||||
module_param(tune_timeout, uint, 0);
|
||||
MODULE_PARM_DESC(tune_timeout, "Tune timeout: *3000*");
|
||||
|
||||
/* Seek timeout */
|
||||
static unsigned int seek_timeout = 5000;
|
||||
module_param(seek_timeout, uint, 0);
|
||||
MODULE_PARM_DESC(seek_timeout, "Seek timeout: *5000*");
|
||||
|
||||
/* RDS buffer blocks */
|
||||
static unsigned int rds_buf = 100;
|
||||
module_param(rds_buf, uint, 0);
|
||||
@ -425,7 +447,8 @@ struct si470x_device {
|
||||
|
||||
/* driver management */
|
||||
unsigned int users;
|
||||
unsigned char disconnected;
|
||||
unsigned char disconnected;
|
||||
struct mutex disconnect_lock;
|
||||
|
||||
/* Silabs internal registers (0..15) */
|
||||
unsigned short registers[RADIO_REGISTER_NUM];
|
||||
@ -441,12 +464,6 @@ struct si470x_device {
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Lock to prevent kfree of data before all users have releases the device.
|
||||
*/
|
||||
static DEFINE_MUTEX(open_close_lock);
|
||||
|
||||
|
||||
/*
|
||||
* The frequency is set in units of 62.5 Hz when using V4L2_TUNER_CAP_LOW,
|
||||
* 62.5 kHz otherwise.
|
||||
@ -476,11 +493,11 @@ static int si470x_get_report(struct si470x_device *radio, void *buf, int size)
|
||||
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
|
||||
report[0], 2,
|
||||
buf, size, usb_timeout);
|
||||
|
||||
if (retval < 0)
|
||||
printk(KERN_WARNING DRIVER_NAME
|
||||
": si470x_get_report: usb_control_msg returned %d\n",
|
||||
retval);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
@ -499,11 +516,11 @@ static int si470x_set_report(struct si470x_device *radio, void *buf, int size)
|
||||
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
|
||||
report[0], 2,
|
||||
buf, size, usb_timeout);
|
||||
|
||||
if (retval < 0)
|
||||
printk(KERN_WARNING DRIVER_NAME
|
||||
": si470x_set_report: usb_control_msg returned %d\n",
|
||||
retval);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
@ -521,8 +538,7 @@ static int si470x_get_register(struct si470x_device *radio, int regnr)
|
||||
retval = si470x_get_report(radio, (void *) &buf, sizeof(buf));
|
||||
|
||||
if (retval >= 0)
|
||||
radio->registers[regnr] = be16_to_cpu(get_unaligned(
|
||||
(unsigned short *) &buf[1]));
|
||||
radio->registers[regnr] = get_unaligned_be16(&buf[1]);
|
||||
|
||||
return (retval < 0) ? -EINVAL : 0;
|
||||
}
|
||||
@ -537,8 +553,7 @@ static int si470x_set_register(struct si470x_device *radio, int regnr)
|
||||
int retval;
|
||||
|
||||
buf[0] = REGISTER_REPORT(regnr);
|
||||
put_unaligned(cpu_to_be16(radio->registers[regnr]),
|
||||
(unsigned short *) &buf[1]);
|
||||
put_unaligned_be16(radio->registers[regnr], &buf[1]);
|
||||
|
||||
retval = si470x_set_report(radio, (void *) &buf, sizeof(buf));
|
||||
|
||||
@ -561,9 +576,8 @@ static int si470x_get_all_registers(struct si470x_device *radio)
|
||||
|
||||
if (retval >= 0)
|
||||
for (regnr = 0; regnr < RADIO_REGISTER_NUM; regnr++)
|
||||
radio->registers[regnr] = be16_to_cpu(get_unaligned(
|
||||
(unsigned short *)
|
||||
&buf[regnr * RADIO_REGISTER_SIZE + 1]));
|
||||
radio->registers[regnr] = get_unaligned_be16(
|
||||
&buf[regnr * RADIO_REGISTER_SIZE + 1]);
|
||||
|
||||
return (retval < 0) ? -EINVAL : 0;
|
||||
}
|
||||
@ -585,7 +599,7 @@ static int si470x_get_rds_registers(struct si470x_device *radio)
|
||||
usb_rcvintpipe(radio->usbdev, 1),
|
||||
(void *) &buf, sizeof(buf), &size, usb_timeout);
|
||||
if (size != sizeof(buf))
|
||||
printk(KERN_WARNING DRIVER_NAME ": si470x_get_rds_registers: "
|
||||
printk(KERN_WARNING DRIVER_NAME ": si470x_get_rds_registers: "
|
||||
"return size differs: %d != %zu\n", size, sizeof(buf));
|
||||
if (retval < 0)
|
||||
printk(KERN_WARNING DRIVER_NAME ": si470x_get_rds_registers: "
|
||||
@ -594,8 +608,8 @@ static int si470x_get_rds_registers(struct si470x_device *radio)
|
||||
if (retval >= 0)
|
||||
for (regnr = 0; regnr < RDS_REGISTER_NUM; regnr++)
|
||||
radio->registers[STATUSRSSI + regnr] =
|
||||
be16_to_cpu(get_unaligned((unsigned short *)
|
||||
&buf[regnr * RADIO_REGISTER_SIZE + 1]));
|
||||
get_unaligned_be16(
|
||||
&buf[regnr * RADIO_REGISTER_SIZE + 1]);
|
||||
|
||||
return (retval < 0) ? -EINVAL : 0;
|
||||
}
|
||||
@ -615,33 +629,39 @@ static int si470x_set_chan(struct si470x_device *radio, unsigned short chan)
|
||||
radio->registers[CHANNEL] |= CHANNEL_TUNE | chan;
|
||||
retval = si470x_set_register(radio, CHANNEL);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
goto done;
|
||||
|
||||
/* wait till seek operation has completed */
|
||||
/* wait till tune operation has completed */
|
||||
timeout = jiffies + msecs_to_jiffies(tune_timeout);
|
||||
do {
|
||||
retval = si470x_get_register(radio, STATUSRSSI);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
goto stop;
|
||||
timed_out = time_after(jiffies, timeout);
|
||||
} while (((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0) &&
|
||||
(!timed_out));
|
||||
if ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0)
|
||||
printk(KERN_WARNING DRIVER_NAME ": tune does not complete\n");
|
||||
if (timed_out)
|
||||
printk(KERN_WARNING DRIVER_NAME
|
||||
": seek does not finish after %u ms\n", tune_timeout);
|
||||
": tune timed out after %u ms\n", tune_timeout);
|
||||
|
||||
stop:
|
||||
/* stop tuning */
|
||||
radio->registers[CHANNEL] &= ~CHANNEL_TUNE;
|
||||
return si470x_set_register(radio, CHANNEL);
|
||||
retval = si470x_set_register(radio, CHANNEL);
|
||||
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* si470x_get_freq - get the frequency
|
||||
*/
|
||||
static unsigned int si470x_get_freq(struct si470x_device *radio)
|
||||
static int si470x_get_freq(struct si470x_device *radio, unsigned int *freq)
|
||||
{
|
||||
unsigned int spacing, band_bottom, freq;
|
||||
unsigned int spacing, band_bottom;
|
||||
unsigned short chan;
|
||||
int retval;
|
||||
|
||||
@ -667,14 +687,12 @@ static unsigned int si470x_get_freq(struct si470x_device *radio)
|
||||
|
||||
/* read channel */
|
||||
retval = si470x_get_register(radio, READCHAN);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
chan = radio->registers[READCHAN] & READCHAN_READCHAN;
|
||||
|
||||
/* Frequency (MHz) = Spacing (kHz) x Channel + Bottom of Band (MHz) */
|
||||
freq = chan * spacing + band_bottom;
|
||||
*freq = chan * spacing + band_bottom;
|
||||
|
||||
return freq;
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
@ -713,6 +731,62 @@ static int si470x_set_freq(struct si470x_device *radio, unsigned int freq)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* si470x_set_seek - set seek
|
||||
*/
|
||||
static int si470x_set_seek(struct si470x_device *radio,
|
||||
unsigned int wrap_around, unsigned int seek_upward)
|
||||
{
|
||||
int retval = 0;
|
||||
unsigned long timeout;
|
||||
bool timed_out = 0;
|
||||
|
||||
/* start seeking */
|
||||
radio->registers[POWERCFG] |= POWERCFG_SEEK;
|
||||
if (wrap_around == 1)
|
||||
radio->registers[POWERCFG] &= ~POWERCFG_SKMODE;
|
||||
else
|
||||
radio->registers[POWERCFG] |= POWERCFG_SKMODE;
|
||||
if (seek_upward == 1)
|
||||
radio->registers[POWERCFG] |= POWERCFG_SEEKUP;
|
||||
else
|
||||
radio->registers[POWERCFG] &= ~POWERCFG_SEEKUP;
|
||||
retval = si470x_set_register(radio, POWERCFG);
|
||||
if (retval < 0)
|
||||
goto done;
|
||||
|
||||
/* wait till seek operation has completed */
|
||||
timeout = jiffies + msecs_to_jiffies(seek_timeout);
|
||||
do {
|
||||
retval = si470x_get_register(radio, STATUSRSSI);
|
||||
if (retval < 0)
|
||||
goto stop;
|
||||
timed_out = time_after(jiffies, timeout);
|
||||
} while (((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0) &&
|
||||
(!timed_out));
|
||||
if ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0)
|
||||
printk(KERN_WARNING DRIVER_NAME ": seek does not complete\n");
|
||||
if (radio->registers[STATUSRSSI] & STATUSRSSI_SF)
|
||||
printk(KERN_WARNING DRIVER_NAME
|
||||
": seek failed / band limit reached\n");
|
||||
if (timed_out)
|
||||
printk(KERN_WARNING DRIVER_NAME
|
||||
": seek timed out after %u ms\n", seek_timeout);
|
||||
|
||||
stop:
|
||||
/* stop seeking */
|
||||
radio->registers[POWERCFG] &= ~POWERCFG_SEEK;
|
||||
retval = si470x_set_register(radio, POWERCFG);
|
||||
|
||||
done:
|
||||
/* try again, if timed out */
|
||||
if ((retval == 0) && timed_out)
|
||||
retval = -EAGAIN;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* si470x_start - switch on radio
|
||||
*/
|
||||
@ -725,27 +799,30 @@ static int si470x_start(struct si470x_device *radio)
|
||||
POWERCFG_DMUTE | POWERCFG_ENABLE | POWERCFG_RDSM;
|
||||
retval = si470x_set_register(radio, POWERCFG);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
goto done;
|
||||
|
||||
/* sysconfig 1 */
|
||||
radio->registers[SYSCONFIG1] = SYSCONFIG1_DE;
|
||||
retval = si470x_set_register(radio, SYSCONFIG1);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
goto done;
|
||||
|
||||
/* sysconfig 2 */
|
||||
radio->registers[SYSCONFIG2] =
|
||||
(0x3f << 8) | /* SEEKTH */
|
||||
(band << 6) | /* BAND */
|
||||
(space << 4) | /* SPACE */
|
||||
15; /* VOLUME (max) */
|
||||
(0x3f << 8) | /* SEEKTH */
|
||||
((band << 6) & SYSCONFIG2_BAND) | /* BAND */
|
||||
((space << 4) & SYSCONFIG2_SPACE) | /* SPACE */
|
||||
15; /* VOLUME (max) */
|
||||
retval = si470x_set_register(radio, SYSCONFIG2);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
goto done;
|
||||
|
||||
/* reset last channel */
|
||||
return si470x_set_chan(radio,
|
||||
retval = si470x_set_chan(radio,
|
||||
radio->registers[CHANNEL] & CHANNEL_CHAN);
|
||||
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
@ -760,13 +837,16 @@ static int si470x_stop(struct si470x_device *radio)
|
||||
radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_RDS;
|
||||
retval = si470x_set_register(radio, SYSCONFIG1);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
goto done;
|
||||
|
||||
/* powercfg */
|
||||
radio->registers[POWERCFG] &= ~POWERCFG_DMUTE;
|
||||
/* POWERCFG_ENABLE has to automatically go low */
|
||||
radio->registers[POWERCFG] |= POWERCFG_ENABLE | POWERCFG_DISABLE;
|
||||
return si470x_set_register(radio, POWERCFG);
|
||||
retval = si470x_set_register(radio, POWERCFG);
|
||||
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
@ -843,7 +923,7 @@ static void si470x_rds(struct si470x_device *radio)
|
||||
};
|
||||
|
||||
/* Fill the V4L2 RDS buffer */
|
||||
put_unaligned(cpu_to_le16(rds), (unsigned short *) &tmpbuf);
|
||||
put_unaligned_le16(rds, &tmpbuf);
|
||||
tmpbuf[2] = blocknum; /* offset name */
|
||||
tmpbuf[2] |= blocknum << 3; /* received offset */
|
||||
if (bler > max_rds_errors)
|
||||
@ -883,8 +963,9 @@ static void si470x_work(struct work_struct *work)
|
||||
struct si470x_device *radio = container_of(work, struct si470x_device,
|
||||
work.work);
|
||||
|
||||
if (radio->disconnected)
|
||||
return;
|
||||
/* safety checks */
|
||||
if (radio->disconnected)
|
||||
return;
|
||||
if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
|
||||
return;
|
||||
|
||||
@ -917,11 +998,15 @@ static ssize_t si470x_fops_read(struct file *file, char __user *buf,
|
||||
|
||||
/* block if no new data available */
|
||||
while (radio->wr_index == radio->rd_index) {
|
||||
if (file->f_flags & O_NONBLOCK)
|
||||
return -EWOULDBLOCK;
|
||||
if (file->f_flags & O_NONBLOCK) {
|
||||
retval = -EWOULDBLOCK;
|
||||
goto done;
|
||||
}
|
||||
if (wait_event_interruptible(radio->read_queue,
|
||||
radio->wr_index != radio->rd_index) < 0)
|
||||
return -EINTR;
|
||||
radio->wr_index != radio->rd_index) < 0) {
|
||||
retval = -EINTR;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
/* calculate block count from byte count */
|
||||
@ -950,6 +1035,7 @@ static ssize_t si470x_fops_read(struct file *file, char __user *buf,
|
||||
}
|
||||
mutex_unlock(&radio->lock);
|
||||
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
@ -961,6 +1047,7 @@ static unsigned int si470x_fops_poll(struct file *file,
|
||||
struct poll_table_struct *pts)
|
||||
{
|
||||
struct si470x_device *radio = video_get_drvdata(video_devdata(file));
|
||||
int retval = 0;
|
||||
|
||||
/* switch on rds reception */
|
||||
if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) {
|
||||
@ -972,9 +1059,9 @@ static unsigned int si470x_fops_poll(struct file *file,
|
||||
poll_wait(file, &radio->read_queue, pts);
|
||||
|
||||
if (radio->rd_index != radio->wr_index)
|
||||
return POLLIN | POLLRDNORM;
|
||||
retval = POLLIN | POLLRDNORM;
|
||||
|
||||
return 0;
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
@ -991,17 +1078,18 @@ static int si470x_fops_open(struct inode *inode, struct file *file)
|
||||
retval = usb_autopm_get_interface(radio->intf);
|
||||
if (retval < 0) {
|
||||
radio->users--;
|
||||
return -EIO;
|
||||
retval = -EIO;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (radio->users == 1) {
|
||||
retval = si470x_start(radio);
|
||||
if (retval < 0)
|
||||
usb_autopm_put_interface(radio->intf);
|
||||
return retval;
|
||||
}
|
||||
|
||||
return 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
@ -1011,20 +1099,23 @@ static int si470x_fops_open(struct inode *inode, struct file *file)
|
||||
static int si470x_fops_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct si470x_device *radio = video_get_drvdata(video_devdata(file));
|
||||
int retval = 0;
|
||||
int retval = 0;
|
||||
|
||||
if (!radio)
|
||||
return -ENODEV;
|
||||
/* safety check */
|
||||
if (!radio) {
|
||||
retval = -ENODEV;
|
||||
goto done;
|
||||
}
|
||||
|
||||
mutex_lock(&open_close_lock);
|
||||
mutex_lock(&radio->disconnect_lock);
|
||||
radio->users--;
|
||||
if (radio->users == 0) {
|
||||
if (radio->disconnected) {
|
||||
video_unregister_device(radio->videodev);
|
||||
kfree(radio->buffer);
|
||||
kfree(radio);
|
||||
goto done;
|
||||
}
|
||||
if (radio->disconnected) {
|
||||
video_unregister_device(radio->videodev);
|
||||
kfree(radio->buffer);
|
||||
kfree(radio);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
/* stop rds reception */
|
||||
cancel_delayed_work_sync(&radio->work);
|
||||
@ -1036,9 +1127,11 @@ static int si470x_fops_release(struct inode *inode, struct file *file)
|
||||
usb_autopm_put_interface(radio->intf);
|
||||
}
|
||||
|
||||
unlock:
|
||||
mutex_unlock(&radio->disconnect_lock);
|
||||
|
||||
done:
|
||||
mutex_unlock(&open_close_lock);
|
||||
return retval;
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
@ -1116,7 +1209,8 @@ static int si470x_vidioc_querycap(struct file *file, void *priv,
|
||||
strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
|
||||
sprintf(capability->bus_info, "USB");
|
||||
capability->version = DRIVER_KERNEL_VERSION;
|
||||
capability->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
|
||||
capability->capabilities = V4L2_CAP_HW_FREQ_SEEK |
|
||||
V4L2_CAP_TUNER | V4L2_CAP_RADIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1125,7 +1219,7 @@ static int si470x_vidioc_querycap(struct file *file, void *priv,
|
||||
/*
|
||||
* si470x_vidioc_g_input - get input
|
||||
*/
|
||||
static int si470x_vidioc_g_input(struct file *filp, void *priv,
|
||||
static int si470x_vidioc_g_input(struct file *file, void *priv,
|
||||
unsigned int *i)
|
||||
{
|
||||
*i = 0;
|
||||
@ -1137,12 +1231,18 @@ static int si470x_vidioc_g_input(struct file *filp, void *priv,
|
||||
/*
|
||||
* si470x_vidioc_s_input - set input
|
||||
*/
|
||||
static int si470x_vidioc_s_input(struct file *filp, void *priv, unsigned int i)
|
||||
static int si470x_vidioc_s_input(struct file *file, void *priv, unsigned int i)
|
||||
{
|
||||
if (i != 0)
|
||||
return -EINVAL;
|
||||
int retval = 0;
|
||||
|
||||
return 0;
|
||||
/* safety checks */
|
||||
if (i != 0)
|
||||
retval = -EINVAL;
|
||||
|
||||
if (retval < 0)
|
||||
printk(KERN_WARNING DRIVER_NAME
|
||||
": set input failed with %d\n", retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
@ -1155,17 +1255,22 @@ static int si470x_vidioc_queryctrl(struct file *file, void *priv,
|
||||
unsigned char i;
|
||||
int retval = -EINVAL;
|
||||
|
||||
/* safety checks */
|
||||
if (!qc->id)
|
||||
goto done;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(si470x_v4l2_queryctrl); i++) {
|
||||
if (qc->id && qc->id == si470x_v4l2_queryctrl[i].id) {
|
||||
if (qc->id == si470x_v4l2_queryctrl[i].id) {
|
||||
memcpy(qc, &(si470x_v4l2_queryctrl[i]), sizeof(*qc));
|
||||
retval = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
if (retval < 0)
|
||||
printk(KERN_WARNING DRIVER_NAME
|
||||
": query control failed with %d\n", retval);
|
||||
|
||||
": query controls failed with %d\n", retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
@ -1177,9 +1282,13 @@ static int si470x_vidioc_g_ctrl(struct file *file, void *priv,
|
||||
struct v4l2_control *ctrl)
|
||||
{
|
||||
struct si470x_device *radio = video_get_drvdata(video_devdata(file));
|
||||
int retval = 0;
|
||||
|
||||
if (radio->disconnected)
|
||||
return -EIO;
|
||||
/* safety checks */
|
||||
if (radio->disconnected) {
|
||||
retval = -EIO;
|
||||
goto done;
|
||||
}
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_VOLUME:
|
||||
@ -1190,9 +1299,15 @@ static int si470x_vidioc_g_ctrl(struct file *file, void *priv,
|
||||
ctrl->value = ((radio->registers[POWERCFG] &
|
||||
POWERCFG_DMUTE) == 0) ? 1 : 0;
|
||||
break;
|
||||
default:
|
||||
retval = -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
done:
|
||||
if (retval < 0)
|
||||
printk(KERN_WARNING DRIVER_NAME
|
||||
": get control failed with %d\n", retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
@ -1203,10 +1318,13 @@ static int si470x_vidioc_s_ctrl(struct file *file, void *priv,
|
||||
struct v4l2_control *ctrl)
|
||||
{
|
||||
struct si470x_device *radio = video_get_drvdata(video_devdata(file));
|
||||
int retval;
|
||||
int retval = 0;
|
||||
|
||||
if (radio->disconnected)
|
||||
return -EIO;
|
||||
/* safety checks */
|
||||
if (radio->disconnected) {
|
||||
retval = -EIO;
|
||||
goto done;
|
||||
}
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_VOLUME:
|
||||
@ -1224,10 +1342,11 @@ static int si470x_vidioc_s_ctrl(struct file *file, void *priv,
|
||||
default:
|
||||
retval = -EINVAL;
|
||||
}
|
||||
|
||||
done:
|
||||
if (retval < 0)
|
||||
printk(KERN_WARNING DRIVER_NAME
|
||||
": set control failed with %d\n", retval);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
@ -1238,13 +1357,22 @@ static int si470x_vidioc_s_ctrl(struct file *file, void *priv,
|
||||
static int si470x_vidioc_g_audio(struct file *file, void *priv,
|
||||
struct v4l2_audio *audio)
|
||||
{
|
||||
if (audio->index > 1)
|
||||
return -EINVAL;
|
||||
int retval = 0;
|
||||
|
||||
/* safety checks */
|
||||
if (audio->index != 0) {
|
||||
retval = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
strcpy(audio->name, "Radio");
|
||||
audio->capability = V4L2_AUDCAP_STEREO;
|
||||
|
||||
return 0;
|
||||
done:
|
||||
if (retval < 0)
|
||||
printk(KERN_WARNING DRIVER_NAME
|
||||
": get audio failed with %d\n", retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
@ -1254,10 +1382,19 @@ static int si470x_vidioc_g_audio(struct file *file, void *priv,
|
||||
static int si470x_vidioc_s_audio(struct file *file, void *priv,
|
||||
struct v4l2_audio *audio)
|
||||
{
|
||||
if (audio->index != 0)
|
||||
return -EINVAL;
|
||||
int retval = 0;
|
||||
|
||||
return 0;
|
||||
/* safety checks */
|
||||
if (audio->index != 0) {
|
||||
retval = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
done:
|
||||
if (retval < 0)
|
||||
printk(KERN_WARNING DRIVER_NAME
|
||||
": set audio failed with %d\n", retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
@ -1268,20 +1405,23 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv,
|
||||
struct v4l2_tuner *tuner)
|
||||
{
|
||||
struct si470x_device *radio = video_get_drvdata(video_devdata(file));
|
||||
int retval;
|
||||
int retval = 0;
|
||||
|
||||
if (radio->disconnected)
|
||||
return -EIO;
|
||||
if (tuner->index > 0)
|
||||
return -EINVAL;
|
||||
/* safety checks */
|
||||
if (radio->disconnected) {
|
||||
retval = -EIO;
|
||||
goto done;
|
||||
}
|
||||
if ((tuner->index != 0) && (tuner->type != V4L2_TUNER_RADIO)) {
|
||||
retval = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* read status rssi */
|
||||
retval = si470x_get_register(radio, STATUSRSSI);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
goto done;
|
||||
|
||||
strcpy(tuner->name, "FM");
|
||||
tuner->type = V4L2_TUNER_RADIO;
|
||||
switch (band) {
|
||||
/* 0: 87.5 - 108 MHz (USA, Europe, default) */
|
||||
default:
|
||||
@ -1313,9 +1453,14 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv,
|
||||
* 0x0101;
|
||||
|
||||
/* automatic frequency control: -1: freq to low, 1 freq to high */
|
||||
tuner->afc = 0;
|
||||
/* AFCRL does only indicate that freq. differs, not if too low/high */
|
||||
tuner->afc = (radio->registers[STATUSRSSI] & STATUSRSSI_AFCRL) ? 1 : 0;
|
||||
|
||||
return 0;
|
||||
done:
|
||||
if (retval < 0)
|
||||
printk(KERN_WARNING DRIVER_NAME
|
||||
": get tuner failed with %d\n", retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
@ -1326,12 +1471,17 @@ static int si470x_vidioc_s_tuner(struct file *file, void *priv,
|
||||
struct v4l2_tuner *tuner)
|
||||
{
|
||||
struct si470x_device *radio = video_get_drvdata(video_devdata(file));
|
||||
int retval;
|
||||
int retval = 0;
|
||||
|
||||
if (radio->disconnected)
|
||||
return -EIO;
|
||||
if (tuner->index > 0)
|
||||
return -EINVAL;
|
||||
/* safety checks */
|
||||
if (radio->disconnected) {
|
||||
retval = -EIO;
|
||||
goto done;
|
||||
}
|
||||
if ((tuner->index != 0) && (tuner->type != V4L2_TUNER_RADIO)) {
|
||||
retval = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (tuner->audmode == V4L2_TUNER_MODE_MONO)
|
||||
radio->registers[POWERCFG] |= POWERCFG_MONO; /* force mono */
|
||||
@ -1339,10 +1489,11 @@ static int si470x_vidioc_s_tuner(struct file *file, void *priv,
|
||||
radio->registers[POWERCFG] &= ~POWERCFG_MONO; /* try stereo */
|
||||
|
||||
retval = si470x_set_register(radio, POWERCFG);
|
||||
|
||||
done:
|
||||
if (retval < 0)
|
||||
printk(KERN_WARNING DRIVER_NAME
|
||||
": set tuner failed with %d\n", retval);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
@ -1354,14 +1505,25 @@ static int si470x_vidioc_g_frequency(struct file *file, void *priv,
|
||||
struct v4l2_frequency *freq)
|
||||
{
|
||||
struct si470x_device *radio = video_get_drvdata(video_devdata(file));
|
||||
int retval = 0;
|
||||
|
||||
if (radio->disconnected)
|
||||
return -EIO;
|
||||
/* safety checks */
|
||||
if (radio->disconnected) {
|
||||
retval = -EIO;
|
||||
goto done;
|
||||
}
|
||||
if ((freq->tuner != 0) && (freq->type != V4L2_TUNER_RADIO)) {
|
||||
retval = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
freq->type = V4L2_TUNER_RADIO;
|
||||
freq->frequency = si470x_get_freq(radio);
|
||||
retval = si470x_get_freq(radio, &freq->frequency);
|
||||
|
||||
return 0;
|
||||
done:
|
||||
if (retval < 0)
|
||||
printk(KERN_WARNING DRIVER_NAME
|
||||
": get frequency failed with %d\n", retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
@ -1372,19 +1534,55 @@ static int si470x_vidioc_s_frequency(struct file *file, void *priv,
|
||||
struct v4l2_frequency *freq)
|
||||
{
|
||||
struct si470x_device *radio = video_get_drvdata(video_devdata(file));
|
||||
int retval;
|
||||
int retval = 0;
|
||||
|
||||
if (radio->disconnected)
|
||||
return -EIO;
|
||||
if (freq->type != V4L2_TUNER_RADIO)
|
||||
return -EINVAL;
|
||||
/* safety checks */
|
||||
if (radio->disconnected) {
|
||||
retval = -EIO;
|
||||
goto done;
|
||||
}
|
||||
if ((freq->tuner != 0) && (freq->type != V4L2_TUNER_RADIO)) {
|
||||
retval = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
retval = si470x_set_freq(radio, freq->frequency);
|
||||
|
||||
done:
|
||||
if (retval < 0)
|
||||
printk(KERN_WARNING DRIVER_NAME
|
||||
": set frequency failed with %d\n", retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* si470x_vidioc_s_hw_freq_seek - set hardware frequency seek
|
||||
*/
|
||||
static int si470x_vidioc_s_hw_freq_seek(struct file *file, void *priv,
|
||||
struct v4l2_hw_freq_seek *seek)
|
||||
{
|
||||
struct si470x_device *radio = video_get_drvdata(video_devdata(file));
|
||||
int retval = 0;
|
||||
|
||||
/* safety checks */
|
||||
if (radio->disconnected) {
|
||||
retval = -EIO;
|
||||
goto done;
|
||||
}
|
||||
if ((seek->tuner != 0) && (seek->type != V4L2_TUNER_RADIO)) {
|
||||
retval = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
retval = si470x_set_seek(radio, seek->wrap_around, seek->seek_upward);
|
||||
|
||||
done:
|
||||
if (retval < 0)
|
||||
printk(KERN_WARNING DRIVER_NAME
|
||||
": set hardware frequency seek failed with %d\n",
|
||||
retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
@ -1408,6 +1606,7 @@ static struct video_device si470x_viddev_template = {
|
||||
.vidioc_s_tuner = si470x_vidioc_s_tuner,
|
||||
.vidioc_g_frequency = si470x_vidioc_g_frequency,
|
||||
.vidioc_s_frequency = si470x_vidioc_s_frequency,
|
||||
.vidioc_s_hw_freq_seek = si470x_vidioc_s_hw_freq_seek,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
@ -1424,31 +1623,36 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
struct si470x_device *radio;
|
||||
int retval = -ENOMEM;
|
||||
int retval = 0;
|
||||
|
||||
/* private data allocation */
|
||||
/* private data allocation and initialization */
|
||||
radio = kzalloc(sizeof(struct si470x_device), GFP_KERNEL);
|
||||
if (!radio)
|
||||
if (!radio) {
|
||||
retval = -ENOMEM;
|
||||
goto err_initial;
|
||||
|
||||
/* video device allocation */
|
||||
radio->videodev = video_device_alloc();
|
||||
if (!radio->videodev)
|
||||
goto err_radio;
|
||||
|
||||
/* initial configuration */
|
||||
memcpy(radio->videodev, &si470x_viddev_template,
|
||||
sizeof(si470x_viddev_template));
|
||||
}
|
||||
radio->users = 0;
|
||||
radio->disconnected = 0;
|
||||
radio->usbdev = interface_to_usbdev(intf);
|
||||
radio->intf = intf;
|
||||
mutex_init(&radio->disconnect_lock);
|
||||
mutex_init(&radio->lock);
|
||||
|
||||
/* video device allocation and initialization */
|
||||
radio->videodev = video_device_alloc();
|
||||
if (!radio->videodev) {
|
||||
retval = -ENOMEM;
|
||||
goto err_radio;
|
||||
}
|
||||
memcpy(radio->videodev, &si470x_viddev_template,
|
||||
sizeof(si470x_viddev_template));
|
||||
video_set_drvdata(radio->videodev, radio);
|
||||
|
||||
/* show some infos about the specific device */
|
||||
retval = -EIO;
|
||||
if (si470x_get_all_registers(radio) < 0)
|
||||
if (si470x_get_all_registers(radio) < 0) {
|
||||
retval = -EIO;
|
||||
goto err_all;
|
||||
}
|
||||
printk(KERN_INFO DRIVER_NAME ": DeviceID=0x%4.4hx ChipID=0x%4.4hx\n",
|
||||
radio->registers[DEVICEID], radio->registers[CHIPID]);
|
||||
|
||||
@ -1474,8 +1678,10 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
|
||||
/* rds buffer allocation */
|
||||
radio->buf_size = rds_buf * 3;
|
||||
radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL);
|
||||
if (!radio->buffer)
|
||||
if (!radio->buffer) {
|
||||
retval = -EIO;
|
||||
goto err_all;
|
||||
}
|
||||
|
||||
/* rds buffer configuration */
|
||||
radio->wr_index = 0;
|
||||
@ -1487,6 +1693,7 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
|
||||
|
||||
/* register video device */
|
||||
if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr)) {
|
||||
retval = -EIO;
|
||||
printk(KERN_WARNING DRIVER_NAME
|
||||
": Could not register video device\n");
|
||||
goto err_all;
|
||||
@ -1546,16 +1753,16 @@ static void si470x_usb_driver_disconnect(struct usb_interface *intf)
|
||||
{
|
||||
struct si470x_device *radio = usb_get_intfdata(intf);
|
||||
|
||||
mutex_lock(&open_close_lock);
|
||||
radio->disconnected = 1;
|
||||
mutex_lock(&radio->disconnect_lock);
|
||||
radio->disconnected = 1;
|
||||
cancel_delayed_work_sync(&radio->work);
|
||||
usb_set_intfdata(intf, NULL);
|
||||
if (radio->users == 0) {
|
||||
video_unregister_device(radio->videodev);
|
||||
kfree(radio->buffer);
|
||||
kfree(radio);
|
||||
}
|
||||
mutex_unlock(&open_close_lock);
|
||||
if (radio->users == 0) {
|
||||
video_unregister_device(radio->videodev);
|
||||
kfree(radio->buffer);
|
||||
kfree(radio);
|
||||
}
|
||||
mutex_unlock(&radio->disconnect_lock);
|
||||
}
|
||||
|
||||
|
||||
|
@ -24,21 +24,21 @@ config VIDEOBUF_VMALLOC
|
||||
select VIDEOBUF_GEN
|
||||
tristate
|
||||
|
||||
config VIDEOBUF_DMA_CONTIG
|
||||
depends on HAS_DMA
|
||||
select VIDEOBUF_GEN
|
||||
tristate
|
||||
|
||||
config VIDEOBUF_DVB
|
||||
tristate
|
||||
select VIDEOBUF_GEN
|
||||
select VIDEOBUF_DMA_SG
|
||||
|
||||
config VIDEO_BTCX
|
||||
tristate
|
||||
|
||||
config VIDEO_IR_I2C
|
||||
tristate
|
||||
|
||||
config VIDEO_IR
|
||||
tristate
|
||||
depends on INPUT
|
||||
select VIDEO_IR_I2C if I2C
|
||||
|
||||
config VIDEO_TVEEPROM
|
||||
tristate
|
||||
@ -84,6 +84,19 @@ config VIDEO_HELPER_CHIPS_AUTO
|
||||
|
||||
In doubt, say Y.
|
||||
|
||||
config VIDEO_IR_I2C
|
||||
tristate "I2C module for IR" if !VIDEO_HELPER_CHIPS_AUTO
|
||||
depends on I2C && VIDEO_IR
|
||||
default y
|
||||
---help---
|
||||
Most boards have an IR chip directly connected via GPIO. However,
|
||||
some video boards have the IR connected via I2C bus.
|
||||
|
||||
If your board doesn't have an I2C IR chip, you may disable this
|
||||
option.
|
||||
|
||||
In doubt, say Y.
|
||||
|
||||
#
|
||||
# Encoder / Decoder module configuration
|
||||
#
|
||||
@ -600,9 +613,6 @@ config VIDEO_STRADIS
|
||||
driver for PCI. There is a product page at
|
||||
<http://www.stradis.com/>.
|
||||
|
||||
config VIDEO_ZORAN_ZR36060
|
||||
tristate
|
||||
|
||||
config VIDEO_ZORAN
|
||||
tristate "Zoran ZR36057/36067 Video For Linux"
|
||||
depends on PCI && I2C_ALGOBIT && VIDEO_V4L1 && VIRT_TO_BUS
|
||||
@ -616,25 +626,6 @@ config VIDEO_ZORAN
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called zr36067.
|
||||
|
||||
config VIDEO_ZORAN_BUZ
|
||||
tristate "Iomega Buz support"
|
||||
depends on VIDEO_ZORAN
|
||||
select VIDEO_SAA7111 if VIDEO_HELPER_CHIPS_AUTO
|
||||
select VIDEO_SAA7185 if VIDEO_HELPER_CHIPS_AUTO
|
||||
select VIDEO_ZORAN_ZR36060
|
||||
help
|
||||
Support for the Iomega Buz MJPEG capture/playback card.
|
||||
|
||||
config VIDEO_ZORAN_DC10
|
||||
tristate "Pinnacle/Miro DC10(+) support"
|
||||
depends on VIDEO_ZORAN
|
||||
select VIDEO_SAA7110
|
||||
select VIDEO_ADV7175 if VIDEO_HELPER_CHIPS_AUTO
|
||||
select VIDEO_ZORAN_ZR36060
|
||||
help
|
||||
Support for the Pinnacle/Miro DC10(+) MJPEG capture/playback
|
||||
card.
|
||||
|
||||
config VIDEO_ZORAN_DC30
|
||||
tristate "Pinnacle/Miro DC30(+) support"
|
||||
depends on VIDEO_ZORAN
|
||||
@ -645,32 +636,54 @@ config VIDEO_ZORAN_DC30
|
||||
card. This also supports really old DC10 cards based on the
|
||||
zr36050 MJPEG codec and zr36016 VFE.
|
||||
|
||||
config VIDEO_ZORAN_ZR36060
|
||||
tristate "Zoran ZR36060"
|
||||
depends on VIDEO_ZORAN
|
||||
help
|
||||
Say Y to support Zoran boards based on 36060 chips.
|
||||
This includes Iomega Bus, Pinnacle DC10, Linux media Labs 33
|
||||
and 33 R10 and AverMedia 6 boards.
|
||||
|
||||
config VIDEO_ZORAN_BUZ
|
||||
tristate "Iomega Buz support"
|
||||
depends on VIDEO_ZORAN_ZR36060
|
||||
select VIDEO_SAA7111 if VIDEO_HELPER_CHIPS_AUTO
|
||||
select VIDEO_SAA7185 if VIDEO_HELPER_CHIPS_AUTO
|
||||
help
|
||||
Support for the Iomega Buz MJPEG capture/playback card.
|
||||
|
||||
config VIDEO_ZORAN_DC10
|
||||
tristate "Pinnacle/Miro DC10(+) support"
|
||||
depends on VIDEO_ZORAN_ZR36060
|
||||
select VIDEO_SAA7110 if VIDEO_HELPER_CHIPS_AUTO
|
||||
select VIDEO_ADV7175 if VIDEO_HELPER_CHIPS_AUTO
|
||||
help
|
||||
Support for the Pinnacle/Miro DC10(+) MJPEG capture/playback
|
||||
card.
|
||||
|
||||
config VIDEO_ZORAN_LML33
|
||||
tristate "Linux Media Labs LML33 support"
|
||||
depends on VIDEO_ZORAN
|
||||
depends on VIDEO_ZORAN_ZR36060
|
||||
select VIDEO_BT819 if VIDEO_HELPER_CHIPS_AUTO
|
||||
select VIDEO_BT856 if VIDEO_HELPER_CHIPS_AUTO
|
||||
select VIDEO_ZORAN_ZR36060
|
||||
help
|
||||
Support for the Linux Media Labs LML33 MJPEG capture/playback
|
||||
card.
|
||||
|
||||
config VIDEO_ZORAN_LML33R10
|
||||
tristate "Linux Media Labs LML33R10 support"
|
||||
depends on VIDEO_ZORAN
|
||||
depends on VIDEO_ZORAN_ZR36060
|
||||
select VIDEO_SAA7114 if VIDEO_HELPER_CHIPS_AUTO
|
||||
select VIDEO_ADV7170 if VIDEO_HELPER_CHIPS_AUTO
|
||||
select VIDEO_ZORAN_ZR36060
|
||||
help
|
||||
support for the Linux Media Labs LML33R10 MJPEG capture/playback
|
||||
card.
|
||||
|
||||
config VIDEO_ZORAN_AVS6EYES
|
||||
tristate "AverMedia 6 Eyes support (EXPERIMENTAL)"
|
||||
depends on VIDEO_ZORAN && EXPERIMENTAL && VIDEO_V4L1
|
||||
depends on VIDEO_ZORAN_ZR36060 && EXPERIMENTAL && VIDEO_V4L1
|
||||
select VIDEO_BT856 if VIDEO_HELPER_CHIPS_AUTO
|
||||
select VIDEO_KS0127 if VIDEO_HELPER_CHIPS_AUTO
|
||||
select VIDEO_ZORAN_ZR36060
|
||||
help
|
||||
Support for the AverMedia 6 Eyes video surveillance card.
|
||||
|
||||
@ -801,6 +814,8 @@ config USB_VIDEO_CLASS
|
||||
|
||||
For more information see: <http://linux-uvc.berlios.de/>
|
||||
|
||||
source "drivers/media/video/gspca/Kconfig"
|
||||
|
||||
source "drivers/media/video/pvrusb2/Kconfig"
|
||||
|
||||
source "drivers/media/video/em28xx/Kconfig"
|
||||
@ -905,12 +920,21 @@ config USB_STKWEBCAM
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called stkwebcam.
|
||||
|
||||
config USB_S2255
|
||||
tristate "USB Sensoray 2255 video capture device"
|
||||
depends on VIDEO_V4L2
|
||||
select VIDEOBUF_VMALLOC
|
||||
default n
|
||||
help
|
||||
Say Y here if you want support for the Sensoray 2255 USB device.
|
||||
This driver can be compiled as a module, called s2255drv.
|
||||
|
||||
endif # V4L_USB_DRIVERS
|
||||
|
||||
config SOC_CAMERA
|
||||
tristate "SoC camera support"
|
||||
depends on VIDEO_V4L2 && HAS_DMA
|
||||
select VIDEOBUF_DMA_SG
|
||||
select VIDEOBUF_GEN
|
||||
help
|
||||
SoC Camera is a common API to several cameras, not connecting
|
||||
over a bus like PCI or USB. For example some i2c camera connected
|
||||
@ -945,11 +969,26 @@ config MT9V022_PCA9536_SWITCH
|
||||
Select this if your MT9V022 camera uses a PCA9536 I2C GPIO
|
||||
extender to switch between 8 and 10 bit datawidth modes
|
||||
|
||||
config SOC_CAMERA_PLATFORM
|
||||
tristate "platform camera support"
|
||||
depends on SOC_CAMERA
|
||||
help
|
||||
This is a generic SoC camera platform driver, useful for testing
|
||||
|
||||
config VIDEO_PXA27x
|
||||
tristate "PXA27x Quick Capture Interface driver"
|
||||
depends on VIDEO_DEV && PXA27x
|
||||
select SOC_CAMERA
|
||||
select VIDEOBUF_DMA_SG
|
||||
---help---
|
||||
This is a v4l2 driver for the PXA27x Quick Capture Interface
|
||||
|
||||
config VIDEO_SH_MOBILE_CEU
|
||||
tristate "SuperH Mobile CEU Interface driver"
|
||||
depends on VIDEO_DEV
|
||||
select SOC_CAMERA
|
||||
select VIDEOBUF_DMA_CONTIG
|
||||
---help---
|
||||
This is a v4l2 driver for the SuperH Mobile CEU Interface
|
||||
|
||||
endif # VIDEO_CAPTURE_DRIVERS
|
||||
|
@ -88,6 +88,7 @@ obj-$(CONFIG_VIDEO_TUNER) += tuner.o
|
||||
|
||||
obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o
|
||||
obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o
|
||||
obj-$(CONFIG_VIDEOBUF_DMA_CONTIG) += videobuf-dma-contig.o
|
||||
obj-$(CONFIG_VIDEOBUF_VMALLOC) += videobuf-vmalloc.o
|
||||
obj-$(CONFIG_VIDEOBUF_DVB) += videobuf-dvb.o
|
||||
obj-$(CONFIG_VIDEO_BTCX) += btcx-risc.o
|
||||
@ -117,11 +118,13 @@ 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/
|
||||
obj-$(CONFIG_USB_VICAM) += usbvideo/
|
||||
obj-$(CONFIG_USB_QUICKCAM_MESSENGER) += usbvideo/
|
||||
obj-$(CONFIG_USB_S2255) += s2255drv.o
|
||||
|
||||
obj-$(CONFIG_VIDEO_IVTV) += ivtv/
|
||||
obj-$(CONFIG_VIDEO_CX18) += cx18/
|
||||
@ -130,9 +133,11 @@ obj-$(CONFIG_VIDEO_VIVI) += vivi.o
|
||||
obj-$(CONFIG_VIDEO_CX23885) += cx23885/
|
||||
|
||||
obj-$(CONFIG_VIDEO_PXA27x) += pxa_camera.o
|
||||
obj-$(CONFIG_VIDEO_SH_MOBILE_CEU) += sh_mobile_ceu_camera.o
|
||||
obj-$(CONFIG_SOC_CAMERA) += soc_camera.o
|
||||
obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o
|
||||
obj-$(CONFIG_SOC_CAMERA_MT9V022) += mt9v022.o
|
||||
obj-$(CONFIG_SOC_CAMERA_PLATFORM) += soc_camera_platform.o
|
||||
|
||||
obj-$(CONFIG_VIDEO_AU0828) += au0828/
|
||||
|
||||
|
@ -516,7 +516,7 @@ bt819_detect_client (struct i2c_adapter *adapter,
|
||||
|
||||
dprintk(1,
|
||||
KERN_INFO
|
||||
"saa7111.c: detecting bt819 client on address 0x%x\n",
|
||||
"bt819: detecting bt819 client on address 0x%x\n",
|
||||
address << 1);
|
||||
|
||||
/* Check if the adapter supports the needed features */
|
||||
|
@ -179,7 +179,6 @@ static int bt832_attach(struct i2c_adapter *adap, int addr, int kind)
|
||||
|
||||
v4l_info(&t->client,"chip found @ 0x%x\n", addr<<1);
|
||||
|
||||
|
||||
if(! bt832_init(&t->client)) {
|
||||
bt832_detach(&t->client);
|
||||
return -1;
|
||||
|
@ -2448,7 +2448,7 @@ pix_format_set_size (struct v4l2_pix_format * f,
|
||||
}
|
||||
}
|
||||
|
||||
static int bttv_g_fmt_cap(struct file *file, void *priv,
|
||||
static int bttv_g_fmt_vid_cap(struct file *file, void *priv,
|
||||
struct v4l2_format *f)
|
||||
{
|
||||
struct bttv_fh *fh = priv;
|
||||
@ -2461,7 +2461,7 @@ static int bttv_g_fmt_cap(struct file *file, void *priv,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bttv_g_fmt_overlay(struct file *file, void *priv,
|
||||
static int bttv_g_fmt_vid_overlay(struct file *file, void *priv,
|
||||
struct v4l2_format *f)
|
||||
{
|
||||
struct bttv_fh *fh = priv;
|
||||
@ -2472,7 +2472,7 @@ static int bttv_g_fmt_overlay(struct file *file, void *priv,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bttv_try_fmt_cap(struct file *file, void *priv,
|
||||
static int bttv_try_fmt_vid_cap(struct file *file, void *priv,
|
||||
struct v4l2_format *f)
|
||||
{
|
||||
const struct bttv_format *fmt;
|
||||
@ -2532,7 +2532,7 @@ static int bttv_try_fmt_cap(struct file *file, void *priv,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bttv_try_fmt_overlay(struct file *file, void *priv,
|
||||
static int bttv_try_fmt_vid_overlay(struct file *file, void *priv,
|
||||
struct v4l2_format *f)
|
||||
{
|
||||
struct bttv_fh *fh = priv;
|
||||
@ -2542,7 +2542,7 @@ static int bttv_try_fmt_overlay(struct file *file, void *priv,
|
||||
/* adjust_crop */ 0);
|
||||
}
|
||||
|
||||
static int bttv_s_fmt_cap(struct file *file, void *priv,
|
||||
static int bttv_s_fmt_vid_cap(struct file *file, void *priv,
|
||||
struct v4l2_format *f)
|
||||
{
|
||||
int retval;
|
||||
@ -2556,7 +2556,7 @@ static int bttv_s_fmt_cap(struct file *file, void *priv,
|
||||
if (0 != retval)
|
||||
return retval;
|
||||
|
||||
retval = bttv_try_fmt_cap(file, priv, f);
|
||||
retval = bttv_try_fmt_vid_cap(file, priv, f);
|
||||
if (0 != retval)
|
||||
return retval;
|
||||
|
||||
@ -2591,7 +2591,7 @@ static int bttv_s_fmt_cap(struct file *file, void *priv,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bttv_s_fmt_overlay(struct file *file, void *priv,
|
||||
static int bttv_s_fmt_vid_overlay(struct file *file, void *priv,
|
||||
struct v4l2_format *f)
|
||||
{
|
||||
struct bttv_fh *fh = priv;
|
||||
@ -2661,7 +2661,7 @@ static int bttv_querycap(struct file *file, void *priv,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bttv_enum_fmt_vbi(struct file *file, void *priv,
|
||||
static int bttv_enum_fmt_vbi_cap(struct file *file, void *priv,
|
||||
struct v4l2_fmtdesc *f)
|
||||
{
|
||||
if (0 != f->index)
|
||||
@ -2692,7 +2692,7 @@ static int bttv_enum_fmt_cap_ovr(struct v4l2_fmtdesc *f)
|
||||
return i;
|
||||
}
|
||||
|
||||
static int bttv_enum_fmt_cap(struct file *file, void *priv,
|
||||
static int bttv_enum_fmt_vid_cap(struct file *file, void *priv,
|
||||
struct v4l2_fmtdesc *f)
|
||||
{
|
||||
int rc = bttv_enum_fmt_cap_ovr(f);
|
||||
@ -2703,7 +2703,7 @@ static int bttv_enum_fmt_cap(struct file *file, void *priv,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bttv_enum_fmt_overlay(struct file *file, void *priv,
|
||||
static int bttv_enum_fmt_vid_overlay(struct file *file, void *priv,
|
||||
struct v4l2_fmtdesc *f)
|
||||
{
|
||||
int rc;
|
||||
@ -3362,18 +3362,18 @@ static struct video_device bttv_video_template =
|
||||
.fops = &bttv_fops,
|
||||
.minor = -1,
|
||||
.vidioc_querycap = bttv_querycap,
|
||||
.vidioc_enum_fmt_cap = bttv_enum_fmt_cap,
|
||||
.vidioc_g_fmt_cap = bttv_g_fmt_cap,
|
||||
.vidioc_try_fmt_cap = bttv_try_fmt_cap,
|
||||
.vidioc_s_fmt_cap = bttv_s_fmt_cap,
|
||||
.vidioc_enum_fmt_overlay = bttv_enum_fmt_overlay,
|
||||
.vidioc_g_fmt_overlay = bttv_g_fmt_overlay,
|
||||
.vidioc_try_fmt_overlay = bttv_try_fmt_overlay,
|
||||
.vidioc_s_fmt_overlay = bttv_s_fmt_overlay,
|
||||
.vidioc_enum_fmt_vbi = bttv_enum_fmt_vbi,
|
||||
.vidioc_g_fmt_vbi = bttv_g_fmt_vbi,
|
||||
.vidioc_try_fmt_vbi = bttv_try_fmt_vbi,
|
||||
.vidioc_s_fmt_vbi = bttv_s_fmt_vbi,
|
||||
.vidioc_enum_fmt_vid_cap = bttv_enum_fmt_vid_cap,
|
||||
.vidioc_g_fmt_vid_cap = bttv_g_fmt_vid_cap,
|
||||
.vidioc_try_fmt_vid_cap = bttv_try_fmt_vid_cap,
|
||||
.vidioc_s_fmt_vid_cap = bttv_s_fmt_vid_cap,
|
||||
.vidioc_enum_fmt_vid_overlay = bttv_enum_fmt_vid_overlay,
|
||||
.vidioc_g_fmt_vid_overlay = bttv_g_fmt_vid_overlay,
|
||||
.vidioc_try_fmt_vid_overlay = bttv_try_fmt_vid_overlay,
|
||||
.vidioc_s_fmt_vid_overlay = bttv_s_fmt_vid_overlay,
|
||||
.vidioc_enum_fmt_vbi_cap = bttv_enum_fmt_vbi_cap,
|
||||
.vidioc_g_fmt_vbi_cap = bttv_g_fmt_vbi_cap,
|
||||
.vidioc_try_fmt_vbi_cap = bttv_try_fmt_vbi_cap,
|
||||
.vidioc_s_fmt_vbi_cap = bttv_s_fmt_vbi_cap,
|
||||
.vidioc_g_audio = bttv_g_audio,
|
||||
.vidioc_s_audio = bttv_s_audio,
|
||||
.vidioc_cropcap = bttv_cropcap,
|
||||
@ -3705,7 +3705,7 @@ static void bttv_risc_disasm(struct bttv *btv,
|
||||
for (i = 0; i < (risc->size >> 2); i += n) {
|
||||
printk("%s: 0x%lx: ", btv->c.name,
|
||||
(unsigned long)(risc->dma + (i<<2)));
|
||||
n = bttv_risc_decode(risc->cpu[i]);
|
||||
n = bttv_risc_decode(le32_to_cpu(risc->cpu[i]));
|
||||
for (j = 1; j < n; j++)
|
||||
printk("%s: 0x%lx: 0x%08x [ arg #%d ]\n",
|
||||
btv->c.name, (unsigned long)(risc->dma + ((i+j)<<2)),
|
||||
@ -3774,8 +3774,8 @@ static void bttv_irq_debug_low_latency(struct bttv *btv, u32 rc)
|
||||
printk("bttv%d: irq: skipped frame [main=%lx,o_vbi=%lx,o_field=%lx,rc=%lx]\n",
|
||||
btv->c.nr,
|
||||
(unsigned long)btv->main.dma,
|
||||
(unsigned long)btv->main.cpu[RISC_SLOT_O_VBI+1],
|
||||
(unsigned long)btv->main.cpu[RISC_SLOT_O_FIELD+1],
|
||||
(unsigned long)le32_to_cpu(btv->main.cpu[RISC_SLOT_O_VBI+1]),
|
||||
(unsigned long)le32_to_cpu(btv->main.cpu[RISC_SLOT_O_FIELD+1]),
|
||||
(unsigned long)rc);
|
||||
|
||||
if (0 == (btread(BT848_DSTATUS) & BT848_DSTATUS_HLOC)) {
|
||||
@ -4188,6 +4188,7 @@ static struct video_device *vdev_init(struct bttv *btv,
|
||||
vfd->dev = &btv->c.pci->dev;
|
||||
vfd->release = video_device_release;
|
||||
vfd->type = type;
|
||||
vfd->debug = bttv_debug;
|
||||
snprintf(vfd->name, sizeof(vfd->name), "BT%d%s %s (%s)",
|
||||
btv->id, (btv->id==848 && btv->revision==0x12) ? "A" : "",
|
||||
type_name, bttv_tvcards[btv->c.type].name);
|
||||
|
@ -36,11 +36,6 @@
|
||||
#include <linux/jiffies.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
static struct i2c_algo_bit_data bttv_i2c_algo_bit_template;
|
||||
static struct i2c_adapter bttv_i2c_adap_sw_template;
|
||||
static struct i2c_adapter bttv_i2c_adap_hw_template;
|
||||
static struct i2c_client bttv_i2c_client_template;
|
||||
|
||||
static int attach_inform(struct i2c_client *client);
|
||||
|
||||
static int i2c_debug;
|
||||
@ -104,7 +99,7 @@ static int bttv_bit_getsda(void *data)
|
||||
return state;
|
||||
}
|
||||
|
||||
static struct i2c_algo_bit_data bttv_i2c_algo_bit_template = {
|
||||
static struct i2c_algo_bit_data __devinitdata bttv_i2c_algo_bit_template = {
|
||||
.setsda = bttv_bit_setsda,
|
||||
.setscl = bttv_bit_setscl,
|
||||
.getsda = bttv_bit_getsda,
|
||||
@ -113,14 +108,6 @@ static struct i2c_algo_bit_data bttv_i2c_algo_bit_template = {
|
||||
.timeout = 200,
|
||||
};
|
||||
|
||||
static struct i2c_adapter bttv_i2c_adap_sw_template = {
|
||||
.owner = THIS_MODULE,
|
||||
.class = I2C_CLASS_TV_ANALOG,
|
||||
.name = "bttv",
|
||||
.id = I2C_HW_B_BT848,
|
||||
.client_register = attach_inform,
|
||||
};
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
/* I2C functions - hardware i2c */
|
||||
|
||||
@ -270,20 +257,11 @@ static int bttv_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int
|
||||
return retval;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm bttv_algo = {
|
||||
static const struct i2c_algorithm bttv_algo = {
|
||||
.master_xfer = bttv_i2c_xfer,
|
||||
.functionality = functionality,
|
||||
};
|
||||
|
||||
static struct i2c_adapter bttv_i2c_adap_hw_template = {
|
||||
.owner = THIS_MODULE,
|
||||
.class = I2C_CLASS_TV_ANALOG,
|
||||
.name = "bt878",
|
||||
.id = I2C_HW_B_BT848 /* FIXME */,
|
||||
.algo = &bttv_algo,
|
||||
.client_register = attach_inform,
|
||||
};
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
/* I2C functions - common stuff */
|
||||
|
||||
@ -332,10 +310,6 @@ void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg)
|
||||
i2c_clients_command(&btv->c.i2c_adap, cmd, arg);
|
||||
}
|
||||
|
||||
static struct i2c_client bttv_i2c_client_template = {
|
||||
.name = "bttv internal",
|
||||
};
|
||||
|
||||
|
||||
/* read I2C */
|
||||
int bttv_I2CRead(struct bttv *btv, unsigned char addr, char *probe_for)
|
||||
@ -417,29 +391,34 @@ static void do_i2c_scan(char *name, struct i2c_client *c)
|
||||
/* init + register i2c algo-bit adapter */
|
||||
int __devinit init_bttv_i2c(struct bttv *btv)
|
||||
{
|
||||
memcpy(&btv->i2c_client, &bttv_i2c_client_template,
|
||||
sizeof(bttv_i2c_client_template));
|
||||
strlcpy(btv->i2c_client.name, "bttv internal", I2C_NAME_SIZE);
|
||||
|
||||
if (i2c_hw)
|
||||
btv->use_i2c_hw = 1;
|
||||
if (btv->use_i2c_hw) {
|
||||
/* bt878 */
|
||||
memcpy(&btv->c.i2c_adap, &bttv_i2c_adap_hw_template,
|
||||
sizeof(bttv_i2c_adap_hw_template));
|
||||
strlcpy(btv->c.i2c_adap.name, "bt878",
|
||||
sizeof(btv->c.i2c_adap.name));
|
||||
btv->c.i2c_adap.id = I2C_HW_B_BT848; /* FIXME */
|
||||
btv->c.i2c_adap.algo = &bttv_algo;
|
||||
} else {
|
||||
/* bt848 */
|
||||
/* Prevents usage of invalid delay values */
|
||||
if (i2c_udelay<5)
|
||||
i2c_udelay=5;
|
||||
bttv_i2c_algo_bit_template.udelay=i2c_udelay;
|
||||
|
||||
memcpy(&btv->c.i2c_adap, &bttv_i2c_adap_sw_template,
|
||||
sizeof(bttv_i2c_adap_sw_template));
|
||||
strlcpy(btv->c.i2c_adap.name, "bttv",
|
||||
sizeof(btv->c.i2c_adap.name));
|
||||
btv->c.i2c_adap.id = I2C_HW_B_BT848;
|
||||
memcpy(&btv->i2c_algo, &bttv_i2c_algo_bit_template,
|
||||
sizeof(bttv_i2c_algo_bit_template));
|
||||
btv->i2c_algo.udelay = i2c_udelay;
|
||||
btv->i2c_algo.data = btv;
|
||||
btv->c.i2c_adap.algo_data = &btv->i2c_algo;
|
||||
}
|
||||
btv->c.i2c_adap.owner = THIS_MODULE;
|
||||
btv->c.i2c_adap.class = I2C_CLASS_TV_ANALOG;
|
||||
btv->c.i2c_adap.client_register = attach_inform;
|
||||
|
||||
btv->c.i2c_adap.dev.parent = &btv->c.pci->dev;
|
||||
snprintf(btv->c.i2c_adap.name, sizeof(btv->c.i2c_adap.name),
|
||||
|
@ -303,7 +303,7 @@ static int try_fmt(struct v4l2_vbi_format *f, const struct bttv_tvnorm *tvnorm,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bttv_try_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt)
|
||||
int bttv_try_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt)
|
||||
{
|
||||
struct bttv_fh *fh = f;
|
||||
struct bttv *btv = fh->btv;
|
||||
@ -321,7 +321,7 @@ int bttv_try_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt)
|
||||
}
|
||||
|
||||
|
||||
int bttv_s_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt)
|
||||
int bttv_s_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt)
|
||||
{
|
||||
struct bttv_fh *fh = f;
|
||||
struct bttv *btv = fh->btv;
|
||||
@ -369,7 +369,7 @@ int bttv_s_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt)
|
||||
}
|
||||
|
||||
|
||||
int bttv_g_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt)
|
||||
int bttv_g_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt)
|
||||
{
|
||||
struct bttv_fh *fh = f;
|
||||
const struct bttv_tvnorm *tvnorm;
|
||||
|
@ -299,7 +299,6 @@ extern int bttv_write_gpio(unsigned int card,
|
||||
/* ---------------------------------------------------------- */
|
||||
/* sysfs/driver-moded based gpio access interface */
|
||||
|
||||
|
||||
struct bttv_sub_device {
|
||||
struct device dev;
|
||||
struct bttv_core *core;
|
||||
|
@ -39,7 +39,6 @@
|
||||
#include <linux/scatterlist.h>
|
||||
#include <asm/io.h>
|
||||
#include <media/v4l2-common.h>
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <media/videobuf-dma-sg.h>
|
||||
#include <media/tveeprom.h>
|
||||
@ -254,21 +253,19 @@ int bttv_overlay_risc(struct bttv *btv, struct bttv_overlay *ov,
|
||||
/* ---------------------------------------------------------- */
|
||||
/* bttv-vbi.c */
|
||||
|
||||
int bttv_try_fmt_vbi(struct file *file, void *fh, struct v4l2_format *f);
|
||||
int bttv_g_fmt_vbi(struct file *file, void *fh, struct v4l2_format *f);
|
||||
int bttv_s_fmt_vbi(struct file *file, void *fh, struct v4l2_format *f);
|
||||
int bttv_try_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f);
|
||||
int bttv_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f);
|
||||
int bttv_s_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f);
|
||||
|
||||
extern struct videobuf_queue_ops bttv_vbi_qops;
|
||||
|
||||
/* ---------------------------------------------------------- */
|
||||
/* bttv-gpio.c */
|
||||
|
||||
|
||||
extern struct bus_type bttv_sub_bus_type;
|
||||
int bttv_sub_add_device(struct bttv_core *core, char *name);
|
||||
int bttv_sub_del_devices(struct bttv_core *core);
|
||||
|
||||
|
||||
/* ---------------------------------------------------------- */
|
||||
/* bttv-driver.c */
|
||||
|
||||
|
@ -1593,7 +1593,7 @@ static struct v4l2_pix_format cafe_def_pix_format = {
|
||||
.sizeimage = VGA_WIDTH*VGA_HEIGHT*2,
|
||||
};
|
||||
|
||||
static int cafe_vidioc_enum_fmt_cap(struct file *filp,
|
||||
static int cafe_vidioc_enum_fmt_vid_cap(struct file *filp,
|
||||
void *priv, struct v4l2_fmtdesc *fmt)
|
||||
{
|
||||
struct cafe_camera *cam = priv;
|
||||
@ -1608,7 +1608,7 @@ static int cafe_vidioc_enum_fmt_cap(struct file *filp,
|
||||
}
|
||||
|
||||
|
||||
static int cafe_vidioc_try_fmt_cap (struct file *filp, void *priv,
|
||||
static int cafe_vidioc_try_fmt_vid_cap(struct file *filp, void *priv,
|
||||
struct v4l2_format *fmt)
|
||||
{
|
||||
struct cafe_camera *cam = priv;
|
||||
@ -1620,7 +1620,7 @@ static int cafe_vidioc_try_fmt_cap (struct file *filp, void *priv,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cafe_vidioc_s_fmt_cap(struct file *filp, void *priv,
|
||||
static int cafe_vidioc_s_fmt_vid_cap(struct file *filp, void *priv,
|
||||
struct v4l2_format *fmt)
|
||||
{
|
||||
struct cafe_camera *cam = priv;
|
||||
@ -1635,7 +1635,7 @@ static int cafe_vidioc_s_fmt_cap(struct file *filp, void *priv,
|
||||
/*
|
||||
* See if the formatting works in principle.
|
||||
*/
|
||||
ret = cafe_vidioc_try_fmt_cap(filp, priv, fmt);
|
||||
ret = cafe_vidioc_try_fmt_vid_cap(filp, priv, fmt);
|
||||
if (ret)
|
||||
return ret;
|
||||
/*
|
||||
@ -1670,7 +1670,7 @@ static int cafe_vidioc_s_fmt_cap(struct file *filp, void *priv,
|
||||
* The V4l2 spec wants us to be smarter, and actually get this from
|
||||
* the camera (and not mess with it at open time). Someday.
|
||||
*/
|
||||
static int cafe_vidioc_g_fmt_cap(struct file *filp, void *priv,
|
||||
static int cafe_vidioc_g_fmt_vid_cap(struct file *filp, void *priv,
|
||||
struct v4l2_format *f)
|
||||
{
|
||||
struct cafe_camera *cam = priv;
|
||||
@ -1780,10 +1780,10 @@ static struct video_device cafe_v4l_template = {
|
||||
.release = cafe_v4l_dev_release,
|
||||
|
||||
.vidioc_querycap = cafe_vidioc_querycap,
|
||||
.vidioc_enum_fmt_cap = cafe_vidioc_enum_fmt_cap,
|
||||
.vidioc_try_fmt_cap = cafe_vidioc_try_fmt_cap,
|
||||
.vidioc_s_fmt_cap = cafe_vidioc_s_fmt_cap,
|
||||
.vidioc_g_fmt_cap = cafe_vidioc_g_fmt_cap,
|
||||
.vidioc_enum_fmt_vid_cap = cafe_vidioc_enum_fmt_vid_cap,
|
||||
.vidioc_try_fmt_vid_cap = cafe_vidioc_try_fmt_vid_cap,
|
||||
.vidioc_s_fmt_vid_cap = cafe_vidioc_s_fmt_vid_cap,
|
||||
.vidioc_g_fmt_vid_cap = cafe_vidioc_g_fmt_vid_cap,
|
||||
.vidioc_enum_input = cafe_vidioc_enum_input,
|
||||
.vidioc_g_input = cafe_vidioc_g_input,
|
||||
.vidioc_s_input = cafe_vidioc_s_input,
|
||||
|
@ -884,6 +884,7 @@ long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
case VIDIOC_G_INPUT32:
|
||||
case VIDIOC_S_INPUT32:
|
||||
case VIDIOC_TRY_FMT32:
|
||||
case VIDIOC_S_HW_FREQ_SEEK:
|
||||
ret = do_video_ioctl(file, cmd, arg);
|
||||
break;
|
||||
|
||||
|
@ -173,4 +173,3 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
|
||||
.probe = cs5345_probe,
|
||||
.id_table = cs5345_id,
|
||||
};
|
||||
|
||||
|
@ -43,7 +43,6 @@ MODULE_PARM_DESC(debug, "Debugging messages\n\t\t\t0=Off (default), 1=On");
|
||||
|
||||
static unsigned short normal_i2c[] = { 0x22 >> 1, I2C_CLIENT_END };
|
||||
|
||||
|
||||
I2C_CLIENT_INSMOD;
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
@ -189,4 +188,3 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
|
||||
.probe = cs53l32a_probe,
|
||||
.id_table = cs53l32a_id,
|
||||
};
|
||||
|
||||
|
@ -26,13 +26,17 @@
|
||||
#include "cx18-cards.h"
|
||||
#include "cx18-audio.h"
|
||||
|
||||
#define CX18_AUDIO_ENABLE 0xc72014
|
||||
|
||||
/* Selects the audio input and output according to the current
|
||||
settings. */
|
||||
int cx18_audio_set_io(struct cx18 *cx)
|
||||
{
|
||||
struct v4l2_routing route;
|
||||
u32 audio_input;
|
||||
u32 val;
|
||||
int mux_input;
|
||||
int err;
|
||||
|
||||
/* Determine which input to use */
|
||||
if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) {
|
||||
@ -51,8 +55,17 @@ int cx18_audio_set_io(struct cx18 *cx)
|
||||
cx18_i2c_hw(cx, cx->card->hw_muxer, VIDIOC_INT_S_AUDIO_ROUTING, &route);
|
||||
|
||||
route.input = audio_input;
|
||||
return cx18_i2c_hw(cx, cx->card->hw_audio_ctrl,
|
||||
err = cx18_i2c_hw(cx, cx->card->hw_audio_ctrl,
|
||||
VIDIOC_INT_S_AUDIO_ROUTING, &route);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
val = read_reg(CX18_AUDIO_ENABLE) & ~0x30;
|
||||
val |= (audio_input > CX18_AV_AUDIO_SERIAL2) ? 0x20 :
|
||||
(audio_input << 4);
|
||||
write_reg(val | 0xb00, CX18_AUDIO_ENABLE);
|
||||
cx18_vapi(cx, CX18_APU_RESETAI, 1, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cx18_audio_set_route(struct cx18 *cx, struct v4l2_routing *route)
|
||||
|
@ -34,7 +34,7 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq)
|
||||
/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x10 */
|
||||
cx18_av_write(cx, 0x127, 0x50);
|
||||
|
||||
if (state->aud_input != CX18_AV_AUDIO_SERIAL) {
|
||||
if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
|
||||
switch (freq) {
|
||||
case 32000:
|
||||
/* VID_PLL and AUX_PLL */
|
||||
@ -148,7 +148,7 @@ void cx18_av_audio_set_path(struct cx18 *cx)
|
||||
/* Mute everything to prevent the PFFT! */
|
||||
cx18_av_write(cx, 0x8d3, 0x1f);
|
||||
|
||||
if (state->aud_input == CX18_AV_AUDIO_SERIAL) {
|
||||
if (state->aud_input <= CX18_AV_AUDIO_SERIAL2) {
|
||||
/* Set Path1 to Serial Audio Input */
|
||||
cx18_av_write4(cx, 0x8d0, 0x01011012);
|
||||
|
||||
@ -165,7 +165,7 @@ void cx18_av_audio_set_path(struct cx18 *cx)
|
||||
/* deassert soft reset */
|
||||
cx18_av_and_or(cx, 0x810, ~0x1, 0x00);
|
||||
|
||||
if (state->aud_input != CX18_AV_AUDIO_SERIAL) {
|
||||
if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
|
||||
/* When the microcontroller detects the
|
||||
* audio format, it will unmute the lines */
|
||||
cx18_av_and_or(cx, 0x803, ~0x10, 0x10);
|
||||
@ -271,7 +271,7 @@ static void set_mute(struct cx18 *cx, int mute)
|
||||
{
|
||||
struct cx18_av_state *state = &cx->av_state;
|
||||
|
||||
if (state->aud_input != CX18_AV_AUDIO_SERIAL) {
|
||||
if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
|
||||
/* Must turn off microcontroller in order to mute sound.
|
||||
* Not sure if this is the best method, but it does work.
|
||||
* If the microcontroller is running, then it will undo any
|
||||
@ -298,14 +298,14 @@ int cx18_av_audio(struct cx18 *cx, unsigned int cmd, void *arg)
|
||||
|
||||
switch (cmd) {
|
||||
case VIDIOC_INT_AUDIO_CLOCK_FREQ:
|
||||
if (state->aud_input != CX18_AV_AUDIO_SERIAL) {
|
||||
if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
|
||||
cx18_av_and_or(cx, 0x803, ~0x10, 0);
|
||||
cx18_av_write(cx, 0x8d3, 0x1f);
|
||||
}
|
||||
cx18_av_and_or(cx, 0x810, ~0x1, 1);
|
||||
retval = set_audclk_freq(cx, *(u32 *)arg);
|
||||
cx18_av_and_or(cx, 0x810, ~0x1, 0);
|
||||
if (state->aud_input != CX18_AV_AUDIO_SERIAL)
|
||||
if (state->aud_input > CX18_AV_AUDIO_SERIAL2)
|
||||
cx18_av_and_or(cx, 0x803, ~0x10, 0x10);
|
||||
return retval;
|
||||
|
||||
|
@ -69,58 +69,6 @@ int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 and_mask,
|
||||
or_value);
|
||||
}
|
||||
|
||||
int cx18_av_write_no_acfg(struct cx18 *cx, u16 addr, u8 value, int no_acfg_mask)
|
||||
{
|
||||
int retval;
|
||||
u32 saved_reg[8] = {0};
|
||||
|
||||
if (no_acfg_mask & CXADEC_NO_ACFG_AFE) {
|
||||
saved_reg[0] = cx18_av_read4(cx, CXADEC_CHIP_CTRL);
|
||||
saved_reg[1] = cx18_av_read4(cx, CXADEC_AFE_CTRL);
|
||||
}
|
||||
|
||||
if (no_acfg_mask & CXADEC_NO_ACFG_PLL) {
|
||||
saved_reg[2] = cx18_av_read4(cx, CXADEC_PLL_CTRL1);
|
||||
saved_reg[3] = cx18_av_read4(cx, CXADEC_VID_PLL_FRAC);
|
||||
}
|
||||
|
||||
if (no_acfg_mask & CXADEC_NO_ACFG_VID) {
|
||||
saved_reg[4] = cx18_av_read4(cx, CXADEC_HORIZ_TIM_CTRL);
|
||||
saved_reg[5] = cx18_av_read4(cx, CXADEC_VERT_TIM_CTRL);
|
||||
saved_reg[6] = cx18_av_read4(cx, CXADEC_SRC_COMB_CFG);
|
||||
saved_reg[7] = cx18_av_read4(cx, CXADEC_CHROMA_VBIOFF_CFG);
|
||||
}
|
||||
|
||||
retval = cx18_av_write(cx, addr, value);
|
||||
|
||||
if (no_acfg_mask & CXADEC_NO_ACFG_AFE) {
|
||||
cx18_av_write4(cx, CXADEC_CHIP_CTRL, saved_reg[0]);
|
||||
cx18_av_write4(cx, CXADEC_AFE_CTRL, saved_reg[1]);
|
||||
}
|
||||
|
||||
if (no_acfg_mask & CXADEC_NO_ACFG_PLL) {
|
||||
cx18_av_write4(cx, CXADEC_PLL_CTRL1, saved_reg[2]);
|
||||
cx18_av_write4(cx, CXADEC_VID_PLL_FRAC, saved_reg[3]);
|
||||
}
|
||||
|
||||
if (no_acfg_mask & CXADEC_NO_ACFG_VID) {
|
||||
cx18_av_write4(cx, CXADEC_HORIZ_TIM_CTRL, saved_reg[4]);
|
||||
cx18_av_write4(cx, CXADEC_VERT_TIM_CTRL, saved_reg[5]);
|
||||
cx18_av_write4(cx, CXADEC_SRC_COMB_CFG, saved_reg[6]);
|
||||
cx18_av_write4(cx, CXADEC_CHROMA_VBIOFF_CFG, saved_reg[7]);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int cx18_av_and_or_no_acfg(struct cx18 *cx, u16 addr, unsigned and_mask,
|
||||
u8 or_value, int no_acfg_mask)
|
||||
{
|
||||
return cx18_av_write_no_acfg(cx, addr,
|
||||
(cx18_av_read(cx, addr) & and_mask) |
|
||||
or_value, no_acfg_mask);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input,
|
||||
@ -132,6 +80,7 @@ static void log_video_status(struct cx18 *cx);
|
||||
|
||||
static void cx18_av_initialize(struct cx18 *cx)
|
||||
{
|
||||
struct cx18_av_state *state = &cx->av_state;
|
||||
u32 v;
|
||||
|
||||
cx18_av_loadfw(cx);
|
||||
@ -211,6 +160,149 @@ static void cx18_av_initialize(struct cx18 *cx)
|
||||
/* CxDevWrReg(CXADEC_SRC_COMB_CFG, 0x6628021F); */
|
||||
/* } */
|
||||
cx18_av_write4(cx, CXADEC_SRC_COMB_CFG, 0x6628021F);
|
||||
state->default_volume = 228 - cx18_av_read(cx, 0x8d4);
|
||||
state->default_volume = ((state->default_volume / 2) + 23) << 9;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
void cx18_av_std_setup(struct cx18 *cx)
|
||||
{
|
||||
struct cx18_av_state *state = &cx->av_state;
|
||||
v4l2_std_id std = state->std;
|
||||
int hblank, hactive, burst, vblank, vactive, sc;
|
||||
int vblank656, src_decimation;
|
||||
int luma_lpf, uv_lpf, comb;
|
||||
u32 pll_int, pll_frac, pll_post;
|
||||
|
||||
/* datasheet startup, step 8d */
|
||||
if (std & ~V4L2_STD_NTSC)
|
||||
cx18_av_write(cx, 0x49f, 0x11);
|
||||
else
|
||||
cx18_av_write(cx, 0x49f, 0x14);
|
||||
|
||||
if (std & V4L2_STD_625_50) {
|
||||
hblank = 132;
|
||||
hactive = 720;
|
||||
burst = 93;
|
||||
vblank = 36;
|
||||
vactive = 580;
|
||||
vblank656 = 40;
|
||||
src_decimation = 0x21f;
|
||||
|
||||
luma_lpf = 2;
|
||||
if (std & V4L2_STD_PAL) {
|
||||
uv_lpf = 1;
|
||||
comb = 0x20;
|
||||
sc = 688739;
|
||||
} else if (std == V4L2_STD_PAL_Nc) {
|
||||
uv_lpf = 1;
|
||||
comb = 0x20;
|
||||
sc = 556453;
|
||||
} else { /* SECAM */
|
||||
uv_lpf = 0;
|
||||
comb = 0;
|
||||
sc = 672351;
|
||||
}
|
||||
} else {
|
||||
hactive = 720;
|
||||
hblank = 122;
|
||||
vactive = 487;
|
||||
luma_lpf = 1;
|
||||
uv_lpf = 1;
|
||||
vblank = 26;
|
||||
vblank656 = 26;
|
||||
|
||||
src_decimation = 0x21f;
|
||||
if (std == V4L2_STD_PAL_60) {
|
||||
burst = 0x5b;
|
||||
luma_lpf = 2;
|
||||
comb = 0x20;
|
||||
sc = 688739;
|
||||
} else if (std == V4L2_STD_PAL_M) {
|
||||
burst = 0x61;
|
||||
comb = 0x20;
|
||||
sc = 555452;
|
||||
} else {
|
||||
burst = 0x5b;
|
||||
comb = 0x66;
|
||||
sc = 556063;
|
||||
}
|
||||
}
|
||||
|
||||
/* DEBUG: Displays configured PLL frequency */
|
||||
pll_int = cx18_av_read(cx, 0x108);
|
||||
pll_frac = cx18_av_read4(cx, 0x10c) & 0x1ffffff;
|
||||
pll_post = cx18_av_read(cx, 0x109);
|
||||
CX18_DEBUG_INFO("PLL regs = int: %u, frac: %u, post: %u\n",
|
||||
pll_int, pll_frac, pll_post);
|
||||
|
||||
if (pll_post) {
|
||||
int fin, fsc;
|
||||
int pll = 28636363L * ((((u64)pll_int) << 25) + pll_frac);
|
||||
|
||||
pll >>= 25;
|
||||
pll /= pll_post;
|
||||
CX18_DEBUG_INFO("PLL = %d.%06d MHz\n",
|
||||
pll / 1000000, pll % 1000000);
|
||||
CX18_DEBUG_INFO("PLL/8 = %d.%06d MHz\n",
|
||||
pll / 8000000, (pll / 8) % 1000000);
|
||||
|
||||
fin = ((u64)src_decimation * pll) >> 12;
|
||||
CX18_DEBUG_INFO("ADC Sampling freq = %d.%06d MHz\n",
|
||||
fin / 1000000, fin % 1000000);
|
||||
|
||||
fsc = (((u64)sc) * pll) >> 24L;
|
||||
CX18_DEBUG_INFO("Chroma sub-carrier freq = %d.%06d MHz\n",
|
||||
fsc / 1000000, fsc % 1000000);
|
||||
|
||||
CX18_DEBUG_INFO("hblank %i, hactive %i, "
|
||||
"vblank %i , vactive %i, vblank656 %i, src_dec %i,"
|
||||
"burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x,"
|
||||
" sc 0x%06x\n",
|
||||
hblank, hactive, vblank, vactive, vblank656,
|
||||
src_decimation, burst, luma_lpf, uv_lpf, comb, sc);
|
||||
}
|
||||
|
||||
/* Sets horizontal blanking delay and active lines */
|
||||
cx18_av_write(cx, 0x470, hblank);
|
||||
cx18_av_write(cx, 0x471, 0xff & (((hblank >> 8) & 0x3) |
|
||||
(hactive << 4)));
|
||||
cx18_av_write(cx, 0x472, hactive >> 4);
|
||||
|
||||
/* Sets burst gate delay */
|
||||
cx18_av_write(cx, 0x473, burst);
|
||||
|
||||
/* Sets vertical blanking delay and active duration */
|
||||
cx18_av_write(cx, 0x474, vblank);
|
||||
cx18_av_write(cx, 0x475, 0xff & (((vblank >> 8) & 0x3) |
|
||||
(vactive << 4)));
|
||||
cx18_av_write(cx, 0x476, vactive >> 4);
|
||||
cx18_av_write(cx, 0x477, vblank656);
|
||||
|
||||
/* Sets src decimation rate */
|
||||
cx18_av_write(cx, 0x478, 0xff & src_decimation);
|
||||
cx18_av_write(cx, 0x479, 0xff & (src_decimation >> 8));
|
||||
|
||||
/* Sets Luma and UV Low pass filters */
|
||||
cx18_av_write(cx, 0x47a, luma_lpf << 6 | ((uv_lpf << 4) & 0x30));
|
||||
|
||||
/* Enables comb filters */
|
||||
cx18_av_write(cx, 0x47b, comb);
|
||||
|
||||
/* Sets SC Step*/
|
||||
cx18_av_write(cx, 0x47c, sc);
|
||||
cx18_av_write(cx, 0x47d, 0xff & sc >> 8);
|
||||
cx18_av_write(cx, 0x47e, 0xff & sc >> 16);
|
||||
|
||||
/* Sets VBI parameters */
|
||||
if (std & V4L2_STD_625_50) {
|
||||
cx18_av_write(cx, 0x47f, 0x01);
|
||||
state->vbi_line_offset = 5;
|
||||
} else {
|
||||
cx18_av_write(cx, 0x47f, 0x00);
|
||||
state->vbi_line_offset = 8;
|
||||
}
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
@ -221,16 +313,9 @@ static void input_change(struct cx18 *cx)
|
||||
v4l2_std_id std = state->std;
|
||||
|
||||
/* Follow step 8c and 8d of section 3.16 in the cx18_av datasheet */
|
||||
if (std & V4L2_STD_SECAM)
|
||||
cx18_av_write_no_acfg(cx, 0x402, 0, CXADEC_NO_ACFG_ALL);
|
||||
else {
|
||||
cx18_av_write_no_acfg(cx, 0x402, 0x04, CXADEC_NO_ACFG_ALL);
|
||||
cx18_av_write(cx, 0x49f, (std & V4L2_STD_NTSC) ? 0x14 : 0x11);
|
||||
}
|
||||
cx18_av_and_or_no_acfg(cx, 0x401, ~0x60, 0,
|
||||
CXADEC_NO_ACFG_PLL | CXADEC_NO_ACFG_VID);
|
||||
cx18_av_and_or_no_acfg(cx, 0x401, ~0x60, 0x60,
|
||||
CXADEC_NO_ACFG_PLL | CXADEC_NO_ACFG_VID);
|
||||
cx18_av_write(cx, 0x49f, (std & V4L2_STD_NTSC) ? 0x14 : 0x11);
|
||||
cx18_av_and_or(cx, 0x401, ~0x60, 0);
|
||||
cx18_av_and_or(cx, 0x401, ~0x60, 0x60);
|
||||
|
||||
if (std & V4L2_STD_525_60) {
|
||||
if (std == V4L2_STD_NTSC_M_JP) {
|
||||
@ -300,7 +385,8 @@ static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input,
|
||||
}
|
||||
|
||||
switch (aud_input) {
|
||||
case CX18_AV_AUDIO_SERIAL:
|
||||
case CX18_AV_AUDIO_SERIAL1:
|
||||
case CX18_AV_AUDIO_SERIAL2:
|
||||
/* do nothing, use serial audio input */
|
||||
break;
|
||||
case CX18_AV_AUDIO4: reg &= ~0x30; break;
|
||||
@ -316,8 +402,7 @@ static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input,
|
||||
|
||||
cx18_av_write(cx, 0x103, reg);
|
||||
/* Set INPUT_MODE to Composite (0) or S-Video (1) */
|
||||
cx18_av_and_or_no_acfg(cx, 0x401, ~0x6, is_composite ? 0 : 0x02,
|
||||
CXADEC_NO_ACFG_PLL | CXADEC_NO_ACFG_VID);
|
||||
cx18_av_and_or(cx, 0x401, ~0x6, is_composite ? 0 : 0x02);
|
||||
/* Set CH_SEL_ADC2 to 1 if input comes from CH3 */
|
||||
cx18_av_and_or(cx, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0);
|
||||
/* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2 and CH3 */
|
||||
@ -373,13 +458,13 @@ static int set_v4lstd(struct cx18 *cx)
|
||||
This happens for example with the Yuan MPC622. */
|
||||
if (fmt >= 4 && fmt < 8) {
|
||||
/* Set format to NTSC-M */
|
||||
cx18_av_and_or_no_acfg(cx, 0x400, ~0xf, 1, CXADEC_NO_ACFG_AFE);
|
||||
cx18_av_and_or(cx, 0x400, ~0xf, 1);
|
||||
/* Turn off LCOMB */
|
||||
cx18_av_and_or(cx, 0x47b, ~6, 0);
|
||||
}
|
||||
cx18_av_and_or_no_acfg(cx, 0x400, ~0xf, fmt, CXADEC_NO_ACFG_AFE);
|
||||
cx18_av_and_or_no_acfg(cx, 0x403, ~0x3, pal_m, CXADEC_NO_ACFG_ALL);
|
||||
cx18_av_vbi_setup(cx);
|
||||
cx18_av_and_or(cx, 0x400, ~0x2f, fmt | 0x20);
|
||||
cx18_av_and_or(cx, 0x403, ~0x3, pal_m);
|
||||
cx18_av_std_setup(cx);
|
||||
input_change(cx);
|
||||
return 0;
|
||||
}
|
||||
@ -618,6 +703,8 @@ int cx18_av_cmd(struct cx18 *cx, unsigned int cmd, void *arg)
|
||||
|
||||
switch (qc->id) {
|
||||
case V4L2_CID_AUDIO_VOLUME:
|
||||
return v4l2_ctrl_query_fill(qc, 0, 65535,
|
||||
65535 / 100, state->default_volume);
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
case V4L2_CID_AUDIO_BALANCE:
|
||||
case V4L2_CID_AUDIO_BASS:
|
||||
|
@ -62,7 +62,8 @@ enum cx18_av_video_input {
|
||||
|
||||
enum cx18_av_audio_input {
|
||||
/* Audio inputs: serial or In4-In8 */
|
||||
CX18_AV_AUDIO_SERIAL,
|
||||
CX18_AV_AUDIO_SERIAL1,
|
||||
CX18_AV_AUDIO_SERIAL2,
|
||||
CX18_AV_AUDIO4 = 4,
|
||||
CX18_AV_AUDIO5,
|
||||
CX18_AV_AUDIO6,
|
||||
@ -78,6 +79,7 @@ struct cx18_av_state {
|
||||
u32 audclk_freq;
|
||||
int audmode;
|
||||
int vbi_line_offset;
|
||||
int default_volume;
|
||||
u32 id;
|
||||
u32 rev;
|
||||
int is_initialized;
|
||||
@ -295,25 +297,16 @@ struct cx18_av_state {
|
||||
#define CXADEC_SELECT_AUDIO_STANDARD_FM 0xF9 /* FM radio */
|
||||
#define CXADEC_SELECT_AUDIO_STANDARD_AUTO 0xFF /* Auto detect */
|
||||
|
||||
/* Flags on what to preserve on write to 0x400-0x403 with cx18_av_.*_no_acfg()*/
|
||||
#define CXADEC_NO_ACFG_AFE 0x01 /* Preserve 0x100-0x107 */
|
||||
#define CXADEC_NO_ACFG_PLL 0x02 /* Preserve 0x108-0x10f */
|
||||
#define CXADEC_NO_ACFG_VID 0x04 /* Preserve 0x470-0x47f */
|
||||
#define CXADEC_NO_ACFG_ALL 0x07
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
/* cx18_av-core.c */
|
||||
int cx18_av_write(struct cx18 *cx, u16 addr, u8 value);
|
||||
int cx18_av_write4(struct cx18 *cx, u16 addr, u32 value);
|
||||
int cx18_av_write_no_acfg(struct cx18 *cx, u16 addr, u8 value,
|
||||
int no_acfg_mask);
|
||||
u8 cx18_av_read(struct cx18 *cx, u16 addr);
|
||||
u32 cx18_av_read4(struct cx18 *cx, u16 addr);
|
||||
int cx18_av_and_or(struct cx18 *cx, u16 addr, unsigned mask, u8 value);
|
||||
int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 mask, u32 value);
|
||||
int cx18_av_and_or_no_acfg(struct cx18 *cx, u16 addr, unsigned mask, u8 value,
|
||||
int no_acfg_mask);
|
||||
int cx18_av_cmd(struct cx18 *cx, unsigned int cmd, void *arg);
|
||||
void cx18_av_std_setup(struct cx18 *cx);
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
/* cx18_av-firmware.c */
|
||||
@ -326,7 +319,6 @@ void cx18_av_audio_set_path(struct cx18 *cx);
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
/* cx18_av-vbi.c */
|
||||
void cx18_av_vbi_setup(struct cx18 *cx);
|
||||
int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg);
|
||||
|
||||
#endif
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "cx18-driver.h"
|
||||
#include <linux/firmware.h>
|
||||
|
||||
#define CX18_AUDIO_ENABLE 0xc72014
|
||||
#define FWFILE "v4l-cx23418-dig.fw"
|
||||
|
||||
int cx18_av_loadfw(struct cx18 *cx)
|
||||
@ -31,40 +32,58 @@ int cx18_av_loadfw(struct cx18 *cx)
|
||||
u32 v;
|
||||
const u8 *ptr;
|
||||
int i;
|
||||
int retries = 0;
|
||||
|
||||
if (request_firmware(&fw, FWFILE, &cx->dev->dev) != 0) {
|
||||
CX18_ERR("unable to open firmware %s\n", FWFILE);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cx18_av_write4(cx, CXADEC_CHIP_CTRL, 0x00010000);
|
||||
cx18_av_write(cx, CXADEC_STD_DET_CTL, 0xf6); /* Byte 0 */
|
||||
/* The firmware load often has byte errors, so allow for several
|
||||
retries, both at byte level and at the firmware load level. */
|
||||
while (retries < 5) {
|
||||
cx18_av_write4(cx, CXADEC_CHIP_CTRL, 0x00010000);
|
||||
cx18_av_write(cx, CXADEC_STD_DET_CTL, 0xf6);
|
||||
|
||||
/* Reset the Mako core (Register is undocumented.) */
|
||||
cx18_av_write4(cx, 0x8100, 0x00010000);
|
||||
/* Reset the Mako core (Register is undocumented.) */
|
||||
cx18_av_write4(cx, 0x8100, 0x00010000);
|
||||
|
||||
/* Put the 8051 in reset and enable firmware upload */
|
||||
cx18_av_write4(cx, CXADEC_DL_CTL, 0x0F000000);
|
||||
/* Put the 8051 in reset and enable firmware upload */
|
||||
cx18_av_write4(cx, CXADEC_DL_CTL, 0x0F000000);
|
||||
|
||||
ptr = fw->data;
|
||||
size = fw->size;
|
||||
ptr = fw->data;
|
||||
size = fw->size;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
u32 dl_control = 0x0F000000 | ((u32)ptr[i] << 16);
|
||||
u32 value = 0;
|
||||
int retries;
|
||||
for (i = 0; i < size; i++) {
|
||||
u32 dl_control = 0x0F000000 | i | ((u32)ptr[i] << 16);
|
||||
u32 value = 0;
|
||||
int retries;
|
||||
|
||||
for (retries = 0; retries < 5; retries++) {
|
||||
cx18_av_write4(cx, CXADEC_DL_CTL, dl_control);
|
||||
value = cx18_av_read4(cx, CXADEC_DL_CTL);
|
||||
if ((value & 0x3F00) == (dl_control & 0x3F00))
|
||||
for (retries = 0; retries < 5; retries++) {
|
||||
cx18_av_write4(cx, CXADEC_DL_CTL, dl_control);
|
||||
udelay(10);
|
||||
value = cx18_av_read4(cx, CXADEC_DL_CTL);
|
||||
if (value == dl_control)
|
||||
break;
|
||||
/* Check if we can correct the byte by changing
|
||||
the address. We can only write the lower
|
||||
address byte of the address. */
|
||||
if ((value & 0x3F00) != (dl_control & 0x3F00)) {
|
||||
retries = 5;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (retries >= 5)
|
||||
break;
|
||||
}
|
||||
if (retries >= 5) {
|
||||
CX18_ERR("unable to load firmware %s\n", FWFILE);
|
||||
release_firmware(fw);
|
||||
return -EIO;
|
||||
}
|
||||
if (i == size)
|
||||
break;
|
||||
retries++;
|
||||
}
|
||||
if (retries >= 5) {
|
||||
CX18_ERR("unable to load firmware %s\n", FWFILE);
|
||||
release_firmware(fw);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
cx18_av_write4(cx, CXADEC_DL_CTL, 0x13000000 | fw->size);
|
||||
@ -100,7 +119,6 @@ int cx18_av_loadfw(struct cx18 *cx)
|
||||
have a name in the spec. */
|
||||
cx18_av_write4(cx, 0x09CC, 1);
|
||||
|
||||
#define CX18_AUDIO_ENABLE 0xc72014
|
||||
v = read_reg(CX18_AUDIO_ENABLE);
|
||||
/* If bit 11 is 1 */
|
||||
if (v & 0x800)
|
||||
|
@ -83,150 +83,6 @@ static int decode_vps(u8 *dst, u8 *p)
|
||||
return err & 0xf0;
|
||||
}
|
||||
|
||||
void cx18_av_vbi_setup(struct cx18 *cx)
|
||||
{
|
||||
struct cx18_av_state *state = &cx->av_state;
|
||||
v4l2_std_id std = state->std;
|
||||
int hblank, hactive, burst, vblank, vactive, sc;
|
||||
int vblank656, src_decimation;
|
||||
int luma_lpf, uv_lpf, comb;
|
||||
u32 pll_int, pll_frac, pll_post;
|
||||
|
||||
/* datasheet startup, step 8d */
|
||||
if (std & ~V4L2_STD_NTSC)
|
||||
cx18_av_write(cx, 0x49f, 0x11);
|
||||
else
|
||||
cx18_av_write(cx, 0x49f, 0x14);
|
||||
|
||||
if (std & V4L2_STD_625_50) {
|
||||
hblank = 0x084;
|
||||
hactive = 0x2d0;
|
||||
burst = 0x5d;
|
||||
vblank = 0x024;
|
||||
vactive = 0x244;
|
||||
vblank656 = 0x28;
|
||||
src_decimation = 0x21f;
|
||||
|
||||
luma_lpf = 2;
|
||||
if (std & V4L2_STD_SECAM) {
|
||||
uv_lpf = 0;
|
||||
comb = 0;
|
||||
sc = 0x0a425f;
|
||||
} else if (std == V4L2_STD_PAL_Nc) {
|
||||
uv_lpf = 1;
|
||||
comb = 0x20;
|
||||
sc = 556453;
|
||||
} else {
|
||||
uv_lpf = 1;
|
||||
comb = 0x20;
|
||||
sc = 0x0a8263;
|
||||
}
|
||||
} else {
|
||||
hactive = 720;
|
||||
hblank = 122;
|
||||
vactive = 487;
|
||||
luma_lpf = 1;
|
||||
uv_lpf = 1;
|
||||
|
||||
src_decimation = 0x21f;
|
||||
if (std == V4L2_STD_PAL_60) {
|
||||
vblank = 26;
|
||||
vblank656 = 26;
|
||||
burst = 0x5b;
|
||||
luma_lpf = 2;
|
||||
comb = 0x20;
|
||||
sc = 0x0a8263;
|
||||
} else if (std == V4L2_STD_PAL_M) {
|
||||
vblank = 20;
|
||||
vblank656 = 24;
|
||||
burst = 0x61;
|
||||
comb = 0x20;
|
||||
|
||||
sc = 555452;
|
||||
} else {
|
||||
vblank = 26;
|
||||
vblank656 = 26;
|
||||
burst = 0x5b;
|
||||
comb = 0x66;
|
||||
sc = 556063;
|
||||
}
|
||||
}
|
||||
|
||||
/* DEBUG: Displays configured PLL frequency */
|
||||
pll_int = cx18_av_read(cx, 0x108);
|
||||
pll_frac = cx18_av_read4(cx, 0x10c) & 0x1ffffff;
|
||||
pll_post = cx18_av_read(cx, 0x109);
|
||||
CX18_DEBUG_INFO("PLL regs = int: %u, frac: %u, post: %u\n",
|
||||
pll_int, pll_frac, pll_post);
|
||||
|
||||
if (pll_post) {
|
||||
int fin, fsc;
|
||||
int pll = 28636363L * ((((u64)pll_int) << 25) + pll_frac);
|
||||
|
||||
pll >>= 25;
|
||||
pll /= pll_post;
|
||||
CX18_DEBUG_INFO("PLL = %d.%06d MHz\n",
|
||||
pll / 1000000, pll % 1000000);
|
||||
CX18_DEBUG_INFO("PLL/8 = %d.%06d MHz\n",
|
||||
pll / 8000000, (pll / 8) % 1000000);
|
||||
|
||||
fin = ((u64)src_decimation * pll) >> 12;
|
||||
CX18_DEBUG_INFO("ADC Sampling freq = %d.%06d MHz\n",
|
||||
fin / 1000000, fin % 1000000);
|
||||
|
||||
fsc = (((u64)sc) * pll) >> 24L;
|
||||
CX18_DEBUG_INFO("Chroma sub-carrier freq = %d.%06d MHz\n",
|
||||
fsc / 1000000, fsc % 1000000);
|
||||
|
||||
CX18_DEBUG_INFO("hblank %i, hactive %i, "
|
||||
"vblank %i , vactive %i, vblank656 %i, src_dec %i,"
|
||||
"burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x,"
|
||||
" sc 0x%06x\n",
|
||||
hblank, hactive, vblank, vactive, vblank656,
|
||||
src_decimation, burst, luma_lpf, uv_lpf, comb, sc);
|
||||
}
|
||||
|
||||
/* Sets horizontal blanking delay and active lines */
|
||||
cx18_av_write(cx, 0x470, hblank);
|
||||
cx18_av_write(cx, 0x471, 0xff & (((hblank >> 8) & 0x3) |
|
||||
(hactive << 4)));
|
||||
cx18_av_write(cx, 0x472, hactive >> 4);
|
||||
|
||||
/* Sets burst gate delay */
|
||||
cx18_av_write(cx, 0x473, burst);
|
||||
|
||||
/* Sets vertical blanking delay and active duration */
|
||||
cx18_av_write(cx, 0x474, vblank);
|
||||
cx18_av_write(cx, 0x475, 0xff & (((vblank >> 8) & 0x3) |
|
||||
(vactive << 4)));
|
||||
cx18_av_write(cx, 0x476, vactive >> 4);
|
||||
cx18_av_write(cx, 0x477, vblank656);
|
||||
|
||||
/* Sets src decimation rate */
|
||||
cx18_av_write(cx, 0x478, 0xff & src_decimation);
|
||||
cx18_av_write(cx, 0x479, 0xff & (src_decimation >> 8));
|
||||
|
||||
/* Sets Luma and UV Low pass filters */
|
||||
cx18_av_write(cx, 0x47a, luma_lpf << 6 | ((uv_lpf << 4) & 0x30));
|
||||
|
||||
/* Enables comb filters */
|
||||
cx18_av_write(cx, 0x47b, comb);
|
||||
|
||||
/* Sets SC Step*/
|
||||
cx18_av_write(cx, 0x47c, sc);
|
||||
cx18_av_write(cx, 0x47d, 0xff & sc >> 8);
|
||||
cx18_av_write(cx, 0x47e, 0xff & sc >> 16);
|
||||
|
||||
/* Sets VBI parameters */
|
||||
if (std & V4L2_STD_625_50) {
|
||||
cx18_av_write(cx, 0x47f, 0x01);
|
||||
state->vbi_line_offset = 5;
|
||||
} else {
|
||||
cx18_av_write(cx, 0x47f, 0x00);
|
||||
state->vbi_line_offset = 8;
|
||||
}
|
||||
}
|
||||
|
||||
int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg)
|
||||
{
|
||||
struct cx18_av_state *state = &cx->av_state;
|
||||
@ -292,8 +148,8 @@ int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg)
|
||||
/* raw VBI */
|
||||
memset(svbi, 0, sizeof(*svbi));
|
||||
|
||||
/* Setup VBI */
|
||||
cx18_av_vbi_setup(cx);
|
||||
/* Setup standard */
|
||||
cx18_av_std_setup(cx);
|
||||
|
||||
/* VBI Offset */
|
||||
cx18_av_write(cx, 0x47f, vbi_offset);
|
||||
@ -304,8 +160,8 @@ int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg)
|
||||
for (x = 0; x <= 23; x++)
|
||||
lcr[x] = 0x00;
|
||||
|
||||
/* Setup VBI */
|
||||
cx18_av_vbi_setup(cx);
|
||||
/* Setup standard */
|
||||
cx18_av_std_setup(cx);
|
||||
|
||||
/* Sliced VBI */
|
||||
cx18_av_write(cx, 0x404, 0x32); /* Ancillary data */
|
||||
|
@ -27,6 +27,8 @@
|
||||
#include "cx18-i2c.h"
|
||||
#include <media/cs5345.h>
|
||||
|
||||
#define V4L2_STD_PAL_SECAM (V4L2_STD_PAL|V4L2_STD_SECAM)
|
||||
|
||||
/********************** card configuration *******************************/
|
||||
|
||||
/* usual i2c tuner addresses to probe */
|
||||
@ -65,12 +67,12 @@ static const struct cx18_card cx18_card_hvr1600_esmt = {
|
||||
{ CX18_CARD_INPUT_AUD_TUNER,
|
||||
CX18_AV_AUDIO8, CS5345_IN_1 | CS5345_MCLK_1_5 },
|
||||
{ CX18_CARD_INPUT_LINE_IN1,
|
||||
CX18_AV_AUDIO_SERIAL, CS5345_IN_2 },
|
||||
CX18_AV_AUDIO_SERIAL1, CS5345_IN_2 },
|
||||
{ CX18_CARD_INPUT_LINE_IN2,
|
||||
CX18_AV_AUDIO_SERIAL, CS5345_IN_3 },
|
||||
CX18_AV_AUDIO_SERIAL1, CS5345_IN_3 },
|
||||
},
|
||||
.radio_input = { CX18_CARD_INPUT_AUD_TUNER,
|
||||
CX18_AV_AUDIO_SERIAL, CS5345_IN_4 },
|
||||
CX18_AV_AUDIO_SERIAL1, CS5345_IN_4 },
|
||||
.ddr = {
|
||||
/* ESMT M13S128324A-5B memory */
|
||||
.chip_config = 0x003,
|
||||
@ -86,6 +88,7 @@ static const struct cx18_card cx18_card_hvr1600_esmt = {
|
||||
.active_lo_mask = 0x3001,
|
||||
.msecs_asserted = 10,
|
||||
.msecs_recovery = 40,
|
||||
.ir_reset_mask = 0x0001,
|
||||
},
|
||||
.i2c = &cx18_i2c_std,
|
||||
};
|
||||
@ -110,12 +113,12 @@ static const struct cx18_card cx18_card_hvr1600_samsung = {
|
||||
{ CX18_CARD_INPUT_AUD_TUNER,
|
||||
CX18_AV_AUDIO8, CS5345_IN_1 | CS5345_MCLK_1_5 },
|
||||
{ CX18_CARD_INPUT_LINE_IN1,
|
||||
CX18_AV_AUDIO_SERIAL, CS5345_IN_2 },
|
||||
CX18_AV_AUDIO_SERIAL1, CS5345_IN_2 },
|
||||
{ CX18_CARD_INPUT_LINE_IN2,
|
||||
CX18_AV_AUDIO_SERIAL, CS5345_IN_3 },
|
||||
CX18_AV_AUDIO_SERIAL1, CS5345_IN_3 },
|
||||
},
|
||||
.radio_input = { CX18_CARD_INPUT_AUD_TUNER,
|
||||
CX18_AV_AUDIO_SERIAL, CS5345_IN_4 },
|
||||
CX18_AV_AUDIO_SERIAL1, CS5345_IN_4 },
|
||||
.ddr = {
|
||||
/* Samsung K4D263238G-VC33 memory */
|
||||
.chip_config = 0x003,
|
||||
@ -131,6 +134,7 @@ static const struct cx18_card cx18_card_hvr1600_samsung = {
|
||||
.active_lo_mask = 0x3001,
|
||||
.msecs_asserted = 10,
|
||||
.msecs_recovery = 40,
|
||||
.ir_reset_mask = 0x0001,
|
||||
},
|
||||
.i2c = &cx18_i2c_std,
|
||||
};
|
||||
@ -161,10 +165,10 @@ static const struct cx18_card cx18_card_h900 = {
|
||||
{ CX18_CARD_INPUT_AUD_TUNER,
|
||||
CX18_AV_AUDIO8, 0 },
|
||||
{ CX18_CARD_INPUT_LINE_IN1,
|
||||
CX18_AV_AUDIO_SERIAL, 0 },
|
||||
CX18_AV_AUDIO_SERIAL1, 0 },
|
||||
},
|
||||
.radio_input = { CX18_CARD_INPUT_AUD_TUNER,
|
||||
CX18_AV_AUDIO_SERIAL, 0 },
|
||||
CX18_AV_AUDIO_SERIAL1, 0 },
|
||||
.tuners = {
|
||||
{ .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
|
||||
},
|
||||
@ -194,7 +198,7 @@ static const struct cx18_card_pci_info cx18_pci_mpc718[] = {
|
||||
static const struct cx18_card cx18_card_mpc718 = {
|
||||
.type = CX18_CARD_YUAN_MPC718,
|
||||
.name = "Yuan MPC718",
|
||||
.comment = "Some Composite and S-Video inputs are currently working.\n",
|
||||
.comment = "Analog video capture works; some audio line in may not.\n",
|
||||
.v4l2_capabilities = CX18_CAP_ENCODER,
|
||||
.hw_audio_ctrl = CX18_HW_CX23418,
|
||||
.hw_all = CX18_HW_TUNER,
|
||||
@ -209,11 +213,11 @@ static const struct cx18_card cx18_card_mpc718 = {
|
||||
{ CX18_CARD_INPUT_COMPOSITE3, 2, CX18_AV_COMPOSITE3 },
|
||||
},
|
||||
.audio_inputs = {
|
||||
{ CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 0 },
|
||||
{ CX18_CARD_INPUT_LINE_IN1, CX18_AV_AUDIO_SERIAL, 0 },
|
||||
{ CX18_CARD_INPUT_LINE_IN2, CX18_AV_AUDIO_SERIAL, 0 },
|
||||
{ CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 0 },
|
||||
{ CX18_CARD_INPUT_LINE_IN1, CX18_AV_AUDIO_SERIAL1, 0 },
|
||||
{ CX18_CARD_INPUT_LINE_IN2, CX18_AV_AUDIO_SERIAL1, 0 },
|
||||
},
|
||||
.radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO_SERIAL, 0 },
|
||||
.radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO_SERIAL1, 0 },
|
||||
.tuners = {
|
||||
/* XC3028 tuner */
|
||||
{ .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
|
||||
@ -227,16 +231,73 @@ static const struct cx18_card cx18_card_mpc718 = {
|
||||
.tune_lane = 0,
|
||||
.initial_emrs = 2,
|
||||
},
|
||||
.xceive_pin = 15,
|
||||
.xceive_pin = 0,
|
||||
.pci_list = cx18_pci_mpc718,
|
||||
.i2c = &cx18_i2c_std,
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
/* Conexant Raptor PAL/SECAM: note that this card is analog only! */
|
||||
|
||||
static const struct cx18_card_pci_info cx18_pci_cnxt_raptor_pal[] = {
|
||||
{ PCI_DEVICE_ID_CX23418, CX18_PCI_ID_CONEXANT, 0x0009 },
|
||||
{ 0, 0, 0 }
|
||||
};
|
||||
|
||||
static const struct cx18_card cx18_card_cnxt_raptor_pal = {
|
||||
.type = CX18_CARD_CNXT_RAPTOR_PAL,
|
||||
.name = "Conexant Raptor PAL/SECAM",
|
||||
.comment = "VBI is not yet supported\n",
|
||||
.v4l2_capabilities = CX18_CAP_ENCODER,
|
||||
.hw_audio_ctrl = CX18_HW_CX23418,
|
||||
.hw_muxer = CX18_HW_GPIO,
|
||||
.hw_all = CX18_HW_TUNER | CX18_HW_GPIO,
|
||||
.video_inputs = {
|
||||
{ CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE2 },
|
||||
{ CX18_CARD_INPUT_SVIDEO1, 1,
|
||||
CX18_AV_SVIDEO_LUMA3 | CX18_AV_SVIDEO_CHROMA4 },
|
||||
{ CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE1 },
|
||||
{ CX18_CARD_INPUT_SVIDEO2, 2,
|
||||
CX18_AV_SVIDEO_LUMA7 | CX18_AV_SVIDEO_CHROMA8 },
|
||||
{ CX18_CARD_INPUT_COMPOSITE2, 2, CX18_AV_COMPOSITE6 },
|
||||
},
|
||||
.audio_inputs = {
|
||||
{ CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 0 },
|
||||
{ CX18_CARD_INPUT_LINE_IN1, CX18_AV_AUDIO_SERIAL1, 1 },
|
||||
{ CX18_CARD_INPUT_LINE_IN2, CX18_AV_AUDIO_SERIAL2, 1 },
|
||||
},
|
||||
.tuners = {
|
||||
{ .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
|
||||
},
|
||||
.radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO_SERIAL1, 2 },
|
||||
.ddr = {
|
||||
/* MT 46V16M16 memory */
|
||||
.chip_config = 0x50306,
|
||||
.refresh = 0x753,
|
||||
.timing1 = 0x33220953,
|
||||
.timing2 = 0x09,
|
||||
.tune_lane = 0,
|
||||
.initial_emrs = 0,
|
||||
},
|
||||
.gpio_init.initial_value = 0x1002,
|
||||
.gpio_init.direction = 0xf002,
|
||||
.gpio_audio_input = { .mask = 0xf002,
|
||||
.tuner = 0x1002, /* LED D1 Tuner AF */
|
||||
.linein = 0x2000, /* LED D2 Line In 1 */
|
||||
.radio = 0x4002 }, /* LED D3 Tuner AF */
|
||||
.pci_list = cx18_pci_cnxt_raptor_pal,
|
||||
.i2c = &cx18_i2c_std,
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
static const struct cx18_card *cx18_card_list[] = {
|
||||
&cx18_card_hvr1600_esmt,
|
||||
&cx18_card_hvr1600_samsung,
|
||||
&cx18_card_h900,
|
||||
&cx18_card_mpc718,
|
||||
&cx18_card_cnxt_raptor_pal,
|
||||
};
|
||||
|
||||
const struct cx18_card *cx18_get_card(u16 index)
|
||||
|
@ -83,6 +83,14 @@ struct cx18_gpio_i2c_slave_reset {
|
||||
u32 active_hi_mask; /* GPIO outputs that reset i2c chips when high */
|
||||
int msecs_asserted; /* time period reset must remain asserted */
|
||||
int msecs_recovery; /* time after deassert for chips to be ready */
|
||||
u32 ir_reset_mask; /* GPIO to reset the Zilog Z8F0811 IR contoller */
|
||||
};
|
||||
|
||||
struct cx18_gpio_audio_input { /* select tuner/line in input */
|
||||
u32 mask; /* leave to 0 if not supported */
|
||||
u32 tuner;
|
||||
u32 linein;
|
||||
u32 radio;
|
||||
};
|
||||
|
||||
struct cx18_card_tuner {
|
||||
@ -123,6 +131,7 @@ struct cx18_card {
|
||||
u8 xceive_pin; /* XCeive tuner GPIO reset pin */
|
||||
struct cx18_gpio_init gpio_init;
|
||||
struct cx18_gpio_i2c_slave_reset gpio_i2c_slave_reset;
|
||||
struct cx18_gpio_audio_input gpio_audio_input;
|
||||
|
||||
struct cx18_card_tuner tuners[CX18_CARD_MAX_TUNERS];
|
||||
struct cx18_card_tuner_i2c *i2c;
|
||||
|
@ -51,12 +51,11 @@ static const u32 *ctrl_classes[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
static int cx18_queryctrl(struct cx18 *cx, struct v4l2_queryctrl *qctrl)
|
||||
int cx18_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qctrl)
|
||||
{
|
||||
struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
|
||||
const char *name;
|
||||
|
||||
CX18_DEBUG_IOCTL("VIDIOC_QUERYCTRL(%08x)\n", qctrl->id);
|
||||
|
||||
qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
|
||||
if (qctrl->id == 0)
|
||||
return -EINVAL;
|
||||
@ -91,21 +90,35 @@ static int cx18_queryctrl(struct cx18 *cx, struct v4l2_queryctrl *qctrl)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cx18_querymenu(struct cx18 *cx, struct v4l2_querymenu *qmenu)
|
||||
int cx18_querymenu(struct file *file, void *fh, struct v4l2_querymenu *qmenu)
|
||||
{
|
||||
struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
|
||||
struct v4l2_queryctrl qctrl;
|
||||
|
||||
qctrl.id = qmenu->id;
|
||||
cx18_queryctrl(cx, &qctrl);
|
||||
return v4l2_ctrl_query_menu(qmenu, &qctrl, cx2341x_ctrl_get_menu(qmenu->id));
|
||||
cx18_queryctrl(file, fh, &qctrl);
|
||||
return v4l2_ctrl_query_menu(qmenu, &qctrl,
|
||||
cx2341x_ctrl_get_menu(&cx->params, qmenu->id));
|
||||
}
|
||||
|
||||
static int cx18_try_ctrl(struct file *file, void *fh,
|
||||
struct v4l2_ext_control *vctrl)
|
||||
{
|
||||
struct v4l2_queryctrl qctrl;
|
||||
const char **menu_items = NULL;
|
||||
int err;
|
||||
|
||||
qctrl.id = vctrl->id;
|
||||
err = cx18_queryctrl(file, fh, &qctrl);
|
||||
if (err)
|
||||
return err;
|
||||
if (qctrl.type == V4L2_CTRL_TYPE_MENU)
|
||||
menu_items = v4l2_ctrl_get_menu(qctrl.id);
|
||||
return v4l2_ctrl_check(vctrl, &qctrl, menu_items);
|
||||
}
|
||||
|
||||
static int cx18_s_ctrl(struct cx18 *cx, struct v4l2_control *vctrl)
|
||||
{
|
||||
s32 v = vctrl->value;
|
||||
|
||||
CX18_DEBUG_IOCTL("VIDIOC_S_CTRL(%08x, %x)\n", vctrl->id, v);
|
||||
|
||||
switch (vctrl->id) {
|
||||
/* Standard V4L2 controls */
|
||||
case V4L2_CID_BRIGHTNESS:
|
||||
@ -123,7 +136,7 @@ static int cx18_s_ctrl(struct cx18 *cx, struct v4l2_control *vctrl)
|
||||
return cx18_i2c_hw(cx, cx->card->hw_audio_ctrl, VIDIOC_S_CTRL, vctrl);
|
||||
|
||||
default:
|
||||
CX18_DEBUG_IOCTL("invalid control %x\n", vctrl->id);
|
||||
CX18_DEBUG_IOCTL("invalid control 0x%x\n", vctrl->id);
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
@ -131,8 +144,6 @@ static int cx18_s_ctrl(struct cx18 *cx, struct v4l2_control *vctrl)
|
||||
|
||||
static int cx18_g_ctrl(struct cx18 *cx, struct v4l2_control *vctrl)
|
||||
{
|
||||
CX18_DEBUG_IOCTL("VIDIOC_G_CTRL(%08x)\n", vctrl->id);
|
||||
|
||||
switch (vctrl->id) {
|
||||
/* Standard V4L2 controls */
|
||||
case V4L2_CID_BRIGHTNESS:
|
||||
@ -149,7 +160,7 @@ static int cx18_g_ctrl(struct cx18 *cx, struct v4l2_control *vctrl)
|
||||
case V4L2_CID_AUDIO_LOUDNESS:
|
||||
return cx18_i2c_hw(cx, cx->card->hw_audio_ctrl, VIDIOC_G_CTRL, vctrl);
|
||||
default:
|
||||
CX18_DEBUG_IOCTL("invalid control %x\n", vctrl->id);
|
||||
CX18_DEBUG_IOCTL("invalid control 0x%x\n", vctrl->id);
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
@ -194,113 +205,110 @@ static int cx18_setup_vbi_fmt(struct cx18 *cx, enum v4l2_mpeg_stream_vbi_fmt fmt
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cx18_control_ioctls(struct cx18 *cx, unsigned int cmd, void *arg)
|
||||
int cx18_g_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
|
||||
{
|
||||
struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
|
||||
struct v4l2_control ctrl;
|
||||
|
||||
switch (cmd) {
|
||||
case VIDIOC_QUERYMENU:
|
||||
CX18_DEBUG_IOCTL("VIDIOC_QUERYMENU\n");
|
||||
return cx18_querymenu(cx, arg);
|
||||
if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
|
||||
int i;
|
||||
int err = 0;
|
||||
|
||||
case VIDIOC_QUERYCTRL:
|
||||
return cx18_queryctrl(cx, arg);
|
||||
|
||||
case VIDIOC_S_CTRL:
|
||||
return cx18_s_ctrl(cx, arg);
|
||||
|
||||
case VIDIOC_G_CTRL:
|
||||
return cx18_g_ctrl(cx, arg);
|
||||
|
||||
case VIDIOC_S_EXT_CTRLS:
|
||||
{
|
||||
struct v4l2_ext_controls *c = arg;
|
||||
|
||||
if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
|
||||
int i;
|
||||
int err = 0;
|
||||
|
||||
for (i = 0; i < c->count; i++) {
|
||||
ctrl.id = c->controls[i].id;
|
||||
ctrl.value = c->controls[i].value;
|
||||
err = cx18_s_ctrl(cx, &ctrl);
|
||||
c->controls[i].value = ctrl.value;
|
||||
if (err) {
|
||||
c->error_idx = i;
|
||||
break;
|
||||
}
|
||||
for (i = 0; i < c->count; i++) {
|
||||
ctrl.id = c->controls[i].id;
|
||||
ctrl.value = c->controls[i].value;
|
||||
err = cx18_g_ctrl(cx, &ctrl);
|
||||
c->controls[i].value = ctrl.value;
|
||||
if (err) {
|
||||
c->error_idx = i;
|
||||
break;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
CX18_DEBUG_IOCTL("VIDIOC_S_EXT_CTRLS\n");
|
||||
if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
|
||||
struct cx2341x_mpeg_params p = cx->params;
|
||||
int err = cx2341x_ext_ctrls(&p, atomic_read(&cx->ana_capturing), arg, cmd);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (p.video_encoding != cx->params.video_encoding) {
|
||||
int is_mpeg1 = p.video_encoding ==
|
||||
V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
|
||||
struct v4l2_format fmt;
|
||||
|
||||
/* fix videodecoder resolution */
|
||||
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
fmt.fmt.pix.width = cx->params.width / (is_mpeg1 ? 2 : 1);
|
||||
fmt.fmt.pix.height = cx->params.height;
|
||||
cx18_av_cmd(cx, VIDIOC_S_FMT, &fmt);
|
||||
}
|
||||
err = cx2341x_update(cx, cx18_api_func, &cx->params, &p);
|
||||
if (!err && cx->params.stream_vbi_fmt != p.stream_vbi_fmt)
|
||||
err = cx18_setup_vbi_fmt(cx, p.stream_vbi_fmt);
|
||||
cx->params = p;
|
||||
cx->dualwatch_stereo_mode = p.audio_properties & 0x0300;
|
||||
cx18_audio_set_audio_clock_freq(cx, p.audio_properties & 0x03);
|
||||
return err;
|
||||
}
|
||||
return -EINVAL;
|
||||
return err;
|
||||
}
|
||||
|
||||
case VIDIOC_G_EXT_CTRLS:
|
||||
{
|
||||
struct v4l2_ext_controls *c = arg;
|
||||
|
||||
if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
|
||||
int i;
|
||||
int err = 0;
|
||||
|
||||
for (i = 0; i < c->count; i++) {
|
||||
ctrl.id = c->controls[i].id;
|
||||
ctrl.value = c->controls[i].value;
|
||||
err = cx18_g_ctrl(cx, &ctrl);
|
||||
c->controls[i].value = ctrl.value;
|
||||
if (err) {
|
||||
c->error_idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return err;
|
||||
}
|
||||
CX18_DEBUG_IOCTL("VIDIOC_G_EXT_CTRLS\n");
|
||||
if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG)
|
||||
return cx2341x_ext_ctrls(&cx->params, 0, arg, cmd);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
case VIDIOC_TRY_EXT_CTRLS:
|
||||
{
|
||||
struct v4l2_ext_controls *c = arg;
|
||||
|
||||
CX18_DEBUG_IOCTL("VIDIOC_TRY_EXT_CTRLS\n");
|
||||
if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG)
|
||||
return cx2341x_ext_ctrls(&cx->params,
|
||||
atomic_read(&cx->ana_capturing), arg, cmd);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG)
|
||||
return cx2341x_ext_ctrls(&cx->params, 0, c, VIDIOC_G_EXT_CTRLS);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int cx18_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
|
||||
{
|
||||
struct cx18_open_id *id = fh;
|
||||
struct cx18 *cx = id->cx;
|
||||
int ret;
|
||||
struct v4l2_control ctrl;
|
||||
|
||||
ret = v4l2_prio_check(&cx->prio, &id->prio);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
|
||||
int i;
|
||||
int err = 0;
|
||||
|
||||
for (i = 0; i < c->count; i++) {
|
||||
ctrl.id = c->controls[i].id;
|
||||
ctrl.value = c->controls[i].value;
|
||||
err = cx18_s_ctrl(cx, &ctrl);
|
||||
c->controls[i].value = ctrl.value;
|
||||
if (err) {
|
||||
c->error_idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return err;
|
||||
}
|
||||
if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
|
||||
struct cx2341x_mpeg_params p = cx->params;
|
||||
int err = cx2341x_ext_ctrls(&p, atomic_read(&cx->ana_capturing),
|
||||
c, VIDIOC_S_EXT_CTRLS);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (p.video_encoding != cx->params.video_encoding) {
|
||||
int is_mpeg1 = p.video_encoding ==
|
||||
V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
|
||||
struct v4l2_format fmt;
|
||||
|
||||
/* fix videodecoder resolution */
|
||||
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
fmt.fmt.pix.width = cx->params.width
|
||||
/ (is_mpeg1 ? 2 : 1);
|
||||
fmt.fmt.pix.height = cx->params.height;
|
||||
cx18_av_cmd(cx, VIDIOC_S_FMT, &fmt);
|
||||
}
|
||||
err = cx2341x_update(cx, cx18_api_func, &cx->params, &p);
|
||||
if (!err && cx->params.stream_vbi_fmt != p.stream_vbi_fmt)
|
||||
err = cx18_setup_vbi_fmt(cx, p.stream_vbi_fmt);
|
||||
cx->params = p;
|
||||
cx->dualwatch_stereo_mode = p.audio_properties & 0x0300;
|
||||
cx18_audio_set_audio_clock_freq(cx, p.audio_properties & 0x03);
|
||||
return err;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int cx18_try_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
|
||||
{
|
||||
struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
|
||||
|
||||
if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
|
||||
int i;
|
||||
int err = 0;
|
||||
|
||||
for (i = 0; i < c->count; i++) {
|
||||
err = cx18_try_ctrl(file, fh, &c->controls[i]);
|
||||
if (err) {
|
||||
c->error_idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return err;
|
||||
}
|
||||
if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG)
|
||||
return cx2341x_ext_ctrls(&cx->params,
|
||||
atomic_read(&cx->ana_capturing),
|
||||
c, VIDIOC_TRY_EXT_CTRLS);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -21,4 +21,9 @@
|
||||
* 02111-1307 USA
|
||||
*/
|
||||
|
||||
int cx18_control_ioctls(struct cx18 *cx, unsigned int cmd, void *arg);
|
||||
int cx18_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *a);
|
||||
int cx18_g_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *a);
|
||||
int cx18_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *a);
|
||||
int cx18_try_ext_ctrls(struct file *file, void *fh,
|
||||
struct v4l2_ext_controls *a);
|
||||
int cx18_querymenu(struct file *file, void *fh, struct v4l2_querymenu *a);
|
||||
|
@ -120,6 +120,7 @@ MODULE_PARM_DESC(cardtype,
|
||||
"\t\t\t 2 = Hauppauge HVR 1600 (Samsung memory)\n"
|
||||
"\t\t\t 3 = Compro VideoMate H900\n"
|
||||
"\t\t\t 4 = Yuan MPC718\n"
|
||||
"\t\t\t 5 = Conexant Raptor PAL/SECAM\n"
|
||||
"\t\t\t 0 = Autodetect (default)\n"
|
||||
"\t\t\t-1 = Ignore this card\n\t\t");
|
||||
MODULE_PARM_DESC(pal, "Set PAL standard: B, G, H, D, K, I, M, N, Nc, 60");
|
||||
@ -420,6 +421,7 @@ static int __devinit cx18_init_struct1(struct cx18 *cx)
|
||||
mutex_init(&cx->serialize_lock);
|
||||
mutex_init(&cx->i2c_bus_lock[0]);
|
||||
mutex_init(&cx->i2c_bus_lock[1]);
|
||||
mutex_init(&cx->gpio_lock);
|
||||
|
||||
spin_lock_init(&cx->lock);
|
||||
spin_lock_init(&cx->dma_reg_lock);
|
||||
@ -435,7 +437,7 @@ static int __devinit cx18_init_struct1(struct cx18 *cx)
|
||||
(cx->params.video_temporal_filter_mode << 1) |
|
||||
(cx->params.video_median_filter_type << 2);
|
||||
cx->params.port = CX2341X_PORT_MEMORY;
|
||||
cx->params.capabilities = CX2341X_CAP_HAS_SLICED_VBI;
|
||||
cx->params.capabilities = CX2341X_CAP_HAS_TS;
|
||||
init_waitqueue_head(&cx->cap_w);
|
||||
init_waitqueue_head(&cx->mb_apu_waitq);
|
||||
init_waitqueue_head(&cx->mb_cpu_waitq);
|
||||
@ -614,7 +616,7 @@ static int __devinit cx18_probe(struct pci_dev *dev,
|
||||
cx18_cards[cx18_cards_active] = cx;
|
||||
cx->dev = dev;
|
||||
cx->num = cx18_cards_active++;
|
||||
snprintf(cx->name, sizeof(cx->name) - 1, "cx18-%d", cx->num);
|
||||
snprintf(cx->name, sizeof(cx->name), "cx18-%d", cx->num);
|
||||
CX18_INFO("Initializing card #%d\n", cx->num);
|
||||
|
||||
spin_unlock(&cx18_cards_lock);
|
||||
@ -721,6 +723,12 @@ static int __devinit cx18_probe(struct pci_dev *dev,
|
||||
/* if no tuner was found, then pick the first tuner in the card list */
|
||||
if (cx->options.tuner == -1 && cx->card->tuners[0].std) {
|
||||
cx->std = cx->card->tuners[0].std;
|
||||
if (cx->std & V4L2_STD_PAL)
|
||||
cx->std = V4L2_STD_PAL_BG | V4L2_STD_PAL_H;
|
||||
else if (cx->std & V4L2_STD_NTSC)
|
||||
cx->std = V4L2_STD_NTSC_M;
|
||||
else if (cx->std & V4L2_STD_SECAM)
|
||||
cx->std = V4L2_STD_SECAM_L;
|
||||
cx->options.tuner = cx->card->tuners[0].tuner;
|
||||
}
|
||||
if (cx->options.radio == -1)
|
||||
@ -818,6 +826,9 @@ int cx18_init_on_first_open(struct cx18 *cx)
|
||||
int video_input;
|
||||
int fw_retry_count = 3;
|
||||
struct v4l2_frequency vf;
|
||||
struct cx18_open_id fh;
|
||||
|
||||
fh.cx = cx;
|
||||
|
||||
if (test_bit(CX18_F_I_FAILED, &cx->i_flags))
|
||||
return -ENXIO;
|
||||
@ -869,13 +880,13 @@ int cx18_init_on_first_open(struct cx18 *cx)
|
||||
|
||||
video_input = cx->active_input;
|
||||
cx->active_input++; /* Force update of input */
|
||||
cx18_v4l2_ioctls(cx, NULL, VIDIOC_S_INPUT, &video_input);
|
||||
cx18_s_input(NULL, &fh, video_input);
|
||||
|
||||
/* Let the VIDIOC_S_STD ioctl do all the work, keeps the code
|
||||
in one place. */
|
||||
cx->std++; /* Force full standard initialization */
|
||||
cx18_v4l2_ioctls(cx, NULL, VIDIOC_S_STD, &cx->tuner_std);
|
||||
cx18_v4l2_ioctls(cx, NULL, VIDIOC_S_FREQUENCY, &vf);
|
||||
cx18_s_std(NULL, &fh, &cx->tuner_std);
|
||||
cx18_s_frequency(NULL, &fh, &vf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -75,7 +75,8 @@
|
||||
#define CX18_CARD_HVR_1600_SAMSUNG 1 /* Hauppauge HVR 1600 (Samsung memory) */
|
||||
#define CX18_CARD_COMPRO_H900 2 /* Compro VideoMate H900 */
|
||||
#define CX18_CARD_YUAN_MPC718 3 /* Yuan MPC718 */
|
||||
#define CX18_CARD_LAST 3
|
||||
#define CX18_CARD_CNXT_RAPTOR_PAL 4 /* Conexant Raptor PAL */
|
||||
#define CX18_CARD_LAST 4
|
||||
|
||||
#define CX18_ENC_STREAM_TYPE_MPG 0
|
||||
#define CX18_ENC_STREAM_TYPE_TS 1
|
||||
@ -94,6 +95,7 @@
|
||||
#define CX18_PCI_ID_HAUPPAUGE 0x0070
|
||||
#define CX18_PCI_ID_COMPRO 0x185b
|
||||
#define CX18_PCI_ID_YUAN 0x12ab
|
||||
#define CX18_PCI_ID_CONEXANT 0x14f1
|
||||
|
||||
/* ======================================================================== */
|
||||
/* ========================== START USER SETTABLE DMA VARIABLES =========== */
|
||||
@ -228,9 +230,7 @@ struct cx18_dvb {
|
||||
struct dvb_net dvbnet;
|
||||
int enabled;
|
||||
int feeding;
|
||||
|
||||
struct mutex feedlock;
|
||||
|
||||
};
|
||||
|
||||
struct cx18; /* forward reference */
|
||||
@ -427,6 +427,7 @@ struct cx18 {
|
||||
/* gpio */
|
||||
u32 gpio_dir;
|
||||
u32 gpio_val;
|
||||
struct mutex gpio_lock;
|
||||
|
||||
/* v4l2 and User settings */
|
||||
|
||||
|
@ -41,9 +41,6 @@
|
||||
|
||||
#define CX18_REG_BUS_TIMEOUT_EN 0xc72024
|
||||
|
||||
#define CX18_AUDIO_ENABLE 0xc72014
|
||||
#define CX18_REG_BUS_TIMEOUT_EN 0xc72024
|
||||
|
||||
#define CX18_FAST_CLOCK_PLL_INT 0xc78000
|
||||
#define CX18_FAST_CLOCK_PLL_FRAC 0xc78004
|
||||
#define CX18_FAST_CLOCK_PLL_POST 0xc78008
|
||||
@ -90,7 +87,7 @@
|
||||
#define CX18_DSP0_INTERRUPT_MASK 0xd0004C
|
||||
|
||||
/* Encoder/decoder firmware sizes */
|
||||
#define CX18_FW_CPU_SIZE (174716)
|
||||
#define CX18_FW_CPU_SIZE (158332)
|
||||
#define CX18_FW_APU_SIZE (141200)
|
||||
|
||||
#define APU_ROM_SYNC1 0x6D676553 /* "mgeS" */
|
||||
@ -345,6 +342,11 @@ int cx18_firmware_init(struct cx18 *cx)
|
||||
int sz = load_apu_fw_direct("v4l-cx23418-apu.fw",
|
||||
cx->enc_mem, cx, CX18_FW_APU_SIZE);
|
||||
|
||||
write_enc(0xE51FF004, 0);
|
||||
write_enc(0xa00000, 4); /* todo: not hardcoded */
|
||||
write_reg(0x00010000, CX18_PROC_SOFT_RESET); /* Start APU */
|
||||
cx18_msleep_timeout(500, 0);
|
||||
|
||||
sz = sz <= 0 ? sz : load_cpu_fw_direct("v4l-cx23418-cpu.fw",
|
||||
cx->enc_mem, cx, CX18_FW_CPU_SIZE);
|
||||
|
||||
|
@ -69,6 +69,7 @@ void cx18_reset_i2c_slaves_gpio(struct cx18 *cx)
|
||||
/* Assuming that the masks are a subset of the bits in gpio_dir */
|
||||
|
||||
/* Assert */
|
||||
mutex_lock(&cx->gpio_lock);
|
||||
cx->gpio_val =
|
||||
(cx->gpio_val | p->active_hi_mask) & ~(p->active_lo_mask);
|
||||
gpio_write(cx);
|
||||
@ -79,10 +80,53 @@ void cx18_reset_i2c_slaves_gpio(struct cx18 *cx)
|
||||
(cx->gpio_val | p->active_lo_mask) & ~(p->active_hi_mask);
|
||||
gpio_write(cx);
|
||||
schedule_timeout_uninterruptible(msecs_to_jiffies(p->msecs_recovery));
|
||||
mutex_unlock(&cx->gpio_lock);
|
||||
}
|
||||
|
||||
void cx18_reset_ir_gpio(void *data)
|
||||
{
|
||||
struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx;
|
||||
const struct cx18_gpio_i2c_slave_reset *p;
|
||||
|
||||
p = &cx->card->gpio_i2c_slave_reset;
|
||||
|
||||
if (p->ir_reset_mask == 0)
|
||||
return;
|
||||
|
||||
CX18_DEBUG_INFO("Resetting IR microcontroller\n");
|
||||
|
||||
/*
|
||||
Assert timing for the Z8F0811 on HVR-1600 boards:
|
||||
1. Assert RESET for min of 4 clock cycles at 18.432 MHz to initiate
|
||||
2. Reset then takes 66 WDT cycles at 10 kHz + 16 xtal clock cycles
|
||||
(6,601,085 nanoseconds ~= 7 milliseconds)
|
||||
3. DBG pin must be high before chip exits reset for normal operation.
|
||||
DBG is open drain and hopefully pulled high since we don't
|
||||
normally drive it (GPIO 1?) for the HVR-1600
|
||||
4. Z8F0811 won't exit reset until RESET is deasserted
|
||||
*/
|
||||
mutex_lock(&cx->gpio_lock);
|
||||
cx->gpio_val = cx->gpio_val & ~p->ir_reset_mask;
|
||||
gpio_write(cx);
|
||||
mutex_unlock(&cx->gpio_lock);
|
||||
schedule_timeout_uninterruptible(msecs_to_jiffies(p->msecs_asserted));
|
||||
|
||||
/*
|
||||
Zilog comes out of reset, loads reset vector address and executes
|
||||
from there. Required recovery delay unknown.
|
||||
*/
|
||||
mutex_lock(&cx->gpio_lock);
|
||||
cx->gpio_val = cx->gpio_val | p->ir_reset_mask;
|
||||
gpio_write(cx);
|
||||
mutex_unlock(&cx->gpio_lock);
|
||||
schedule_timeout_uninterruptible(msecs_to_jiffies(p->msecs_recovery));
|
||||
}
|
||||
EXPORT_SYMBOL(cx18_reset_ir_gpio);
|
||||
/* This symbol is exported for use by an infrared module for the IR-blaster */
|
||||
|
||||
void cx18_gpio_init(struct cx18 *cx)
|
||||
{
|
||||
mutex_lock(&cx->gpio_lock);
|
||||
cx->gpio_dir = cx->card->gpio_init.direction;
|
||||
cx->gpio_val = cx->card->gpio_init.initial_value;
|
||||
|
||||
@ -91,14 +135,17 @@ void cx18_gpio_init(struct cx18 *cx)
|
||||
cx->gpio_val |= 1 << cx->card->xceive_pin;
|
||||
}
|
||||
|
||||
if (cx->gpio_dir == 0)
|
||||
if (cx->gpio_dir == 0) {
|
||||
mutex_unlock(&cx->gpio_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
CX18_DEBUG_INFO("GPIO initial dir: %08x/%08x out: %08x/%08x\n",
|
||||
read_reg(CX18_REG_GPIO_DIR1), read_reg(CX18_REG_GPIO_DIR2),
|
||||
read_reg(CX18_REG_GPIO_OUT1), read_reg(CX18_REG_GPIO_OUT2));
|
||||
|
||||
gpio_write(cx);
|
||||
mutex_unlock(&cx->gpio_lock);
|
||||
}
|
||||
|
||||
/* Xceive tuner reset function */
|
||||
@ -112,13 +159,52 @@ int cx18_reset_tuner_gpio(void *dev, int cmd, int value)
|
||||
return 0;
|
||||
CX18_DEBUG_INFO("Resetting tuner\n");
|
||||
|
||||
mutex_lock(&cx->gpio_lock);
|
||||
cx->gpio_val &= ~(1 << cx->card->xceive_pin);
|
||||
|
||||
gpio_write(cx);
|
||||
mutex_unlock(&cx->gpio_lock);
|
||||
schedule_timeout_interruptible(msecs_to_jiffies(1));
|
||||
|
||||
mutex_lock(&cx->gpio_lock);
|
||||
cx->gpio_val |= 1 << cx->card->xceive_pin;
|
||||
gpio_write(cx);
|
||||
mutex_unlock(&cx->gpio_lock);
|
||||
schedule_timeout_interruptible(msecs_to_jiffies(1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cx18_gpio(struct cx18 *cx, unsigned int command, void *arg)
|
||||
{
|
||||
struct v4l2_routing *route = arg;
|
||||
u32 mask, data;
|
||||
|
||||
switch (command) {
|
||||
case VIDIOC_INT_S_AUDIO_ROUTING:
|
||||
if (route->input > 2)
|
||||
return -EINVAL;
|
||||
mask = cx->card->gpio_audio_input.mask;
|
||||
switch (route->input) {
|
||||
case 0:
|
||||
data = cx->card->gpio_audio_input.tuner;
|
||||
break;
|
||||
case 1:
|
||||
data = cx->card->gpio_audio_input.linein;
|
||||
break;
|
||||
case 2:
|
||||
default:
|
||||
data = cx->card->gpio_audio_input.radio;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
if (mask) {
|
||||
mutex_lock(&cx->gpio_lock);
|
||||
cx->gpio_val = (cx->gpio_val & ~mask) | (data & mask);
|
||||
gpio_write(cx);
|
||||
mutex_unlock(&cx->gpio_lock);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -22,4 +22,6 @@
|
||||
|
||||
void cx18_gpio_init(struct cx18 *cx);
|
||||
void cx18_reset_i2c_slaves_gpio(struct cx18 *cx);
|
||||
void cx18_reset_ir_gpio(void *data);
|
||||
int cx18_reset_tuner_gpio(void *dev, int cmd, int value);
|
||||
int cx18_gpio(struct cx18 *cx, unsigned int command, void *arg);
|
||||
|
@ -39,10 +39,6 @@
|
||||
#define GETSCL_BIT 0x0004
|
||||
#define GETSDL_BIT 0x0008
|
||||
|
||||
#ifndef I2C_ADAP_CLASS_TV_ANALOG
|
||||
#define I2C_ADAP_CLASS_TV_ANALOG I2C_CLASS_TV_ANALOG
|
||||
#endif
|
||||
|
||||
#define CX18_CS5345_I2C_ADDR 0x4c
|
||||
|
||||
/* This array should match the CX18_HW_ defines */
|
||||
@ -311,8 +307,12 @@ int cx18_i2c_hw(struct cx18 *cx, u32 hw, unsigned int cmd, void *arg)
|
||||
{
|
||||
int addr;
|
||||
|
||||
if (hw == CX18_HW_GPIO || hw == 0)
|
||||
if (hw == 0)
|
||||
return 0;
|
||||
|
||||
if (hw == CX18_HW_GPIO)
|
||||
return cx18_gpio(cx, cmd, arg);
|
||||
|
||||
if (hw == CX18_HW_CX23418)
|
||||
return cx18_av_cmd(cx, cmd, arg);
|
||||
|
||||
@ -350,6 +350,8 @@ void cx18_call_i2c_clients(struct cx18 *cx, unsigned int cmd, void *arg)
|
||||
cx18_av_cmd(cx, cmd, arg);
|
||||
i2c_clients_command(&cx->i2c_adap[0], cmd, arg);
|
||||
i2c_clients_command(&cx->i2c_adap[1], cmd, arg);
|
||||
if (cx->hw_flags & CX18_HW_GPIO)
|
||||
cx18_gpio(cx, cmd, arg);
|
||||
}
|
||||
|
||||
/* init + register i2c algo-bit adapter */
|
||||
@ -358,6 +360,18 @@ int init_cx18_i2c(struct cx18 *cx)
|
||||
int i;
|
||||
CX18_DEBUG_I2C("i2c init\n");
|
||||
|
||||
/* Sanity checks for the I2C hardware arrays. They must be the
|
||||
* same size and GPIO/CX23418 must be the last entries.
|
||||
*/
|
||||
if (ARRAY_SIZE(hw_driverids) != ARRAY_SIZE(hw_addrs) ||
|
||||
ARRAY_SIZE(hw_devicenames) != ARRAY_SIZE(hw_addrs) ||
|
||||
CX18_HW_GPIO != (1 << (ARRAY_SIZE(hw_addrs) - 2)) ||
|
||||
CX18_HW_CX23418 != (1 << (ARRAY_SIZE(hw_addrs) - 1)) ||
|
||||
hw_driverids[ARRAY_SIZE(hw_addrs) - 1]) {
|
||||
CX18_ERR("Mismatched I2C hardware arrays\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
memcpy(&cx->i2c_adap[i], &cx18_i2c_adap_template,
|
||||
sizeof(struct i2c_adapter));
|
||||
@ -391,6 +405,7 @@ int init_cx18_i2c(struct cx18 *cx)
|
||||
write_reg_sync(0x00c000c0, 0xc7001c);
|
||||
mdelay(10);
|
||||
write_reg_sync(0x00c00000, 0xc7001c);
|
||||
mdelay(10);
|
||||
|
||||
write_reg_sync(0x00c00000, 0xc730c8); /* Set to edge-triggered intrs. */
|
||||
write_reg_sync(0x00c00000, 0xc730c4); /* Clear any stale intrs */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -24,7 +24,9 @@
|
||||
u16 cx18_service2vbi(int type);
|
||||
void cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal);
|
||||
u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt);
|
||||
void cx18_set_funcs(struct video_device *vdev);
|
||||
int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std);
|
||||
int cx18_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf);
|
||||
int cx18_s_input(struct file *file, void *fh, unsigned int inp);
|
||||
int cx18_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
|
||||
unsigned long arg);
|
||||
int cx18_v4l2_ioctls(struct cx18 *cx, struct file *filp, unsigned cmd,
|
||||
void *arg);
|
||||
|
@ -81,6 +81,7 @@ static const struct cx18_api_info api_info[] = {
|
||||
API_ENTRY(CPU, CX18_CPU_GET_ENC_PTS, 0),
|
||||
API_ENTRY(CPU, CX18_CPU_DE_SET_MDL_ACK, 0),
|
||||
API_ENTRY(CPU, CX18_CPU_DE_SET_MDL, API_FAST),
|
||||
API_ENTRY(CPU, CX18_APU_RESETAI, API_FAST),
|
||||
API_ENTRY(0, 0, 0),
|
||||
};
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user