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:
Linus Torvalds 2008-07-20 21:14:42 -07:00
commit f894d18380
290 changed files with 47638 additions and 5412 deletions

View File

@ -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]

View File

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

View File

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

View File

@ -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.

View 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

View File

@ -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.

View File

@ -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:
*/

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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/

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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.

View File

@ -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.

View File

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

View 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");

View 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
----------------------------------------------------------------------------
*/

View File

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

View File

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

View File

@ -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,

View File

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

View File

@ -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,

View File

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

View File

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

View File

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

View File

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

View File

@ -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 {

View File

@ -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,
};
/* ----------------------------------------------------------- */

View File

@ -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.

View File

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

View File

@ -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 {

View File

@ -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 {

View File

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

View File

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

View File

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

View 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/>.

View 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)

View 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];
}

View 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__ */

File diff suppressed because it is too large Load Diff

View 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__ */

View 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, &params, &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);
}

View 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(&params, 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(&params, &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);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View 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)

View File

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

View File

@ -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,
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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/

View File

@ -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 */

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 */

View File

@ -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,

View File

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

View File

@ -173,4 +173,3 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.probe = cs5345_probe,
.id_table = cs5345_id,
};

View File

@ -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,
};

View File

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

View File

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

View File

@ -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:

View File

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

View File

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

View File

@ -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 */

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 */

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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